diff --git a/AKDashboard/locale/de_DE/LC_MESSAGES/django.po b/AKDashboard/locale/de_DE/LC_MESSAGES/django.po index feb56e89e977b73e6bc069f546008f063f1fa290..75b92633f39f1c658d216594c9fc6516a0c250f8 100644 --- a/AKDashboard/locale/de_DE/LC_MESSAGES/django.po +++ b/AKDashboard/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: 2025-01-01 17:28+0100\n" +"POT-Creation-Date: 2025-02-27 15:13+0000\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" @@ -113,22 +113,22 @@ msgstr "AK-Einreichung" msgid "AK History" msgstr "AK-Verlauf" -#: AKDashboard/views.py:69 +#: AKDashboard/views.py:70 #, python-format msgid "New AK: %(ak)s." msgstr "Neuer AK: %(ak)s." -#: AKDashboard/views.py:72 +#: AKDashboard/views.py:73 #, python-format msgid "AK \"%(ak)s\" edited." msgstr "AK \"%(ak)s\" bearbeitet." -#: AKDashboard/views.py:75 +#: AKDashboard/views.py:76 #, python-format msgid "AK \"%(ak)s\" deleted." msgstr "AK \"%(ak)s\" gelöscht." -#: AKDashboard/views.py:90 +#: AKDashboard/views.py:91 #, python-format msgid "AK \"%(ak)s\" (re-)scheduled." msgstr "AK \"%(ak)s\" (um-)geplant." diff --git a/AKModel/admin.py b/AKModel/admin.py index d2ba18f334c2f6762f7f7fbde69b8674655b1afc..56833b20bfdd2471e0bb52fe0e94291981dbb79c 100644 --- a/AKModel/admin.py +++ b/AKModel/admin.py @@ -2,6 +2,8 @@ from django import forms from django.apps import apps from django.contrib import admin, messages from django.contrib.admin import SimpleListFilter, RelatedFieldListFilter, action, display +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.models import User # pylint: disable=E5142 from django.db.models import Count, F from django.http import HttpResponseRedirect from django.shortcuts import render, redirect @@ -15,7 +17,7 @@ from simple_history.admin import SimpleHistoryAdmin from AKModel.availability.models import Availability from AKModel.forms import RoomFormWithAvailabilities from AKModel.models import Event, AKOwner, AKCategory, AKTrack, AKRequirement, AK, AKSlot, Room, AKOrgaMessage, \ - ConstraintViolation, DefaultSlot + ConstraintViolation, DefaultSlot, AKType from AKModel.urls import get_admin_urls_event_wizard, get_admin_urls_event from AKModel.views.ak import AKResetInterestView, AKResetInterestCounterView from AKModel.views.manage import CVMarkResolvedView, CVSetLevelViolationView, CVSetLevelWarningView @@ -215,6 +217,18 @@ class AKRequirementAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmin): ordering = ['name'] +@admin.register(AKType) +class AKTypeAdmin(PrepopulateWithNextActiveEventMixin, admin.ModelAdmin): + """ + Admin interface for AKRequirements + """ + model = AKType + list_display = ['name', 'event'] + list_filter = ['event'] + list_editable = [] + ordering = ['name'] + + class WishFilter(SimpleListFilter): """ Re-usable filter for wishes @@ -257,6 +271,7 @@ class AKAdminForm(forms.ModelForm): self.fields["requirements"].queryset = AKRequirement.objects.filter(event=self.instance.event) self.fields["conflicts"].queryset = AK.objects.filter(event=self.instance.event) self.fields["prerequisites"].queryset = AK.objects.filter(event=self.instance.event) + self.fields["types"].queryset = AKType.objects.filter(event=self.instance.event) @admin.register(AK) @@ -555,3 +570,41 @@ class DefaultSlotAdmin(EventTimezoneFormMixin, admin.ModelAdmin): list_display = ['start_simplified', 'end_simplified', 'event'] list_filter = ['event'] form = DefaultSlotAdminForm + + +# Define a new User admin +class UserAdmin(BaseUserAdmin): + """ + Admin interface for Users + Enhances the built-in UserAdmin with additional actions to activate and deactivate users and a custom selection + of displayed properties in overview list + """ + list_display = ["username", "email", "is_active", "is_staff", "is_superuser"] + actions = ['activate', 'deactivate'] + + @admin.action(description=_("Activate selected users")) + def activate(self, request, queryset): + """ + Bulk activate users + + :param request: HTTP request + :param queryset: queryset containing all users that should be activated + """ + queryset.update(is_active=True) + self.message_user(request, _("The selected users have been activated.")) + + @admin.action(description=_("Deactivate selected users")) + def deactivate(self, request, queryset): + """ + Bulk deactivate users + + :param request: HTTP request + :param queryset: queryset containing all users that should be deactivated + """ + queryset.update(is_active=False) + self.message_user(request, _("The selected users have been deactivated.")) + + +# Re-register UserAdmin +admin.site.unregister(User) +admin.site.register(User, UserAdmin) diff --git a/AKModel/fixtures/model.json b/AKModel/fixtures/model.json index 42cf6c81740353dd8228ede14fe1102162f32740..7694f2c901b0a056025fcba292b26b9b66af7f19 100644 --- a/AKModel/fixtures/model.json +++ b/AKModel/fixtures/model.json @@ -193,6 +193,14 @@ "event": 2 } }, +{ + "model": "AKModel.aktype", + "pk": 1, + "fields": { + "name": "Input", + "event": 2 + } +}, { "model": "AKModel.historicalak", "pk": 1, @@ -206,7 +214,6 @@ "reso": false, "present": true, "notes": "", - "interest": -1, "category": 4, "track": null, "event": 2, @@ -229,7 +236,6 @@ "reso": false, "present": true, "notes": "", - "interest": -1, "category": 4, "track": null, "event": 2, @@ -252,7 +258,6 @@ "reso": false, "present": null, "notes": "", - "interest": -1, "category": 5, "track": null, "event": 2, @@ -275,7 +280,6 @@ "reso": false, "present": null, "notes": "", - "interest": -1, "category": 5, "track": null, "event": 2, @@ -298,7 +302,6 @@ "reso": false, "present": null, "notes": "We need to find a volunteer first...", - "interest": -1, "category": 3, "track": null, "event": 2, @@ -321,7 +324,6 @@ "reso": false, "present": null, "notes": "We need to find a volunteer first...", - "interest": -1, "category": 3, "track": null, "event": 2, @@ -344,7 +346,6 @@ "reso": false, "present": null, "notes": "", - "interest": -1, "category": 5, "track": 1, "event": 2, diff --git a/AKModel/forms.py b/AKModel/forms.py index bf77085c6c21a75fafc2711c2cc58c94a8953d46..9ec3d24ec5f73148be7f135b8aa9f97965b3a4cc 100644 --- a/AKModel/forms.py +++ b/AKModel/forms.py @@ -10,7 +10,7 @@ from django.forms.utils import ErrorList from django.utils.translation import gettext_lazy as _ from AKModel.availability.forms import AvailabilitiesFormMixin -from AKModel.models import Event, AKCategory, AKRequirement, Room +from AKModel.models import Event, AKCategory, AKRequirement, Room, AKType class DateTimeInput(forms.DateInput): @@ -101,6 +101,13 @@ class NewEventWizardImportForm(forms.Form): required=False, ) + import_types = forms.ModelMultipleChoiceField( + queryset=AKType.objects.all(), + widget=forms.CheckboxSelectMultiple, + label=_("Copy types"), + required=False, + ) + # pylint: disable=too-many-arguments def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=ErrorList, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None, @@ -111,6 +118,8 @@ class NewEventWizardImportForm(forms.Form): event=self.initial["import_event"]) self.fields["import_requirements"].queryset = self.fields["import_requirements"].queryset.filter( event=self.initial["import_event"]) + self.fields["import_types"].queryset = self.fields["import_types"].queryset.filter( + event=self.initial["import_event"]) # pylint: disable=import-outside-toplevel # Local imports used to prevent cyclic imports and to only import when AKDashboard is available diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po index d4f3db1bdfc604b443f52e30eea7d465567e2666..00b78ea9754cfa7e7089bab71d09c15029f40543 100644 --- a/AKModel/locale/de_DE/LC_MESSAGES/django.po +++ b/AKModel/locale/de_DE/LC_MESSAGES/django.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-06 16:38+0000\n" +"POT-Creation-Date: 2025-02-27 15:13+0000\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" @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: AKModel/admin.py:86 AKModel/admin.py:96 +#: AKModel/admin.py:88 AKModel/admin.py:98 #: AKModel/templates/admin/AKModel/event_wizard/activate.html:35 #: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:51 #: AKModel/templates/admin/AKModel/event_wizard/finish.html:21 @@ -21,69 +21,85 @@ msgstr "" msgid "Status" msgstr "Status" -#: AKModel/admin.py:98 +#: AKModel/admin.py:100 msgid "Toggle plan visibility" msgstr "Plansichtbarkeit ändern" -#: AKModel/admin.py:110 AKModel/admin.py:121 AKModel/views/manage.py:140 +#: AKModel/admin.py:112 AKModel/admin.py:123 AKModel/views/manage.py:140 msgid "Publish plan" msgstr "Plan veröffentlichen" -#: AKModel/admin.py:113 AKModel/admin.py:129 AKModel/views/manage.py:153 +#: AKModel/admin.py:115 AKModel/admin.py:131 AKModel/views/manage.py:153 msgid "Unpublish plan" msgstr "Plan verbergen" -#: AKModel/admin.py:168 AKModel/models.py:698 AKModel/models.py:1128 -#: AKModel/models.py:1164 +#: AKModel/admin.py:170 AKModel/models.py:720 AKModel/models.py:1167 +#: AKModel/models.py:1203 AKModel/templates/admin/AKModel/aks_by_user.html:12 #: AKModel/templates/admin/AKModel/status/event_aks.html:10 -#: AKModel/views/manage.py:75 AKModel/views/status.py:97 +#: AKModel/views/manage.py:75 AKModel/views/status.py:102 msgid "AKs" msgstr "AKs" -#: AKModel/admin.py:222 +#: AKModel/admin.py:236 msgid "Wish" msgstr "AK-Wunsch" -#: AKModel/admin.py:228 +#: AKModel/admin.py:242 msgid "Is wish" msgstr "Ist ein Wunsch" -#: AKModel/admin.py:229 +#: AKModel/admin.py:243 msgid "Is not a wish" msgstr "Ist kein Wunsch" -#: AKModel/admin.py:288 +#: AKModel/admin.py:303 msgid "Export to wiki syntax" msgstr "In Wiki-Syntax exportieren" -#: AKModel/admin.py:305 +#: AKModel/admin.py:320 msgid "Cannot export AKs from more than one event at the same time." msgstr "Kann nicht AKs von mehreren Events zur selben Zeit exportieren." -#: AKModel/admin.py:320 AKModel/views/ak.py:235 +#: AKModel/admin.py:335 AKModel/views/ak.py:257 msgid "Reset interest in AKs" msgstr "Interesse an AKs zurücksetzen" -#: AKModel/admin.py:330 AKModel/views/ak.py:250 +#: AKModel/admin.py:345 AKModel/views/ak.py:272 msgid "Reset AKs' interest counters" msgstr "Interessenszähler der AKs zurücksetzen" -#: AKModel/admin.py:429 AKModel/admin.py:443 +#: AKModel/admin.py:444 AKModel/admin.py:458 msgid "AK Details" msgstr "AK-Details" -#: AKModel/admin.py:505 AKModel/views/manage.py:101 +#: AKModel/admin.py:520 AKModel/views/manage.py:101 msgid "Mark Constraint Violations as manually resolved" msgstr "Markiere Constraintverletzungen als manuell behoben" -#: AKModel/admin.py:514 AKModel/views/manage.py:114 +#: AKModel/admin.py:529 AKModel/views/manage.py:114 msgid "Set Constraint Violations to level \"violation\"" msgstr "Constraintverletzungen auf Level \"Violation\" setzen" -#: AKModel/admin.py:523 AKModel/views/manage.py:127 +#: AKModel/admin.py:538 AKModel/views/manage.py:127 msgid "Set Constraint Violations to level \"warning\"" msgstr "Constraintverletzungen auf Level \"Warning\" setzen" +#: AKModel/admin.py:585 +msgid "Activate selected users" +msgstr "Ausgewählte Benutzer*innen aktivieren" + +#: AKModel/admin.py:594 +msgid "The selected users have been activated." +msgstr "Benutzer*innen aktiviert" + +#: AKModel/admin.py:596 +msgid "Deactivate selected users" +msgstr "Ausgewählte Benutzer*innen deaktivieren" + +#: AKModel/admin.py:605 +msgid "The selected users have been deactivated." +msgstr "Benutzer*innen deaktiviert" + #: AKModel/availability/forms.py:25 AKModel/availability/models.py:308 msgid "Availability" msgstr "Verfügbarkeit" @@ -110,17 +126,18 @@ msgid "Please fill in your availabilities!" msgstr "Bitte Verfügbarkeiten eintragen!" #: AKModel/availability/models.py:43 AKModel/models.py:166 -#: AKModel/models.py:498 AKModel/models.py:575 AKModel/models.py:608 -#: AKModel/models.py:634 AKModel/models.py:688 AKModel/models.py:830 -#: AKModel/models.py:906 AKModel/models.py:1067 AKModel/models.py:1124 -#: AKModel/models.py:1315 +#: AKModel/models.py:499 AKModel/models.py:576 AKModel/models.py:609 +#: AKModel/models.py:635 AKModel/models.py:654 AKModel/models.py:710 +#: AKModel/models.py:868 AKModel/models.py:944 AKModel/models.py:1106 +#: AKModel/models.py:1163 AKModel/models.py:1354 msgid "Event" msgstr "Event" -#: AKModel/availability/models.py:44 AKModel/models.py:499 -#: AKModel/models.py:576 AKModel/models.py:609 AKModel/models.py:635 -#: AKModel/models.py:689 AKModel/models.py:831 AKModel/models.py:907 -#: AKModel/models.py:1068 AKModel/models.py:1125 AKModel/models.py:1316 +#: AKModel/availability/models.py:44 AKModel/models.py:500 +#: AKModel/models.py:577 AKModel/models.py:610 AKModel/models.py:636 +#: AKModel/models.py:655 AKModel/models.py:711 AKModel/models.py:869 +#: AKModel/models.py:945 AKModel/models.py:1107 AKModel/models.py:1164 +#: AKModel/models.py:1355 msgid "Associated event" msgstr "Zugehöriges Event" @@ -132,8 +149,8 @@ msgstr "Person" msgid "Person whose availability this is" msgstr "Person deren Verfügbarkeit hier abgebildet wird" -#: AKModel/availability/models.py:61 AKModel/models.py:834 -#: AKModel/models.py:896 AKModel/models.py:1134 +#: AKModel/availability/models.py:61 AKModel/models.py:872 +#: AKModel/models.py:934 AKModel/models.py:1173 msgid "Room" msgstr "Raum" @@ -141,8 +158,8 @@ msgstr "Raum" msgid "Room whose availability this is" msgstr "Raum dessen Verfügbarkeit hier abgebildet wird" -#: AKModel/availability/models.py:70 AKModel/models.py:697 -#: AKModel/models.py:895 AKModel/models.py:1062 +#: AKModel/availability/models.py:70 AKModel/models.py:719 +#: AKModel/models.py:933 AKModel/models.py:1101 msgid "AK" msgstr "AK" @@ -150,8 +167,8 @@ msgstr "AK" msgid "AK whose availability this is" msgstr "Verfügbarkeiten" -#: AKModel/availability/models.py:79 AKModel/models.py:579 -#: AKModel/models.py:1140 +#: AKModel/availability/models.py:79 AKModel/models.py:580 +#: AKModel/models.py:1179 msgid "AK Category" msgstr "AK-Kategorie" @@ -159,7 +176,7 @@ msgstr "AK-Kategorie" msgid "AK Category whose availability this is" msgstr "AK-Kategorie, deren Verfügbarkeit hier abgebildet wird" -#: AKModel/availability/models.py:309 AKModel/models.py:730 +#: AKModel/availability/models.py:309 AKModel/models.py:768 msgid "Availabilities" msgstr "Verfügbarkeiten" @@ -180,39 +197,43 @@ msgstr "AK-Kategorien kopieren" msgid "Copy ak requirements" msgstr "AK-Anforderungen kopieren" -#: AKModel/forms.py:124 +#: AKModel/forms.py:107 +msgid "Copy types" +msgstr "Typen kopieren" + +#: AKModel/forms.py:133 msgid "Copy dashboard buttons" msgstr "Dashboard-Buttons kopieren" -#: AKModel/forms.py:165 +#: AKModel/forms.py:174 msgid "# next AKs" msgstr "# nächste AKs" -#: AKModel/forms.py:166 +#: AKModel/forms.py:175 msgid "How many next AKs should be shown on a slide?" msgstr "Wie viele nächste AKs sollen auf einer Folie angezeigt werden?" -#: AKModel/forms.py:169 +#: AKModel/forms.py:178 msgid "Presentation only?" msgstr "Nur Vorstellung?" -#: AKModel/forms.py:171 AKModel/forms.py:178 +#: AKModel/forms.py:180 AKModel/forms.py:187 msgid "Yes" msgstr "Ja" -#: AKModel/forms.py:171 AKModel/forms.py:178 +#: AKModel/forms.py:180 AKModel/forms.py:187 msgid "No" msgstr "Nein" -#: AKModel/forms.py:173 +#: AKModel/forms.py:182 msgid "Restrict AKs to those that asked for chance to be presented?" msgstr "AKs auf solche, die um eine Vorstellung gebeten haben, einschränken?" -#: AKModel/forms.py:176 +#: AKModel/forms.py:185 msgid "Space for notes in wishes?" msgstr "Platz für Notizen bei den Wünschen?" -#: AKModel/forms.py:180 +#: AKModel/forms.py:189 msgid "" "Create symbols indicating space to note down owners and timeslots for " "wishes, e.g., to be filled out on a touch screen while presenting?" @@ -221,11 +242,11 @@ msgstr "" "fürWünsche markieren, z.B. um während der Präsentation auf einem Touchscreen " "ausgefüllt zu werden?" -#: AKModel/forms.py:189 AKModel/models.py:1309 +#: AKModel/forms.py:198 AKModel/models.py:1348 msgid "Default Slots" msgstr "Standardslots" -#: AKModel/forms.py:191 +#: AKModel/forms.py:200 msgid "" "Click and drag to add default slots, double-click to delete. Or use the " "start and end inputs to add entries to the calendar view." @@ -234,11 +255,11 @@ msgstr "" "Einträge zu löschen. Oder Start- und End-Eingabe verwenden, um der " "Kalenderansicht neue Einträge hinzuzufügen." -#: AKModel/forms.py:207 +#: AKModel/forms.py:216 msgid "New rooms" msgstr "Neue Räume" -#: AKModel/forms.py:208 +#: AKModel/forms.py:217 msgid "" "Enter room details in CSV format. Required colum is \"name\", optional " "colums are \"location\", \"capacity\", and \"url\" for online/hybrid rooms. " @@ -248,23 +269,23 @@ msgstr "" "Spalten sind \"location\", \"capacity\", und \"url\" for Online-/" "HybridräumeTrennzeichen: Semikolon" -#: AKModel/forms.py:214 +#: AKModel/forms.py:223 msgid "Default availabilities?" msgstr "Standardverfügbarkeiten?" -#: AKModel/forms.py:215 +#: AKModel/forms.py:224 msgid "Create default availabilities for all rooms?" msgstr "Standardverfügbarkeiten für alle Räume anlegen?" -#: AKModel/forms.py:231 +#: AKModel/forms.py:240 msgid "CSV must contain a name column" msgstr "CSV muss eine name-Spalte enthalten" -#: AKModel/forms.py:282 +#: AKModel/forms.py:291 msgid "JSON data" msgstr "JSON-Daten" -#: AKModel/forms.py:283 +#: AKModel/forms.py:292 msgid "JSON data from the scheduling solver" msgstr "JSON-Daten, die der scheduling-solver produziert hat" @@ -293,8 +314,9 @@ msgstr "Aktivieren?" msgid "Finish" msgstr "Abschluss" -#: AKModel/models.py:120 AKModel/models.py:567 AKModel/models.py:605 -#: AKModel/models.py:632 AKModel/models.py:650 AKModel/models.py:822 +#: AKModel/models.py:120 AKModel/models.py:568 AKModel/models.py:606 +#: AKModel/models.py:633 AKModel/models.py:652 AKModel/models.py:670 +#: AKModel/models.py:860 msgid "Name" msgstr "Name" @@ -429,8 +451,8 @@ msgid "" "Slot duration in hours that is used in the timeslot discretization, when " "this event is exported for the solver." msgstr "" -"Länge von Slots (in Stunden) in der Zeitslot-Diskretisierung beim " -"JSON-Export dieses Events." +"Länge von Slots (in Stunden) in der Zeitslot-Diskretisierung beim JSON-" +"Export dieses Events." #: AKModel/models.py:161 msgid "Contact email address" @@ -448,12 +470,12 @@ msgstr "" msgid "Events" msgstr "Events" -#: AKModel/models.py:439 +#: AKModel/models.py:440 #, python-brace-format msgid "AK {ak_name} is not assigned any timeslot by the solver" msgstr "Dem AK {ak_name} wurde vom Solver kein Zeitslot zugewiesen" -#: AKModel/models.py:449 +#: AKModel/models.py:450 #, python-brace-format msgid "" "Duration of AK {ak_name} assigned by solver ({solver_duration} hours) is " @@ -463,7 +485,7 @@ msgstr "" "Stunden) ist kürzer als die aktuell vorgesehene Dauer des Slots " "({slot_duration} Stunden)" -#: AKModel/models.py:463 +#: AKModel/models.py:464 #, python-brace-format msgid "" "Fixed AK {ak_name} assigned by solver to room {solver_room} is fixed to room " @@ -472,7 +494,7 @@ msgstr "" "Dem fix geplanten AK {ak_name} wurde vom Solver Raum {solver_room} " "zugewiesen, dabei ist der AK bereits fix in Raum {slot_room} eingeplant." -#: AKModel/models.py:474 +#: AKModel/models.py:475 #, python-brace-format msgid "" "Fixed AK {ak_name} assigned by solver to start at {solver_start} is fixed to " @@ -481,71 +503,71 @@ msgstr "" "Dem fix geplanten AK {ak_name} wurde vom Solver die Startzeit {solver_start} " "zugewiesen, dabei ist der AK bereits für {slot_start} eingeplant." -#: AKModel/models.py:493 +#: AKModel/models.py:494 msgid "Nickname" msgstr "Spitzname" -#: AKModel/models.py:493 +#: AKModel/models.py:494 msgid "Name to identify an AK owner by" msgstr "Name, durch den eine AK-Leitung identifiziert wird" -#: AKModel/models.py:494 +#: AKModel/models.py:495 msgid "Slug" msgstr "Slug" -#: AKModel/models.py:494 +#: AKModel/models.py:495 msgid "Slug for URL generation" msgstr "Slug für URL-Generierung" -#: AKModel/models.py:495 +#: AKModel/models.py:496 msgid "Institution" msgstr "Instutution" -#: AKModel/models.py:495 +#: AKModel/models.py:496 msgid "Uni etc." msgstr "Universität o.ä." -#: AKModel/models.py:496 AKModel/models.py:659 +#: AKModel/models.py:497 AKModel/models.py:679 msgid "Web Link" msgstr "Internet Link" -#: AKModel/models.py:496 +#: AKModel/models.py:497 msgid "Link to Homepage" msgstr "Link zu Homepage oder Webseite" -#: AKModel/models.py:502 AKModel/models.py:1133 +#: AKModel/models.py:503 AKModel/models.py:1172 msgid "AK Owner" msgstr "AK-Leitung" -#: AKModel/models.py:503 +#: AKModel/models.py:504 msgid "AK Owners" msgstr "AK-Leitungen" -#: AKModel/models.py:567 +#: AKModel/models.py:568 msgid "Name of the AK Category" msgstr "Name der AK-Kategorie" -#: AKModel/models.py:568 AKModel/models.py:606 +#: AKModel/models.py:569 AKModel/models.py:607 msgid "Color" msgstr "Farbe" -#: AKModel/models.py:568 AKModel/models.py:606 +#: AKModel/models.py:569 AKModel/models.py:607 msgid "Color for displaying" msgstr "Farbe für die Anzeige" -#: AKModel/models.py:569 AKModel/models.py:653 +#: AKModel/models.py:570 AKModel/models.py:673 msgid "Description" msgstr "Beschreibung" -#: AKModel/models.py:570 +#: AKModel/models.py:571 msgid "Short description of this AK Category" msgstr "Beschreibung der AK-Kategorie" -#: AKModel/models.py:571 +#: AKModel/models.py:572 msgid "Present by default" msgstr "Defaultmäßig präsentieren" -#: AKModel/models.py:572 +#: AKModel/models.py:573 msgid "" "Present AKs of this category by default if AK owner did not specify whether " "this AK should be presented?" @@ -553,132 +575,152 @@ msgstr "" "AKs dieser Kategorie standardmäßig vorstellen, wenn die Leitungen das für " "ihren AK nicht explizit spezifiziert haben?" -#: AKModel/models.py:580 +#: AKModel/models.py:581 msgid "AK Categories" msgstr "AK-Kategorien" -#: AKModel/models.py:605 +#: AKModel/models.py:606 msgid "Name of the AK Track" msgstr "Name des AK-Tracks" -#: AKModel/models.py:612 +#: AKModel/models.py:613 msgid "AK Track" msgstr "AK-Track" -#: AKModel/models.py:613 +#: AKModel/models.py:614 msgid "AK Tracks" msgstr "AK-Tracks" -#: AKModel/models.py:632 +#: AKModel/models.py:633 msgid "Name of the Requirement" msgstr "Name der Anforderung" -#: AKModel/models.py:638 AKModel/models.py:1137 +#: AKModel/models.py:639 AKModel/models.py:1176 msgid "AK Requirement" msgstr "AK-Anforderung" -#: AKModel/models.py:639 +#: AKModel/models.py:640 msgid "AK Requirements" msgstr "AK-Anforderungen" -#: AKModel/models.py:650 +#: AKModel/models.py:652 +msgid "Name describing the type" +msgstr "Name, der den Typ beschreibt" + +#: AKModel/models.py:658 +msgid "AK Type" +msgstr "AK Typ" + +#: AKModel/models.py:659 +msgid "AK Types" +msgstr "AK-Typen" + +#: AKModel/models.py:670 msgid "Name of the AK" msgstr "Name des AKs" -#: AKModel/models.py:651 +#: AKModel/models.py:671 msgid "Short Name" msgstr "Kurzer Name" -#: AKModel/models.py:652 +#: AKModel/models.py:672 msgid "Name displayed in the schedule" msgstr "Name zur Anzeige im AK-Plan" -#: AKModel/models.py:653 +#: AKModel/models.py:673 msgid "Description of the AK" msgstr "Beschreibung des AKs" -#: AKModel/models.py:655 +#: AKModel/models.py:675 msgid "Owners" msgstr "Leitungen" -#: AKModel/models.py:656 +#: AKModel/models.py:676 msgid "Those organizing the AK" msgstr "Menschen, die den AK organisieren und halten" -#: AKModel/models.py:659 +#: AKModel/models.py:679 msgid "Link to wiki page" msgstr "Link zur Wiki Seite" -#: AKModel/models.py:660 +#: AKModel/models.py:680 msgid "Protocol Link" msgstr "Protokolllink" -#: AKModel/models.py:660 +#: AKModel/models.py:680 msgid "Link to protocol" msgstr "Link zum Protokoll" -#: AKModel/models.py:662 +#: AKModel/models.py:682 msgid "Category" msgstr "Kategorie" -#: AKModel/models.py:663 +#: AKModel/models.py:683 msgid "Category of the AK" msgstr "Kategorie des AKs" -#: AKModel/models.py:664 +#: AKModel/models.py:684 AKModel/models.py:749 +msgid "Types" +msgstr "Typen" + +#: AKModel/models.py:685 +msgid "This AK is" +msgstr "Dieser AK ist" + +#: AKModel/models.py:686 msgid "Track" msgstr "Track" -#: AKModel/models.py:665 +#: AKModel/models.py:687 msgid "Track the AK belongs to" msgstr "Track zu dem der AK gehört" -#: AKModel/models.py:667 +#: AKModel/models.py:689 msgid "Resolution Intention" msgstr "Resolutionsabsicht" -#: AKModel/models.py:668 +#: AKModel/models.py:690 msgid "Intends to submit a resolution" msgstr "Beabsichtigt eine Resolution einzureichen" -#: AKModel/models.py:669 +#: AKModel/models.py:691 msgid "Present this AK" msgstr "AK präsentieren" -#: AKModel/models.py:670 +#: AKModel/models.py:692 msgid "Present results of this AK" msgstr "Die Ergebnisse dieses AKs vorstellen" -#: AKModel/models.py:672 AKModel/models.py:725 AKModel/views/status.py:170 +#: AKModel/models.py:694 AKModel/models.py:747 AKModel/views/status.py:175 msgid "Requirements" msgstr "Anforderungen" -#: AKModel/models.py:673 +#: AKModel/models.py:695 msgid "AK's Requirements" msgstr "Anforderungen des AKs" -#: AKModel/models.py:675 +#: AKModel/models.py:697 msgid "Conflicting AKs" msgstr "AK-Konflikte" -#: AKModel/models.py:676 +#: AKModel/models.py:698 msgid "AKs that conflict and thus must not take place at the same time" msgstr "" "AKs, die Konflikte haben und deshalb nicht gleichzeitig stattfinden dürfen" -#: AKModel/models.py:677 +#: AKModel/models.py:699 msgid "Prerequisite AKs" msgstr "Vorausgesetzte AKs" -#: AKModel/models.py:678 +#: AKModel/models.py:700 msgid "AKs that should precede this AK in the schedule" msgstr "AKs die im AK-Plan vor diesem AK stattfinden müssen" -#: AKModel/models.py:680 +#: AKModel/models.py:702 msgid "Organizational Notes" msgstr "Notizen zur Organisation" -#: AKModel/models.py:681 +#: AKModel/models.py:703 msgid "" "Notes to organizers. These are public. For private notes, please use the " "button for private messages on the detail page of this AK (after creation/" @@ -688,299 +730,299 @@ msgstr "" "Anmerkungen bitte den Button für Direktnachrichten verwenden (nach dem " "Anlegen/Bearbeiten)." -#: AKModel/models.py:684 AKModel/models.py:723 +#: AKModel/models.py:706 AKModel/models.py:745 msgid "Interest" msgstr "Interesse" -#: AKModel/models.py:684 +#: AKModel/models.py:706 msgid "Expected number of people" msgstr "Erwartete Personenzahl" -#: AKModel/models.py:685 +#: AKModel/models.py:707 msgid "Interest Counter" msgstr "Interessenszähler" -#: AKModel/models.py:686 +#: AKModel/models.py:708 msgid "People who have indicated interest online" msgstr "Anzahl Personen, die online Interesse bekundet haben" -#: AKModel/models.py:691 +#: AKModel/models.py:713 msgid "Export?" msgstr "Export?" -#: AKModel/models.py:692 +#: AKModel/models.py:714 msgid "Include AK in wiki export?" msgstr "AK bei Wiki-Export berücksichtigen?" -#: AKModel/models.py:727 +#: AKModel/models.py:764 msgid "Conflicts" msgstr "Konflikte" -#: AKModel/models.py:729 +#: AKModel/models.py:767 msgid "Prerequisites" msgstr "Voraussetzungen" -#: AKModel/models.py:822 +#: AKModel/models.py:860 msgid "Name or number of the room" msgstr "Name oder Nummer des Raums" -#: AKModel/models.py:823 +#: AKModel/models.py:861 msgid "Location" msgstr "Ort" -#: AKModel/models.py:824 +#: AKModel/models.py:862 msgid "Name or number of the location" msgstr "Name oder Nummer des Ortes" -#: AKModel/models.py:825 +#: AKModel/models.py:863 msgid "Capacity" msgstr "Kapazität" -#: AKModel/models.py:826 +#: AKModel/models.py:864 msgid "Maximum number of people (-1 for unlimited)." msgstr "Maximale Personenzahl (-1 wenn unbeschränkt)." -#: AKModel/models.py:827 +#: AKModel/models.py:865 msgid "Properties" msgstr "Eigenschaften" -#: AKModel/models.py:828 +#: AKModel/models.py:866 msgid "AK requirements fulfilled by the room" msgstr "AK-Anforderungen, die dieser Raum erfüllt" -#: AKModel/models.py:835 AKModel/views/status.py:59 +#: AKModel/models.py:873 AKModel/views/status.py:59 msgid "Rooms" msgstr "Räume" -#: AKModel/models.py:895 +#: AKModel/models.py:933 msgid "AK being mapped" msgstr "AK, der zugeordnet wird" -#: AKModel/models.py:897 +#: AKModel/models.py:935 msgid "Room the AK will take place in" msgstr "Raum in dem der AK stattfindet" -#: AKModel/models.py:898 AKModel/models.py:1312 +#: AKModel/models.py:936 AKModel/models.py:1351 msgid "Slot Begin" msgstr "Beginn des Slots" -#: AKModel/models.py:898 AKModel/models.py:1312 +#: AKModel/models.py:936 AKModel/models.py:1351 msgid "Time and date the slot begins" msgstr "Zeit und Datum zu der der AK beginnt" -#: AKModel/models.py:900 +#: AKModel/models.py:938 msgid "Duration" msgstr "Dauer" -#: AKModel/models.py:901 +#: AKModel/models.py:939 msgid "Length in hours" msgstr "Länge in Stunden" -#: AKModel/models.py:903 +#: AKModel/models.py:941 msgid "Scheduling fixed" msgstr "Planung fix" -#: AKModel/models.py:904 +#: AKModel/models.py:942 msgid "Length and time of this AK should not be changed" msgstr "Dauer und Zeit dieses AKs sollten nicht verändert werden" -#: AKModel/models.py:909 +#: AKModel/models.py:947 msgid "Last update" msgstr "Letzte Aktualisierung" -#: AKModel/models.py:912 +#: AKModel/models.py:950 msgid "AK Slot" msgstr "AK-Slot" -#: AKModel/models.py:913 AKModel/models.py:1130 AKModel/models.py:1165 +#: AKModel/models.py:951 AKModel/models.py:1169 AKModel/models.py:1204 msgid "AK Slots" msgstr "AK-Slot" -#: AKModel/models.py:935 AKModel/models.py:944 +#: AKModel/models.py:973 AKModel/models.py:982 msgid "Not scheduled yet" msgstr "Noch nicht geplant" -#: AKModel/models.py:1063 +#: AKModel/models.py:1102 msgid "AK this message belongs to" msgstr "AK zu dem die Nachricht gehört" -#: AKModel/models.py:1064 +#: AKModel/models.py:1103 msgid "Message text" msgstr "Nachrichtentext" -#: AKModel/models.py:1065 +#: AKModel/models.py:1104 msgid "Message to the organizers. This is not publicly visible." msgstr "" "Nachricht an die Organisator*innen. Diese ist nicht öffentlich sichtbar." -#: AKModel/models.py:1069 +#: AKModel/models.py:1108 msgid "Resolved" msgstr "Erledigt" -#: AKModel/models.py:1070 +#: AKModel/models.py:1109 msgid "This message has been resolved (no further action needed)" msgstr "" "Diese Nachricht wurde vollständig bearbeitet (keine weiteren Aktionen " "notwendig)" -#: AKModel/models.py:1073 +#: AKModel/models.py:1112 msgid "AK Orga Message" msgstr "AK-Organachricht" -#: AKModel/models.py:1074 +#: AKModel/models.py:1113 msgid "AK Orga Messages" msgstr "AK-Organachrichten" -#: AKModel/models.py:1091 +#: AKModel/models.py:1130 msgid "Constraint Violation" msgstr "Constraintverletzung" -#: AKModel/models.py:1092 +#: AKModel/models.py:1131 msgid "Constraint Violations" msgstr "Constraintverletzungen" -#: AKModel/models.py:1099 +#: AKModel/models.py:1138 msgid "Owner has two parallel slots" msgstr "Leitung hat zwei Slots parallel" -#: AKModel/models.py:1100 +#: AKModel/models.py:1139 msgid "AK Slot was scheduled outside the AK's availabilities" msgstr "AK Slot wurde außerhalb der Verfügbarkeit des AKs platziert" -#: AKModel/models.py:1101 +#: AKModel/models.py:1140 msgid "Room has two AK slots scheduled at the same time" msgstr "Raum hat zwei AK Slots gleichzeitig" -#: AKModel/models.py:1102 +#: AKModel/models.py:1141 msgid "Room does not satisfy the requirement of the scheduled AK" msgstr "Room erfüllt die Anforderungen des platzierten AKs nicht" -#: AKModel/models.py:1103 +#: AKModel/models.py:1142 msgid "AK Slot is scheduled at the same time as an AK listed as a conflict" msgstr "" "AK Slot wurde wurde zur gleichen Zeit wie ein Konflikt des AKs platziert" -#: AKModel/models.py:1104 +#: AKModel/models.py:1143 msgid "AK Slot is scheduled before an AK listed as a prerequisite" msgstr "AK Slot wurde vor einem als Voraussetzung gelisteten AK platziert" -#: AKModel/models.py:1106 +#: AKModel/models.py:1145 msgid "" "AK Slot for AK with intention to submit a resolution is scheduled after " "resolution deadline" msgstr "" "AK Slot eines AKs mit Resoabsicht wurde nach der Resodeadline platziert" -#: AKModel/models.py:1107 +#: AKModel/models.py:1146 msgid "AK Slot in a category is outside that categories availabilities" msgstr "AK Slot wurde außerhalb der Verfügbarkeiten seiner Kategorie" -#: AKModel/models.py:1108 +#: AKModel/models.py:1147 msgid "Two AK Slots for the same AK scheduled at the same time" msgstr "Zwei AK Slots eines AKs wurden zur selben Zeit platziert" -#: AKModel/models.py:1109 +#: AKModel/models.py:1148 msgid "Room does not have enough space for interest in scheduled AK Slot" msgstr "Room hat nicht genug Platz für das Interesse am geplanten AK-Slot" -#: AKModel/models.py:1110 +#: AKModel/models.py:1149 msgid "AK Slot is scheduled outside the event's availabilities" msgstr "AK Slot wurde außerhalb der Verfügbarkeit des Events platziert" -#: AKModel/models.py:1116 +#: AKModel/models.py:1155 msgid "Warning" msgstr "Warnung" -#: AKModel/models.py:1117 +#: AKModel/models.py:1156 msgid "Violation" msgstr "Verletzung" -#: AKModel/models.py:1119 +#: AKModel/models.py:1158 msgid "Type" msgstr "Art" -#: AKModel/models.py:1120 +#: AKModel/models.py:1159 msgid "Type of violation, i.e. what kind of constraint was violated" msgstr "Art der Verletzung, gibt an welche Art Constraint verletzt wurde" -#: AKModel/models.py:1121 +#: AKModel/models.py:1160 msgid "Level" msgstr "Level" -#: AKModel/models.py:1122 +#: AKModel/models.py:1161 msgid "Severity level of the violation" msgstr "Schweregrad der Verletzung" -#: AKModel/models.py:1129 +#: AKModel/models.py:1168 msgid "AK(s) belonging to this constraint" msgstr "AK(s), die zu diesem Constraint gehören" -#: AKModel/models.py:1131 +#: AKModel/models.py:1170 msgid "AK Slot(s) belonging to this constraint" msgstr "AK Slot(s), die zu diesem Constraint gehören" -#: AKModel/models.py:1133 +#: AKModel/models.py:1172 msgid "AK Owner belonging to this constraint" msgstr "AK Leitung(en), die zu diesem Constraint gehören" -#: AKModel/models.py:1135 +#: AKModel/models.py:1174 msgid "Room belonging to this constraint" msgstr "Raum, der zu diesem Constraint gehört" -#: AKModel/models.py:1138 +#: AKModel/models.py:1177 msgid "AK Requirement belonging to this constraint" msgstr "AK Anforderung, die zu diesem Constraint gehört" -#: AKModel/models.py:1140 +#: AKModel/models.py:1179 msgid "AK Category belonging to this constraint" msgstr "AK Kategorie, di zu diesem Constraint gehört" -#: AKModel/models.py:1142 +#: AKModel/models.py:1181 msgid "Comment" msgstr "Kommentar" -#: AKModel/models.py:1142 +#: AKModel/models.py:1181 msgid "Comment or further details for this violation" msgstr "Kommentar oder weitere Details zu dieser Vereletzung" -#: AKModel/models.py:1145 +#: AKModel/models.py:1184 msgid "Timestamp" msgstr "Timestamp" -#: AKModel/models.py:1145 +#: AKModel/models.py:1184 msgid "Time of creation" msgstr "Zeitpunkt der ERstellung" -#: AKModel/models.py:1146 +#: AKModel/models.py:1185 msgid "Manually Resolved" msgstr "Manuell behoben" -#: AKModel/models.py:1147 +#: AKModel/models.py:1186 msgid "Mark this violation manually as resolved" msgstr "Markiere diese Verletzung manuell als behoben" -#: AKModel/models.py:1174 +#: AKModel/models.py:1213 AKModel/templates/admin/AKModel/aks_by_user.html:22 #: AKModel/templates/admin/AKModel/requirements_overview.html:27 msgid "Details" msgstr "Details" -#: AKModel/models.py:1308 +#: AKModel/models.py:1347 msgid "Default Slot" msgstr "Standardslot" -#: AKModel/models.py:1313 +#: AKModel/models.py:1352 msgid "Slot End" msgstr "Ende des Slots" -#: AKModel/models.py:1313 +#: AKModel/models.py:1352 msgid "Time and date the slot ends" msgstr "Zeit und Datum zu der der Slot endet" -#: AKModel/models.py:1318 +#: AKModel/models.py:1357 msgid "Primary categories" msgstr "Primäre Kategorien" -#: AKModel/models.py:1319 +#: AKModel/models.py:1358 msgid "Categories that should be assigned to this slot primarily" msgstr "Kategorieren, die diesem Slot primär zugewiesen werden sollen" @@ -1017,6 +1059,19 @@ msgstr "Bestätigen" msgid "Cancel" msgstr "Abbrechen" +#: AKModel/templates/admin/AKModel/aks_by_user.html:8 +msgid "AKs by Owner" +msgstr "AKs der Leitung" + +#: AKModel/templates/admin/AKModel/aks_by_user.html:26 +#: AKModel/templates/admin/AKModel/requirements_overview.html:31 +msgid "Edit" +msgstr "Bearbeiten" + +#: AKModel/templates/admin/AKModel/aks_by_user.html:33 +msgid "This user does not have any AKs currently" +msgstr "Diese Leitung hat aktuell keine AKs" + #: AKModel/templates/admin/AKModel/event_wizard/activate.html:9 #: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:9 #: AKModel/templates/admin/AKModel/event_wizard/finish.html:9 @@ -1083,16 +1138,12 @@ msgstr "" msgid "Requirements Overview" msgstr "Übersicht Anforderungen" -#: AKModel/templates/admin/AKModel/requirements_overview.html:31 -msgid "Edit" -msgstr "Bearbeiten" - #: AKModel/templates/admin/AKModel/requirements_overview.html:38 msgid "No AKs with this requirement" msgstr "Kein AK mit dieser Anforderung" #: AKModel/templates/admin/AKModel/requirements_overview.html:45 -#: AKModel/views/status.py:186 +#: AKModel/views/status.py:191 msgid "Add Requirement" msgstr "Anforderung hinzufügen" @@ -1145,7 +1196,7 @@ msgstr "Bisher keine Räume" msgid "Active Events" msgstr "Aktive Events" -#: AKModel/templates/admin/ak_index.html:16 AKModel/views/status.py:108 +#: AKModel/templates/admin/ak_index.html:16 AKModel/views/status.py:113 msgid "Scheduling" msgstr "Scheduling" @@ -1190,35 +1241,35 @@ msgstr "AK-CSV-Export" msgid "AK JSON Export" msgstr "AK-JSON-Export" -#: AKModel/views/ak.py:184 +#: AKModel/views/ak.py:206 msgid "AK Wiki Export" msgstr "AK-Wiki-Export" -#: AKModel/views/ak.py:195 AKModel/views/manage.py:55 +#: AKModel/views/ak.py:217 AKModel/views/manage.py:55 msgid "Wishes" msgstr "Wünsche" -#: AKModel/views/ak.py:207 +#: AKModel/views/ak.py:229 msgid "Delete AK Orga Messages" msgstr "AK-Organachrichten löschen" -#: AKModel/views/ak.py:225 +#: AKModel/views/ak.py:247 msgid "AK Orga Messages successfully deleted" msgstr "AK-Organachrichten erfolgreich gelöscht" -#: AKModel/views/ak.py:237 +#: AKModel/views/ak.py:259 msgid "Interest of the following AKs will be set to not filled (-1):" msgstr "Interesse an den folgenden AKs wird auf nicht ausgefüllt (-1) gesetzt:" -#: AKModel/views/ak.py:238 +#: AKModel/views/ak.py:260 msgid "Reset of interest in AKs successful." msgstr "Interesse an AKs erfolgreich zurückgesetzt." -#: AKModel/views/ak.py:252 +#: AKModel/views/ak.py:274 msgid "Interest counter of the following AKs will be set to 0:" msgstr "Interessensbekundungszähler der folgenden AKs wird auf 0 gesetzt:" -#: AKModel/views/ak.py:253 +#: AKModel/views/ak.py:275 msgid "AKs' interest counters set back to 0." msgstr "Interessenszähler der AKs zurückgesetzt" @@ -1232,7 +1283,7 @@ msgstr "'%(obj)s' kopiert" msgid "Could not copy '%(obj)s' (%(error)s)" msgstr "'%(obj)s' konnte nicht kopiert werden (%(error)s)" -#: AKModel/views/manage.py:37 AKModel/views/status.py:153 +#: AKModel/views/manage.py:37 AKModel/views/status.py:158 msgid "Export AK Slides" msgstr "AK-Folien exportieren" @@ -1300,7 +1351,7 @@ msgstr "Den Plan/die Pläne verbergen von:" msgid "Plan unpublished" msgstr "Plan verborgen" -#: AKModel/views/manage.py:168 AKModel/views/status.py:129 +#: AKModel/views/manage.py:168 AKModel/views/status.py:134 msgid "Edit Default Slots" msgstr "Standardslots bearbeiten" @@ -1334,7 +1385,7 @@ msgstr "AK-Plan importieren fehlgeschlagen! Grund: " msgid "Created Room '%(room)s'" msgstr "Raum '%(room)s' angelegt" -#: AKModel/views/room.py:51 AKModel/views/status.py:81 +#: AKModel/views/room.py:51 AKModel/views/status.py:86 msgid "Import Rooms from CSV" msgstr "Räume aus CSV importieren" @@ -1368,48 +1419,42 @@ msgstr "Kategorie hinzufügen" msgid "Add Room" msgstr "Raum hinzufügen" -#: AKModel/views/status.py:115 +#: AKModel/views/status.py:120 msgid "AKs requiring special attention" msgstr "AKs, die besondere Aufmerksamkeit benötigen" -#: AKModel/views/status.py:121 +#: AKModel/views/status.py:126 msgid "Enter Interest" msgstr "Interesse erfassen" -#: AKModel/views/status.py:133 +#: AKModel/views/status.py:138 msgid "Manage ak tracks" msgstr "AK-Tracks verwalten" -#: AKModel/views/status.py:137 +#: AKModel/views/status.py:142 msgid "Import AK schedule from JSON" msgstr "AK-Plan aus JSON importieren" -#: AKModel/views/status.py:141 +#: AKModel/views/status.py:146 msgid "Export AKs as CSV" msgstr "AKs als CSV exportieren" -#: AKModel/views/status.py:145 +#: AKModel/views/status.py:150 msgid "Export AKs as JSON" msgstr "AKs als JSON exportieren" -#: AKModel/views/status.py:149 +#: AKModel/views/status.py:154 msgid "Export AKs for Wiki" msgstr "AKs im Wiki-Format exportieren" -#: AKModel/views/status.py:182 +#: AKModel/views/status.py:187 msgid "Show AKs for requirements" msgstr "Zu Anforderungen gehörige AKs anzeigen" -#: AKModel/views/status.py:196 +#: AKModel/views/status.py:201 msgid "Event Status" msgstr "Eventstatus" -#~ msgid "AKs by Owner" -#~ msgstr "AKs der Leitung" - -#~ msgid "This user does not have any AKs currently" -#~ msgstr "Diese Leitung hat aktuell keine AKs" - #~ msgid "Opening time for expression of interest." #~ msgstr "Öffnungszeitpunkt für die Angabe von Interesse an AKs." diff --git a/AKModel/migrations/0061_types.py b/AKModel/migrations/0061_types.py new file mode 100644 index 0000000000000000000000000000000000000000..815a1563bd9eb81dfcb6c093bf0bd582e2e91a6c --- /dev/null +++ b/AKModel/migrations/0061_types.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.13 on 2025-02-25 20:58 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0060_orga_message_resolved'), + ] + + operations = [ + migrations.CreateModel( + name='AKType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Name describing the type', max_length=128, verbose_name='Name')), + ('event', models.ForeignKey(help_text='Associated event', on_delete=django.db.models.deletion.CASCADE, to='AKModel.event', verbose_name='Event')), + ], + options={ + 'verbose_name': 'AK Type', + 'verbose_name_plural': 'AK Types', + 'ordering': ['name'], + 'unique_together': {('event', 'name')}, + }, + ), + migrations.AddField( + model_name='ak', + name='types', + field=models.ManyToManyField(blank=True, help_text='This AK is', to='AKModel.aktype', verbose_name='Types'), + ), + ] diff --git a/AKModel/migrations/0062_interest_no_history.py b/AKModel/migrations/0062_interest_no_history.py new file mode 100644 index 0000000000000000000000000000000000000000..bad3647a25231487948abc86efa2c9d30d2852fb --- /dev/null +++ b/AKModel/migrations/0062_interest_no_history.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.13 on 2025-02-26 22:35 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('AKModel', '0061_types'), + ] + + operations = [ + migrations.RemoveField( + model_name='historicalak', + name='interest', + ), + ] diff --git a/AKModel/migrations/0063_merge_0061_event_export_slot_0062_interest_no_history.py b/AKModel/migrations/0063_merge_0061_event_export_slot_0062_interest_no_history.py new file mode 100644 index 0000000000000000000000000000000000000000..1e64026c1e18c08a82126443030c598da0ddf8ed --- /dev/null +++ b/AKModel/migrations/0063_merge_0061_event_export_slot_0062_interest_no_history.py @@ -0,0 +1,13 @@ +# Generated by Django 4.2.13 on 2025-02-27 18:10 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("AKModel", "0061_event_export_slot"), + ("AKModel", "0062_interest_no_history"), + ] + + operations = [] diff --git a/AKModel/models.py b/AKModel/models.py index 7c1a920b8eac51bf5fbe5f36bda47de159c0aca8..c2383c33b74495eb5976e630b109d729a197841b 100644 --- a/AKModel/models.py +++ b/AKModel/models.py @@ -645,6 +645,25 @@ class AKRequirement(models.Model): return self.name +class AKType(models.Model): + """ An AKType allows to associate one or multiple types with an AK, e.g., to better describe the format of that AK + or to which group of people it is addressed. Types are specified per event and are an optional feature. + """ + name = models.CharField(max_length=128, verbose_name=_('Name'), help_text=_('Name describing the type')) + + event = models.ForeignKey(to=Event, on_delete=models.CASCADE, verbose_name=_('Event'), + help_text=_('Associated event')) + + class Meta: + verbose_name = _('AK Type') + verbose_name_plural = _('AK Types') + ordering = ['name'] + unique_together = ['event', 'name'] + + def __str__(self): + return self.name + + class AK(models.Model): """ An AK is a slot-based activity to be scheduled during an event. """ @@ -662,6 +681,8 @@ class AK(models.Model): category = models.ForeignKey(to=AKCategory, on_delete=models.PROTECT, verbose_name=_('Category'), help_text=_('Category of the AK')) + types = models.ManyToManyField(to=AKType, blank=True, verbose_name=_('Types'), + help_text=_("This AK is")) track = models.ForeignKey(to=AKTrack, blank=True, on_delete=models.SET_NULL, null=True, verbose_name=_('Track'), help_text=_('Track the AK belongs to')) @@ -692,7 +713,7 @@ class AK(models.Model): include_in_export = models.BooleanField(default=True, verbose_name=_('Export?'), help_text=_("Include AK in wiki export?")) - history = HistoricalRecords(excluded_fields=['interest_counter', 'include_in_export']) + history = HistoricalRecords(excluded_fields=['interest', 'interest_counter', 'include_in_export']) class Meta: verbose_name = _('AK') @@ -724,8 +745,24 @@ class AK(models.Model): {_('Interest')}: {self.interest}""" if self.requirements.count() > 0: detail_string += f"\n{_('Requirements')}: {', '.join(str(r) for r in self.requirements.all())}" + if self.types.count() > 0: + detail_string += f"\n{_('Types')}: {', '.join(str(r) for r in self.types.all())}" + + # Find conflicts + # (both directions, those specified for this AK and those were this AK was specified as conflict) + # Deduplicate and order list alphabetically + conflicts = set() if self.conflicts.count() > 0: - detail_string += f"\n{_('Conflicts')}: {', '.join(str(c) for c in self.conflicts.all())}" + for c in self.conflicts.all(): + conflicts.add(str(c)) + if self.conflict.count() > 0: + for c in self.conflict.all(): + conflicts.add(str(c)) + if len(conflicts) > 0: + conflicts = list(conflicts) + conflicts.sort() + detail_string += f"\n{_('Conflicts')}: {', '.join(conflicts)}" + if self.prerequisites.count() > 0: detail_string += f"\n{_('Prerequisites')}: {', '.join(str(p) for p in self.prerequisites.all())}" detail_string += f"\n{_('Availabilities')}: \n{availabilities}" diff --git a/AKModel/templates/admin/AKModel/ak_csv_export.html b/AKModel/templates/admin/AKModel/ak_csv_export.html index b6f1e08994f80f869d29b738704811ce1108aace..dfd0f04dca6fd4ba5d980d709661e3fd86c0d846 100644 --- a/AKModel/templates/admin/AKModel/ak_csv_export.html +++ b/AKModel/templates/admin/AKModel/ak_csv_export.html @@ -4,8 +4,8 @@ {% block content %} <pre> -title;duration;who;requirements;prerequisites;conflicts;availabilities;category;track;reso;notes; -{% for slot in slots %}{{ slot.ak.short_name }};{{ slot.duration }};{{ slot.ak.owners.all|join:", " }};{{ slot.ak.requirements.all|join:", " }};{{ slot.ak.prerequisites.all|join:", " }};{{ slot.ak.conflicts.all|join:", " }};{% for a in slot.ak.availabilities.all %}{{ a.start | timezone:event.timezone | date:"l H:i" }} - {{ a.end | timezone:event.timezone | date:"l H:i" }}, {% endfor %};{{ slot.ak.category }};{{ slot.ak.track }};{{ slot.ak.reso }};{{ slot.ak.notes }}; +title;duration;who;requirements;prerequisites;conflicts;availabilities;category;types;track;reso;notes; +{% for slot in slots %}{{ slot.ak.short_name }};{{ slot.duration }};{{ slot.ak.owners.all|join:", " }};{{ slot.ak.requirements.all|join:", " }};{{ slot.ak.prerequisites.all|join:", " }};{{ slot.ak.conflicts.all|join:", " }};{% for a in slot.ak.availabilities.all %}{{ a.start | timezone:event.timezone | date:"l H:i" }} - {{ a.end | timezone:event.timezone | date:"l H:i" }}, {% endfor %};{{ slot.ak.category }};{{ slot.ak.types.all|join:", " }};{{ slot.ak.track }};{{ slot.ak.reso }};{{ slot.ak.notes }}; {% endfor %} </pre> {% endblock %} diff --git a/AKScheduling/forms.py b/AKScheduling/forms.py index 47a19f7857c3c9e68d2c6e2b59cecf0d79fbcebf..5eff1fcaa65515ac2f14ccc6a5b3c0eaef151b61 100644 --- a/AKScheduling/forms.py +++ b/AKScheduling/forms.py @@ -24,7 +24,8 @@ class AKAddSlotForm(forms.Form): start = forms.CharField(label=_("Start"), disabled=True) end = forms.CharField(label=_("End"), disabled=True) duration = forms.CharField(label=_("Duration"), disabled=True) - room = forms.IntegerField(label=_("Room"), disabled=True) + room = forms.IntegerField(label=_("Room"), disabled=True, widget=forms.HiddenInput()) + room_name = forms.CharField(label=_("Room"), disabled=True) def __init__(self, event): super().__init__() diff --git a/AKScheduling/locale/de_DE/LC_MESSAGES/django.po b/AKScheduling/locale/de_DE/LC_MESSAGES/django.po index 1e391c1fa08573165d8d02636ffd40027437b583..a2fb73ef747f3bc8e7aef7e38ddaef1d28275acd 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: 2025-01-22 19:00+0000\n" +"POT-Creation-Date: 2025-02-27 15:13+0000\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" @@ -29,12 +29,12 @@ msgstr "Ende" msgid "Duration" msgstr "Dauer" -#: AKScheduling/forms.py:27 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:171 +#: AKScheduling/forms.py:27 AKScheduling/forms.py:28 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:172 msgid "Room" msgstr "Raum" -#: AKScheduling/forms.py:31 +#: AKScheduling/forms.py:32 msgid "AK" msgstr "AK" @@ -62,13 +62,13 @@ msgstr "" #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:44 #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:105 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:240 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:375 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:241 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:378 msgid "No violations" msgstr "Keine Verletzungen" #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:82 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:346 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:347 msgid "Violation(s)" msgstr "Verletzung(en)" @@ -81,12 +81,12 @@ msgid "Reload now" msgstr "Jetzt neu laden" #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:95 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:228 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:229 msgid "Violation" msgstr "Verletzung" #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:96 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:369 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:372 msgid "Problem" msgstr "Problem" @@ -100,14 +100,14 @@ msgstr "Seit" #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:111 #: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:256 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:332 -#: AKScheduling/templates/admin/AKScheduling/special_attention.html:48 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:333 +#: AKScheduling/templates/admin/AKScheduling/special_attention.html:58 #: AKScheduling/templates/admin/AKScheduling/unscheduled.html:34 msgid "Event Status" msgstr "Event-Status" #: AKScheduling/templates/admin/AKScheduling/constraint_violations.html:113 -#: AKScheduling/views.py:48 +#: AKScheduling/views.py:50 msgid "Scheduling" msgstr "Scheduling" @@ -117,7 +117,7 @@ msgstr "Abschicken" #: AKScheduling/templates/admin/AKScheduling/manage_tracks.html:11 #: AKScheduling/templates/admin/AKScheduling/scheduling.html:21 -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:329 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:330 msgid "Scheduling for" msgstr "Scheduling für" @@ -169,31 +169,31 @@ msgstr "Event (horizontal)" msgid "Event (Vertical)" msgstr "Event (vertikal)" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:271 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:272 msgid "Please choose AK" msgstr "Bitte AK auswählen" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:291 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:292 msgid "Could not create slot" msgstr "Konnte Slot nicht anlegen" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:307 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:308 msgid "Add slot" msgstr "Slot hinzufügen" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:315 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:316 msgid "Add" msgstr "Hinzufügen" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:316 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:317 msgid "Cancel" msgstr "Abbrechen" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:343 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:344 msgid "Unscheduled" msgstr "Nicht gescheduled" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:368 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:371 msgid "Level" msgstr "Level" @@ -201,23 +201,23 @@ msgstr "Level" msgid "AKs with public notes" msgstr "AKs mit öffentlichen Kommentaren" -#: AKScheduling/templates/admin/AKScheduling/special_attention.html:21 +#: AKScheduling/templates/admin/AKScheduling/special_attention.html:24 msgid "AKs without availabilities" msgstr "AKs ohne Verfügbarkeiten" -#: AKScheduling/templates/admin/AKScheduling/special_attention.html:28 +#: AKScheduling/templates/admin/AKScheduling/special_attention.html:33 msgid "Create default availabilities" msgstr "Standardverfügbarkeiten anlegen" -#: AKScheduling/templates/admin/AKScheduling/special_attention.html:31 +#: AKScheduling/templates/admin/AKScheduling/special_attention.html:36 msgid "AK wishes with slots" msgstr "AK-Wünsche mit Slots" -#: AKScheduling/templates/admin/AKScheduling/special_attention.html:38 +#: AKScheduling/templates/admin/AKScheduling/special_attention.html:46 msgid "Delete slots for wishes" msgstr "" -#: AKScheduling/templates/admin/AKScheduling/special_attention.html:40 +#: AKScheduling/templates/admin/AKScheduling/special_attention.html:48 msgid "AKs without slots" msgstr "AKs ohne Slots" @@ -248,31 +248,31 @@ msgstr "Noch nicht geschedulte AK-Slots" msgid "Count" msgstr "Anzahl" -#: AKScheduling/views.py:89 +#: AKScheduling/views.py:91 msgid "Constraint violations for" msgstr "Constraintverletzungen für" -#: AKScheduling/views.py:104 +#: AKScheduling/views.py:106 msgid "AKs requiring special attention for" msgstr "AKs die besondere Aufmerksamkeit erfordern für" -#: AKScheduling/views.py:150 +#: AKScheduling/views.py:152 msgid "Interest updated" msgstr "Interesse aktualisiert" -#: AKScheduling/views.py:157 +#: AKScheduling/views.py:166 msgid "Enter interest" msgstr "Interesse eingeben" -#: AKScheduling/views.py:201 +#: AKScheduling/views.py:210 msgid "Wishes" msgstr "Wünsche" -#: AKScheduling/views.py:219 +#: AKScheduling/views.py:228 msgid "Cleanup: Delete unscheduled slots for wishes" msgstr "Aufräumen: Noch nicht geplante Slots für Wünsche löschen" -#: AKScheduling/views.py:226 +#: AKScheduling/views.py:235 #, python-brace-format msgid "" "The following {count} unscheduled slots of wishes will be deleted:\n" @@ -284,15 +284,15 @@ msgstr "" "\n" " {slots}" -#: AKScheduling/views.py:233 +#: AKScheduling/views.py:242 msgid "Unscheduled slots for wishes successfully deleted" msgstr "Noch nicht geplante Slots für Wünsche erfolgreich gelöscht" -#: AKScheduling/views.py:247 +#: AKScheduling/views.py:256 msgid "Create default availabilities for AKs" msgstr "Standardverfügbarkeiten für AKs anlegen" -#: AKScheduling/views.py:254 +#: AKScheduling/views.py:263 #, python-brace-format msgid "" "The following {count} AKs don't have any availability information. Create " @@ -305,17 +305,17 @@ msgstr "" "\n" " {aks}" -#: AKScheduling/views.py:274 +#: AKScheduling/views.py:283 #, 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:279 +#: AKScheduling/views.py:288 #, python-brace-format msgid "Created default availabilities for {count} AKs" msgstr "Standardverfügbarkeiten für {count} AKs angelegt" -#: AKScheduling/views.py:290 +#: AKScheduling/views.py:299 msgid "Constraint Violations" msgstr "Constraintverletzungen" diff --git a/AKScheduling/templates/admin/AKScheduling/scheduling.html b/AKScheduling/templates/admin/AKScheduling/scheduling.html index 8d592aecba3cab360c8fb944715ffe0ec36fecf8..872534551d0daf3aa457860ef4246dbb4b241c7e 100644 --- a/AKScheduling/templates/admin/AKScheduling/scheduling.html +++ b/AKScheduling/templates/admin/AKScheduling/scheduling.html @@ -157,6 +157,7 @@ $('#id_start').val(info.startStr); $('#id_end').val(info.endStr); $('#id_room').val(info.resource._resource.id); + $('#id_room_name').val(info.resource._resource.title); $('#id_duration').val(Math.abs(info.end-info.start)/1000/60/60); $('#id_ak').val(""); $('#newAKSlotModal').modal('show'); @@ -354,9 +355,11 @@ <h5 class="mt-2">{{ track_slots.grouper }}</h5> {% endif %} {% for slot in track_slots.list %} - <div class="unscheduled-slot badge" style='background-color: {{ slot.ak.category.color }}' - data-event='{ "title": "{{ slot.ak.short_name }}", "duration": {"hours": "{{ slot.duration|unlocalize }}"}, "constraint": "roomAvailable", "description": "{{ slot.ak.details | escapejs }}", "slotID": "{{ slot.pk }}", "backgroundColor": "{{ slot.ak.category.color }}", "url": "{% url "admin:AKModel_akslot_change" slot.pk %}"}' data-details="{{ slot.ak.details }}">{{ slot.ak.short_name }} + <div class="unscheduled-slot badge" style='background-color: {% with slot.ak.category.color as color %} {% if color %}{{ color }}{% else %}#000000;{% endif %}{% endwith %}' + {% with slot.ak.details as details %} + data-event='{ "title": "{{ slot.ak.short_name }}", "duration": {"hours": "{{ slot.duration|unlocalize }}"}, "constraint": "roomAvailable", "description": "{{ details | escapejs }}", "slotID": "{{ slot.pk }}", "backgroundColor": "{{ slot.ak.category.color }}", "url": "{% url "admin:AKModel_akslot_change" slot.pk %}"}' data-details="{{ details }}">{{ slot.ak.short_name }} ({{ slot.duration }} h)<br>{{ slot.ak.owners_list }} + {% endwith %} </div> {% endfor %} {% endfor %} diff --git a/AKScheduling/templates/admin/AKScheduling/special_attention.html b/AKScheduling/templates/admin/AKScheduling/special_attention.html index 7591cdb5143751a7990f83decf555fb3673e4700..c5a29f037e97e5a382607485889645328cec130f 100644 --- a/AKScheduling/templates/admin/AKScheduling/special_attention.html +++ b/AKScheduling/templates/admin/AKScheduling/special_attention.html @@ -13,14 +13,19 @@ {% block content %} <h4 class="mt-4 mb-4">{% trans "AKs with public notes" %}</h4> {% for ak in aks_with_comment %} - <a href="{{ ak.edit_url }}">{{ ak }}</a><br>{{ ak.notes }}<br><br> + <a href="{{ ak.detail_url }}">{{ ak }}</a> + <a href="{{ ak.edit_url }}">{% fa6_icon "pen-to-square" %}</a> + <a class="link-warning" href="{% url "admin:AKModel_ak_change" object_id=ak.pk %}">{% fa6_icon "pen-to-square" %}</a><br> + {{ ak.notes }}<br><br> {% empty %} - {% endfor %} <h4 class="mt-4 mb-4">{% trans "AKs without availabilities" %}</h4> {% for ak in aks_without_availabilities %} - <a href="{{ ak.edit_url }}">{{ ak }}</a><br> + <a href="{{ ak.detail_url }}">{{ ak }}</a> + <a href="{{ ak.edit_url }}">{% fa6_icon "pen-to-square" %}</a> + <a class="link-warning" href="{% url "admin:AKModel_ak_change" object_id=ak.pk %}">{% fa6_icon "pen-to-square" %}</a><br> {% empty %} -<br> {% endfor %} @@ -30,7 +35,10 @@ <h4 class="mt-4 mb-4">{% trans "AK wishes with slots" %}</h4> {% for ak in ak_wishes_with_slots %} - <a href="{{ ak.detail_url }}">{{ ak }}</a> <a href="{% url "admin:AKModel_akslot_changelist" %}?ak={{ ak.pk }}">({{ ak.akslot__count }})</a><br> + <a href="{% url "admin:AKModel_akslot_changelist" %}?ak={{ ak.pk }}">({{ ak.akslot__count }})</a> + <a href="{{ ak.detail_url }}">{{ ak }}</a> + <a href="{{ ak.edit_url }}">{% fa6_icon "pen-to-square" %}</a> + <a class="link-warning" href="{% url "admin:AKModel_ak_change" object_id=ak.pk %}">{% fa6_icon "pen-to-square" %}</a><br> {% empty %} -<br> {% endfor %} @@ -39,7 +47,9 @@ <h4 class="mt-4 mb-4">{% trans "AKs without slots" %}</h4> {% for ak in aks_without_slots %} - <a href="{{ ak.detail_url }}">{{ ak }}</a><br> + <a href="{{ ak.detail_url }}">{{ ak }}</a> + <a href="{{ ak.edit_url }}">{% fa6_icon "pen-to-square" %}</a> + <a class="link-warning" href="{% url "admin:AKModel_ak_change" object_id=ak.pk %}">{% fa6_icon "pen-to-square" %}</a><br> {% empty %} -<br> {% endfor %} diff --git a/AKScheduling/views.py b/AKScheduling/views.py index c7ecd4fc3d419c00857d6f53d4e8abc1893f61c6..ea8d1cc4981bb79999ecc5f80263a1cf052bee94 100644 --- a/AKScheduling/views.py +++ b/AKScheduling/views.py @@ -41,7 +41,9 @@ class SchedulingAdminView(AdminViewMixin, FilterByEventSlugMixin, ListView): context_object_name = "slots_unscheduled" def get_queryset(self): - return super().get_queryset().filter(start__isnull=True).select_related('event', 'ak').order_by('ak__track') + return super().get_queryset().filter(start__isnull=True).select_related('event', 'ak', 'ak__track', + 'ak__category').prefetch_related('ak__types', 'ak__owners', 'ak__conflicts', 'ak__prerequisites', + 'ak__requirements', 'ak__conflict').order_by('ak__track', 'ak') def get_context_data(self, *, object_list=None, **kwargs): context = super().get_context_data(object_list=object_list, **kwargs) @@ -152,6 +154,13 @@ class InterestEnteringAdminView(SuccessMessageMixin, AdminViewMixin, EventSlugMi def get_success_url(self): return self.request.path + def form_valid(self, form): + # Don't create a history entry for this change + form.instance.skip_history_when_saving = True + r = super().form_valid(form) + del form.instance.skip_history_when_saving + return r + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["title"] = f"{_('Enter interest')}" diff --git a/AKSubmission/forms.py b/AKSubmission/forms.py index 644ff5aae630f0ea8e713b7adee2d9351451cffa..70913ae780adc8d55239c651036d23b97a7871c6 100644 --- a/AKSubmission/forms.py +++ b/AKSubmission/forms.py @@ -11,7 +11,7 @@ from django.utils.translation import gettext_lazy as _ from AKModel.availability.forms import AvailabilitiesFormMixin from AKModel.availability.models import Availability -from AKModel.models import AK, AKOwner, AKCategory, AKRequirement, AKSlot, AKOrgaMessage +from AKModel.models import AK, AKOwner, AKCategory, AKRequirement, AKSlot, AKOrgaMessage, AKType class AKForm(AvailabilitiesFormMixin, forms.ModelForm): @@ -37,6 +37,7 @@ class AKForm(AvailabilitiesFormMixin, forms.ModelForm): 'owners', 'description', 'category', + 'types', 'reso', 'present', 'requirements', @@ -48,6 +49,7 @@ class AKForm(AvailabilitiesFormMixin, forms.ModelForm): widgets = { 'requirements': forms.CheckboxSelectMultiple, + 'types': forms.CheckboxSelectMultiple, 'event': forms.HiddenInput, } @@ -61,6 +63,10 @@ class AKForm(AvailabilitiesFormMixin, forms.ModelForm): self.fields["prerequisites"].widget.attrs = {'class': 'chosen-select'} self.fields['category'].queryset = AKCategory.objects.filter(event=self.initial.get('event')) + self.fields['types'].queryset = AKType.objects.filter(event=self.initial.get('event')) + # Don't ask for types if there are no types configured for this event + if self.fields['types'].queryset.count() == 0: + self.fields.pop('types') self.fields['requirements'].queryset = AKRequirement.objects.filter(event=self.initial.get('event')) # Don't ask for requirements if there are no requirements configured for this event if self.fields['requirements'].queryset.count() == 0: diff --git a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po index 478eb3efe0d84fb473be0d911d91be6d9237a890..f47345a6b052651a9a8e049f95a41be97b463f07 100644 --- a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po +++ b/AKSubmission/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: 2025-02-02 23:53+0100\n" +"POT-Creation-Date: 2025-02-27 15:13+0000\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" @@ -17,16 +17,16 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: AKSubmission/forms.py:95 +#: AKSubmission/forms.py:101 #, python-format msgid "\"%(duration)s\" is not a valid duration" msgstr "\"%(duration)s\" ist keine gültige Dauer" -#: AKSubmission/forms.py:155 +#: AKSubmission/forms.py:161 msgid "Duration(s)" msgstr "Dauer(n)" -#: AKSubmission/forms.py:157 +#: AKSubmission/forms.py:163 msgid "" "Enter at least one planned duration (in hours). If your AK should have " "multiple slots, use multiple lines" @@ -34,7 +34,7 @@ msgstr "" "Mindestens eine geplante Dauer (in Stunden) angeben. Wenn der AK mehrere " "Slots haben soll, mehrere Zeilen verwenden" -#: AKSubmission/templates/AKSubmission/ak_detail.html:23 +#: AKSubmission/templates/AKSubmission/ak_detail.html:22 #: AKSubmission/templates/AKSubmission/ak_edit.html:13 #: AKSubmission/templates/AKSubmission/ak_history.html:16 #: AKSubmission/templates/AKSubmission/ak_overview.html:22 @@ -52,61 +52,61 @@ msgstr "" msgid "AK Submission" msgstr "AK-Eintragung" -#: AKSubmission/templates/AKSubmission/ak_detail.html:127 +#: AKSubmission/templates/AKSubmission/ak_detail.html:126 #: AKSubmission/templates/AKSubmission/ak_interest_script.html:50 msgid "Interest indication currently not allowed. Sorry." msgstr "Interessenangabe aktuell nicht erlaubt. Sorry." -#: AKSubmission/templates/AKSubmission/ak_detail.html:129 +#: AKSubmission/templates/AKSubmission/ak_detail.html:128 #: AKSubmission/templates/AKSubmission/ak_interest_script.html:52 msgid "Could not save your interest. Sorry." msgstr "Interesse konnte nicht gespeichert werden. Sorry." -#: AKSubmission/templates/AKSubmission/ak_detail.html:150 +#: AKSubmission/templates/AKSubmission/ak_detail.html:149 msgid "Interest" msgstr "Interesse" -#: AKSubmission/templates/AKSubmission/ak_detail.html:152 -#: AKSubmission/templates/AKSubmission/ak_table.html:55 +#: AKSubmission/templates/AKSubmission/ak_detail.html:151 +#: AKSubmission/templates/AKSubmission/ak_table.html:65 msgid "Show Interest" msgstr "Interesse bekunden" -#: AKSubmission/templates/AKSubmission/ak_detail.html:158 -#: AKSubmission/templates/AKSubmission/ak_table.html:46 +#: AKSubmission/templates/AKSubmission/ak_detail.html:157 +#: AKSubmission/templates/AKSubmission/ak_table.html:56 msgid "Open external link" msgstr "Externen Link öffnen" -#: AKSubmission/templates/AKSubmission/ak_detail.html:163 +#: AKSubmission/templates/AKSubmission/ak_detail.html:162 msgid "Open protocol link" msgstr "Protokolllink öffnen" -#: AKSubmission/templates/AKSubmission/ak_detail.html:168 +#: AKSubmission/templates/AKSubmission/ak_detail.html:167 #: AKSubmission/templates/AKSubmission/ak_history.html:19 #: AKSubmission/templates/AKSubmission/ak_history.html:31 msgid "History" msgstr "Versionsgeschichte" -#: AKSubmission/templates/AKSubmission/ak_detail.html:171 +#: AKSubmission/templates/AKSubmission/ak_detail.html:170 #: AKSubmission/templates/AKSubmission/akmessage_add.html:8 #: AKSubmission/templates/AKSubmission/akmessage_add.html:16 #: AKSubmission/templates/AKSubmission/akmessage_add.html:22 msgid "Add confidential message to organizers" msgstr "Sende eine private Nachricht an das Organisationsteam" -#: AKSubmission/templates/AKSubmission/ak_detail.html:174 -#: AKSubmission/templates/AKSubmission/ak_detail.html:317 +#: AKSubmission/templates/AKSubmission/ak_detail.html:173 +#: AKSubmission/templates/AKSubmission/ak_detail.html:326 #: AKSubmission/templates/AKSubmission/ak_edit.html:16 -#: AKSubmission/templates/AKSubmission/ak_table.html:51 +#: AKSubmission/templates/AKSubmission/ak_table.html:61 msgid "Edit" msgstr "Bearbeiten" -#: AKSubmission/templates/AKSubmission/ak_detail.html:179 +#: AKSubmission/templates/AKSubmission/ak_detail.html:178 #: AKSubmission/templates/AKSubmission/ak_history.html:31 -#: AKSubmission/templates/AKSubmission/ak_table.html:34 +#: AKSubmission/templates/AKSubmission/ak_table.html:37 msgid "AK Wish" msgstr "AK-Wunsch" -#: AKSubmission/templates/AKSubmission/ak_detail.html:187 +#: AKSubmission/templates/AKSubmission/ak_detail.html:186 #, python-format msgid "" "This AK currently takes place for another <span v-html=\"timeUntilEnd\">" @@ -116,7 +116,8 @@ msgstr "" "%(featured_slot_remaining)s</span> Minute(n) in %(room)s statt. \n" " " -#: AKSubmission/templates/AKSubmission/ak_detail.html:190 +#: AKSubmission/templates/AKSubmission/ak_detail.html:189 +#, python-format msgid "" "This AK starts in <span v-html=\"timeUntilStart\">" "%(featured_slot_remaining)s</span> minute(s) in %(room)s. " @@ -125,89 +126,94 @@ msgstr "" "%(featured_slot_remaining)s</span> Minute(n) in %(room)s. \n" " " -#: AKSubmission/templates/AKSubmission/ak_detail.html:195 -#: AKSubmission/templates/AKSubmission/ak_detail.html:325 +#: AKSubmission/templates/AKSubmission/ak_detail.html:194 +#: AKSubmission/templates/AKSubmission/ak_detail.html:334 msgid "Go to virtual room" msgstr "Zum virtuellen Raum" -#: AKSubmission/templates/AKSubmission/ak_detail.html:206 +#: AKSubmission/templates/AKSubmission/ak_detail.html:205 #: AKSubmission/templates/AKSubmission/ak_table.html:10 msgid "Who?" msgstr "Wer?" -#: AKSubmission/templates/AKSubmission/ak_detail.html:212 +#: AKSubmission/templates/AKSubmission/ak_detail.html:211 #: AKSubmission/templates/AKSubmission/ak_history.html:36 #: AKSubmission/templates/AKSubmission/ak_table.html:11 msgid "Category" msgstr "Kategorie" -#: AKSubmission/templates/AKSubmission/ak_detail.html:219 +#: AKSubmission/templates/AKSubmission/ak_detail.html:218 +#: AKSubmission/templates/AKSubmission/ak_table.html:13 +msgid "Types" +msgstr "Typen" + +#: AKSubmission/templates/AKSubmission/ak_detail.html:228 #: AKSubmission/templates/AKSubmission/ak_history.html:37 msgid "Track" msgstr "Track" -#: AKSubmission/templates/AKSubmission/ak_detail.html:225 +#: AKSubmission/templates/AKSubmission/ak_detail.html:234 msgid "Present this AK" msgstr "Diesen AK vorstellen" -#: AKSubmission/templates/AKSubmission/ak_detail.html:230 +#: AKSubmission/templates/AKSubmission/ak_detail.html:239 msgid "(Category Default)" msgstr "(Kategorievoreinstellung)" -#: AKSubmission/templates/AKSubmission/ak_detail.html:236 +#: AKSubmission/templates/AKSubmission/ak_detail.html:245 msgid "Reso intention?" msgstr "Resoabsicht?" -#: AKSubmission/templates/AKSubmission/ak_detail.html:243 +#: AKSubmission/templates/AKSubmission/ak_detail.html:252 msgid "Requirements" msgstr "Anforderungen" -#: AKSubmission/templates/AKSubmission/ak_detail.html:256 +#: AKSubmission/templates/AKSubmission/ak_detail.html:265 msgid "Conflicting AKs" msgstr "AK-Konflikte" -#: AKSubmission/templates/AKSubmission/ak_detail.html:264 +#: AKSubmission/templates/AKSubmission/ak_detail.html:273 msgid "Prerequisite AKs" msgstr "Vorausgesetzte AKs" -#: AKSubmission/templates/AKSubmission/ak_detail.html:272 +#: AKSubmission/templates/AKSubmission/ak_detail.html:281 msgid "Notes" msgstr "Notizen" -#: AKSubmission/templates/AKSubmission/ak_detail.html:285 +#: AKSubmission/templates/AKSubmission/ak_detail.html:294 msgid "When?" msgstr "Wann?" -#: AKSubmission/templates/AKSubmission/ak_detail.html:287 +#: AKSubmission/templates/AKSubmission/ak_detail.html:296 #: AKSubmission/templates/AKSubmission/akslot_delete.html:35 msgid "Duration" msgstr "Dauer" -#: AKSubmission/templates/AKSubmission/ak_detail.html:289 +#: AKSubmission/templates/AKSubmission/ak_detail.html:298 msgid "Room" msgstr "Raum" -#: AKSubmission/templates/AKSubmission/ak_detail.html:320 +#: AKSubmission/templates/AKSubmission/ak_detail.html:329 msgid "Delete" msgstr "Löschen" -#: AKSubmission/templates/AKSubmission/ak_detail.html:331 +#: AKSubmission/templates/AKSubmission/ak_detail.html:340 msgid "Schedule" msgstr "Schedule" -#: AKSubmission/templates/AKSubmission/ak_detail.html:343 +#: AKSubmission/templates/AKSubmission/ak_detail.html:352 msgid "Add another slot" msgstr "Einen neuen AK-Slot hinzufügen" -#: AKSubmission/templates/AKSubmission/ak_detail.html:353 +#: AKSubmission/templates/AKSubmission/ak_detail.html:362 msgid "Possible Times" msgstr "Mögliche Zeiten" -#: AKSubmission/templates/AKSubmission/ak_detail.html:357 +#: AKSubmission/templates/AKSubmission/ak_detail.html:366 msgid "Start" msgstr "Start" -#: AKSubmission/templates/AKSubmission/ak_detail.html:358 +#: AKSubmission/templates/AKSubmission/ak_detail.html:367 msgid "End" msgstr "Ende" @@ -259,12 +265,12 @@ msgid "Time" msgstr "Zeit" #: AKSubmission/templates/AKSubmission/ak_history.html:48 -#: AKSubmission/templates/AKSubmission/ak_table.html:25 +#: AKSubmission/templates/AKSubmission/ak_table.html:28 msgid "Present results of this AK" msgstr "Die Ergebnisse dieses AKs vorstellen" #: AKSubmission/templates/AKSubmission/ak_history.html:52 -#: AKSubmission/templates/AKSubmission/ak_table.html:29 +#: AKSubmission/templates/AKSubmission/ak_table.html:32 msgid "Intends to submit a resolution" msgstr "Beabsichtigt eine Resolution einzureichen" @@ -284,11 +290,11 @@ msgstr "AK-Liste" msgid "Add AK" msgstr "AK hinzufügen" -#: AKSubmission/templates/AKSubmission/ak_table.html:42 +#: AKSubmission/templates/AKSubmission/ak_table.html:52 msgid "Details" msgstr "Details" -#: AKSubmission/templates/AKSubmission/ak_table.html:66 +#: AKSubmission/templates/AKSubmission/ak_table.html:76 msgid "There are no AKs in this category yet" msgstr "Es gibt noch keine AKs in dieser Kategorie" @@ -404,68 +410,68 @@ msgstr "" "AKs die sich gewünscht wurden, aber bei denen noch nicht klar ist, wer sie " "macht. Falls du dir das vorstellen kannst, trag dich einfach ein" -#: AKSubmission/views.py:167 +#: AKSubmission/views.py:169 msgid "Currently planned AKs" msgstr "Aktuell geplante AKs" -#: AKSubmission/views.py:231 +#: AKSubmission/views.py:233 msgid "AKs with Track" msgstr "AK mit Track" -#: AKSubmission/views.py:300 +#: AKSubmission/views.py:302 msgid "Event inactive. Cannot create or update." msgstr "Event inaktiv. Hinzufügen/Bearbeiten nicht möglich." -#: AKSubmission/views.py:325 +#: AKSubmission/views.py:327 msgid "AK successfully created" msgstr "AK erfolgreich angelegt" -#: AKSubmission/views.py:398 +#: AKSubmission/views.py:400 msgid "AK successfully updated" msgstr "AK erfolgreich aktualisiert" -#: AKSubmission/views.py:449 +#: AKSubmission/views.py:451 #, python-brace-format msgid "Added '{owner}' as new owner of '{ak.name}'" msgstr "'{owner}' als neue Leitung von '{ak.name}' hinzugefügt" -#: AKSubmission/views.py:553 +#: AKSubmission/views.py:555 msgid "No user selected" msgstr "Keine Person ausgewählt" -#: AKSubmission/views.py:569 +#: AKSubmission/views.py:571 msgid "Person Info successfully updated" msgstr "Personen-Info erfolgreich aktualisiert" -#: AKSubmission/views.py:605 +#: AKSubmission/views.py:607 msgid "AK Slot successfully added" msgstr "AK-Slot erfolgreich angelegt" -#: AKSubmission/views.py:624 +#: AKSubmission/views.py:626 msgid "You cannot edit a slot that has already been scheduled" msgstr "Bereits geplante AK-Slots können nicht mehr bearbeitet werden" -#: AKSubmission/views.py:634 +#: AKSubmission/views.py:636 msgid "AK Slot successfully updated" msgstr "AK-Slot erfolgreich aktualisiert" -#: AKSubmission/views.py:652 +#: AKSubmission/views.py:654 msgid "You cannot delete a slot that has already been scheduled" msgstr "Bereits geplante AK-Slots können nicht mehr gelöscht werden" -#: AKSubmission/views.py:662 +#: AKSubmission/views.py:664 msgid "AK Slot successfully deleted" msgstr "AK-Slot erfolgreich angelegt" -#: AKSubmission/views.py:674 +#: AKSubmission/views.py:676 msgid "Messages" msgstr "Nachrichten" -#: AKSubmission/views.py:684 +#: AKSubmission/views.py:686 msgid "Delete all messages" msgstr "Alle Nachrichten löschen" -#: AKSubmission/views.py:711 +#: AKSubmission/views.py:713 msgid "Message to organizers successfully saved" msgstr "Nachricht an die Organisator*innen erfolgreich gespeichert" diff --git a/AKSubmission/templates/AKSubmission/ak_detail.html b/AKSubmission/templates/AKSubmission/ak_detail.html index 08c584854a17890d62f329a47b7c511f2979d230..82fcb64a714bf6e2771063fa5bf32bd86caca01c 100644 --- a/AKSubmission/templates/AKSubmission/ak_detail.html +++ b/AKSubmission/templates/AKSubmission/ak_detail.html @@ -213,6 +213,16 @@ {% category_linked_badge ak.category ak.event.slug %} </td> </tr> + {% if ak.types.count > 0 %} + <tr> + <td>{% trans "Types" %}</td> + <td> + {% for type in ak.types.all %} + <span class="badge bg-info">{{ type }}</span> + {% endfor %} + </td> + </tr> + {% endif %} {% if ak.track %} <tr> <td>{% trans 'Track' %}</td> diff --git a/AKSubmission/templates/AKSubmission/ak_table.html b/AKSubmission/templates/AKSubmission/ak_table.html index 775e95e003bd7d19a16b2954d9d6a193d1861a33..1d21554adad1fd4d140cef4b23ee009eeadf7b87 100644 --- a/AKSubmission/templates/AKSubmission/ak_table.html +++ b/AKSubmission/templates/AKSubmission/ak_table.html @@ -9,6 +9,9 @@ <th>{% trans "Name" %}</th> <th>{% trans "Who?" %}</th> <th>{% trans 'Category' %}</th> + {% if show_types %} + <th>{% trans 'Types' %}</th> + {% endif %} <th></th> </tr> </thead> @@ -37,6 +40,13 @@ {% endif %} </td> <td>{% category_linked_badge ak.category event.slug %}</td> + {% if show_types %} + <td> + {% for aktype in ak.types.all %} + <span class="badge bg-info">{{ aktype }}</span> + {% endfor %} + </td> + {% endif %} <td class="text-end" style="white-space: nowrap;"> <a href="{{ ak.detail_url }}" data-bs-toggle="tooltip" title="{% trans 'Details' %}" diff --git a/AKSubmission/tests.py b/AKSubmission/tests.py index 423a977688e4a16ad9c7d2e37242276882ed45ee..8180ea3c10a4b5d28d741467bbc6df4906f25003 100644 --- a/AKSubmission/tests.py +++ b/AKSubmission/tests.py @@ -6,6 +6,7 @@ from django.utils.datetime_safe import datetime from AKModel.models import AK, AKSlot, Event from AKModel.tests.test_views import BasicViewTests +from AKSubmission.forms import AKSubmissionForm class ModelViewTests(BasicViewTests, TestCase): @@ -236,3 +237,37 @@ class ModelViewTests(BasicViewTests, TestCase): msg_prefix=f"No correct redirect: {add_new_user_to_ak_url} (POST) -> {detail_url}") self._assert_message(response, "Added 'New test owner' as new owner of 'Test AK Inhalt'") self.assertEqual(AK.objects.get(pk=1).owners.count(), 2) + + def test_visibility_requirements_in_submission_form(self): + """ + Test visibility of requirements field in submission form + """ + event = Event.get_by_slug('kif42') + form = AKSubmissionForm(data={'name': 'Test AK', 'event': event}, instance=None, initial={"event":event}) + self.assertIn('requirements', form.fields, + msg="Requirements field not present in form even though event has requirements") + + event2 = Event.objects.create(name='Event without requirements', + slug='no_req', + start=datetime.now(), end=datetime.now(), + active=True) + form2 = AKSubmissionForm(data={'name': 'Test AK', 'event': event2}, instance=None, initial={"event": event2}) + self.assertNotIn('requirements', form2.fields, + msg="Requirements field should not be present for events without requirements") + + def test_visibility_types_in_submission_form(self): + """ + Test visibility of types field in submission form + """ + event = Event.get_by_slug('kif42') + form = AKSubmissionForm(data={'name': 'Test AK', 'event': event}, instance=None, initial={"event":event}) + self.assertIn('types', form.fields, + msg="Requirements field not present in form even though event has requirements") + + event2 = Event.objects.create(name='Event without types', + slug='no_types', + start=datetime.now(), end=datetime.now(), + active=True) + form2 = AKSubmissionForm(data={'name': 'Test AK', 'event': event2}, instance=None, initial={"event": event2}) + self.assertNotIn('types', form2.fields, + msg="Requirements field should not be present for events without types") diff --git a/AKSubmission/views.py b/AKSubmission/views.py index e7940a01c0d97a9fba0118265efe3fc9cdd9f84e..5263b875ea21399a5f98d37914403c2f674ec391 100644 --- a/AKSubmission/views.py +++ b/AKSubmission/views.py @@ -59,7 +59,7 @@ class AKOverviewView(FilterByEventSlugMixin, ListView): :rtype: QuerySet[AK] """ # Use prefetching and relation selection/joining to reduce the amount of necessary queries - return category.ak_set.select_related('event').prefetch_related('owners').all() + return category.ak_set.select_related('event').prefetch_related('owners').prefetch_related('types').all() def get_active_category_name(self, context): """ @@ -130,6 +130,8 @@ class AKOverviewView(FilterByEventSlugMixin, ListView): context["active_category"] = self.get_active_category_name(context) context['table_title'] = self.get_table_title(context) + context['show_types'] = self.event.aktype_set.count() > 0 + # ========================================================== # Display interest indication button? # ========================================================== diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po index c1bbd2db4e5c22f703d2acc6a7388eb37116792b..67103fbfa9c4d81665a77037fd3cb432b1a117f2 100644 --- a/locale/de_DE/LC_MESSAGES/django.po +++ b/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: 2023-08-16 16:30+0200\n" +"POT-Creation-Date: 2025-02-27 15:13+0000\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" @@ -18,24 +18,24 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -#: templates/base.html:43 +#: templates/base.html:44 msgid "" "Are you sure you want to change the language now? This will clear the form!" msgstr "Wirklich jetzt die Sprache ändern? Das wird das Formular zurücksetzen!" -#: templates/base.html:108 +#: templates/base.html:109 msgid "Go to backend" msgstr "Zum Backend" -#: templates/base.html:109 +#: templates/base.html:110 msgid "Docs" msgstr "Doku" -#: templates/base.html:115 +#: templates/base.html:116 msgid "Impress" msgstr "Impressum" -#: templates/base.html:118 +#: templates/base.html:119 msgid "This software is open source" msgstr "Diese Software ist Open Source"