diff --git a/AKModel/models.py b/AKModel/models.py index e8fcf8aa8ea277e910d2b368a301ed2029aa3ce0..ef86329edd234ac32bd909cc81402df1b69ef901 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 3bf6a9e5a686f1091bc2a8271be543e5ae576faa..ceb03d7f640b6ca44ca57fd8442ef16bf2a99c6e 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 68cbb11e72487a9a2b1f804cc782aa063c81221c..44d2ced14900b383ee9034cc00eb8b1ffe0a6553 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 40f293a16eac9b41f7f86044fdb989e41d3f6d30..1db4c182b9ab8d135a9217196a2c4596d555e38b 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 381c0a1ea374d317d46d5696eda0a51800104534..3b40d07cb68c486e73326bccf51eaf06bdc93091 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)