From 5fd2fc96090c8aad8a02cc4548259c2c5882c724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?= <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de> Date: Tue, 27 Sep 2022 18:10:03 +0200 Subject: [PATCH] Create admin action to create default availabilities Introduce admin action Add function to find AKs without availabilities to event model Link new action on view of AKs requiring special attention Minor design improvements This implements the final part of #145 --- AKModel/models.py | 12 ++--- .../locale/de_DE/LC_MESSAGES/django.po | 52 +++++++++++++++---- .../admin/AKScheduling/special_attention.html | 9 ++-- AKScheduling/urls.py | 5 +- AKScheduling/views.py | 37 +++++++++++++ 5 files changed, 93 insertions(+), 22 deletions(-) diff --git a/AKModel/models.py b/AKModel/models.py index e8fcf8aa..ef86329e 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -109,6 +109,10 @@ class Event(models.Model): def get_unscheduled_wish_slots(self): return self.akslot_set.filter(start__isnull=True).annotate(Count('ak__owners')).filter(ak__owners__count=0) + def get_aks_without_availabilities(self): + return self.ak_set.annotate(Count('availabilities', distinct=True)).annotate(Count('owners', distinct=True)).filter(availabilities__count=0, owners__count__gt=0) + + class AKOwner(models.Model): """ An AKOwner describes the person organizing/holding an AK. """ @@ -331,14 +335,6 @@ class AK(models.Model): def availabilities(self): return "Availability".objects.filter(ak=self) - @property - def availabilities_total_duration(self): - from AKModel.availability.models import Availability - for a in Availability.objects.filter(ak=self): - print(a) - print(a.end) - # [a.end - a.start for a in ] - return 0 class Room(models.Model): """ A room describes where an AK can be held. diff --git a/AKScheduling/locale/de_DE/LC_MESSAGES/django.po b/AKScheduling/locale/de_DE/LC_MESSAGES/django.po index 3bf6a9e5..ceb03d7f 100644 --- a/AKScheduling/locale/de_DE/LC_MESSAGES/django.po +++ b/AKScheduling/locale/de_DE/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-09-27 14:14+0200\n" +"POT-Creation-Date: 2022-09-27 17:59+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -79,7 +79,7 @@ msgstr "Seit" #: .\AKScheduling\templates\admin\AKScheduling\constraint_violations.html:139 #: .\AKScheduling\templates\admin\AKScheduling\manage_tracks.html:243 #: .\AKScheduling\templates\admin\AKScheduling\scheduling.html:208 -#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:44 +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:48 #: .\AKScheduling\templates\admin\AKScheduling\unscheduled.html:34 msgid "Event Status" msgstr "Event-Status" @@ -158,14 +158,18 @@ msgid "AKs without availabilities" msgstr "AKs ohne Verfügbarkeiten" #: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:28 +msgid "Create default availabilities" +msgstr "Standardverfügbarkeiten anlegen" + +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:31 msgid "AK wishes with slots" msgstr "AK-Wünsche mit Slots" -#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:34 +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:38 msgid "Delete slots for wishes" msgstr "" -#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:36 +#: .\AKScheduling\templates\admin\AKScheduling\special_attention.html:40 msgid "AKs without slots" msgstr "AKs ohne Slots" @@ -177,29 +181,57 @@ msgstr "Noch nicht geschedulte AK-Slots" msgid "Count" msgstr "Anzahl" -#: .\AKScheduling\views.py:108 +#: .\AKScheduling\views.py:109 msgid "Interest updated" msgstr "Interesse aktualisiert" -#: .\AKScheduling\views.py:146 +#: .\AKScheduling\views.py:147 msgid "Wishes" msgstr "Wünsche" -#: .\AKScheduling\views.py:154 +#: .\AKScheduling\views.py:155 msgid "Cleanup: Delete unscheduled slots for wishes" msgstr "Aufräumen: Noch nicht geplante Slots für Wünsche löschen" -#: .\AKScheduling\views.py:160 +#: .\AKScheduling\views.py:162 #, python-brace-format msgid "" "The following {count} unscheduled slots of wishes will be deleted:\n" "\n" " {slots}" msgstr "" -"Die folgenden {count} noch nicht geplanten Slots von Wünschen werden gelöscht:\n" +"Die folgenden {count} noch nicht geplanten Slots von Wünschen werden " +"gelöscht:\n" "\n" " {slots}" -#: .\AKScheduling\views.py:167 +#: .\AKScheduling\views.py:169 msgid "Unscheduled slots for wishes successfully deleted" msgstr "Noch nicht geplante Slots für Wünsche erfolgreich gelöscht" + +#: .\AKScheduling\views.py:174 +msgid "Create default availabilities for AKs" +msgstr "Standardverfügbarkeiten für AKs anlegen" + +#: .\AKScheduling\views.py:181 +#, python-brace-format +msgid "" +"The following {count} AKs don't have any availability information. Create " +"default availability for them:\n" +"\n" +" {aks}" +msgstr "" +"Die folgenden {count} AKs haben keine Verfügbarkeitsinformationen. " +"Standardverfügbarkeiten für sie anlegen:\n" +"\n" +" {aks}" + +#: .\AKScheduling\views.py:199 +#, python-brace-format +msgid "Could not create default availabilities for AK: {ak}" +msgstr "Konnte keine Verfügbarkeit anlegen für AK: {ak}" + +#: .\AKScheduling\views.py:204 +#, python-brace-format +msgid "Created default availabilities for {count} AKs" +msgstr "Standardverfügbarkeiten für {count} AKs angelegt" diff --git a/AKScheduling/templates/admin/AKScheduling/special_attention.html b/AKScheduling/templates/admin/AKScheduling/special_attention.html index 68cbb11e..44d2ced1 100644 --- a/AKScheduling/templates/admin/AKScheduling/special_attention.html +++ b/AKScheduling/templates/admin/AKScheduling/special_attention.html @@ -22,14 +22,17 @@ {% for ak in aks_without_availabilities %} <a href="{% url "submit:ak_edit" event_slug=event.slug pk=ak.pk %}">{{ ak }}</a><br> {% empty %} - - + -<br> {% endfor %} + <a class="btn btn-warning mt-2" href="{% url "admin:autocreate-availabilities" event_slug=event.slug %}">{% trans "Create default availabilities" %}</a> + + <h4 class="mt-4 mb-4">{% trans "AK wishes with slots" %}</h4> {% for ak in ak_wishes_with_slots %} <a href="{% url "submit:ak_detail" event_slug=event.slug pk=ak.pk %}">{{ ak }}</a> <a href="{% url "admin:AKModel_akslot_changelist" %}?ak={{ ak.pk }}">({{ ak.akslot__count }})</a><br> {% empty %} - - + -<br> {% endfor %} <a class="btn btn-warning mt-2" href="{% url "admin:cleanup-wish-slots" event_slug=event.slug %}">{% trans "Delete slots for wishes" %}</a> @@ -38,7 +41,7 @@ {% for ak in aks_without_slots %} <a href="{% url "submit:ak_detail" event_slug=event.slug pk=ak.pk %}">{{ ak }}</a><br> {% empty %} - - + -<br> {% endfor %} <div class="mt-5"> diff --git a/AKScheduling/urls.py b/AKScheduling/urls.py index 40f293a1..1db4c182 100644 --- a/AKScheduling/urls.py +++ b/AKScheduling/urls.py @@ -1,7 +1,8 @@ from django.urls import path from AKScheduling.views import SchedulingAdminView, UnscheduledSlotsAdminView, TrackAdminView, \ - ConstraintViolationsAdminView, SpecialAttentionAKsAdminView, InterestEnteringAdminView, WishSlotCleanupView + ConstraintViolationsAdminView, SpecialAttentionAKsAdminView, InterestEnteringAdminView, WishSlotCleanupView, \ + AvailabilityAutocreateView def get_admin_urls_scheduling(admin_site): @@ -16,6 +17,8 @@ def get_admin_urls_scheduling(admin_site): name="special-attention"), path('<slug:event_slug>/cleanup-wish-slots/', admin_site.admin_view(WishSlotCleanupView.as_view()), name="cleanup-wish-slots"), + path('<slug:event_slug>/autocreate-availabilities/', admin_site.admin_view(AvailabilityAutocreateView.as_view()), + name="autocreate-availabilities"), path('<slug:event_slug>/tracks/', admin_site.admin_view(TrackAdminView.as_view()), name="tracks_manage"), path('<slug:event_slug>/enter-interest/<int:pk>', admin_site.admin_view(InterestEnteringAdminView.as_view()), diff --git a/AKScheduling/views.py b/AKScheduling/views.py index 381c0a1e..3b40d07c 100644 --- a/AKScheduling/views.py +++ b/AKScheduling/views.py @@ -160,6 +160,7 @@ class InterestEnteringAdminView(SuccessMessageMixin, AdminViewMixin, EventSlugMi class WishSlotCleanupView(EventSlugMixin, IntermediateAdminView): title = _('Cleanup: Delete unscheduled slots for wishes') + def get_success_url(self): return reverse_lazy('admin:special-attention', kwargs={'slug': self.event.slug}) @@ -174,3 +175,39 @@ class WishSlotCleanupView(EventSlugMixin, IntermediateAdminView): self.event.get_unscheduled_wish_slots().delete() messages.add_message(self.request, messages.SUCCESS, _("Unscheduled slots for wishes successfully deleted")) return super().form_valid(form) + + +class AvailabilityAutocreateView(EventSlugMixin, IntermediateAdminView): + title = _('Create default availabilities for AKs') + + def get_success_url(self): + return reverse_lazy('admin:special-attention', kwargs={'slug': self.event.slug}) + + def get_preview(self): + aks = self.event.get_aks_without_availabilities() + return _("The following {count} AKs don't have any availability information. " + "Create default availability for them:\n\n {aks}").format( + count=len(aks), + aks=", ".join(str(ak) for ak in aks) + ) + + def form_valid(self, form): + from AKModel.availability.models import Availability + + success_count = 0 + for ak in self.event.get_aks_without_availabilities(): + try: + availability = Availability.with_event_length(event=self.event, ak=ak) + availability.save() + success_count += 1 + except: + messages.add_message( + self.request, messages.WARNING, + _("Could not create default availabilities for AK: {ak}").format(ak=ak) + ) + + messages.add_message( + self.request, messages.SUCCESS, + _("Created default availabilities for {count} AKs").format(count=success_count) + ) + return super().form_valid(form) -- GitLab