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

Add support for groups and persons as recipients for announcements

parent f63c1fe5
No related branches found
No related tags found
1 merge request!173Frontend based announcement management
Pipeline #982 failed
from datetime import time
from typing import Optional
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
......@@ -9,7 +11,7 @@ from django.utils.translation import ugettext_lazy as _
from django_select2.forms import ModelSelect2MultipleWidget, Select2Widget
from material import Layout, Fieldset, Row
from .models import Group, Person, School, SchoolTerm, Announcement
from .models import Group, Person, School, SchoolTerm, Announcement, AnnouncementRecipient
class PersonAccountForm(forms.ModelForm):
......@@ -149,26 +151,44 @@ class AnnouncementForm(forms.ModelForm):
valid_until_date = forms.DateField(label=_("Date"))
valid_until_time = forms.TimeField(label=_("Time"))
persons = forms.ModelMultipleChoiceField(Person.objects.all(), label=_("Persons"), required=False)
groups = forms.ModelMultipleChoiceField(Group.objects.all(), label=_("Groups"), required=False)
layout = Layout(
Fieldset(
_("From when until when should the announcement be displayed?"),
Row("valid_from_date", "valid_from_time", "valid_until_date", "valid_until_time"),
),
Fieldset(_("Who should see the announcement?"), Row("groups", "persons")),
Fieldset(_("Write your announcement:"), "title", "description"),
)
@classmethod
def get_initial(cls):
return {
"valid_from_date": timezone.datetime.now(),
"valid_from_time": time(0,0),
"valid_until_date": timezone.datetime.now(),
"valid_until_time": time(23, 59)
}
def __init__(self, *args, **kwargs):
if "instance" not in kwargs:
kwargs["initial"] = {
"valid_from_date": timezone.datetime.now(),
"valid_from_time": time(0, 0),
"valid_until_date": timezone.datetime.now(),
"valid_until_time": time(23, 59),
}
else:
announcement = kwargs["instance"]
# Fill special fields from given announcement instance
kwargs["initial"] = {
"valid_from_date": announcement.valid_from.date(),
"valid_from_time": announcement.valid_from.time(),
"valid_until_date": announcement.valid_until.date(),
"valid_until_time": announcement.valid_until.time(),
"groups": announcement.get_recipients_for_model(Group),
"persons": announcement.get_recipients_for_model(Person),
}
super().__init__(*args, **kwargs)
def clean(self):
data = super().clean()
# Check date and time
from_date = data["valid_from_date"]
from_time = data["valid_from_time"]
until_date = data["valid_until_date"]
......@@ -189,16 +209,31 @@ class AnnouncementForm(forms.ModelForm):
data["valid_from"] = valid_from
data["valid_until"] = valid_until
# Check recipients
if "groups" not in data and "persons" not in data:
raise ValidationError(_("You need at least one recipient."))
recipients = []
recipients += data.get("groups", [])
recipients += data.get("persons", [])
data["recipients"] = recipients
return data
def save(self, _ = False):
def save(self, _=False):
# Save announcement
a = self.instance if self.instance is not None else Announcement()
a.valid_from = self.cleaned_data["valid_from"]
a.valid_until = self.cleaned_data["valid_until"]
a.title = self.cleaned_data["title"]
a.description = self.cleaned_data["description"]
a.save()
# Save recipients
a.recipients.all().delete()
for recipient in self.cleaned_data["recipients"]:
a.recipients.create(recipient=recipient)
a.save()
return a
......
......@@ -330,6 +330,12 @@ class Announcement(ExtensibleModel):
persons += recipient.persons
return persons
def get_recipients_for_model(self, obj: Union[models.Model]) -> Sequence[models.Model]:
""" Get all recipients for this announcement with a special content type (provided through model) """
ct = ContentType.objects.get_for_model(obj)
return [r.recipient for r in self.recipients.filter(content_type=ct)]
def __str__(self):
return self.title
......
......@@ -30,16 +30,24 @@
<td>{{ announcement.valid_until }}</td>
<td>{{ announcement.recipients.all|join:", " }}</td>
<td>
<a class="btn-flat waves-effect waves-orange orange-text" href="{% url "edit_announcement" announcement.id %}">
<a class="btn-flat waves-effect waves-orange orange-text"
href="{% url "edit_announcement" announcement.id %}">
<i class="material-icons left">edit</i>
{% trans "Edit" %}
</a>
<form action="{% url "delete_announcement" announcement.id %}" method="post">
{% csrf_token %}
<button class="btn-flat waves-effect waves-re red-text" type="submit">
<i class="material-icons left">delete</i>
{% trans "Delete" %}
</button>
</form>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4">
<p class="flow-text">{% trans "There are no announcements." %}</p>
<td colspan="5">
<p class="flow-text center-align">{% trans "There are no announcements." %}</p>
</td>
</tr>
{% endfor %}
......
......@@ -38,6 +38,7 @@ urlpatterns = [
path("announcements/", views.announcements, name="announcements"),
path("announcement/create/", views.announcement_form, name="add_announcement"),
path("announcement/edit/<int:pk>/", views.announcement_form, name="edit_announcement"),
path("announcement/delete/<int:pk>/", views.delete_announcement, name="delete_announcement"),
path("maintenance-mode/", include("maintenance_mode.urls")),
path("impersonate/", include("impersonate.urls")),
path("__i18n__/", include("django.conf.urls.i18n")),
......
......@@ -293,17 +293,11 @@ def announcement_form(request: HttpRequest, pk: Optional[int] = None) -> HttpRes
announcement = get_object_or_404(Announcement, pk=pk)
form = AnnouncementForm(
request.POST or None,
instance=announcement,
initial={
"valid_from_date": announcement.valid_from.date(),
"valid_from_time": announcement.valid_from.time(),
"valid_until_date": announcement.valid_until.date(),
"valid_until_time": announcement.valid_until.time()
}
instance=announcement
)
context["mode"] = "edit"
else:
form = AnnouncementForm(request.POST or None, initial=AnnouncementForm.get_initial())
form = AnnouncementForm(request.POST or None)
context["mode"] = "add"
if request.method == "POST":
......@@ -316,3 +310,13 @@ def announcement_form(request: HttpRequest, pk: Optional[int] = None) -> HttpRes
context["form"] = form
return render(request, "core/announcement/form.html", context)
@admin_required
def delete_announcement(request: HttpRequest, pk: int) -> HttpResponse:
if request.method == "POST":
announcement = get_object_or_404(Announcement, pk=pk)
announcement.delete()
messages.success(request, _("The announcement has been deleted."))
return redirect("announcements")
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