Skip to content
Snippets Groups Projects
Commit 71e07c06 authored by Nadja Geisler's avatar Nadja Geisler :sunny:
Browse files

WIP: enable availability selection for AKs

availabilities in AK submission
availabilities in AK wish submission
parent 55f5ee2d
No related branches found
No related tags found
No related merge requests found
Showing
with 236 additions and 36 deletions
......@@ -6,7 +6,7 @@ from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from simple_history.admin import SimpleHistoryAdmin
from AKModel.availability import Availability
from AKModel.availability.models import Availability
from AKModel.models import Event, AKOwner, AKCategory, AKTrack, AKTag, AKRequirement, AK, AKSlot, Room
......
# This part of the code was adapted from pretalx (https://github.com/pretalx/pretalx)
# Copyright 2017-2019, Tobias Kunze
# Original Copyrights licensed under the Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0
# Changes are marked in the code
import datetime
import json
from django import forms
from django.db import transaction
from django.utils.dateparse import parse_datetime
from django.utils.translation import gettext_lazy as _
from AKModel.availability.models import Availability
from AKModel.availability.serializers import AvailabilitySerializer
from AKModel.models import Event
class AvailabilitiesFormMixin(forms.Form):
availabilities = forms.CharField(
label=_('Availability'),
help_text=_(
'Please click and drag to mark the availability during the event.'
),
widget=forms.TextInput(attrs={'class': 'availabilities-editor-data'}),
required=False,
)
def _serialize(self, event, instance):
if instance:
availabilities = AvailabilitySerializer(
instance.availabilities.all(), many=True
).data
else:
availabilities = []
return json.dumps(
{
'availabilities': availabilities,
'event': {
# 'timezone': event.timezone,
'date_from': str(event.start),
'date_to': str(event.end),
},
}
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.event = self.initial.get('event')
if isinstance(self.event, int):
self.event = Event.objects.get(pk=self.event)
initial = kwargs.pop('initial', dict())
initial['availabilities'] = self._serialize(self.event, kwargs['instance'])
if not isinstance(self, forms.BaseModelForm):
kwargs.pop('instance')
kwargs['initial'] = initial
def _parse_availabilities_json(self, jsonavailabilities):
try:
rawdata = json.loads(jsonavailabilities)
except ValueError:
raise forms.ValidationError("Submitted availabilities are not valid json.")
if not isinstance(rawdata, dict):
raise forms.ValidationError(
"Submitted json does not comply with expected format, should be object."
)
availabilities = rawdata.get('availabilities')
if not isinstance(availabilities, list):
raise forms.ValidationError(
"Submitted json does not comply with expected format, missing or malformed availabilities field"
)
return availabilities
def _parse_datetime(self, strdate):
tz = self.event.timezone # adapt to our event model
obj = parse_datetime(strdate)
if not obj:
raise TypeError
if obj.tzinfo is None:
obj = tz.localize(obj)
return obj
def _validate_availability(self, rawavail):
message = _("The submitted availability does not comply with the required format.")
if not isinstance(rawavail, dict):
raise forms.ValidationError(message)
rawavail.pop('id', None)
rawavail.pop('allDay', None)
if not set(rawavail.keys()) == {'start', 'end'}:
raise forms.ValidationError(message)
try:
rawavail['start'] = self._parse_datetime(rawavail['start'])
rawavail['end'] = self._parse_datetime(rawavail['end'])
except (TypeError, ValueError):
raise forms.ValidationError(
_("The submitted availability contains an invalid date.")
)
tz = self.event.timezone # adapt to our event model
timeframe_start = self.event.start # adapt to our event model
if rawavail['start'] < timeframe_start:
rawavail['start'] = timeframe_start
# add 1 day, not 24 hours, https://stackoverflow.com/a/25427822/2486196
timeframe_end = self.event.end # adapt to our event model
timeframe_end = timeframe_end + datetime.timedelta(days=1)
if rawavail['end'] > timeframe_end:
# If the submitted availability ended outside the event timeframe, fix it silently
rawavail['end'] = timeframe_end
def clean_availabilities(self):
data = self.cleaned_data.get('availabilities')
required = (
'availabilities' in self.fields and self.fields['availabilities'].required
)
if not data:
if required:
raise forms.ValidationError(_('Please fill in your availabilities!'))
return None
rawavailabilities = self._parse_availabilities_json(data)
availabilities = []
for rawavail in rawavailabilities:
self._validate_availability(rawavail)
availabilities.append(Availability(event_id=self.event.id, **rawavail))
if not availabilities and required:
raise forms.ValidationError(_('Please fill in your availabilities!'))
return availabilities
def _set_foreignkeys(self, instance, availabilities):
"""Set the reference to `instance` in each given availability.
For example, set the availabilitiy.room_id to instance.id, in
case instance of type Room.
"""
reference_name = instance.availabilities.field.name + '_id'
for avail in availabilities:
setattr(avail, reference_name, instance.id)
def _replace_availabilities(self, instance, availabilities):
with transaction.atomic():
# TODO: do not recreate objects unnecessarily, give the client the IDs, so we can track modifications and leave unchanged objects alone
instance.availabilities.all().delete()
Availability.objects.bulk_create(availabilities)
def save(self, *args, **kwargs):
instance = super().save(*args, **kwargs)
availabilities = self.cleaned_data.get('availabilities')
if availabilities is not None:
self._set_foreignkeys(instance, availabilities)
self._replace_availabilities(instance, availabilities)
return instance # adapt to our forms
File moved
# This part of the code was adapted from pretalx (https://github.com/pretalx/pretalx)
# Copyright 2017-2019, Tobias Kunze
# Original Copyrights licensed under the Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0
# Changes are marked in the code
from rest_framework.fields import SerializerMethodField
from rest_framework.serializers import ModelSerializer
from AKModel.availability.models import Availability
class AvailabilitySerializer(ModelSerializer):
allDay = SerializerMethodField()
def get_allDay(self, obj):
return obj.all_day
class Meta:
model = Availability
fields = ('id', 'start', 'end', 'allDay')
......@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-12 22:53+0000\n"
"POT-Creation-Date: 2020-05-14 22:48+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -27,55 +27,73 @@ msgstr "Ist kein Wunsch"
msgid "Export to wiki syntax"
msgstr "In Wiki-Syntax exportieren"
#: AKModel/availability.py:38 AKModel/models.py:40 AKModel/models.py:69
#: AKModel/availability/forms.py:20 AKModel/availability/models.py:235
msgid "Availability"
msgstr "Verfügbarkeit"
#: AKModel/availability/forms.py:22
msgid "Please click and drag to mark the availability during the event."
msgstr "Bitte klicken und ziehen um die Verfügbarkeiten während des Events zu markieren."
#: AKModel/availability/forms.py:86
msgid "The submitted availability does not comply with the required format."
msgstr "Die eingetragenen Verfügbarkeit haben nicht das notwendige Format."
#: AKModel/availability/forms.py:99
msgid "The submitted availability contains an invalid date."
msgstr "Die eingegebene Verfügbarkeit enthält ein ungültiges Datum."
#: AKModel/availability/forms.py:122 AKModel/availability/forms.py:132
msgid "Please fill in your availabilities!"
msgstr "Bitte Verfügbarkeiten eintragen!"
#: AKModel/availability/models.py:38 AKModel/models.py:40 AKModel/models.py:69
#: AKModel/models.py:121 AKModel/models.py:140 AKModel/models.py:172
#: AKModel/models.py:225 AKModel/models.py:267 AKModel/models.py:297
msgid "Event"
msgstr "Event"
#: AKModel/availability.py:39 AKModel/models.py:70 AKModel/models.py:122
#: AKModel/availability/models.py:39 AKModel/models.py:70 AKModel/models.py:122
#: AKModel/models.py:141 AKModel/models.py:173 AKModel/models.py:226
#: AKModel/models.py:268 AKModel/models.py:298
msgid "Associated event"
msgstr "Zugehöriges Event"
#: AKModel/availability.py:47
#: AKModel/availability/models.py:47
msgid "Person"
msgstr "Person"
#: AKModel/availability.py:48
#: AKModel/availability/models.py:48
msgid "Person whose availability this is"
msgstr "Person deren Verfügbarkeit hier abgebildet wird"
#: AKModel/availability.py:56 AKModel/models.py:271 AKModel/models.py:290
#: AKModel/availability/models.py:56 AKModel/models.py:271
#: AKModel/models.py:290
msgid "Room"
msgstr "Raum"
#: AKModel/availability.py:57
#: AKModel/availability/models.py:57
msgid "Room whose availability this is"
msgstr "Raum dessen Verfügbarkeit hier abgebildet wird"
#: AKModel/availability.py:65 AKModel/models.py:231 AKModel/models.py:289
#: AKModel/availability/models.py:65 AKModel/models.py:231
#: AKModel/models.py:289
msgid "AK"
msgstr "AK"
#: AKModel/availability.py:66
#: AKModel/availability/models.py:66
msgid "AK whose availability this is"
msgstr "Verfügbarkeiten"
#: AKModel/availability.py:74 AKModel/models.py:125
#: AKModel/availability/models.py:74 AKModel/models.py:125
msgid "AK Category"
msgstr "AK Kategorie"
#: AKModel/availability.py:75
#: AKModel/availability/models.py:75
msgid "AK Category whose availability this is"
msgstr "AK Kategorie dessen Verfügbarkeit hier abgebildet wird"
#: AKModel/availability.py:235
msgid "Availability"
msgstr "Verfügbarkeit"
#: AKModel/availability.py:236
#: AKModel/availability/models.py:236
msgid "Availabilities"
msgstr "Verfügbarkeiten"
......
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-11 22:27+0000\n"
"POT-Creation-Date: 2020-05-14 22:48+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -21,10 +21,6 @@ msgstr ""
msgid "Write to organizers of this event for questions and comments"
msgstr "Fragen oder Kommentare? Schreib den Orgas dieses Events eine Mail"
#: AKPlan/templates/AKPlan/plan_breadcrumbs.html:13
msgid "AK Plan"
msgstr "AK-Plan"
#: AKPlan/templates/AKPlan/plan_index.html:40
msgid "Day"
msgstr "Tag"
......@@ -34,42 +30,48 @@ msgid "Event"
msgstr "Veranstaltung"
#: AKPlan/templates/AKPlan/plan_index.html:59
#: AKPlan/templates/AKPlan/plan_room.html:8
#: AKPlan/templates/AKPlan/plan_room.html:44
#: AKPlan/templates/AKPlan/plan_room.html:11
#: AKPlan/templates/AKPlan/plan_room.html:46
#: AKPlan/templates/AKPlan/plan_wall.html:64
msgid "Room"
msgstr "Raum"
#: AKPlan/templates/AKPlan/plan_index.html:82
#: AKPlan/templates/AKPlan/plan_room.html:34
#: AKPlan/templates/AKPlan/plan_index.html:74
#: AKPlan/templates/AKPlan/plan_room.html:9
#: AKPlan/templates/AKPlan/plan_track.html:9
msgid "AK Plan"
msgstr "AK-Plan"
#: AKPlan/templates/AKPlan/plan_index.html:86
#: AKPlan/templates/AKPlan/plan_room.html:36
msgid "Rooms"
msgstr "Räume"
#: AKPlan/templates/AKPlan/plan_index.html:94
#: AKPlan/templates/AKPlan/plan_track.html:34
#: AKPlan/templates/AKPlan/plan_index.html:99
#: AKPlan/templates/AKPlan/plan_track.html:36
msgid "Tracks"
msgstr "Tracks"
#: AKPlan/templates/AKPlan/plan_index.html:106
#: AKPlan/templates/AKPlan/plan_index.html:111
msgid "AK Wall"
msgstr "AK-Wall"
#: AKPlan/templates/AKPlan/plan_index.html:118
#: AKPlan/templates/AKPlan/plan_index.html:123
#: AKPlan/templates/AKPlan/plan_wall.html:88
msgid "Current AKs"
msgstr "Aktuelle AKs"
#: AKPlan/templates/AKPlan/plan_index.html:125
#: AKPlan/templates/AKPlan/plan_index.html:130
#: AKPlan/templates/AKPlan/plan_wall.html:93
msgid "Next AKs"
msgstr "Nächste AKs"
#: AKPlan/templates/AKPlan/plan_index.html:133
#: AKPlan/templates/AKPlan/plan_index.html:138
msgid "This event is not active."
msgstr "Dieses Event ist nicht aktiv."
#: AKPlan/templates/AKPlan/plan_track.html:8
#: AKPlan/templates/AKPlan/plan_track.html:44
#: AKPlan/templates/AKPlan/plan_track.html:11
#: AKPlan/templates/AKPlan/plan_track.html:46
msgid "Track"
msgstr "Track"
......
......@@ -3,9 +3,11 @@
// ../../../../../@fullcalendar/core
declare module '@fullcalendar/bootstrap' {
import { Theme } from '@fullcalendar/core';
import {Theme} from '@fullcalendar/core';
export class BootstrapTheme extends Theme {
}
const _default: import("@fullcalendar/core").PluginDef;
export default _default;
}
......
......@@ -4,7 +4,7 @@ Docs & License: https://fullcalendar.io/
(c) 2019 Adam Shaw
*/
import { createPlugin, Theme } from '@fullcalendar/core';
import {createPlugin, Theme} from '@fullcalendar/core';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment