Skip to content
Snippets Groups Projects
Verified Commit 6cbc7db6 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Setup basic infrastructure for calendar events and iCal feeds

parent 4160245a
No related branches found
No related tags found
1 merge request!1148Calendar events and iCal feeds
......@@ -22,6 +22,7 @@ from django.views.generic import CreateView, UpdateView
from django.views.generic.edit import DeleteView, ModelFormMixin
import reversion
from django_ical.feedgenerator import ITEM_EVENT_FIELD_MAP, ICal20Feed
from dynamic_preferences.settings import preferences_settings
from dynamic_preferences.types import FilePreference
from guardian.admin import GuardedModelAdmin
......@@ -575,3 +576,74 @@ class RegistryObject:
@classmethod
def get_object_by_name(cls, name):
cls.registered_objects_dict.get(name)
class CalendarEventMixin(RegistryObject):
name: str = "" # The source name
verbose_name: str = "" # The shown name of the feed
link: str = ""
description: str = ""
@classmethod
def get_verbose_name(cls):
return cls.verbose_name
@classmethod
def get_link(cls):
return cls.link
@classmethod
def get_description(cls):
return cls.description
@classmethod
def get_language(cls):
return "en" # FIXME
@classmethod
def create_event(cls, reference_object, feed: ICal20Feed):
values = {}
for field in cls.get_event_field_names():
field_value = cls.get_event_field_value(reference_object, field)
if field_value is not None:
values[field] = field_value
feed.add_item(**values)
return values
@classmethod
def start_feed(cls):
feed = ICal20Feed(
title=cls.get_verbose_name(),
link=cls.get_link(),
description=cls.get_description(),
language=cls.get_language(),
)
return feed
@classmethod
def get_objects(cls):
raise NotImplementendError
@classmethod
def create_feed(cls):
feed = cls.start_feed()
for reference_object in cls.get_objects():
cls.create_event(reference_object, feed)
return feed
@classmethod
def get_event_field_names(cls):
return [field_map[0] for field_map in ITEM_EVENT_FIELD_MAP]
@classmethod
def get_event_field_value(cls, reference_object, field_name):
method_name = f"value_{field_name}"
if hasattr(cls, method_name) and callable(getattr(cls, method_name)):
return getattr(cls, method_name)(reference_object)
return None
@classmethod
def value_link(cls, reference_object):
return ""
......@@ -22,6 +22,7 @@ from django.dispatch import receiver
from django.forms.widgets import Media
from django.urls import reverse
from django.utils import timezone
from django.utils.formats import date_format
from django.utils.functional import classproperty
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
......@@ -35,6 +36,7 @@ from celery_progress.backend import Progress
from ckeditor.fields import RichTextField
from django_celery_results.models import TaskResult
from django_cte import CTEQuerySet, With
from django_ical.utils import build_rrule_from_text
from dynamic_preferences.models import PerInstancePreferenceModel
from invitations import signals
from invitations.adapters import get_invitations_adapter
......@@ -51,6 +53,7 @@ from oauth2_provider.models import (
)
from phonenumber_field.modelfields import PhoneNumberField
from polymorphic.models import PolymorphicModel
from recurrence.fields import RecurrenceField
from aleksis.core.data_checks import (
BrokenDashboardWidgetDataCheck,
......@@ -67,7 +70,9 @@ from .managers import (
UninstallRenitentPolymorphicManager,
)
from .mixins import (
CalendarEventMixin,
ExtensibleModel,
ExtensiblePolymorphicModel,
GlobalPermissionModel,
PureDjangoModel,
RegistryObject,
......@@ -1455,3 +1460,67 @@ class Room(ExtensibleModel):
fields=["site_id", "short_name"], name="unique_room_short_name_per_site"
),
]
class CalendarEvent(CalendarEventMixin, ExtensiblePolymorphicModel):
start = models.DateTimeField(verbose_name=_("Start date and time"))
end = models.DateTimeField(verbose_name=_("End date and time"))
recurrences = RecurrenceField(verbose_name=_("Recurrences"), null=True, blank=True)
ammends = models.ForeignKey(
"self",
on_delete=models.CASCADE,
null=True,
blank=True,
verbose_name=_("Ammended base event"),
)
@classmethod
def value_title(cls, self):
raise NotImplementedError()
@classmethod
def value_start_datetime(cls, self):
return self.start
@classmethod
def value_end_datetime(cls, self):
return self.end
@classmethod
def get_objects(cls):
# FIXME Polymorphic only this one!!
return cls.objects.all()
class Meta:
verbose_name = _("Calendar Event")
verbose_name_plural = _("Calendar Events")
class BirthdayEvent(CalendarEventMixin):
name = "birthdays"
verbose_name = _("Birthdays")
@classmethod
def value_title(cls, reference_object):
return _("{}'s birthday").format(reference_object.addressing_name)
@classmethod
def value_description(cls, reference_object):
return ("{name} was born on {birthday}.").format(
name=reference_object.addressing_name,
birthday=date_format(reference_object.date_of_birth),
)
@classmethod
def value_start_datetime(cls, reference_object):
return reference_object.date_of_birth
@classmethod
def value_rrule(cls, reference_object):
return build_rrule_from_text("FREQ=YEARLY")
@classmethod
def get_objects(cls):
qs = Person.objects.filter(date_of_birth__isnull=False)
# FIXME FILTER PERMISSIONS but without queryset_ruk
return qs
......@@ -151,6 +151,7 @@ INSTALLED_APPS = [
"rest_framework",
"graphene_django",
"dj_iconify.apps.DjIconifyConfig",
"recurrence",
]
merge_app_settings("INSTALLED_APPS", INSTALLED_APPS, True)
......
......@@ -127,6 +127,8 @@ customidenticon = "^0.1.5"
graphene-django = "^3.0.0"
selenium = "^4.4.3"
django-vite = "^2.0.2"
django-ical = "^1.8.3"
django-recurrence = "^1.11.1"
[tool.poetry.extras]
ldap = ["django-auth-ldap"]
......
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