Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow for events to be cancelled #883

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions ephios/core/forms/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
),
)
45 changes: 44 additions & 1 deletion ephios/core/services/notifications/types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import List, Optional
from urllib.parse import urljoin

from django.conf import settings
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -549,6 +591,7 @@ def as_plaintext(cls, notification):
NewEventNotification,
EventReminderNotification,
CustomEventParticipantNotification,
EventCancellationNotification,
ConsequenceApprovedNotification,
ConsequenceDeniedNotification,
]
12 changes: 12 additions & 0 deletions ephios/core/templates/core/event_cancellation.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load i18n %}

{% block title %}
{% translate "Cancel event" %}
{% endblock %}

{% block content %}
<h1 class="page-header">{% blocktranslate %}Cancel event "{{ event }}"{% endblocktranslate %}</h1>
{% crispy form %}
{% endblock %}
6 changes: 6 additions & 0 deletions ephios/core/templates/core/event_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ <h1 class="card-title fw-bold fs-1">
<span class="fas fa-plus"></span>
{% trans "Add another shift" %}
</a></li>
<li><a class="dropdown-item"
href="{% url "core:event_cancel" event.pk %}">
<span class="fas fa-ban"></span>
{% translate "Cancel event" %}
</a>
</li>
<li><a class="dropdown-item"
href="{% url "core:event_delete" event.pk %}">
<span class="fas fa-trash-alt"></span>
Expand Down
2 changes: 2 additions & 0 deletions ephios/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from ephios.core.views.consequences import ConsequenceUpdateView
from ephios.core.views.event import (
EventActivateView,
EventCancellationView,
EventCopyView,
EventCreateView,
EventDeleteView,
Expand Down Expand Up @@ -99,6 +100,7 @@
name="event_notifications",
),
path("events/<int:pk>/pdf/", pdf.EventDetailPDFView.as_view(), name="event_detail_pdf"),
path("events/<int:pk>/cancel/", EventCancellationView.as_view(), name="event_cancel"),
path(
"events/<int:pk>/copy/",
EventCopyView.as_view(),
Expand Down
31 changes: 30 additions & 1 deletion ephios/core/views/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,16 @@
from recurrence.forms import RecurrenceField

from ephios.core.calendar import ShiftCalendar
from ephios.core.forms.events import EventDuplicationForm, EventForm, EventNotificationForm
from ephios.core.forms.events import (
EventCancellationForm,
EventDuplicationForm,
EventForm,
EventNotificationForm,
)
from ephios.core.models import AbstractParticipation, Event, EventType, Shift
from ephios.core.services.notifications.types import (
CustomEventParticipantNotification,
EventCancellationNotification,
EventReminderNotification,
NewEventNotification,
)
Expand Down Expand Up @@ -509,3 +515,26 @@ def form_valid(self, form):
CustomEventParticipantNotification.send(self.object, form.cleaned_data["mail_content"])
messages.success(self.request, _("Notifications sent succesfully."))
return redirect(self.object.get_absolute_url())


class EventCancellationView(CustomPermissionRequiredMixin, SingleObjectMixin, FormView):
model = Event
permission_required = "core.change_event"
template_name = "core/event_cancellation.html"
form_class = EventCancellationForm

def get_form_kwargs(self):
return {**super().get_form_kwargs(), "event": self.object}

def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.object = self.get_object()

def form_valid(self, form):
EventCancellationNotification.send(self.object, form.cleaned_data["explanation"])
event_title = self.object.title
self.object.delete()
messages.info(
self.request, _("Event {title} has been cancelled.").format(title=event_title)
)
return redirect(reverse("core:event_list"))