diff --git a/ephios/core/forms/events.py b/ephios/core/forms/events.py index e55e578fe..b9ffa5965 100644 --- a/ephios/core/forms/events.py +++ b/ephios/core/forms/events.py @@ -300,3 +300,26 @@ def clean(self): ): raise ValidationError(_("You cannot send an empty mail.")) return super().clean() + + +class EventCancellationForm(forms.Form): + explanation = forms.CharField( + required=False, + widget=forms.Textarea, + label=_("Explanation"), + help_text=_( + "All participants will be notified about the cancellation and this message will be included." + ), + ) + + def __init__(self, *args, **kwargs): + self.event = kwargs.pop("event") + super().__init__(*args, **kwargs) + self.helper = FormHelper(self) + self.helper.layout = Layout( + Field("explanation"), + FormActions( + Submit("submit", _("Cancel event"), css_class="float-end"), + AbortLink(href=self.event.get_absolute_url()), + ), + ) diff --git a/ephios/core/services/notifications/types.py b/ephios/core/services/notifications/types.py index ce798d492..8a399cb5c 100644 --- a/ephios/core/services/notifications/types.py +++ b/ephios/core/services/notifications/types.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Optional from urllib.parse import urljoin from django.conf import settings @@ -497,6 +497,48 @@ def as_plaintext(cls, notification): return notification.data.get("content") +class EventCancellationNotification(AbstractNotificationHandler): + slug = "ephios_event_cancellation" + title = _("An event has been cancelled") + unsubscribe_allowed = False + + @classmethod + def send(cls, event: Event, explanation: Optional[str]): + participants = set() + for shift in event.shifts.all(): + participants.update(shift.get_participants()) + notifications = [] + for participant in participants: + notifications.append( + Notification( + slug=cls.slug, + data={ + "email": participant.email, + "event_title": event.title, + "start_time": date_format(event.get_start_time(), "SHORT_DATETIME_FORMAT"), + "end_time": date_format(event.get_start_time(), "SHORT_DATETIME_FORMAT"), + "explanation": explanation, + }, + ) + ) + Notification.objects.bulk_create(notifications) + + @classmethod + def get_subject(cls, notification): + return _("{title} has been cancelled").format(title=notification.data.get("event_title")) + + @classmethod + def as_plaintext(cls, notification): + result = _("{title} ({start_time} - {end_time}) has been cancelled.").format( + title=notification.data.get("event_title"), + start_time=notification.data.get("start_time"), + end_time=notification.data.get("end_time"), + ) + if explanation := notification.data.get("explanation"): + result += _(" Further information:\n{explanation}").format(explanation=explanation) + return result + + class ConsequenceApprovedNotification(AbstractNotificationHandler): slug = "ephios_consequence_approved" title = _("Your request has been approved") @@ -549,6 +591,7 @@ def as_plaintext(cls, notification): NewEventNotification, EventReminderNotification, CustomEventParticipantNotification, + EventCancellationNotification, ConsequenceApprovedNotification, ConsequenceDeniedNotification, ] diff --git a/ephios/core/templates/core/event_cancellation.html b/ephios/core/templates/core/event_cancellation.html new file mode 100644 index 000000000..848305403 --- /dev/null +++ b/ephios/core/templates/core/event_cancellation.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% load crispy_forms_tags %} +{% load i18n %} + +{% block title %} + {% translate "Cancel event" %} +{% endblock %} + +{% block content %} +