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

Merge branch 'availability' into 'master'

Availability

Closes #38 and #12

See merge request kif/akplanning!36
parents 55f5ee2d 71e07c06
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.
Finish editing this message first!
Please register or to comment