From b41d9752095ca2a5d199889e703027e163a6f225 Mon Sep 17 00:00:00 2001 From: Hangzhi Yu <hangzhi@protonmail.com> Date: Tue, 20 Aug 2024 11:38:26 +0200 Subject: [PATCH] Add status-based handling of notifications --- .../migrations/0018_add_lessoneventalarm.py | 3 +- aleksis/apps/chronos/models.py | 58 ++++++++++++++++--- .../lesson_event_notification_description.txt | 1 + .../lesson_event_notification_title.txt | 1 + 4 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 aleksis/apps/chronos/templates/chronos/lesson_event_notification_description.txt create mode 100644 aleksis/apps/chronos/templates/chronos/lesson_event_notification_title.txt diff --git a/aleksis/apps/chronos/migrations/0018_add_lessoneventalarm.py b/aleksis/apps/chronos/migrations/0018_add_lessoneventalarm.py index b813aa84..dd44633e 100644 --- a/aleksis/apps/chronos/migrations/0018_add_lessoneventalarm.py +++ b/aleksis/apps/chronos/migrations/0018_add_lessoneventalarm.py @@ -8,7 +8,7 @@ class Migration(migrations.Migration): dependencies = [ ('chronos', '0017_optional_slot_number'), - ('core', '0066_alter_freebusy_options_and_more'), + ('core', '0066_add_calendar_alarm'), ] operations = [ @@ -16,6 +16,7 @@ class Migration(migrations.Migration): name='LessonEventAlarm', fields=[ ('calendaralarm_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.calendaralarm')), + ('status', models.CharField(choices=[('c', 'Created'), ('e', 'Edited'), ('d', 'Deleted')], default='c', max_length=1, verbose_name='Status')), ], options={ 'verbose_name': 'Lesson event alarm', diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py index 25a16143..98a3ef9e 100644 --- a/aleksis/apps/chronos/models.py +++ b/aleksis/apps/chronos/models.py @@ -1359,10 +1359,10 @@ class LessonEvent(CalendarEvent): @property def all_teachers(self: LessonEvent) -> list[Person]: """Get list of all teachers for this lesson event.""" - all_teachers = list(self.teachers.all()) + all_teachers = self.teachers.all() if self.amends: - all_teachers += list(self.amends.teachers.all()) - return all_teachers + all_teachers = all_teachers.union(self.amends.teachers.all()) + return list(all_teachers) @property def group_names(self: LessonEvent) -> str: @@ -1589,11 +1589,26 @@ class LessonEvent(CalendarEvent): return objs def save(self, *args, **kwargs): + adding_status = self._state.adding + super().save(*args, **kwargs) # Save alarm in lesson event alarm model if self.amends: - alarm, created = LessonEventAlarm.objects.get_or_create(event=self, defaults={"send_notifications": True}) + if adding_status: + # TODO: allow for generating multiple alarms for one event + alarm = LessonEventAlarm(event=self, send_notifications=True) + alarm.save() + else: + alarms = LessonEventAlarm.objects.filter(event=self, status="c") + for alarm in alarms: + if alarm.notifications.filter(sent=True).exists(): + follow_up_alarm = LessonEventAlarm( + event=self, send_notifications=True, status="e" + ) + follow_up_alarm.save() + else: + alarm.update_or_create_notifications() class Meta: verbose_name = _("Lesson Event") @@ -1603,11 +1618,16 @@ class LessonEvent(CalendarEvent): class LessonEventAlarm(CalendarAlarm): """Alarm model for lesson events.""" + STATUS_CHOICES = {"c": _("Created"), "e": _("Edited"), "d": _("Deleted")} + + status = models.CharField( + verbose_name=_("Status"), max_length=1, choices=STATUS_CHOICES, default="c" + ) + def value_description(self, request: HttpRequest | None = None) -> str: return LessonEvent.value_title(self.event) - def value_trigger(self, request: HttpRequest | None = None) -> Union[datetime, timedelta]: - # question: allow for generating multiple alarms for one event? + def value_trigger(self, request: HttpRequest | None = None) -> datetime | timedelta: if "fixed_time_relative" in get_site_preferences()["chronos__alarm_trigger_mode"]: return ( self.event.datetime_start @@ -1618,15 +1638,37 @@ class LessonEventAlarm(CalendarAlarm): ) elif "strictly_relative" in get_site_preferences()["chronos__alarm_trigger_mode"]: return get_site_preferences()["chronos__time_in_advance_alarms"] - + def value_notification_sender(self, request: HttpRequest | None = None) -> str: return _("Lesson notification") def value_notification_recipients(self, request: HttpRequest | None = None) -> [Person]: return self.event.all_teachers + def value_notification_title(self, request: HttpRequest | None = None) -> str: + return render_to_string( + "chronos/lesson_event_notification_title.txt", + { + "event": self.event, + "event_title": LessonEvent.value_title(self.event, request), + "status": self.STATUS_CHOICES[self.status].lower(), + }, + ) + def value_notification_description(self, request: HttpRequest | None = None) -> str: - return _("bliblablubb") + # FIXME: In some (?) cases, this is incomplete (e.g. room names are missing) + return render_to_string( + "chronos/lesson_event_notification_description.txt", + {"event": self.event, "status": self.STATUS_CHOICES[self.status].lower()}, + ) + + def value_notification_icon(self, request: HttpRequest | None = None) -> str: + return "calendar-remove-outline" if self.event.cancelled else "calendar-alert-outline" + + # TODO: how to get fitting link (from vue-router)? + # TODO: timetable overview page needs to be fitted so that CW is specified + # def value_notification_link(self, request: HttpRequest | None = None) -> str: + # raise NotImplementedError() class Meta: verbose_name = _("Lesson event alarm") diff --git a/aleksis/apps/chronos/templates/chronos/lesson_event_notification_description.txt b/aleksis/apps/chronos/templates/chronos/lesson_event_notification_description.txt new file mode 100644 index 00000000..308e1677 --- /dev/null +++ b/aleksis/apps/chronos/templates/chronos/lesson_event_notification_description.txt @@ -0,0 +1 @@ +{% load i18n %}{% with rooms=event.room_names_with_amends comment=event.comment %}{% trans "Groups" %}: {{ event.group_names|default:"–" }}{% if event.subject or event.amends and event.amends.subject %} · {% trans "Subject" %}: {{ event.subject_name_with_amends }}{% endif %} · {% trans "Teachers" %}: {{ event.teacher_names_with_amends|default:"–" }}{% if rooms %} · {% trans "Rooms" %}: {{ rooms }}{% endif %}{% if comment %} · {{ comment }}{% endif %}{% endwith %} diff --git a/aleksis/apps/chronos/templates/chronos/lesson_event_notification_title.txt b/aleksis/apps/chronos/templates/chronos/lesson_event_notification_title.txt new file mode 100644 index 00000000..298f4052 --- /dev/null +++ b/aleksis/apps/chronos/templates/chronos/lesson_event_notification_title.txt @@ -0,0 +1 @@ +{% load i18n %}{% trans "Lesson" %}{% if event.amends %} {% if event.cancelled %}{% trans "cancellation" %}{% else %}{% trans "substitution" %}{% endif %}{% endif %} {{ status }}: {{ event.datetime_start|date:"SHORT_DATETIME_FORMAT" }} - {{ event.datetime_end|date:"SHORT_DATETIME_FORMAT" }} · {{ event.group_names }} -- GitLab