diff --git a/AKModel/admin.py b/AKModel/admin.py index 48c1f87833e0c419f409a253a4e7b8642669c85a..81ab14a6139e62ac0eab4c894154955fcfce8332 100644 --- a/AKModel/admin.py +++ b/AKModel/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.contrib.admin import SimpleListFilter from django.db.models import Count, F from django import forms -from django.shortcuts import render +from django.shortcuts import render, redirect from django.urls import path, reverse_lazy from django.utils import timezone from django.utils.html import format_html @@ -16,7 +16,9 @@ from AKModel.availability.forms import AvailabilitiesFormMixin from AKModel.availability.models import Availability from AKModel.models import Event, AKOwner, AKCategory, AKTrack, AKTag, AKRequirement, AK, AKSlot, Room, AKOrgaMessage, \ ConstraintViolation -from AKModel.views import EventStatusView, AKCSVExportView, AKWikiExportView, AKMessageDeleteView +from AKModel.views import EventStatusView, AKCSVExportView, AKWikiExportView, AKMessageDeleteView, \ + NewEventWizardStartView, NewEventWizardSettingsView, NewEventWizardPrepareImportView, NewEventWizardFinishView, \ + NewEventWizardImportView, NewEventWizardActivateView @admin.register(Event) @@ -27,9 +29,29 @@ class EventAdmin(admin.ModelAdmin): list_editable = ['active'] ordering = ['-start'] + def add_view(self, request, form_url='', extra_context=None): + # Always use wizard to create new events + # (the built-in form wouldn't work anyways since the timezone cannot be specified before starting to fill the form) + return redirect("admin:new_event_wizard_start") + def get_urls(self): urls = super().get_urls() custom_urls = [ + path('add/wizard/start/', self.admin_site.admin_view(NewEventWizardStartView.as_view()), + name="new_event_wizard_start"), + path('add/wizard/settings/', self.admin_site.admin_view(NewEventWizardSettingsView.as_view()), + name="new_event_wizard_settings"), + path('add/wizard/created/<slug:event_slug>/', self.admin_site.admin_view(NewEventWizardPrepareImportView.as_view()), + name="new_event_wizard_prepare_import"), + path('add/wizard/import/<slug:event_slug>/from/<slug:import_slug>/', + self.admin_site.admin_view(NewEventWizardImportView.as_view()), + name="new_event_wizard_import"), + path('add/wizard/activate/<slug:slug>/', + self.admin_site.admin_view(NewEventWizardActivateView.as_view()), + name="new_event_wizard_activate"), + path('add/wizard/finish/<slug:slug>/', + self.admin_site.admin_view(NewEventWizardFinishView.as_view()), + name="new_event_wizard_finish"), path('<slug:slug>/status/', self.admin_site.admin_view(EventStatusView.as_view()), name="event_status"), path('<slug:event_slug>/ak-csv-export/', self.admin_site.admin_view(AKCSVExportView.as_view()), name="ak_csv_export"), path('<slug:event_slug>/ak-wiki-export/', self.admin_site.admin_view(AKWikiExportView.as_view()), name="ak_wiki_export"), @@ -45,11 +67,7 @@ class EventAdmin(admin.ModelAdmin): def get_form(self, request, obj=None, change=False, **kwargs): # Use timezone of event - if obj is not None and obj.timezone: - timezone.activate(obj.timezone) - # No timezone available? Use UTC - else: - timezone.activate("UTC") + timezone.activate(obj.timezone) return super().get_form(request, obj, change, **kwargs) diff --git a/AKModel/forms.py b/AKModel/forms.py new file mode 100644 index 0000000000000000000000000000000000000000..3e39dcaa8f47dfed1e696a3ef93e20d59d8b5ebc --- /dev/null +++ b/AKModel/forms.py @@ -0,0 +1,67 @@ +from bootstrap_datepicker_plus import DateTimePickerInput +from django import forms +from django.forms.utils import ErrorList +from django.utils.translation import ugettext_lazy as _ + +from AKModel.models import Event, AKCategory, AKRequirement + + +class NewEventWizardStartForm(forms.ModelForm): + class Meta: + model = Event + fields = ['name', 'slug', 'timezone'] + + is_init = forms.BooleanField(initial=True, widget=forms.HiddenInput) + + +class NewEventWizardSettingsForm(forms.ModelForm): + class Meta: + model = Event + exclude = [] + widgets = { + 'name': forms.HiddenInput(), + 'slug': forms.HiddenInput(), + 'timezone': forms.HiddenInput(), + 'active': forms.HiddenInput(), + 'plan_hidden': forms.HiddenInput(), + 'start': DateTimePickerInput(options={"format": "YYYY-MM-DD HH:mm"}), + 'end': DateTimePickerInput(options={"format": "YYYY-MM-DD HH:mm"}), + 'reso_deadline': DateTimePickerInput(options={"format": "YYYY-MM-DD HH:mm"}), + } + + +class NewEventWizardPrepareImportForm(forms.Form): + import_event = forms.ModelChoiceField( + queryset=Event.objects.all(), + label=_("Copy ak requirements and ak categories of existing event"), + help_text=_("You can choose what to copy in the next step") + ) + +class NewEventWizardImportForm(forms.Form): + import_categories = forms.ModelMultipleChoiceField( + queryset=AKCategory.objects.all(), + widget=forms.CheckboxSelectMultiple, + label=_("Copy ak categories"), + required=False, + ) + + import_requirements = forms.ModelMultipleChoiceField( + queryset=AKRequirement.objects.all(), + widget=forms.CheckboxSelectMultiple, + label=_("Copy ak requirements"), + required=False, + ) + + 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, + renderer=None): + super().__init__(data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, field_order, + use_required_attribute, renderer) + self.fields["import_categories"].queryset = self.fields["import_categories"].queryset.filter(event=self.initial["import_event"]) + self.fields["import_requirements"].queryset = self.fields["import_requirements"].queryset.filter(event=self.initial["import_event"]) + + +class NewEventWizardActivateForm(forms.ModelForm): + class Meta: + fields = ["active"] + model = Event diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po index ebcaa38424d213de8815bff0745ace84149ceb1a..5d16986b5bb557dcb2d8ef04989ca1c26e7e2ab7 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: 2020-11-03 20:41+0000\n" +"POT-Creation-Date: 2021-02-16 14:42+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,28 +11,35 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: AKModel/admin.py:41 AKModel/admin.py:42 +#: AKModel/admin.py:65 AKModel/admin.py:66 +#: AKModel/templates/admin/AKModel/event_wizard/activate.html:32 +#: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:48 +#: AKModel/templates/admin/AKModel/event_wizard/finish.html:21 #: AKModel/templates/admin/AKModel/status.html:7 #: AKModel/templates/admin/ak_index.html:15 msgid "Status" msgstr "Status" -#: AKModel/admin.py:120 +#: AKModel/admin.py:140 msgid "Wish" msgstr "AK-Wunsch" -#: AKModel/admin.py:126 +#: AKModel/admin.py:146 msgid "Is wish" msgstr "Ist ein Wunsch" -#: AKModel/admin.py:127 +#: AKModel/admin.py:147 msgid "Is not a wish" msgstr "Ist kein Wunsch" -#: AKModel/admin.py:154 +#: AKModel/admin.py:174 msgid "Export to wiki syntax" msgstr "In Wiki-Syntax exportieren" +#: AKModel/admin.py:270 +msgid "AK Details" +msgstr "AK-Details" + #: AKModel/availability/forms.py:20 AKModel/availability/models.py:239 msgid "Availability" msgstr "Verfügbarkeit" @@ -60,13 +67,13 @@ msgstr "Bitte Verfügbarkeiten eintragen!" #: AKModel/availability/models.py:38 AKModel/models.py:47 AKModel/models.py:76 #: AKModel/models.py:128 AKModel/models.py:147 AKModel/models.py:179 #: AKModel/models.py:233 AKModel/models.py:292 AKModel/models.py:324 -#: AKModel/models.py:410 +#: AKModel/models.py:431 msgid "Event" msgstr "Event" #: AKModel/availability/models.py:39 AKModel/models.py:77 AKModel/models.py:129 #: AKModel/models.py:148 AKModel/models.py:180 AKModel/models.py:234 -#: AKModel/models.py:293 AKModel/models.py:325 AKModel/models.py:411 +#: AKModel/models.py:293 AKModel/models.py:325 AKModel/models.py:432 msgid "Associated event" msgstr "Zugehöriges Event" @@ -79,7 +86,7 @@ msgid "Person whose availability this is" msgstr "Person deren Verfügbarkeit hier abgebildet wird" #: AKModel/availability/models.py:56 AKModel/models.py:296 -#: AKModel/models.py:315 AKModel/models.py:419 +#: AKModel/models.py:315 AKModel/models.py:440 msgid "Room" msgstr "Raum" @@ -88,7 +95,7 @@ msgid "Room whose availability this is" msgstr "Raum dessen Verfügbarkeit hier abgebildet wird" #: AKModel/availability/models.py:65 AKModel/models.py:239 -#: AKModel/models.py:314 AKModel/models.py:366 +#: AKModel/models.py:314 AKModel/models.py:387 msgid "AK" msgstr "AK" @@ -97,7 +104,7 @@ msgid "AK whose availability this is" msgstr "Verfügbarkeiten" #: AKModel/availability/models.py:74 AKModel/models.py:132 -#: AKModel/models.py:425 +#: AKModel/models.py:446 msgid "AK Category" msgstr "AK-Kategorie" @@ -109,6 +116,23 @@ msgstr "AK-Kategorie, deren Verfügbarkeit hier abgebildet wird" msgid "Availabilities" msgstr "Verfügbarkeiten" +#: AKModel/forms.py:36 +msgid "Copy ak requirements and ak categories of existing event" +msgstr "AK-Anforderungen und AK-Kategorien eines existierenden Events kopieren" + +#: AKModel/forms.py:37 +msgid "You can choose what to copy in the next step" +msgstr "" +"Im nächsten Schritt kann ausgewählt werden, was genau kopiert werden soll" + +#: AKModel/forms.py:44 +msgid "Copy ak categories" +msgstr "AK-Kategorien kopieren" + +#: AKModel/forms.py:51 +msgid "Copy ak requirements" +msgstr "AK-Anforderungen kopieren" + #: AKModel/models.py:16 AKModel/models.py:123 AKModel/models.py:144 #: AKModel/models.py:163 AKModel/models.py:177 AKModel/models.py:195 #: AKModel/models.py:285 @@ -145,7 +169,7 @@ msgstr "Zeitzone" msgid "Time Zone where this event takes place in" msgstr "Zeitzone in der das Event stattfindet" -#: AKModel/models.py:25 +#: AKModel/models.py:25 AKModel/views.py:188 msgid "Start" msgstr "Start" @@ -261,7 +285,7 @@ msgstr "Internet Link" msgid "Link to Homepage" msgstr "Link zu Homepage oder Webseite" -#: AKModel/models.py:80 AKModel/models.py:418 +#: AKModel/models.py:80 AKModel/models.py:439 msgid "AK Owner" msgstr "AK-Leitung" @@ -321,7 +345,7 @@ msgstr "AK-Tags" msgid "Name of the Requirement" msgstr "Name der Anforderung" -#: AKModel/models.py:183 AKModel/models.py:422 +#: AKModel/models.py:183 AKModel/models.py:443 msgid "AK Requirement" msgstr "AK-Anforderung" @@ -458,7 +482,7 @@ msgstr "Interessenszähler" msgid "People who have indicated interest online" msgstr "Anzahl Personen, die online Interesse bekundet haben" -#: AKModel/models.py:240 AKModel/models.py:413 +#: AKModel/models.py:240 AKModel/models.py:434 #: AKModel/templates/admin/AKModel/status.html:49 #: AKModel/templates/admin/AKModel/status.html:56 msgid "AKs" @@ -536,163 +560,168 @@ msgstr "Letzte Aktualisierung" msgid "AK Slot" msgstr "AK-Slot" -#: AKModel/models.py:331 AKModel/models.py:415 +#: AKModel/models.py:331 AKModel/models.py:436 msgid "AK Slots" msgstr "AK-Slot" -#: AKModel/models.py:345 +#: AKModel/models.py:353 AKModel/models.py:362 msgid "Not scheduled yet" msgstr "Noch nicht geplant" -#: AKModel/models.py:367 +#: AKModel/models.py:388 #, fuzzy #| msgid "Track the AK belongs to" msgid "AK this message belongs to" msgstr "Track zu dem der AK gehört" -#: AKModel/models.py:368 +#: AKModel/models.py:389 msgid "Message text" msgstr "Nachrichtentext" -#: AKModel/models.py:369 +#: AKModel/models.py:390 msgid "Message to the organizers. This is not publicly visible." msgstr "" "Nachricht an die Organisator*innen. Diese ist nicht öffentlich sichtbar." -#: AKModel/models.py:373 +#: AKModel/models.py:394 msgid "AK Orga Message" msgstr "AK-Organachricht" -#: AKModel/models.py:374 +#: AKModel/models.py:395 msgid "AK Orga Messages" msgstr "AK-Organachrichten" -#: AKModel/models.py:383 +#: AKModel/models.py:404 msgid "Constraint Violation" msgstr "Constraintverletzung" -#: AKModel/models.py:384 +#: AKModel/models.py:405 msgid "Constraint Violations" msgstr "Constraintverletzungen" -#: AKModel/models.py:388 +#: AKModel/models.py:409 msgid "Owner has two parallel slots" msgstr "Leitung hat zwei Slots parallel" -#: AKModel/models.py:389 +#: AKModel/models.py:410 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:390 +#: AKModel/models.py:411 msgid "Room has two AK slots scheduled at the same time" msgstr "Raum hat AK Slots gleichzeitig" -#: AKModel/models.py:391 +#: AKModel/models.py:412 msgid "Room does not satisfy the requirement of the scheduled AK" msgstr "Room erfüllt die Anforderungen des platzierten AKs nicht" -#: AKModel/models.py:392 +#: AKModel/models.py:413 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" +msgstr "" +"AK Slot wurde wurde zur gleichen Zeit wie ein Konflikt des AKs platziert" -#: AKModel/models.py:393 +#: AKModel/models.py:414 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:395 -msgid "AK Slot for AK with intention to submit a resolution is scheduled after " +#: AKModel/models.py:416 +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" +msgstr "" +"AK Slot eines AKs mit Resoabsicht wurde nach der Resodeadline platziert" -#: AKModel/models.py:396 +#: AKModel/models.py:417 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:397 +#: AKModel/models.py:418 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:398 +#: AKModel/models.py:419 msgid "AK Slot is scheduled in a room with less space than interest" -msgstr "AK Slot wurde in einem Raum mit weniger Plätzen als am AK Interessierten platziert" +msgstr "" +"AK Slot wurde in einem Raum mit weniger Plätzen als am AK Interessierten " +"platziert" -#: AKModel/models.py:399 +#: AKModel/models.py:420 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:402 +#: AKModel/models.py:423 msgid "Warning" msgstr "Warnung" -#: AKModel/models.py:403 +#: AKModel/models.py:424 msgid "Violation" msgstr "Verletzung" -#: AKModel/models.py:405 +#: AKModel/models.py:426 msgid "Type" msgstr "Art" -#: AKModel/models.py:406 +#: AKModel/models.py:427 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:407 +#: AKModel/models.py:428 msgid "Level" msgstr "Level" -#: AKModel/models.py:408 +#: AKModel/models.py:429 msgid "Severity level of the violation" msgstr "Schweregrad der Verletzung" -#: AKModel/models.py:414 +#: AKModel/models.py:435 msgid "AK(s) belonging to this constraint" msgstr "AK(s), die zu diesem Constraint gehören" -#: AKModel/models.py:416 +#: AKModel/models.py:437 msgid "AK Slot(s) belonging to this constraint" msgstr "AK Slot(s), die zu diesem Constraint gehören" -#: AKModel/models.py:418 +#: AKModel/models.py:439 msgid "AK Owner belonging to this constraint" msgstr "AK Leitung(en), die zu diesem Constraint gehören" -#: AKModel/models.py:420 +#: AKModel/models.py:441 msgid "Room belonging to this constraint" msgstr "Raum, der zu diesem Constraint gehört" -#: AKModel/models.py:423 +#: AKModel/models.py:444 msgid "AK Requirement belonging to this constraint" msgstr "AK Anforderung, die zu diesem Constraint gehört" -#: AKModel/models.py:425 +#: AKModel/models.py:446 msgid "AK Category belonging to this constraint" msgstr "AK Kategorie, di zu diesem Constraint gehört" -#: AKModel/models.py:427 +#: AKModel/models.py:448 msgid "Comment" msgstr "Kommentar" -#: AKModel/models.py:427 +#: AKModel/models.py:448 msgid "Comment or further details for this violation" msgstr "Kommentar oder weitere Details zu dieser Vereletzung" -#: AKModel/models.py:430 +#: AKModel/models.py:451 msgid "Timestamp" msgstr "Timestamp" -#: AKModel/models.py:430 +#: AKModel/models.py:451 msgid "Time of creation" msgstr "Zeitpunkt der ERstellung" -#: AKModel/models.py:431 +#: AKModel/models.py:452 msgid "Manually Resolved" msgstr "Manuell behoben" -#: AKModel/models.py:432 +#: AKModel/models.py:453 msgid "Mark this violation manually as resolved" msgstr "Markiere diese Verletzung manuell als behoben" -#: AKModel/models.py:454 +#: AKModel/models.py:475 msgid "Details" msgstr "Details" @@ -717,6 +746,71 @@ msgstr "" msgid "Logout" msgstr "Ausloggen" +#: 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 +#: AKModel/templates/admin/AKModel/event_wizard/import.html:9 +#: AKModel/templates/admin/AKModel/event_wizard/settings.html:9 +#: AKModel/templates/admin/AKModel/event_wizard/start.html:8 +#: AKModel/templates/admin/AKModel/event_wizard/wizard_steps.html:3 +msgid "New event wizard" +msgstr "Assistent zum Anlegen eines neuen Events" + +#: AKModel/templates/admin/AKModel/event_wizard/activate.html:18 +msgid "Successfully imported.<br><br>Do you want to activate your event now?" +msgstr "Erfolgreich importiert.<br><br>Soll das Event jetzt aktiviert werden?" + +#: AKModel/templates/admin/AKModel/event_wizard/activate.html:27 +#: AKModel/views.py:193 +msgid "Finish" +msgstr "Abschluss" + +#: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:16 +msgid "New event:" +msgstr "Neues Event:" + +#: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:30 +msgid "Your event was created and can now be further configured." +msgstr "Das Event wurde angelegt und kann nun weiter konfiguriert werden." + +#: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:39 +msgid "Skip Import" +msgstr "Import überspringen" + +#: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:43 +#: AKModel/templates/admin/AKModel/event_wizard/import.html:20 +#: AKModel/templates/admin/AKModel/event_wizard/settings.html:22 +#: AKModel/templates/admin/AKModel/event_wizard/start.html:19 +msgid "Continue" +msgstr "Fortfahren" + +#: AKModel/templates/admin/AKModel/event_wizard/finish.html:18 +msgid "Congratulations. Everything is set up!" +msgstr "Herzlichen Glückwunsch. Alles ist eingerichtet!" + +#: AKModel/templates/admin/AKModel/event_wizard/import.html:24 +#: AKModel/templates/admin/AKModel/event_wizard/settings.html:29 +#: AKModel/templates/admin/AKModel/event_wizard/start.html:23 +#: AKModel/templates/admin/AKModel/message_delete.html:21 +msgid "Cancel" +msgstr "Abbrechen" + +#: AKModel/templates/admin/AKModel/event_wizard/settings.html:26 +msgid "Back" +msgstr "Zurück" + +#: AKModel/templates/admin/AKModel/event_wizard/start.html:13 +msgid "" +"Add a new event. Please start by filling these basic properties. You can " +"specify more settings later." +msgstr "" +"Neues Event anlegen. Bitte zunächst diese Grundeinstellungen ausfüllen, " +"weitere Einstellungen können später gesetzt werden." + +#: AKModel/templates/admin/AKModel/event_wizard/wizard_steps.html:15 +msgid "Step" +msgstr "Schritt" + #: AKModel/templates/admin/AKModel/message_delete.html:7 msgid "Delete Orga-Messages" msgstr "Organachrichten löschen" @@ -739,10 +833,6 @@ msgstr "" msgid "Delete" msgstr "Löschen" -#: AKModel/templates/admin/AKModel/message_delete.html:21 -msgid "Cancel" -msgstr "Abbrechen" - #: AKModel/templates/admin/AKModel/status.html:16 msgid "Categories" msgstr "Kategorien" @@ -810,22 +900,50 @@ msgstr "Alle Nachrichten löschen" msgid "Active Events" msgstr "Aktive Events" -#: AKModel/views.py:130 +#: AKModel/views.py:131 msgid "Event Status" msgstr "Eventstatus" -#: AKModel/views.py:144 +#: AKModel/views.py:145 msgid "AK CSV Export" msgstr "AK-CSV-Export" -#: AKModel/views.py:158 +#: AKModel/views.py:159 msgid "AK Wiki Export" msgstr "AK-Wiki-Export" -#: AKModel/views.py:178 +#: AKModel/views.py:179 msgid "AK Orga Messages successfully deleted" msgstr "AK-Organachrichten erfolgreich gelöscht" +#: AKModel/views.py:189 +msgid "Settings" +msgstr "Einstellungen" + +#: AKModel/views.py:190 +msgid "Event created, Prepare Import" +msgstr "Event angelegt, Import vorbereiten" + +#: AKModel/views.py:191 +msgid "Import categories & requirements" +msgstr "Kategorien & Anforderungen kopieren" + +#: AKModel/views.py:192 +#, fuzzy +#| msgid "Active State" +msgid "Activate?" +msgstr "Aktivieren?" + +#: AKModel/views.py:250 +#, python-format +msgid "Copied '%(obj)s'" +msgstr "'%(obj)s' kopiert" + +#: AKModel/views.py:252 +#, python-format +msgid "Could not copy '%(obj)s' (%(error)s)" +msgstr "'%(obj)s' konnte nicht kopiert werden (%(error)s)" + #~ msgid "Confirm" #~ msgstr "Bestätigen" diff --git a/AKModel/templates/admin/AKModel/event_wizard/activate.html b/AKModel/templates/admin/AKModel/event_wizard/activate.html new file mode 100644 index 0000000000000000000000000000000000000000..eb460420a410be7ff3b2ac08f761c21c6bd17c5c --- /dev/null +++ b/AKModel/templates/admin/AKModel/event_wizard/activate.html @@ -0,0 +1,36 @@ +{% extends "admin/base_site.html" %} +{% load tags_AKModel %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome_5 %} +{% load tz %} + +{% block title %}{% trans "New event wizard" %}: {{ wizard_step_text }}{% endblock %} + +{% block content %} + {% include "admin/AKModel/event_wizard/wizard_steps.html" %} + + <div class="text-center btn-success disabled mt-3 mb-3" style="font-size: 8em;"> + {% fa5_icon "copy" "fas" %} + </div> + + <h5 class="mb-3">{% trans "Successfully imported.<br><br>Do you want to activate your event now?" %}</h5> + + {{ form.media }} + + <form method="post">{% csrf_token %} + {% bootstrap_form form %} + + <div class="float-right"> + <button type="submit" class="save btn btn-success" value="Submit"> + {% fa5_icon "check" 'fas' %} {% trans "Finish" %} + </button> + </div> + + <a href="{% url 'admin:event_status' event.slug %}" class="btn btn-info"> + {% fa5_icon "info" 'fas' %} {% trans "Status" %} + </a> + </form> + +{% endblock %} diff --git a/AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html b/AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html new file mode 100644 index 0000000000000000000000000000000000000000..e1fc7165a13e039801a70c294ce77049b87b9ba8 --- /dev/null +++ b/AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html @@ -0,0 +1,52 @@ +{% extends "admin/base_site.html" %} +{% load tags_AKModel %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome_5 %} +{% load tz %} + +{% block title %}{% trans "New event wizard" %}: {{ wizard_step_text }}{% endblock %} + +{% block content %} + {% include "admin/AKModel/event_wizard/wizard_steps.html" %} + + {% timezone event.timezone %} + <div class="card border-success mt-3 mb-3" style="max-width: 100%;"> + <div class="card-header">{% trans "New event:" %}</div> + <div class="card-body"> + <h4 class="card-title">{{event}}</h4> + <p class="card-text">{{ event.start }} - {{ event.end }}</p> + </div> + </div> + {% endtimezone %} + + <div class="text-center btn-success disabled mb-3" style="font-size: 8em;"> + {% fa5_icon "calendar-plus" "fas" %} + </div> + + + + <h5 class="mb-3">{% trans "Your event was created and can now be further configured." %}</h5> + + {{ form.media }} + + <form method="post">{% csrf_token %} + {% bootstrap_form form %} + + <div class="float-right"> + <a href="{% url 'admin:new_event_wizard_activate' event.slug %}" class="btn btn-info"> + {% fa5_icon "forward" 'fas' %} {% trans "Skip Import" %} + </a> + + <button type="submit" class="save btn btn-success" value="Submit"> + {% fa5_icon "check" 'fas' %} {% trans "Continue" %} + </button> + </div> + + <a href="{% url 'admin:event_status' event.slug %}" class="btn btn-info"> + {% fa5_icon "info" 'fas' %} {% trans "Status" %} + </a> + </form> + +{% endblock %} diff --git a/AKModel/templates/admin/AKModel/event_wizard/finish.html b/AKModel/templates/admin/AKModel/event_wizard/finish.html new file mode 100644 index 0000000000000000000000000000000000000000..16d3090b0f3d690f3859740b4c9b3cb057f7a1e1 --- /dev/null +++ b/AKModel/templates/admin/AKModel/event_wizard/finish.html @@ -0,0 +1,24 @@ +{% extends "admin/base_site.html" %} +{% load tags_AKModel %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome_5 %} +{% load tz %} + +{% block title %}{% trans "New event wizard" %}: {{ wizard_step_text }}{% endblock %} + +{% block content %} + {% include "admin/AKModel/event_wizard/wizard_steps.html" %} + + <div class="text-center btn-success disabled mt-3 mb-3" style="font-size: 8em;"> + {% fa5_icon "check-circle" "fas" %} + </div> + + <h5>{% trans "Congratulations. Everything is set up!" %}</h5> + + <a href="{% url 'admin:event_status' event.slug %}" class="btn btn-info float-right"> + {% fa5_icon "info" 'fas' %} {% trans "Status" %} + </a> + +{% endblock %} diff --git a/AKModel/templates/admin/AKModel/event_wizard/import.html b/AKModel/templates/admin/AKModel/event_wizard/import.html new file mode 100644 index 0000000000000000000000000000000000000000..d899a2d02c4a4aad6efb1da1ef73e8ebbc6b1173 --- /dev/null +++ b/AKModel/templates/admin/AKModel/event_wizard/import.html @@ -0,0 +1,28 @@ +{% extends "admin/base_site.html" %} +{% load tags_AKModel %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome_5 %} +{% load tz %} + +{% block title %}{% trans "New event wizard" %}: {{ wizard_step_text }}{% endblock %} + +{% block content %} + {% include "admin/AKModel/event_wizard/wizard_steps.html" %} + + {{ form.media }} + + <form method="post">{% csrf_token %} + {% bootstrap_form form %} + + <button type="submit" class="save btn btn-success float-right" value="Submit"> + {% fa5_icon "check" 'fas' %} {% trans "Continue" %} + </button> + + <a href="{% url 'admin:index' %}" class="btn btn-info"> + {% fa5_icon "times" 'fas' %} {% trans "Cancel" %} + </a> + </form> + +{% endblock %} diff --git a/AKModel/templates/admin/AKModel/event_wizard/settings.html b/AKModel/templates/admin/AKModel/event_wizard/settings.html new file mode 100644 index 0000000000000000000000000000000000000000..0b306d7bb6e93f330e01454ea2690332e12e6d8a --- /dev/null +++ b/AKModel/templates/admin/AKModel/event_wizard/settings.html @@ -0,0 +1,34 @@ +{% extends "admin/base_site.html" %} +{% load tags_AKModel %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome_5 %} +{% load tz %} + +{% block title %}{% trans "New event wizard" %}: {{ wizard_step_text }}{% endblock %} + +{% block content %} + {% include "admin/AKModel/event_wizard/wizard_steps.html" %} + + {{ form.media }} + + {% timezone timezone %} + + <form method="post">{% csrf_token %} + {% bootstrap_form form %} + + <button type="submit" class="save btn btn-success float-right" value="Submit"> + {% fa5_icon "check" 'fas' %} {% trans "Continue" %} + </button> + + <a href="{% url 'admin:new_event_wizard_start' %}" class="btn btn-info"> + {% fa5_icon "chevron-left" 'fas' %} {% trans "Back" %} + </a> + <a href="{% url 'admin:index' %}" class="btn btn-warning"> + {% fa5_icon "times" 'fas' %} {% trans "Cancel" %} + </a> + </form> + + {% endtimezone %} +{% endblock %} diff --git a/AKModel/templates/admin/AKModel/event_wizard/start.html b/AKModel/templates/admin/AKModel/event_wizard/start.html new file mode 100644 index 0000000000000000000000000000000000000000..762cadb5932d9b7f65cfaa69ed022572d305a423 --- /dev/null +++ b/AKModel/templates/admin/AKModel/event_wizard/start.html @@ -0,0 +1,26 @@ +{% extends "admin/base_site.html" %} +{% load tags_AKModel %} + +{% load i18n %} +{% load bootstrap4 %} +{% load fontawesome_5 %} + +{% block title %}{% trans "New event wizard" %}: {{ wizard_step_text }}{% endblock %} + +{% block content %} + {% include "admin/AKModel/event_wizard/wizard_steps.html" %} + + {% trans "Add a new event. Please start by filling these basic properties. You can specify more settings later." %} + + <form method="post" action="{% url 'admin:new_event_wizard_settings' %}">{% csrf_token %} + {% bootstrap_form form %} + + <button type="submit" class="save btn btn-success float-right" value="Submit"> + {% fa5_icon "check" 'fas' %} {% trans "Continue" %} + </button> + + <a href="{% url 'admin:index' %}" class="btn btn-info"> + {% fa5_icon "times" 'fas' %} {% trans "Cancel" %} + </a> + </form> +{% endblock %} diff --git a/AKModel/templates/admin/AKModel/event_wizard/wizard_steps.html b/AKModel/templates/admin/AKModel/event_wizard/wizard_steps.html new file mode 100644 index 0000000000000000000000000000000000000000..a006f3d3bb0a573e052de3dfaf41b5137958990d --- /dev/null +++ b/AKModel/templates/admin/AKModel/event_wizard/wizard_steps.html @@ -0,0 +1,15 @@ +{% load i18n %} + +<h2>{% trans "New event wizard" %}</h2> + +<div> + <ul class="pagination pagination-sm"> + {% for step in wizard_steps %} + <li class="page-item {% if forloop.counter == wizard_step %}active{% else %}disabled{% endif %}"> + <a class="page-link" href="#">{{ step }}</a> + </li> + {% endfor %} + </ul> +</div> + +<h3>{% trans "Step" %} {{ wizard_step }}: {{ wizard_step_text }}</h3> diff --git a/AKModel/views.py b/AKModel/views.py index d560e9f644cffce4952993f97b8db0dff0cb8e7b..49269dad6cc8d4a79e27265c7e2b50086b19680f 100644 --- a/AKModel/views.py +++ b/AKModel/views.py @@ -1,12 +1,13 @@ from django.contrib import admin, messages from django.http import HttpResponseRedirect -from django.shortcuts import get_object_or_404 +from django.shortcuts import get_object_or_404, redirect from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ - -from django.views.generic import TemplateView, DetailView, ListView, DeleteView +from django.views.generic import TemplateView, DetailView, ListView, DeleteView, CreateView, FormView, UpdateView from rest_framework import viewsets, permissions, mixins +from AKModel.forms import NewEventWizardStartForm, NewEventWizardSettingsForm, NewEventWizardPrepareImportForm, \ + NewEventWizardImportForm, NewEventWizardActivateForm from AKModel.models import Event, AK, AKSlot, Room, AKTrack, AKCategory, AKOwner, AKOrgaMessage from AKModel.serializers import AKSerializer, AKSlotSerializer, RoomSerializer, AKTrackSerializer, AKCategorySerializer, \ AKOwnerSerializer @@ -177,3 +178,92 @@ class AKMessageDeleteView(AdminViewMixin, DeleteView): self.get_orga_messages_for_event(self.get_object()).delete() messages.add_message(self.request, messages.SUCCESS, _("AK Orga Messages successfully deleted")) return HttpResponseRedirect(reverse_lazy('admin:event_status', kwargs={'slug': self.get_object().slug})) + + +class WizardViewMixin: + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["wizard_step"] = self.wizard_step + context["wizard_steps"] = [ + _("Start"), + _("Settings"), + _("Event created, Prepare Import"), + _("Import categories & requirements"), + _("Activate?"), + _("Finish") + ] + context["wizard_step_text"] = context["wizard_steps"][self.wizard_step - 1] + context["wizard_steps_total"] = len(context["wizard_steps"]) + return context + + +class NewEventWizardStartView(AdminViewMixin, WizardViewMixin, CreateView): + model = Event + form_class = NewEventWizardStartForm + template_name = "admin/AKModel/event_wizard/start.html" + wizard_step = 1 + + +class NewEventWizardSettingsView(AdminViewMixin, WizardViewMixin, CreateView): + model = Event + form_class = NewEventWizardSettingsForm + template_name = "admin/AKModel/event_wizard/settings.html" + wizard_step = 2 + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["timezone"] = context["form"].cleaned_data["timezone"] + return context + + def get_success_url(self): + return reverse_lazy("admin:new_event_wizard_prepare_import", kwargs={"event_slug": self.object.slug}) + + +class NewEventWizardPrepareImportView(WizardViewMixin, EventSlugMixin, FormView): + form_class = NewEventWizardPrepareImportForm + template_name = "admin/AKModel/event_wizard/created_prepare_import.html" + wizard_step = 3 + + def form_valid(self, form): + # Selected a valid event to import from? Use this to go to next step of wizard + return redirect("admin:new_event_wizard_import", event_slug=self.event.slug, import_slug=form.cleaned_data["import_event"].slug) + + +class NewEventWizardImportView(EventSlugMixin, WizardViewMixin, FormView): + form_class = NewEventWizardImportForm + template_name = "admin/AKModel/event_wizard/import.html" + wizard_step = 4 + + def get_initial(self): + initial = super().get_initial() + initial["import_event"] = Event.objects.get(slug=self.kwargs["import_slug"]) + return initial + + def form_valid(self, form): + for import_type in ["import_categories", "import_requirements"]: + for import_obj in form.cleaned_data.get(import_type): + # clone existing entry + try: + import_obj.event = self.event + import_obj.pk = None + import_obj.save() + messages.add_message(self.request, messages.SUCCESS, _("Copied '%(obj)s'" % {'obj': import_obj})) + except BaseException as e: + messages.add_message(self.request, messages.ERROR, _("Could not copy '%(obj)s' (%(error)s)" % {'obj': import_obj, "error": str(e)})) + return redirect("admin:new_event_wizard_activate", slug=self.event.slug) + + +class NewEventWizardActivateView(WizardViewMixin, UpdateView): + model = Event + template_name = "admin/AKModel/event_wizard/activate.html" + form_class = NewEventWizardActivateForm + wizard_step = 5 + + def get_success_url(self): + return reverse_lazy("admin:new_event_wizard_finish", kwargs={"slug": self.object.slug}) + + +class NewEventWizardFinishView(WizardViewMixin, DetailView): + model = Event + template_name = "admin/AKModel/event_wizard/finish.html" + wizard_step = 6 diff --git a/locale/de_DE/LC_MESSAGES/django.po b/locale/de_DE/LC_MESSAGES/django.po index 2f8b8562d98bd544a3ea9a341508dc064edac14b..25b6fc421701f4b25dd5fae81d381f1523c17282 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: 2020-11-03 17:40+0000\n" +"POT-Creation-Date: 2021-02-16 14:42+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" @@ -38,27 +38,27 @@ msgstr "Virtuelle Räume" msgid "Scheduling for" msgstr "Scheduling für" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:94 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:87 msgid "Day (Horizontal)" msgstr "Tag (horizontal)" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:101 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:94 msgid "Day (Vertical)" msgstr "Tag (vertikal)" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:112 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:105 msgid "Event (Horizontal)" msgstr "Event (horizontal)" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:121 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:114 msgid "Event (Vertical)" msgstr "Event (vertikal)" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:148 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:141 msgid "Room" msgstr "Raum" -#: AKScheduling/templates/admin/AKScheduling/scheduling.html:204 +#: AKScheduling/templates/admin/AKScheduling/scheduling.html:197 #: AKScheduling/templates/admin/AKScheduling/unscheduled.html:34 msgid "Event Status" msgstr "Event-Status"