From 028be1ee87e3aed37029927b96f4ca448e6e712b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sun, 26 Mar 2023 20:02:33 +0200
Subject: [PATCH 1/2] Split AKModel views into different files & introduce
 modular status page

Move AKModel views into several subfiles to improve overview and resolve problems with circular imports
Introduce new modular status page handling (widgets and views)
Port main status page to new structure
Move AK messages status page visualization to AKSubmission (therefore, they automatically do not show up when there is no possibility to create them)
Introduce status widget for virtual rooms
Fix timezone issue for rendering of AK messages on status page
Adapt status page URL in several views and tests
---
 AKModel/admin.py                              |   9 +-
 AKModel/locale/de_DE/LC_MESSAGES/django.po    | 663 +++++++++---------
 AKModel/metaviews/__init__.py                 |   3 +
 AKModel/metaviews/admin.py                    | 158 +++++
 AKModel/metaviews/status.py                   | 150 ++++
 .../admin/AKModel/render_ak_messages.html     |  26 +-
 AKModel/templates/admin/AKModel/status.html   | 130 ----
 .../admin/AKModel/status/event_aks.html       |  28 +
 .../AKModel/status/event_categories.html      |  14 +
 .../admin/AKModel/status/event_overview.html  |  14 +
 .../AKModel/status/event_requirements.html    |  14 +
 .../admin/AKModel/status/event_rooms.html     |  15 +
 .../admin/AKModel/status/status.html          |  40 ++
 AKModel/templates/admin/ak_index.html         |   2 +-
 AKModel/tests.py                              |   2 +-
 AKModel/urls.py                               |  26 +-
 AKModel/views.py                              | 651 -----------------
 AKModel/views/__init__.py                     |   0
 AKModel/views/ak.py                           |  96 +++
 AKModel/views/api.py                          |  57 ++
 AKModel/views/event_wizard.py                 |  90 +++
 AKModel/views/manage.py                       | 197 ++++++
 AKModel/views/room.py                         |  75 ++
 AKModel/views/status.py                       | 163 +++++
 AKOnline/locale/de_DE/LC_MESSAGES/django.po   |   8 +-
 .../AKOnline/status/event_virtual_rooms.html  |  11 +
 AKOnline/views.py                             |  11 +-
 AKPlan/views.py                               |   2 +-
 AKScheduling/api.py                           |   2 +-
 AKScheduling/views.py                         |   2 +-
 .../locale/de_DE/LC_MESSAGES/django.po        | 108 +--
 AKSubmission/views.py                         |  24 +-
 32 files changed, 1590 insertions(+), 1201 deletions(-)
 create mode 100644 AKModel/metaviews/__init__.py
 create mode 100644 AKModel/metaviews/admin.py
 create mode 100644 AKModel/metaviews/status.py
 delete mode 100644 AKModel/templates/admin/AKModel/status.html
 create mode 100644 AKModel/templates/admin/AKModel/status/event_aks.html
 create mode 100644 AKModel/templates/admin/AKModel/status/event_categories.html
 create mode 100644 AKModel/templates/admin/AKModel/status/event_overview.html
 create mode 100644 AKModel/templates/admin/AKModel/status/event_requirements.html
 create mode 100644 AKModel/templates/admin/AKModel/status/event_rooms.html
 create mode 100644 AKModel/templates/admin/AKModel/status/status.html
 delete mode 100644 AKModel/views.py
 create mode 100644 AKModel/views/__init__.py
 create mode 100644 AKModel/views/ak.py
 create mode 100644 AKModel/views/api.py
 create mode 100644 AKModel/views/event_wizard.py
 create mode 100644 AKModel/views/manage.py
 create mode 100644 AKModel/views/room.py
 create mode 100644 AKModel/views/status.py
 create mode 100644 AKOnline/templates/admin/AKOnline/status/event_virtual_rooms.html

diff --git a/AKModel/admin.py b/AKModel/admin.py
index ad8b7636..0d48bc6f 100644
--- a/AKModel/admin.py
+++ b/AKModel/admin.py
@@ -10,7 +10,6 @@ from django.utils import timezone
 from django.utils.html import format_html
 from django.utils.safestring import mark_safe
 from django.utils.translation import gettext_lazy as _
-from rest_framework.reverse import reverse
 from simple_history.admin import SimpleHistoryAdmin
 
 from AKModel.availability.models import Availability
@@ -18,8 +17,10 @@ from AKModel.forms import RoomFormWithAvailabilities
 from AKModel.models import Event, AKOwner, AKCategory, AKTrack, AKRequirement, AK, AKSlot, Room, AKOrgaMessage, \
     ConstraintViolation, DefaultSlot
 from AKModel.urls import get_admin_urls_event_wizard, get_admin_urls_event
-from AKModel.views import CVMarkResolvedView, CVSetLevelViolationView, CVSetLevelWarningView, AKResetInterestView, \
-    AKResetInterestCounterView, PlanPublishView, PlanUnpublishView, DefaultSlotEditorView, RoomBatchCreationView
+from AKModel.views.ak import AKResetInterestView, AKResetInterestCounterView
+from AKModel.views.manage import PlanPublishView, PlanUnpublishView, DefaultSlotEditorView, CVMarkResolvedView, \
+    CVSetLevelViolationView, CVSetLevelWarningView
+from AKModel.views.room import RoomBatchCreationView
 
 
 class EventRelatedFieldListFilter(RelatedFieldListFilter):
@@ -64,7 +65,7 @@ class EventAdmin(admin.ModelAdmin):
     @display(description=_("Status"))
     def status_url(self, obj):
         return format_html("<a href='{url}'>{text}</a>",
-                           url=reverse_lazy('admin:event_status', kwargs={'slug': obj.slug}), text=_("Status"))
+                           url=reverse_lazy('admin:event_status', kwargs={'event_slug': obj.slug}), text=_("Status"))
 
     @display(description=_("Toggle plan visibility"))
     def toggle_plan_visibility(self, obj):
diff --git a/AKModel/locale/de_DE/LC_MESSAGES/django.po b/AKModel/locale/de_DE/LC_MESSAGES/django.po
index 2c101f90..ae516495 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: 2023-03-24 17:57+0100\n"
+"POT-Creation-Date: 2023-03-26 19:54+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -11,69 +11,69 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: AKModel/admin.py:64 AKModel/admin.py:67
+#: AKModel/admin.py:65 AKModel/admin.py:68
 #: 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/requirements_overview.html:8
-#: AKModel/templates/admin/AKModel/status.html:7
+#: AKModel/templates/admin/AKModel/status/status.html:8
 #: AKModel/templates/admin/ak_index.html:15
 msgid "Status"
 msgstr "Status"
 
-#: AKModel/admin.py:69
+#: AKModel/admin.py:70
 msgid "Toggle plan visibility"
 msgstr "Plansichtbarkeit ändern"
 
-#: AKModel/admin.py:73 AKModel/admin.py:84 AKModel/views.py:497
+#: AKModel/admin.py:74 AKModel/admin.py:85 AKModel/views/manage.py:105
 msgid "Publish plan"
 msgstr "Plan veröffentlichen"
 
-#: AKModel/admin.py:76 AKModel/admin.py:89 AKModel/views.py:507
+#: AKModel/admin.py:77 AKModel/admin.py:90 AKModel/views/manage.py:115
 msgid "Unpublish plan"
 msgstr "Plan verbergen"
 
-#: AKModel/admin.py:152
+#: AKModel/admin.py:153
 msgid "Wish"
 msgstr "AK-Wunsch"
 
-#: AKModel/admin.py:158
+#: AKModel/admin.py:159
 msgid "Is wish"
 msgstr "Ist ein Wunsch"
 
-#: AKModel/admin.py:159
+#: AKModel/admin.py:160
 msgid "Is not a wish"
 msgstr "Ist kein Wunsch"
 
-#: AKModel/admin.py:203
+#: AKModel/admin.py:204
 msgid "Export to wiki syntax"
 msgstr "In Wiki-Syntax exportieren"
 
-#: AKModel/admin.py:212
+#: AKModel/admin.py:213
 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:227 AKModel/views.py:477
+#: AKModel/admin.py:228 AKModel/views/ak.py:80
 msgid "Reset interest in AKs"
 msgstr "Interesse an AKs zurücksetzen"
 
-#: AKModel/admin.py:232 AKModel/views.py:487
+#: AKModel/admin.py:233 AKModel/views/ak.py:90
 msgid "Reset AKs' interest counters"
 msgstr "Interessenszähler der AKs zurücksetzen"
 
-#: AKModel/admin.py:308 AKModel/admin.py:315
+#: AKModel/admin.py:309 AKModel/admin.py:316
 msgid "AK Details"
 msgstr "AK-Details"
 
-#: AKModel/admin.py:367 AKModel/views.py:447
+#: AKModel/admin.py:368 AKModel/views/manage.py:75
 msgid "Mark Constraint Violations as manually resolved"
 msgstr "Markiere Constraintverletzungen als manuell behoben"
 
-#: AKModel/admin.py:372 AKModel/views.py:457
+#: AKModel/admin.py:373 AKModel/views/manage.py:85
 msgid "Set Constraint Violations to level \"violation\""
 msgstr "Constraintverletzungen auf Level \"Violation\" setzen"
 
-#: AKModel/admin.py:377 AKModel/views.py:467
+#: AKModel/admin.py:378 AKModel/views/manage.py:95
 msgid "Set Constraint Violations to level \"warning\""
 msgstr "Constraintverletzungen auf Level \"Warning\" setzen"
 
@@ -102,17 +102,17 @@ msgstr "Die eingegebene Verfügbarkeit enthält ein ungültiges Datum."
 msgid "Please fill in your availabilities!"
 msgstr "Bitte Verfügbarkeiten eintragen!"
 
-#: AKModel/availability/models.py:38 AKModel/models.py:56 AKModel/models.py:128
-#: AKModel/models.py:183 AKModel/models.py:202 AKModel/models.py:223
-#: AKModel/models.py:276 AKModel/models.py:341 AKModel/models.py:374
-#: AKModel/models.py:445 AKModel/models.py:486 AKModel/models.py:651
+#: AKModel/availability/models.py:38 AKModel/models.py:57 AKModel/models.py:129
+#: AKModel/models.py:184 AKModel/models.py:203 AKModel/models.py:224
+#: AKModel/models.py:277 AKModel/models.py:354 AKModel/models.py:387
+#: AKModel/models.py:458 AKModel/models.py:499 AKModel/models.py:664
 msgid "Event"
 msgstr "Event"
 
-#: AKModel/availability/models.py:39 AKModel/models.py:129
-#: AKModel/models.py:184 AKModel/models.py:203 AKModel/models.py:224
-#: AKModel/models.py:277 AKModel/models.py:342 AKModel/models.py:375
-#: AKModel/models.py:446 AKModel/models.py:487 AKModel/models.py:652
+#: AKModel/availability/models.py:39 AKModel/models.py:130
+#: AKModel/models.py:185 AKModel/models.py:204 AKModel/models.py:225
+#: AKModel/models.py:278 AKModel/models.py:355 AKModel/models.py:388
+#: AKModel/models.py:459 AKModel/models.py:500 AKModel/models.py:665
 msgid "Associated event"
 msgstr "Zugehöriges Event"
 
@@ -124,8 +124,8 @@ msgstr "Person"
 msgid "Person whose availability this is"
 msgstr "Person deren Verfügbarkeit hier abgebildet wird"
 
-#: AKModel/availability/models.py:56 AKModel/models.py:345
-#: AKModel/models.py:364 AKModel/models.py:495
+#: AKModel/availability/models.py:56 AKModel/models.py:358
+#: AKModel/models.py:377 AKModel/models.py:508
 msgid "Room"
 msgstr "Raum"
 
@@ -133,8 +133,8 @@ msgstr "Raum"
 msgid "Room whose availability this is"
 msgstr "Raum dessen Verfügbarkeit hier abgebildet wird"
 
-#: AKModel/availability/models.py:65 AKModel/models.py:285
-#: AKModel/models.py:363 AKModel/models.py:440
+#: AKModel/availability/models.py:65 AKModel/models.py:286
+#: AKModel/models.py:376 AKModel/models.py:453
 msgid "AK"
 msgstr "AK"
 
@@ -142,8 +142,8 @@ msgstr "AK"
 msgid "AK whose availability this is"
 msgstr "Verfügbarkeiten"
 
-#: AKModel/availability/models.py:74 AKModel/models.py:187
-#: AKModel/models.py:501
+#: AKModel/availability/models.py:74 AKModel/models.py:188
+#: AKModel/models.py:514
 msgid "AK Category"
 msgstr "AK-Kategorie"
 
@@ -213,7 +213,7 @@ msgstr ""
 "fürWünsche markieren, z.B. um während der Präsentation auf einem Touchscreen "
 "ausgefüllt zu werden?"
 
-#: AKModel/forms.py:125 AKModel/models.py:645
+#: AKModel/forms.py:125 AKModel/models.py:658
 msgid "Default Slots"
 msgstr "Standardslots"
 
@@ -244,138 +244,159 @@ msgstr ""
 msgid "CSV must contain a name column"
 msgstr "CSV muss eine name-Spalte enthalten"
 
-#: AKModel/models.py:18 AKModel/models.py:175 AKModel/models.py:199
-#: AKModel/models.py:221 AKModel/models.py:239 AKModel/models.py:333
+#: AKModel/metaviews/admin.py:97 AKModel/models.py:28
+msgid "Start"
+msgstr "Start"
+
+#: AKModel/metaviews/admin.py:98
+msgid "Settings"
+msgstr "Einstellungen"
+
+#: AKModel/metaviews/admin.py:99
+msgid "Event created, Prepare Import"
+msgstr "Event angelegt, Import vorbereiten"
+
+#: AKModel/metaviews/admin.py:100
+msgid "Import categories & requirements"
+msgstr "Kategorien & Anforderungen kopieren"
+
+#: AKModel/metaviews/admin.py:101
+msgid "Activate?"
+msgstr "Aktivieren?"
+
+#: AKModel/metaviews/admin.py:102
+#: AKModel/templates/admin/AKModel/event_wizard/activate.html:27
+msgid "Finish"
+msgstr "Abschluss"
+
+#: AKModel/models.py:19 AKModel/models.py:176 AKModel/models.py:200
+#: AKModel/models.py:222 AKModel/models.py:240 AKModel/models.py:346
 msgid "Name"
 msgstr "Name"
 
-#: AKModel/models.py:19
+#: AKModel/models.py:20
 msgid "Name or iteration of the event"
 msgstr "Name oder Iteration des Events"
 
-#: AKModel/models.py:20
+#: AKModel/models.py:21
 msgid "Short Form"
 msgstr "Kurzer Name"
 
-#: AKModel/models.py:21
+#: AKModel/models.py:22
 msgid "Short name of letters/numbers/dots/dashes/underscores used in URLs."
 msgstr ""
 "Kurzname bestehend aus Buchstaben, Nummern, Punkten und Unterstrichen zur "
 "Nutzung in URLs"
 
-#: AKModel/models.py:23
+#: AKModel/models.py:24
 msgid "Place"
 msgstr "Ort"
 
-#: AKModel/models.py:24
+#: AKModel/models.py:25
 msgid "City etc. the event takes place in"
 msgstr "Stadt o.ä. in der das Event stattfindet"
 
-#: AKModel/models.py:26
+#: AKModel/models.py:27
 msgid "Time Zone"
 msgstr "Zeitzone"
 
-#: AKModel/models.py:26
+#: AKModel/models.py:27
 msgid "Time Zone where this event takes place in"
 msgstr "Zeitzone in der das Event stattfindet"
 
-#: AKModel/models.py:27 AKModel/views.py:253
-msgid "Start"
-msgstr "Start"
-
-#: AKModel/models.py:27
+#: AKModel/models.py:28
 msgid "Time the event begins"
 msgstr "Zeit zu der das Event beginnt"
 
-#: AKModel/models.py:28
+#: AKModel/models.py:29
 msgid "End"
 msgstr "Ende"
 
-#: AKModel/models.py:28
+#: AKModel/models.py:29
 msgid "Time the event ends"
 msgstr "Zeit zu der das Event endet"
 
-#: AKModel/models.py:29
+#: AKModel/models.py:30
 msgid "Resolution Deadline"
 msgstr "Resolutionsdeadline"
 
-#: AKModel/models.py:30
+#: AKModel/models.py:31
 msgid "When should AKs with intention to submit a resolution be done?"
 msgstr "Wann sollen AKs mit Resolutionsabsicht stattgefunden haben?"
 
-#: AKModel/models.py:32
+#: AKModel/models.py:33
 msgid "Interest Window Start"
 msgstr "Beginn Interessensbekundung"
 
-#: AKModel/models.py:33
+#: AKModel/models.py:34
 msgid "Opening time for expression of interest."
 msgstr "Öffnungszeitpunkt für die Angabe von Interesse an AKs."
 
-#: AKModel/models.py:34
+#: AKModel/models.py:35
 msgid "Interest Window End"
 msgstr "Ende Interessensbekundung"
 
-#: AKModel/models.py:35
+#: AKModel/models.py:36
 msgid "Closing time for expression of interest."
 msgstr "Öffnungszeitpunkt für die Angabe von Interesse an AKs."
 
-#: AKModel/models.py:37
+#: AKModel/models.py:38
 msgid "Public event"
 msgstr "Öffentliches Event"
 
-#: AKModel/models.py:38
+#: AKModel/models.py:39
 msgid "Show this event on overview page."
 msgstr "Zeige dieses Event auf der Ãœbersichtseite an"
 
-#: AKModel/models.py:40
+#: AKModel/models.py:41
 msgid "Active State"
 msgstr "Aktiver Status"
 
-#: AKModel/models.py:40
+#: AKModel/models.py:41
 msgid "Marks currently active events"
 msgstr "Markiert aktuell aktive Events"
 
-#: AKModel/models.py:41
+#: AKModel/models.py:42
 msgid "Plan Hidden"
 msgstr "Plan verborgen"
 
-#: AKModel/models.py:41
+#: AKModel/models.py:42
 msgid "Hides plan for non-staff users"
 msgstr "Verbirgt den Plan für Nutzer*innen ohne erweiterte Rechte"
 
-#: AKModel/models.py:43
+#: AKModel/models.py:44
 msgid "Plan published at"
 msgstr "Plan veröffentlicht am/um"
 
-#: AKModel/models.py:44
+#: AKModel/models.py:45
 msgid "Timestamp at which the plan was published"
 msgstr "Zeitpunkt, zu dem der Plan veröffentlicht wurde"
 
-#: AKModel/models.py:46
+#: AKModel/models.py:47
 msgid "Base URL"
 msgstr "URL-Prefix"
 
-#: AKModel/models.py:46
+#: AKModel/models.py:47
 msgid "Prefix for wiki link construction"
 msgstr "Prefix für die automatische Generierung von Wiki-Links"
 
-#: AKModel/models.py:47
+#: AKModel/models.py:48
 msgid "Wiki Export Template Name"
 msgstr "Wiki-Export Templatename"
 
-#: AKModel/models.py:48
+#: AKModel/models.py:49
 msgid "Default Slot Length"
 msgstr "Standardslotlänge"
 
-#: AKModel/models.py:49
+#: AKModel/models.py:50
 msgid "Default length in hours that is assumed for AKs in this event."
 msgstr "Standardlänge von Slots (in Stunden) für dieses Event"
 
-#: AKModel/models.py:51
+#: AKModel/models.py:52
 msgid "Contact email address"
 msgstr "E-Mail Kontaktadresse"
 
-#: AKModel/models.py:53
+#: AKModel/models.py:54
 msgid ""
 "An email address that is displayed on every page and can be used for all "
 "kinds of questions"
@@ -383,75 +404,75 @@ msgstr ""
 "Eine Mailadresse die auf jeder Seite angezeigt wird und für alle Arten von "
 "Fragen genutzt werden kann"
 
-#: AKModel/models.py:57
+#: AKModel/models.py:58
 msgid "Events"
 msgstr "Events"
 
-#: AKModel/models.py:123
+#: AKModel/models.py:124
 msgid "Nickname"
 msgstr "Spitzname"
 
-#: AKModel/models.py:123
+#: AKModel/models.py:124
 msgid "Name to identify an AK owner by"
 msgstr "Name, durch den eine AK-Leitung identifiziert wird"
 
-#: AKModel/models.py:124
+#: AKModel/models.py:125
 msgid "Slug"
 msgstr "Slug"
 
-#: AKModel/models.py:124
+#: AKModel/models.py:125
 msgid "Slug for URL generation"
 msgstr "Slug für URL-Generierung"
 
-#: AKModel/models.py:125
+#: AKModel/models.py:126
 msgid "Institution"
 msgstr "Instutution"
 
-#: AKModel/models.py:125
+#: AKModel/models.py:126
 msgid "Uni etc."
 msgstr "Universität o.ä."
 
-#: AKModel/models.py:126 AKModel/models.py:248
+#: AKModel/models.py:127 AKModel/models.py:249
 msgid "Web Link"
 msgstr "Internet Link"
 
-#: AKModel/models.py:126
+#: AKModel/models.py:127
 msgid "Link to Homepage"
 msgstr "Link zu Homepage oder Webseite"
 
-#: AKModel/models.py:132 AKModel/models.py:494
+#: AKModel/models.py:133 AKModel/models.py:507
 msgid "AK Owner"
 msgstr "AK-Leitung"
 
-#: AKModel/models.py:133
+#: AKModel/models.py:134
 msgid "AK Owners"
 msgstr "AK-Leitungen"
 
-#: AKModel/models.py:175
+#: AKModel/models.py:176
 msgid "Name of the AK Category"
 msgstr "Name der AK-Kategorie"
 
-#: AKModel/models.py:176 AKModel/models.py:200
+#: AKModel/models.py:177 AKModel/models.py:201
 msgid "Color"
 msgstr "Farbe"
 
-#: AKModel/models.py:176 AKModel/models.py:200
+#: AKModel/models.py:177 AKModel/models.py:201
 msgid "Color for displaying"
 msgstr "Farbe für die Anzeige"
 
-#: AKModel/models.py:177 AKModel/models.py:242
+#: AKModel/models.py:178 AKModel/models.py:243
 msgid "Description"
 msgstr "Beschreibung"
 
-#: AKModel/models.py:178
+#: AKModel/models.py:179
 msgid "Short description of this AK Category"
 msgstr "Beschreibung der AK-Kategorie"
 
-#: AKModel/models.py:179
+#: AKModel/models.py:180
 msgid "Present by default"
 msgstr "Defaultmäßig präsentieren"
 
-#: AKModel/models.py:181
+#: AKModel/models.py:182
 msgid ""
 "Present AKs of this category by default if AK owner did not specify whether "
 "this AK should be presented?"
@@ -459,132 +480,132 @@ msgstr ""
 "AKs dieser Kategorie standardmäßig vorstellen, wenn die Leitungen das für "
 "ihren AK nicht explizit spezifiziert haben?"
 
-#: AKModel/models.py:188
+#: AKModel/models.py:189
 msgid "AK Categories"
 msgstr "AK-Kategorien"
 
-#: AKModel/models.py:199
+#: AKModel/models.py:200
 msgid "Name of the AK Track"
 msgstr "Name des AK-Tracks"
 
-#: AKModel/models.py:206
+#: AKModel/models.py:207
 msgid "AK Track"
 msgstr "AK-Track"
 
-#: AKModel/models.py:207
+#: AKModel/models.py:208
 msgid "AK Tracks"
 msgstr "AK-Tracks"
 
-#: AKModel/models.py:221
+#: AKModel/models.py:222
 msgid "Name of the Requirement"
 msgstr "Name der Anforderung"
 
-#: AKModel/models.py:227 AKModel/models.py:498
+#: AKModel/models.py:228 AKModel/models.py:511
 msgid "AK Requirement"
 msgstr "AK-Anforderung"
 
-#: AKModel/models.py:228
+#: AKModel/models.py:229
 msgid "AK Requirements"
 msgstr "AK-Anforderungen"
 
-#: AKModel/models.py:239
+#: AKModel/models.py:240
 msgid "Name of the AK"
 msgstr "Name des AKs"
 
-#: AKModel/models.py:240
+#: AKModel/models.py:241
 msgid "Short Name"
 msgstr "Kurzer Name"
 
-#: AKModel/models.py:241
+#: AKModel/models.py:242
 msgid "Name displayed in the schedule"
 msgstr "Name zur Anzeige im AK-Plan"
 
-#: AKModel/models.py:242
+#: AKModel/models.py:243
 msgid "Description of the AK"
 msgstr "Beschreibung des AKs"
 
-#: AKModel/models.py:244
+#: AKModel/models.py:245
 msgid "Owners"
 msgstr "Leitungen"
 
-#: AKModel/models.py:245
+#: AKModel/models.py:246
 msgid "Those organizing the AK"
 msgstr "Menschen, die den AK organisieren und halten"
 
-#: AKModel/models.py:248
+#: AKModel/models.py:249
 msgid "Link to wiki page"
 msgstr "Link zur Wiki Seite"
 
-#: AKModel/models.py:249
+#: AKModel/models.py:250
 msgid "Protocol Link"
 msgstr "Protokolllink"
 
-#: AKModel/models.py:249
+#: AKModel/models.py:250
 msgid "Link to protocol"
 msgstr "Link zum Protokoll"
 
-#: AKModel/models.py:251
+#: AKModel/models.py:252
 msgid "Category"
 msgstr "Kategorie"
 
-#: AKModel/models.py:252
+#: AKModel/models.py:253
 msgid "Category of the AK"
 msgstr "Kategorie des AKs"
 
-#: AKModel/models.py:253
+#: AKModel/models.py:254
 msgid "Track"
 msgstr "Track"
 
-#: AKModel/models.py:254
+#: AKModel/models.py:255
 msgid "Track the AK belongs to"
 msgstr "Track zu dem der AK gehört"
 
-#: AKModel/models.py:256
+#: AKModel/models.py:257
 msgid "Resolution Intention"
 msgstr "Resolutionsabsicht"
 
-#: AKModel/models.py:257
+#: AKModel/models.py:258
 msgid "Intends to submit a resolution"
 msgstr "Beabsichtigt eine Resolution einzureichen"
 
-#: AKModel/models.py:258
+#: AKModel/models.py:259
 msgid "Present this AK"
 msgstr "AK präsentieren"
 
-#: AKModel/models.py:259
+#: AKModel/models.py:260
 msgid "Present results of this AK"
 msgstr "Die Ergebnisse dieses AKs vorstellen"
 
-#: AKModel/models.py:261 AKModel/templates/admin/AKModel/status.html:105
+#: AKModel/models.py:262 AKModel/views/status.py:138
 msgid "Requirements"
 msgstr "Anforderungen"
 
-#: AKModel/models.py:262
+#: AKModel/models.py:263
 msgid "AK's Requirements"
 msgstr "Anforderungen des AKs"
 
-#: AKModel/models.py:264
+#: AKModel/models.py:265
 msgid "Conflicting AKs"
 msgstr "AK-Konflikte"
 
-#: AKModel/models.py:265
+#: AKModel/models.py:266
 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:266
+#: AKModel/models.py:267
 msgid "Prerequisite AKs"
 msgstr "Vorausgesetzte AKs"
 
-#: AKModel/models.py:267
+#: AKModel/models.py:268
 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:269
+#: AKModel/models.py:270
 msgid "Organizational Notes"
 msgstr "Notizen zur Organisation"
 
-#: AKModel/models.py:270
+#: AKModel/models.py:271
 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/"
@@ -594,287 +615,287 @@ msgstr ""
 "Anmerkungen bitte den Button für Direktnachrichten verwenden (nach dem "
 "Anlegen/Bearbeiten)."
 
-#: AKModel/models.py:272
+#: AKModel/models.py:273
 msgid "Interest"
 msgstr "Interesse"
 
-#: AKModel/models.py:272
+#: AKModel/models.py:273
 msgid "Expected number of people"
 msgstr "Erwartete Personenzahl"
 
-#: AKModel/models.py:273
+#: AKModel/models.py:274
 msgid "Interest Counter"
 msgstr "Interessenszähler"
 
-#: AKModel/models.py:274
+#: AKModel/models.py:275
 msgid "People who have indicated interest online"
 msgstr "Anzahl Personen, die online Interesse bekundet haben"
 
-#: AKModel/models.py:279
+#: AKModel/models.py:280
 msgid "Export?"
 msgstr "Export?"
 
-#: AKModel/models.py:280
+#: AKModel/models.py:281
 msgid "Include AK in wiki export?"
 msgstr "AK bei Wiki-Export berücksichtigen?"
 
-#: AKModel/models.py:286 AKModel/models.py:489
-#: AKModel/templates/admin/AKModel/status.html:57
-#: AKModel/templates/admin/AKModel/status.html:64 AKModel/views.py:375
+#: AKModel/models.py:287 AKModel/models.py:502
+#: AKModel/templates/admin/AKModel/status/event_aks.html:10
+#: AKModel/views/manage.py:55 AKModel/views/status.py:76
 msgid "AKs"
 msgstr "AKs"
 
-#: AKModel/models.py:333
+#: AKModel/models.py:346
 msgid "Name or number of the room"
 msgstr "Name oder Nummer des Raums"
 
-#: AKModel/models.py:334
+#: AKModel/models.py:347
 msgid "Location"
 msgstr "Ort"
 
-#: AKModel/models.py:335
+#: AKModel/models.py:348
 msgid "Name or number of the location"
 msgstr "Name oder Nummer des Ortes"
 
-#: AKModel/models.py:336
+#: AKModel/models.py:349
 msgid "Capacity"
 msgstr "Kapazität"
 
-#: AKModel/models.py:337
+#: AKModel/models.py:350
 msgid "Maximum number of people (-1 for unlimited)."
 msgstr "Maximale Personenzahl (-1 wenn unbeschränkt)."
 
-#: AKModel/models.py:338
+#: AKModel/models.py:351
 msgid "Properties"
 msgstr "Eigenschaften"
 
-#: AKModel/models.py:339
+#: AKModel/models.py:352
 msgid "AK requirements fulfilled by the room"
 msgstr "AK-Anforderungen, die dieser Raum erfüllt"
 
-#: AKModel/models.py:346 AKModel/templates/admin/AKModel/status.html:40
+#: AKModel/models.py:359 AKModel/views/status.py:46
 msgid "Rooms"
 msgstr "Räume"
 
-#: AKModel/models.py:363
+#: AKModel/models.py:376
 msgid "AK being mapped"
 msgstr "AK, der zugeordnet wird"
 
-#: AKModel/models.py:365
+#: AKModel/models.py:378
 msgid "Room the AK will take place in"
 msgstr "Raum in dem der AK stattfindet"
 
-#: AKModel/models.py:366 AKModel/models.py:648
+#: AKModel/models.py:379 AKModel/models.py:661
 msgid "Slot Begin"
 msgstr "Beginn des Slots"
 
-#: AKModel/models.py:366 AKModel/models.py:648
+#: AKModel/models.py:379 AKModel/models.py:661
 msgid "Time and date the slot begins"
 msgstr "Zeit und Datum zu der der AK beginnt"
 
-#: AKModel/models.py:368
+#: AKModel/models.py:381
 msgid "Duration"
 msgstr "Dauer"
 
-#: AKModel/models.py:369
+#: AKModel/models.py:382
 msgid "Length in hours"
 msgstr "Länge in Stunden"
 
-#: AKModel/models.py:371
+#: AKModel/models.py:384
 msgid "Scheduling fixed"
 msgstr "Planung fix"
 
-#: AKModel/models.py:372
+#: AKModel/models.py:385
 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:377
+#: AKModel/models.py:390
 msgid "Last update"
 msgstr "Letzte Aktualisierung"
 
-#: AKModel/models.py:380
+#: AKModel/models.py:393
 msgid "AK Slot"
 msgstr "AK-Slot"
 
-#: AKModel/models.py:381 AKModel/models.py:491
+#: AKModel/models.py:394 AKModel/models.py:504
 msgid "AK Slots"
 msgstr "AK-Slot"
 
-#: AKModel/models.py:403 AKModel/models.py:412
+#: AKModel/models.py:416 AKModel/models.py:425
 msgid "Not scheduled yet"
 msgstr "Noch nicht geplant"
 
-#: AKModel/models.py:441
+#: AKModel/models.py:454
 msgid "AK this message belongs to"
 msgstr "AK zu dem die Nachricht gehört"
 
-#: AKModel/models.py:442
+#: AKModel/models.py:455
 msgid "Message text"
 msgstr "Nachrichtentext"
 
-#: AKModel/models.py:443
+#: AKModel/models.py:456
 msgid "Message to the organizers. This is not publicly visible."
 msgstr ""
 "Nachricht an die Organisator*innen. Diese ist nicht öffentlich sichtbar."
 
-#: AKModel/models.py:449
+#: AKModel/models.py:462
 msgid "AK Orga Message"
 msgstr "AK-Organachricht"
 
-#: AKModel/models.py:450
+#: AKModel/models.py:463
 msgid "AK Orga Messages"
 msgstr "AK-Organachrichten"
 
-#: AKModel/models.py:459
+#: AKModel/models.py:472
 msgid "Constraint Violation"
 msgstr "Constraintverletzung"
 
-#: AKModel/models.py:460 AKModel/templates/admin/AKModel/status.html:87
+#: AKModel/models.py:473 AKModel/views/status.py:95
 msgid "Constraint Violations"
 msgstr "Constraintverletzungen"
 
-#: AKModel/models.py:464
+#: AKModel/models.py:477
 msgid "Owner has two parallel slots"
 msgstr "Leitung hat zwei Slots parallel"
 
-#: AKModel/models.py:465
+#: AKModel/models.py:478
 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:466
+#: AKModel/models.py:479
 msgid "Room has two AK slots scheduled at the same time"
 msgstr "Raum hat zwei AK Slots gleichzeitig"
 
-#: AKModel/models.py:467
+#: AKModel/models.py:480
 msgid "Room does not satisfy the requirement of the scheduled AK"
 msgstr "Room erfüllt die Anforderungen des platzierten AKs nicht"
 
-#: AKModel/models.py:468
+#: AKModel/models.py:481
 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:469
+#: AKModel/models.py:482
 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:471
+#: AKModel/models.py:484
 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:472
+#: AKModel/models.py:485
 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:473
+#: AKModel/models.py:486
 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:474
+#: AKModel/models.py:487
 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:475
+#: AKModel/models.py:488
 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:478
+#: AKModel/models.py:491
 msgid "Warning"
 msgstr "Warnung"
 
-#: AKModel/models.py:479
+#: AKModel/models.py:492
 msgid "Violation"
 msgstr "Verletzung"
 
-#: AKModel/models.py:481
+#: AKModel/models.py:494
 msgid "Type"
 msgstr "Art"
 
-#: AKModel/models.py:482
+#: AKModel/models.py:495
 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:483
+#: AKModel/models.py:496
 msgid "Level"
 msgstr "Level"
 
-#: AKModel/models.py:484
+#: AKModel/models.py:497
 msgid "Severity level of the violation"
 msgstr "Schweregrad der Verletzung"
 
-#: AKModel/models.py:490
+#: AKModel/models.py:503
 msgid "AK(s) belonging to this constraint"
 msgstr "AK(s), die zu diesem Constraint gehören"
 
-#: AKModel/models.py:492
+#: AKModel/models.py:505
 msgid "AK Slot(s) belonging to this constraint"
 msgstr "AK Slot(s), die zu diesem Constraint gehören"
 
-#: AKModel/models.py:494
+#: AKModel/models.py:507
 msgid "AK Owner belonging to this constraint"
 msgstr "AK Leitung(en), die zu diesem Constraint gehören"
 
-#: AKModel/models.py:496
+#: AKModel/models.py:509
 msgid "Room belonging to this constraint"
 msgstr "Raum, der zu diesem Constraint gehört"
 
-#: AKModel/models.py:499
+#: AKModel/models.py:512
 msgid "AK Requirement belonging to this constraint"
 msgstr "AK Anforderung, die zu diesem Constraint gehört"
 
-#: AKModel/models.py:501
+#: AKModel/models.py:514
 msgid "AK Category belonging to this constraint"
 msgstr "AK Kategorie, di zu diesem Constraint gehört"
 
-#: AKModel/models.py:503
+#: AKModel/models.py:516
 msgid "Comment"
 msgstr "Kommentar"
 
-#: AKModel/models.py:503
+#: AKModel/models.py:516
 msgid "Comment or further details for this violation"
 msgstr "Kommentar oder weitere Details zu dieser Vereletzung"
 
-#: AKModel/models.py:506
+#: AKModel/models.py:519
 msgid "Timestamp"
 msgstr "Timestamp"
 
-#: AKModel/models.py:506
+#: AKModel/models.py:519
 msgid "Time of creation"
 msgstr "Zeitpunkt der ERstellung"
 
-#: AKModel/models.py:507
+#: AKModel/models.py:520
 msgid "Manually Resolved"
 msgstr "Manuell behoben"
 
-#: AKModel/models.py:508
+#: AKModel/models.py:521
 msgid "Mark this violation manually as resolved"
 msgstr "Markiere diese Verletzung manuell als behoben"
 
-#: AKModel/models.py:535
+#: AKModel/models.py:548
 #: AKModel/templates/admin/AKModel/requirements_overview.html:27
 msgid "Details"
 msgstr "Details"
 
-#: AKModel/models.py:644
+#: AKModel/models.py:657
 msgid "Default Slot"
 msgstr "Standardslot"
 
-#: AKModel/models.py:649
+#: AKModel/models.py:662
 msgid "Slot End"
 msgstr "Ende des Slots"
 
-#: AKModel/models.py:649
+#: AKModel/models.py:662
 msgid "Time and date the slot ends"
 msgstr "Zeit und Datum zu der der Slot endet"
 
-#: AKModel/models.py:654
+#: AKModel/models.py:667
 msgid "Primary categories"
 msgstr "Primäre Kategorien"
 
-#: AKModel/models.py:655
+#: AKModel/models.py:668
 msgid "Categories that should be assigned to this slot primarily"
 msgstr "Kategorieren, die diesem Slot primär zugewiesen werden sollen"
 
@@ -925,11 +946,6 @@ msgstr "Assistent zum Anlegen eines neuen Events"
 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:258
-msgid "Finish"
-msgstr "Abschluss"
-
 #: AKModel/templates/admin/AKModel/event_wizard/created_prepare_import.html:16
 msgid "New event:"
 msgstr "Neues Event:"
@@ -991,7 +1007,7 @@ msgid "No AKs with this requirement"
 msgstr "Kein AK mit dieser Anforderung"
 
 #: AKModel/templates/admin/AKModel/requirements_overview.html:45
-#: AKModel/templates/admin/AKModel/status.html:121
+#: AKModel/views/status.py:152
 msgid "Add Requirement"
 msgstr "Anforderung hinzufügen"
 
@@ -1012,99 +1028,42 @@ msgstr "Sichern und weiter bearbeiten"
 msgid "Save"
 msgstr "Sichern"
 
-#: AKModel/templates/admin/AKModel/status.html:18
-msgid "Plan published?"
-msgstr "Plan veröffentlicht?"
-
-#: AKModel/templates/admin/AKModel/status.html:23
-msgid "Categories"
-msgstr "Kategorien"
-
-#: AKModel/templates/admin/AKModel/status.html:25
-msgid "No categories yet"
-msgstr "Bisher keine Kategorien"
-
-#: AKModel/templates/admin/AKModel/status.html:38
-msgid "Add category"
-msgstr "Kategorie hinzufügen"
-
-#: AKModel/templates/admin/AKModel/status.html:42
-msgid "No rooms yet"
-msgstr "Bisher keine Räume"
-
-#: AKModel/templates/admin/AKModel/status.html:54
-msgid "Add Room"
-msgstr "Raum hinzufügen"
-
-#: AKModel/templates/admin/AKModel/status.html:55 AKModel/views.py:613
-msgid "Import Rooms from CSV"
-msgstr "Räume aus CSV importieren"
-
-#: AKModel/templates/admin/AKModel/status.html:59
+#: AKModel/templates/admin/AKModel/status/event_aks.html:5
 msgid "No AKs yet"
 msgstr "Bisher keine AKs"
 
-#: AKModel/templates/admin/AKModel/status.html:67
+#: AKModel/templates/admin/AKModel/status/event_aks.html:13
 msgid "Slots"
 msgstr "Slots"
 
-#: AKModel/templates/admin/AKModel/status.html:70
+#: AKModel/templates/admin/AKModel/status/event_aks.html:16
 msgid "Unscheduled Slots"
 msgstr "Ungeplante Slots"
 
-#: AKModel/templates/admin/AKModel/status.html:84
-#: AKModel/templates/admin/ak_index.html:16
-msgid "Scheduling"
-msgstr "Scheduling"
-
-#: AKModel/templates/admin/AKModel/status.html:89
-msgid "AKs requiring special attention"
-msgstr "AKs, die besondere Aufmerksamkeit benötigen"
-
-#: AKModel/templates/admin/AKModel/status.html:91
-msgid "Enter Interest"
-msgstr "Interesse erfassen"
-
-#: AKModel/templates/admin/AKModel/status.html:94 AKModel/views.py:519
-msgid "Edit Default Slots"
-msgstr "Standardslots bearbeiten"
-
-#: AKModel/templates/admin/AKModel/status.html:96
-msgid "Manage ak tracks"
-msgstr "AK-Tracks verwalten"
-
-#: AKModel/templates/admin/AKModel/status.html:98
-msgid "Export AKs as CSV"
-msgstr "AKs als CSV exportieren"
-
-#: AKModel/templates/admin/AKModel/status.html:100
-msgid "Export AKs for Wiki"
-msgstr "AKs im Wiki-Format exportieren"
+#: AKModel/templates/admin/AKModel/status/event_categories.html:4
+msgid "No categories yet"
+msgstr "Bisher keine Kategorien"
 
-#: AKModel/templates/admin/AKModel/status.html:102 AKModel/views.py:345
-msgid "Export AK Slides"
-msgstr "AK-Folien exportieren"
+#: AKModel/templates/admin/AKModel/status/event_overview.html:12
+msgid "Plan published?"
+msgstr "Plan veröffentlicht?"
 
-#: AKModel/templates/admin/AKModel/status.html:107
+#: AKModel/templates/admin/AKModel/status/event_requirements.html:4
 msgid "No requirements yet"
 msgstr "Bisher keine Anforderungen"
 
-#: AKModel/templates/admin/AKModel/status.html:120
-msgid "Show AKs for requirements"
-msgstr "Zu Anforderungen gehörige AKs anzeigen"
-
-#: AKModel/templates/admin/AKModel/status.html:124
-msgid "Messages"
-msgstr "Nachrichten"
-
-#: AKModel/templates/admin/AKModel/status.html:126
-msgid "Delete all messages"
-msgstr "Alle Nachrichten löschen"
+#: AKModel/templates/admin/AKModel/status/event_rooms.html:4
+msgid "No rooms yet"
+msgstr "Bisher keine Räume"
 
 #: AKModel/templates/admin/ak_index.html:7
 msgid "Active Events"
 msgstr "Aktive Events"
 
+#: AKModel/templates/admin/ak_index.html:16 AKModel/views/status.py:87
+msgid "Scheduling"
+msgstr "Scheduling"
+
 #: AKModel/templates/admin/login.html:8
 msgid "Please correct the error below."
 msgstr "Bitte den untenstehenden Fehler korrigieren."
@@ -1134,167 +1093,209 @@ msgstr "Login"
 msgid "Register"
 msgstr "Registrieren"
 
-#: AKModel/views.py:156
-msgid "Event Status"
-msgstr "Eventstatus"
-
-#: AKModel/views.py:169
+#: AKModel/views/ak.py:14
 msgid "Requirements for Event"
 msgstr "Anforderungen für das Event"
 
-#: AKModel/views.py:183
+#: AKModel/views/ak.py:28
 msgid "AK CSV Export"
 msgstr "AK-CSV-Export"
 
-#: AKModel/views.py:197
+#: AKModel/views/ak.py:42
 msgid "AK Wiki Export"
 msgstr "AK-Wiki-Export"
 
-#: AKModel/views.py:208 AKModel/views.py:361
+#: AKModel/views/ak.py:53 AKModel/views/manage.py:41
 msgid "Wishes"
 msgstr "Wünsche"
 
-#: AKModel/views.py:229
+#: AKModel/views/ak.py:60
 msgid "Delete AK Orga Messages"
 msgstr "AK-Organachrichten löschen"
 
-#: AKModel/views.py:244
+#: AKModel/views/ak.py:75
 msgid "AK Orga Messages successfully deleted"
 msgstr "AK-Organachrichten erfolgreich gelöscht"
 
-#: AKModel/views.py:254
-msgid "Settings"
-msgstr "Einstellungen"
+#: AKModel/views/ak.py:82
+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.py:255
-msgid "Event created, Prepare Import"
-msgstr "Event angelegt, Import vorbereiten"
+#: AKModel/views/ak.py:83
+msgid "Reset of interest in AKs successful."
+msgstr "Interesse an AKs erfolgreich zurückgesetzt."
 
-#: AKModel/views.py:256
-msgid "Import categories & requirements"
-msgstr "Kategorien & Anforderungen kopieren"
+#: AKModel/views/ak.py:92
+msgid "Interest counter of the following AKs will be set to 0:"
+msgstr "Interessensbekundungszähler der folgenden AKs wird auf 0 gesetzt:"
 
-#: AKModel/views.py:257
-msgid "Activate?"
-msgstr "Aktivieren?"
+#: AKModel/views/ak.py:93
+msgid "AKs' interest counters set back to 0."
+msgstr "Interessenszähler der AKs zurückgesetzt"
 
-#: AKModel/views.py:320
+#: AKModel/views/event_wizard.py:69
 #, python-format
 msgid "Copied '%(obj)s'"
 msgstr "'%(obj)s' kopiert"
 
-#: AKModel/views.py:323
+#: AKModel/views/event_wizard.py:72
 #, python-format
 msgid "Could not copy '%(obj)s' (%(error)s)"
 msgstr "'%(obj)s' konnte nicht kopiert werden (%(error)s)"
 
-#: AKModel/views.py:356
+#: AKModel/views/manage.py:25 AKModel/views/status.py:127
+msgid "Export AK Slides"
+msgstr "AK-Folien exportieren"
+
+#: AKModel/views/manage.py:36
 msgid "Symbols"
 msgstr "Symbole"
 
-#: AKModel/views.py:357
+#: AKModel/views/manage.py:37
 msgid "Who?"
 msgstr "Wer?"
 
-#: AKModel/views.py:358
+#: AKModel/views/manage.py:38
 msgid "Duration(s)"
 msgstr "Dauer(n)"
 
-#: AKModel/views.py:359
+#: AKModel/views/manage.py:39
 msgid "Reso intention?"
 msgstr "Resolutionsabsicht?"
 
-#: AKModel/views.py:360
+#: AKModel/views/manage.py:40
 msgid "Category (for Wishes)"
 msgstr "Kategorie (für Wünsche)"
 
-#: AKModel/views.py:449
+#: AKModel/views/manage.py:77
 msgid "The following Constraint Violations will be marked as manually resolved"
 msgstr ""
 "Die folgenden Constraintverletzungen werden als manuell behoben markiert."
 
-#: AKModel/views.py:450
+#: AKModel/views/manage.py:78
 msgid "Constraint Violations marked as resolved"
 msgstr "Constraintverletzungen als manuell behoben markiert"
 
-#: AKModel/views.py:459
+#: AKModel/views/manage.py:87
 msgid "The following Constraint Violations will be set to level 'violation'"
 msgstr ""
 "Die folgenden Constraintverletzungen werden auf das Level \"Violation\" "
 "gesetzt."
 
-#: AKModel/views.py:460
+#: AKModel/views/manage.py:88
 msgid "Constraint Violations set to level 'violation'"
 msgstr "Constraintverletzungen auf Level \"Violation\" gesetzt"
 
-#: AKModel/views.py:469
+#: AKModel/views/manage.py:97
 msgid "The following Constraint Violations will be set to level 'warning'"
 msgstr ""
 "Die folgenden Constraintverletzungen werden auf das Level 'warning' gesetzt."
 
-#: AKModel/views.py:470
+#: AKModel/views/manage.py:98
 msgid "Constraint Violations set to level 'warning'"
 msgstr "Constraintverletzungen auf Level \"Warning\" gesetzt"
 
-#: AKModel/views.py:479
-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.py:480
-msgid "Reset of interest in AKs successful."
-msgstr "Interesse an AKs erfolgreich zurückgesetzt."
-
-#: AKModel/views.py:489
-msgid "Interest counter of the following AKs will be set to 0:"
-msgstr "Interessensbekundungszähler der folgenden AKs wird auf 0 gesetzt:"
-
-#: AKModel/views.py:490
-msgid "AKs' interest counters set back to 0."
-msgstr "Interessenszähler der AKs zurückgesetzt"
-
-#: AKModel/views.py:499
+#: AKModel/views/manage.py:107
 msgid "Publish the plan(s) of:"
 msgstr "Den Plan/die Pläne veröffentlichen von:"
 
-#: AKModel/views.py:500
+#: AKModel/views/manage.py:108
 msgid "Plan published"
 msgstr "Plan veröffentlicht"
 
-#: AKModel/views.py:509
+#: AKModel/views/manage.py:117
 msgid "Unpublish the plan(s) of:"
 msgstr "Den Plan/die Pläne verbergen von:"
 
-#: AKModel/views.py:510
+#: AKModel/views/manage.py:118
 msgid "Plan unpublished"
 msgstr "Plan verborgen"
 
-#: AKModel/views.py:556
+#: AKModel/views/manage.py:127 AKModel/views/status.py:111
+msgid "Edit Default Slots"
+msgstr "Standardslots bearbeiten"
+
+#: AKModel/views/manage.py:164
 #, python-brace-format
 msgid "Could not update slot {id} since it does not belong to {event}"
 msgstr ""
 "Konnte  Slot {id} nicht bearbeiten, da er nicht zum Event {event} gehört"
 
-#: AKModel/views.py:586
+#: AKModel/views/manage.py:194
 #, python-brace-format
 msgid "Updated {u} slot(s). created {c} new slot(s) and deleted {d} slot(s)"
 msgstr ""
 "{u} Slot(s) aktualisiert, {c} Slot(s) hinzugefügt und {d} Slot(s) gelöscht"
 
-#: AKModel/views.py:607
+#: AKModel/views/room.py:31
 #, python-format
 msgid "Created Room '%(room)s'"
 msgstr "Raum '%(room)s angelegt"
 
-#: AKModel/views.py:644
+#: AKModel/views/room.py:37 AKModel/views/status.py:66
+msgid "Import Rooms from CSV"
+msgstr "Räume aus CSV importieren"
+
+#: AKModel/views/room.py:68
 #, python-brace-format
 msgid "Could not import room {name}: {e}"
 msgstr "Konnte Raum {name} nicht importieren: {e}"
 
-#: AKModel/views.py:648
+#: AKModel/views/room.py:72
 #, python-brace-format
 msgid "Imported {count} room(s)"
 msgstr "{count} Raum/Räume importiert"
 
-#: AKModel/views.py:650
+#: AKModel/views/room.py:74
 msgid "No rooms imported"
 msgstr "Keine Räume importiert"
+
+#: AKModel/views/status.py:16
+msgid "Overview"
+msgstr "Ãœberblick"
+
+#: AKModel/views/status.py:26
+msgid "Categories"
+msgstr "Kategorien"
+
+#: AKModel/views/status.py:30
+msgid "Add category"
+msgstr "Kategorie hinzufügen"
+
+#: AKModel/views/status.py:50
+msgid "Add Room"
+msgstr "Raum hinzufügen"
+
+#: AKModel/views/status.py:100
+msgid "AKs requiring special attention"
+msgstr "AKs, die besondere Aufmerksamkeit benötigen"
+
+#: AKModel/views/status.py:104
+msgid "Enter Interest"
+msgstr "Interesse erfassen"
+
+#: AKModel/views/status.py:115
+msgid "Manage ak tracks"
+msgstr "AK-Tracks verwalten"
+
+#: AKModel/views/status.py:119
+msgid "Export AKs as CSV"
+msgstr "AKs als CSV exportieren"
+
+#: AKModel/views/status.py:123
+msgid "Export AKs for Wiki"
+msgstr "AKs im Wiki-Format exportieren"
+
+#: AKModel/views/status.py:148
+msgid "Show AKs for requirements"
+msgstr "Zu Anforderungen gehörige AKs anzeigen"
+
+#: AKModel/views/status.py:159
+msgid "Event Status"
+msgstr "Eventstatus"
+
+#~ msgid "Messages"
+#~ msgstr "Nachrichten"
+
+#~ msgid "Delete all messages"
+#~ msgstr "Alle Nachrichten löschen"
diff --git a/AKModel/metaviews/__init__.py b/AKModel/metaviews/__init__.py
new file mode 100644
index 00000000..f5a3ee68
--- /dev/null
+++ b/AKModel/metaviews/__init__.py
@@ -0,0 +1,3 @@
+from AKModel.metaviews.status import StatusManager
+
+status_manager = StatusManager()
diff --git a/AKModel/metaviews/admin.py b/AKModel/metaviews/admin.py
new file mode 100644
index 00000000..9c6f9027
--- /dev/null
+++ b/AKModel/metaviews/admin.py
@@ -0,0 +1,158 @@
+from abc import ABC, abstractmethod
+
+from django.contrib import admin, messages
+from django.shortcuts import get_object_or_404
+from django.urls import reverse
+from django.utils.translation import gettext_lazy as _
+from django.views.generic import FormView
+
+from AKModel.forms import AdminIntermediateForm, AdminIntermediateActionForm
+from AKModel.models import Event
+
+
+class EventSlugMixin:
+    """
+    Mixin to handle views with event slugs
+    """
+    event = None
+
+    def _load_event(self):
+        # Find event based on event slug
+        if self.event is None:
+            self.event = get_object_or_404(Event, slug=self.kwargs.get("event_slug", None))
+
+    def get(self, request, *args, **kwargs):
+        self._load_event()
+        return super().get(request, *args, **kwargs)
+
+    def post(self, request, *args, **kwargs):
+        self._load_event()
+        return super().post(request, *args, **kwargs)
+
+    def list(self, request, *args, **kwargs):
+        self._load_event()
+        return super().list(request, *args, **kwargs)
+
+    def create(self, request, *args, **kwargs):
+        self._load_event()
+        return super().create(request, *args, **kwargs)
+
+    def dispatch(self, request, *args, **kwargs):
+        if self.event is None:
+            self._load_event()
+        return super().dispatch(request, *args, **kwargs)
+
+    def get_context_data(self, *, object_list=None, **kwargs):
+        context = super().get_context_data(object_list=object_list, **kwargs)
+        # Add event to context (to make it accessible in templates)
+        context["event"] = self.event
+        return context
+
+
+class FilterByEventSlugMixin(EventSlugMixin):
+    """
+    Mixin to filter different querysets based on a event slug from the request url
+    """
+
+    def get_queryset(self):
+        # Filter current queryset based on url event slug or return 404 if event slug is invalid
+        return super().get_queryset().filter(event=self.event)
+
+
+class AdminViewMixin:
+    site_url = ''
+    title = ''
+
+    def get_context_data(self, **kwargs):
+        extra = admin.site.each_context(self.request)
+        extra.update(super().get_context_data(**kwargs))
+
+        if self.site_url != '':
+            extra["site_url"] = self.site_url
+        if self.title != '':
+            extra["title"] = self.title
+
+        return extra
+
+
+class IntermediateAdminView(AdminViewMixin, FormView):
+    template_name = "admin/AKModel/action_intermediate.html"
+    form_class = AdminIntermediateForm
+
+    def get_preview(self):
+        return ""
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["title"] = self.title
+        context["preview"] = self.get_preview()
+        return context
+
+
+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 IntermediateAdminActionView(IntermediateAdminView, ABC):
+    form_class = AdminIntermediateActionForm
+    entities = None
+
+    def get_queryset(self, pks=None):
+        if pks is None:
+            pks = self.request.GET['pks']
+        return self.model.objects.filter(pk__in=pks.split(","))
+
+    def get_initial(self):
+        initial = super().get_initial()
+        initial['pks'] = self.request.GET['pks']
+        return initial
+
+    def get_preview(self):
+        self.entities = self.get_queryset()
+        joined_entities = '\n'.join(str(e) for e in self.entities)
+        return f"{self.confirmation_message}:\n\n {joined_entities}"
+
+    def get_success_url(self):
+        return reverse(f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_changelist")
+
+    @abstractmethod
+    def action(self, form):
+        pass
+
+    def form_valid(self, form):
+        self.entities = self.get_queryset(pks=form.cleaned_data['pks'])
+        self.action(form)
+        messages.add_message(self.request, messages.SUCCESS, self.success_message)
+        return super().form_valid(form)
+
+
+class LoopActionMixin(ABC):
+    def action(self, form):
+        self.pre_action()
+        for entity in self.entities:
+            self.perform_action(entity)
+            entity.save()
+        self.post_action()
+
+    @abstractmethod
+    def perform_action(self, entity):
+        pass
+
+    def pre_action(self):
+        pass
+
+    def post_action(self):
+        pass
diff --git a/AKModel/metaviews/status.py b/AKModel/metaviews/status.py
new file mode 100644
index 00000000..2e1c3777
--- /dev/null
+++ b/AKModel/metaviews/status.py
@@ -0,0 +1,150 @@
+from abc import ABC, abstractmethod
+from collections import defaultdict
+
+from django.template import loader
+from django.views.generic import TemplateView
+
+from AKModel.metaviews.admin import AdminViewMixin
+
+
+class StatusWidget(ABC):
+    title = "Status Widget"
+    actions = []
+    status = "primary"
+
+    @property
+    @abstractmethod
+    def required_context_type(self) -> str:
+        """
+        Which model/context is needed to render this widget?
+        """
+        pass
+
+    def get_context_data(self, context) -> dict:
+        """
+        Allow to manipulate the context
+        :return: context (with or without changes)
+        """
+        return context
+
+    def render(self, context: {}, request) -> dict:
+        """
+        Render widget based on context
+
+        :param context: Context for rendering
+        :return: Dictionary containing the rendered/prepared information
+        """
+        context = self.get_context_data(context)
+        return {
+            "body": self.render_body(context, request),
+            "title": self.render_title(context),
+            "actions": self.render_actions(context),
+            "status": self.render_status(context),
+        }
+
+    def render_title(self, context: {}) -> str:
+        """
+        Render title for widget based on context
+
+        By default, the title attribute is used without modification
+        :param context: Context for rendering
+        :return: Rendered title
+        """
+        return self.title
+
+    def render_status(self, context: {}) -> str:
+        """
+        Render status for widget based on context
+
+        By default, the status attribute is used without modification
+        :param context: Context for rendering
+        :return: Rendered title
+        """
+        return self.status
+
+    @abstractmethod
+    def render_body(self, context: {}, request) -> str:
+        """
+        Render body for widget based on context
+
+        :param context: Context for rendering
+        :return: Rendered widget body (HTML)
+        """
+        pass
+
+    def render_actions(self, context: {}) -> list[dict]:
+        """
+        Render actions for widget based on context
+
+        By default, all actions specified for this widget are returned without modification
+
+        :param context: Context for rendering
+        :return: List of actions
+        """
+        return [a for a in self.actions]
+
+
+class TemplateStatusWidget(StatusWidget):
+    @property
+    @abstractmethod
+    def template_name(self) -> str:
+        pass
+
+    def render_body(self, context: {}, request) -> str:
+        template = loader.get_template(self.template_name)
+        return template.render(context, request)
+
+
+class StatusManager:
+    """
+    Registry for all status widgets
+    """
+    widgets = {}
+    widgets_by_context_type = defaultdict(list)
+
+    def register(self, name: str):
+        """
+        Call this as
+        @status_manager.register(name="xyz")
+        to register a status widget
+
+        :param name: name of this widget (only used internally). Has to be unique.
+        """
+        def _register(widget_class):
+            w = widget_class()
+            self.widgets[name] = w
+            self.widgets_by_context_type[w.required_context_type].append(w)
+            return widget_class
+
+        return _register
+
+    def get_by_context_type(self, context_type: str):
+        """
+        Filter widgets for ones suitable for provided context
+
+        :param context_type: name of the model provided as context
+        :return: a list of all matching widgets
+        """
+        if context_type in self.widgets_by_context_type.keys():
+            return self.widgets_by_context_type[context_type]
+        return []
+
+
+class StatusView(ABC, AdminViewMixin, TemplateView):
+    template_name = "admin/AKModel/status/status.html"
+
+    @property
+    @abstractmethod
+    def provided_context_type(self) -> str:
+        """
+        Which model/context is provided by this status view?
+        """
+        pass
+
+    def get(self, request, *args, **kwargs):
+        context = self.get_context_data(**kwargs)
+
+        from AKModel.metaviews import status_manager
+        context['widgets'] = [w.render(context, self.request) for w in status_manager.get_by_context_type(self.provided_context_type)]
+
+        return self.render_to_response(context)
diff --git a/AKModel/templates/admin/AKModel/render_ak_messages.html b/AKModel/templates/admin/AKModel/render_ak_messages.html
index e62ccbb7..fbadbc13 100644
--- a/AKModel/templates/admin/AKModel/render_ak_messages.html
+++ b/AKModel/templates/admin/AKModel/render_ak_messages.html
@@ -1,11 +1,15 @@
-<table class="table table-striped">
-{% for message in ak_messages %}
-    <tr><td>
-        <span class="text-secondary float-end">
-            {{ message.timestamp|date:"Y-m-d H:i:s" }}
-        </span>
-        <h5><a href="{{ message.ak.detail_url }}">{{ message.ak }}</a></h5>
-        <p>{{ message.text }}</p>
-    </td></tr>
-{% endfor %}
-</table>
+{% load tz %}
+
+{% timezone event.timezone %}
+    <table class="table table-striped">
+    {% for message in ak_messages %}
+        <tr><td>
+            <span class="text-secondary float-end">
+                {{ message.timestamp|date:"Y-m-d H:i:s" }}
+            </span>
+            <h5><a href="{{ message.ak.detail_url }}">{{ message.ak }}</a></h5>
+            <p>{{ message.text }}</p>
+        </td></tr>
+    {% endfor %}
+    </table>
+{% endtimezone %}
diff --git a/AKModel/templates/admin/AKModel/status.html b/AKModel/templates/admin/AKModel/status.html
deleted file mode 100644
index 8a53f8cd..00000000
--- a/AKModel/templates/admin/AKModel/status.html
+++ /dev/null
@@ -1,130 +0,0 @@
-{% extends "admin/base_site.html" %}
-{% load tags_AKModel %}
-
-{% load i18n %}
-{% load tz %}
-
-{% block title %}{% trans "Status" %}: {{event}}{% endblock %}
-
-{% block content %}
-    {% timezone event.timezone %}
-        <h2><a href="{% url 'admin:AKModel_event_change' event.pk %}">{{event}}</a></h2>
-        <h5>{{ event.start }} - {{ event.end }}</h5>
-
-        <div class="form-check form-switch mt-2 mb-2">
-          <input type="checkbox" class="form-check-input" id="planPublishedSwitch"
-                 {% if not event.plan_hidden %}checked{% endif %}
-                 onclick="location.href='{% if event.plan_hidden %}{% url 'admin:plan-publish' %}{% else %}{% url 'admin:plan-unpublish' %}{% endif %}?pks={{event.pk}}';">
-          <label class="form-check-label" for="planPublishedSwitch">{% trans "Plan published?" %}</label>
-        </div>
-
-        <div class="row">
-            <div class="col-md-8">
-                <h3 class="block-header">{% trans "Categories" %}</h3>
-                {% if event.akcategory_set.count == 0 %}
-                    <p class="text-danger">{% trans "No categories yet" %}</p>
-                {% else %}
-                    <p>
-                        {{ event.akcategory_set.count }}:
-                        {% for category in event.akcategory_set.all %}
-                            {% if forloop.counter0 > 0 %}
-                                &middot;
-                            {% endif %}
-                            <a href="{% url 'admin:AKModel_akcategory_change' category.pk %}">{{ category }}</a>
-                            ({{ category.ak_set.count }})
-                        {% endfor %}
-                    </p>
-                {% endif %}
-                <a class="btn btn-success" href="{% url 'admin:AKModel_akcategory_add' %}">{% trans "Add category" %}</a>
-
-                <h3 class="block-header">{% trans "Rooms" %}</h3>
-                {% if event.room_set.count == 0 %}
-                    <p class="text-danger">{% trans "No rooms yet" %}</p>
-                {% else %}
-                    <p>
-                        {{ event.room_set.count }}:
-                        {% for room in event.room_set.all %}
-                            {% if forloop.counter0 > 0 %}
-                                &middot;
-                            {% endif %}
-                            <a href="{% url 'admin:AKModel_room_change' room.pk %}">{{ room }}</a>
-                        {% endfor %}
-                    </p>
-                {% endif %}
-                <a class="btn btn-success" href="{% url 'admin:AKModel_room_add' %}">{% trans "Add Room" %}</a>
-                <a class="btn btn-success" href="{% url 'admin:room-import' event_slug=event.slug %}">{% trans "Import Rooms from CSV" %}</a>
-
-                <h3 class="block-header">{% trans "AKs" %}</h3>
-                {% if event.ak_set.count == 0 %}
-                    <p class="text-danger">{% trans "No AKs yet" %}</p>
-                {% else %}
-                    <table>
-                        <tbody>
-                            <tr>
-                                <td>{% trans "AKs" %}</td><td>{{ event.ak_set.count }}</td>
-                            </tr>
-                            <tr>
-                                <td>{% trans "Slots" %}</td><td>{{ event.akslot_set.count }}</td>
-                            </tr>
-                            <tr>
-                              <td>{% trans "Unscheduled Slots" %}</td><td>
-                                {% if "AKScheduling"|check_app_installed %}
-                                    <a href="{% url 'admin:slots_unscheduled' event_slug=event.slug %}">
-                                        {{ unscheduled_slots_count }}
-                                    </a>
-                                {% else %}
-                                    {{ unscheduled_slots_count }}
-                                {% endif %}
-                            </td>
-                            </tr>
-                        </tbody>
-                    </table>
-
-                    <a class="btn btn-success"
-                       href="{% url 'admin:schedule' event_slug=event.slug %}">{% trans "Scheduling" %}</a>
-                    {% if "AKScheduling | is_installed" %}
-                        <a class="btn btn-success"
-                            href="{% url 'admin:constraint-violations' slug=event.slug %}">{% trans "Constraint Violations" %} <span class="badge bg-secondary">{{ event.constraintviolation_set.count }}</span></a>
-                        <a class="btn btn-success"
-                            href="{% url 'admin:special-attention' slug=event.slug %}">{% trans "AKs requiring special attention" %}</a>
-                        <a class="btn btn-success"
-                            href="{% url 'admin:enter-interest' event_slug=event.slug pk=event.ak_set.all.first.pk %}">{% trans "Enter Interest" %}</a>
-                    {% endif %}
-                    <a class="btn btn-success"
-                       href="{% url 'admin:default-slots-editor' event_slug=event.slug %}">{% trans "Edit Default Slots" %}</a>
-                    <a class="btn btn-success"
-                       href="{% url 'admin:tracks_manage' event_slug=event.slug %}">{% trans "Manage ak tracks" %}</a>
-                    <a class="btn btn-success"
-                       href="{% url 'admin:ak_csv_export' event_slug=event.slug %}">{% trans "Export AKs as CSV" %}</a>
-                    <a class="btn btn-success"
-                       href="{% url 'admin:ak_wiki_export' slug=event.slug %}">{% trans "Export AKs for Wiki" %}</a>
-                    <a class="btn btn-success"
-                       href="{% url 'admin:ak_slide_export' event_slug=event.slug %}">{% trans "Export AK Slides" %}</a>
-                {% endif %}
-
-                <h3 class="block-header">{% trans "Requirements" %}</h3>
-                {% if event.akrequirement_set.count == 0 %}
-                    <p class="text-danger">{% trans "No requirements yet" %}</p>
-                {% else %}
-                    <p>
-                        {{ event.akrequirement_set.count }}:
-                        {% for requirement in event.akrequirement_set.all %}
-                            {% if forloop.counter0 > 0 %}
-                                &middot;
-                            {% endif %}
-                            <a href="{% url 'admin:AKModel_akrequirement_change' requirement.pk %}">{{ requirement }}</a>
-                            ({{ requirement.ak_set.count }})
-                        {% endfor %}
-                    </p>
-                {% endif %}
-                <a class="btn btn-success" href="{% url 'admin:event_requirement_overview' event.slug %}">{% trans "Show AKs for requirements" %}</a>
-                <a class="btn btn-success" href="{% url 'admin:AKModel_akrequirement_add' %}">{% trans "Add Requirement" %}</a>
-            </div>
-            <div class="col-md-4">
-                <h3 class="block-header">{% trans "Messages" %}</h3>
-                {% include "admin/AKModel/render_ak_messages.html" %}
-                <a class="btn btn-danger" href="{% url 'admin:ak_delete_orga_messages' event_slug=event.slug %}">{% trans "Delete all messages" %}</a>
-            </div>
-        </div>
-    {% endtimezone %}
-{% endblock %}
diff --git a/AKModel/templates/admin/AKModel/status/event_aks.html b/AKModel/templates/admin/AKModel/status/event_aks.html
new file mode 100644
index 00000000..a99852cc
--- /dev/null
+++ b/AKModel/templates/admin/AKModel/status/event_aks.html
@@ -0,0 +1,28 @@
+{% load i18n %}
+{% load tags_AKModel %}
+
+{% if event.ak_set.count == 0 %}
+    <p class="text-danger">{% trans "No AKs yet" %}</p>
+{% else %}
+    <table>
+        <tbody>
+            <tr>
+                <td>{% trans "AKs" %}</td><td>{{ ak_count }}</td>
+            </tr>
+            <tr>
+                <td>{% trans "Slots" %}</td><td>{{ event.akslot_set.count }}</td>
+            </tr>
+            <tr>
+              <td>{% trans "Unscheduled Slots" %}</td><td>
+                {% if "AKScheduling"|check_app_installed %}
+                    <a href="{% url 'admin:slots_unscheduled' event_slug=event.slug %}">
+                        {{ unscheduled_slots_count }}
+                    </a>
+                {% else %}
+                    {{ unscheduled_slots_count }}
+                {% endif %}
+            </td>
+            </tr>
+        </tbody>
+    </table>
+{% endif %}
diff --git a/AKModel/templates/admin/AKModel/status/event_categories.html b/AKModel/templates/admin/AKModel/status/event_categories.html
new file mode 100644
index 00000000..59c2a9ae
--- /dev/null
+++ b/AKModel/templates/admin/AKModel/status/event_categories.html
@@ -0,0 +1,14 @@
+{% load i18n %}
+
+{% if event.akcategory_set.count == 0 %}
+    <p class="text-danger">{% trans "No categories yet" %}</p>
+{% else %}
+    <ul>
+        {% for category in event.akcategory_set.all %}
+            <li>
+                <a href="{% url 'admin:AKModel_akcategory_change' category.pk %}">{{ category }}</a>
+            ({{ category.ak_set.count }})
+            </li>
+        {% endfor %}
+    </ul>
+{% endif %}
diff --git a/AKModel/templates/admin/AKModel/status/event_overview.html b/AKModel/templates/admin/AKModel/status/event_overview.html
new file mode 100644
index 00000000..6c0a7d1e
--- /dev/null
+++ b/AKModel/templates/admin/AKModel/status/event_overview.html
@@ -0,0 +1,14 @@
+{% load i18n %}
+{% load tz %}
+
+{% timezone event.timezone %}
+    <h2><a href="{% url 'admin:AKModel_event_change' event.pk %}">{{event}}</a></h2>
+    <h5>{{ event.start }} - {{ event.end }}</h5>
+
+    <div class="form-check form-switch mt-2 mb-2">
+      <input type="checkbox" class="form-check-input" id="planPublishedSwitch"
+             {% if not event.plan_hidden %}checked{% endif %}
+             onclick="location.href='{% if event.plan_hidden %}{% url 'admin:plan-publish' %}{% else %}{% url 'admin:plan-unpublish' %}{% endif %}?pks={{event.pk}}';">
+      <label class="form-check-label" for="planPublishedSwitch">{% trans "Plan published?" %}</label>
+    </div>
+{% endtimezone %}
diff --git a/AKModel/templates/admin/AKModel/status/event_requirements.html b/AKModel/templates/admin/AKModel/status/event_requirements.html
new file mode 100644
index 00000000..f0e3b11f
--- /dev/null
+++ b/AKModel/templates/admin/AKModel/status/event_requirements.html
@@ -0,0 +1,14 @@
+{% load i18n %}
+
+{% if event.akrequirement_set.count == 0 %}
+    <p class="text-danger">{% trans "No requirements yet" %}</p>
+{% else %}
+    <ul>
+        {% for requirement in event.akrequirement_set.all %}
+            <li>
+                <a href="{% url 'admin:AKModel_akrequirement_change' requirement.pk %}">{{ requirement }}</a>
+            ({{ requirement.ak_set.count }})
+            </li>
+        {% endfor %}
+    </ul>
+{% endif %}
diff --git a/AKModel/templates/admin/AKModel/status/event_rooms.html b/AKModel/templates/admin/AKModel/status/event_rooms.html
new file mode 100644
index 00000000..e58ecedd
--- /dev/null
+++ b/AKModel/templates/admin/AKModel/status/event_rooms.html
@@ -0,0 +1,15 @@
+{% load i18n %}
+
+{% if event.room_set.count == 0 %}
+    <p class="text-danger">{% trans "No rooms yet" %}</p>
+{% else %}
+    <p>
+        {% for room in event.room_set.all %}
+            {% if forloop.counter0 > 0 %}
+                &middot;
+            {% endif %}
+            <a href="{% url 'admin:AKModel_room_change' room.pk %}">{{ room }}</a>
+        {% endfor %}
+    </p>
+{% endif %}
+
diff --git a/AKModel/templates/admin/AKModel/status/status.html b/AKModel/templates/admin/AKModel/status/status.html
new file mode 100644
index 00000000..5918aaf3
--- /dev/null
+++ b/AKModel/templates/admin/AKModel/status/status.html
@@ -0,0 +1,40 @@
+{% extends "admin/base_site.html" %}
+{% load tags_AKModel %}
+
+{% load i18n %}
+{% load tz %}
+{% load fontawesome_6 %}
+
+{% block title %}{% trans "Status" %}: {{ event }}{% endblock %}
+
+{% block content %}
+    {% timezone event.timezone %}
+        <div class="row">
+            {% for widget in widgets %}
+                <div class="card border-{{ widget.status }} mb-3 me-2 col-xl-3 col-md-4 col-sm-6 p-0">
+                    <div class="card-header">
+                        {% if widget.actions %}
+                            <div class="float-end">
+                                <a class="" data-bs-toggle="dropdown" aria-expanded="false">
+                                    {% fa6_icon "ellipsis-vertical" %}
+                                </a>
+                                <ul class="dropdown-menu dropdown-menu-end">
+                                    {% for action in widget.actions %}
+                                    <li>
+                                        <a class="dropdown-item" href="{{ action.url }}">{{ action.text }}</a>
+                                    </li>
+                                    {% endfor %}
+                                </ul>
+                            </div>
+                        {% endif %}
+                        {{ widget.title }}
+                    </div>
+                    <div class="card-body">
+                        {{ widget.body }}
+                    </div>
+                </div>
+            {% endfor %}
+        </div>
+
+    {% endtimezone %}
+{% endblock %}
diff --git a/AKModel/templates/admin/ak_index.html b/AKModel/templates/admin/ak_index.html
index 6999744f..6b424034 100644
--- a/AKModel/templates/admin/ak_index.html
+++ b/AKModel/templates/admin/ak_index.html
@@ -12,7 +12,7 @@
                     <a href="{% url 'admin:AKModel_event_change' event.pk %}">{{ event }}</a>
                     ({{ event.start|timezone:event.timezone|date:"d.m.y" }} -
                     {{ event.end|timezone:event.timezone|date:"d.m.y" }}) &middot;
-                    <a href="{% url 'admin:event_status' slug=event.slug %}">{% trans "Status" %}</a> &middot;
+                    <a href="{% url 'admin:event_status' event_slug=event.slug %}">{% trans "Status" %}</a> &middot;
                     <a href="{% url 'admin:schedule' event_slug=event.slug %}">{% trans "Scheduling" %}</a>
                 </li>
             {% endfor %}
diff --git a/AKModel/tests.py b/AKModel/tests.py
index b6b490de..d676992f 100644
--- a/AKModel/tests.py
+++ b/AKModel/tests.py
@@ -156,7 +156,7 @@ class ModelViewTests(BasicViewTests, TestCase):
 
     VIEWS_STAFF_ONLY = [
         ('admin:index', {}),
-        ('admin:event_status', {'slug': 'kif42'}),
+        ('admin:event_status', {'event_slug': 'kif42'}),
         ('admin:event_requirement_overview', {'event_slug': 'kif42'}),
         ('admin:ak_csv_export', {'event_slug': 'kif42'}),
         ('admin:ak_wiki_export', {'slug': 'kif42'}),
diff --git a/AKModel/urls.py b/AKModel/urls.py
index 8113ee1b..80617814 100644
--- a/AKModel/urls.py
+++ b/AKModel/urls.py
@@ -3,18 +3,20 @@ from django.apps import apps
 from django.urls import include, path
 from rest_framework.routers import DefaultRouter
 
-from AKModel import views
-from AKModel.views import NewEventWizardStartView, NewEventWizardSettingsView, NewEventWizardPrepareImportView, \
-    NewEventWizardImportView, NewEventWizardActivateView, NewEventWizardFinishView, EventStatusView, \
-    AKRequirementOverview, AKCSVExportView, AKWikiExportView, AKMessageDeleteView, ExportSlidesView
+import AKModel.views.api
+from AKModel.views.manage import ExportSlidesView
+from AKModel.views.ak import AKRequirementOverview, AKCSVExportView, AKWikiExportView, AKMessageDeleteView
+from AKModel.views.event_wizard import NewEventWizardStartView, NewEventWizardPrepareImportView, \
+    NewEventWizardImportView, NewEventWizardActivateView, NewEventWizardFinishView, NewEventWizardSettingsView
+from AKModel.views.status import EventStatusView
 
 api_router = DefaultRouter()
-api_router.register('akowner', views.AKOwnerViewSet, basename='AKOwner')
-api_router.register('akcategory', views.AKCategoryViewSet, basename='AKCategory')
-api_router.register('aktrack', views.AKTrackViewSet, basename='AKTrack')
-api_router.register('ak', views.AKViewSet, basename='AK')
-api_router.register('room', views.RoomViewSet, basename='Room')
-api_router.register('akslot', views.AKSlotViewSet, basename='AKSlot')
+api_router.register('akowner', AKModel.views.api.AKOwnerViewSet, basename='AKOwner')
+api_router.register('akcategory', AKModel.views.api.AKCategoryViewSet, basename='AKCategory')
+api_router.register('aktrack', AKModel.views.api.AKTrackViewSet, basename='AKTrack')
+api_router.register('ak', AKModel.views.api.AKViewSet, basename='AK')
+api_router.register('room', AKModel.views.api.RoomViewSet, basename='Room')
+api_router.register('akslot', AKModel.views.api.AKSlotViewSet, basename='AKSlot')
 
 extra_paths = []
 if apps.is_installed("AKScheduling"):
@@ -48,7 +50,7 @@ urlpatterns = [
         '<slug:event_slug>/',
         include(event_specific_paths)
     ),
-    path('user/', views.UserView.as_view(), name="user"),
+    path('user/', AKModel.views.manage.UserView.as_view(), name="user"),
 ]
 
 
@@ -74,7 +76,7 @@ def get_admin_urls_event_wizard(admin_site):
 
 def get_admin_urls_event(admin_site):
     return [
-        path('<slug:slug>/status/', admin_site.admin_view(EventStatusView.as_view()), name="event_status"),
+        path('<slug:event_slug>/status/', admin_site.admin_view(EventStatusView.as_view()), name="event_status"),
         path('<slug:event_slug>/requirements/', admin_site.admin_view(AKRequirementOverview.as_view()),
              name="event_requirement_overview"),
         path('<slug:event_slug>/ak-csv-export/', admin_site.admin_view(AKCSVExportView.as_view()),
diff --git a/AKModel/views.py b/AKModel/views.py
deleted file mode 100644
index 3d4e5632..00000000
--- a/AKModel/views.py
+++ /dev/null
@@ -1,651 +0,0 @@
-import csv
-import datetime
-import json
-import os
-import tempfile
-from abc import ABC, abstractmethod
-from itertools import zip_longest
-
-import django.db
-from django.apps import apps
-from django.contrib import admin, messages
-from django.db.models.functions import Now
-from django.http import HttpResponseRedirect
-from django.shortcuts import get_object_or_404, redirect
-from django.urls import reverse_lazy, reverse
-from django.utils.dateparse import parse_datetime
-from django.utils.translation import gettext_lazy as _
-from django.views.generic import TemplateView, DetailView, ListView, DeleteView, CreateView, FormView, UpdateView
-from django_tex.core import render_template_with_context, run_tex_in_directory
-from django_tex.response import PDFResponse
-from rest_framework import viewsets, permissions, mixins
-
-from AKModel.forms import NewEventWizardStartForm, NewEventWizardSettingsForm, NewEventWizardPrepareImportForm, \
-    NewEventWizardImportForm, NewEventWizardActivateForm, AdminIntermediateForm, SlideExportForm, \
-    AdminIntermediateActionForm, DefaultSlotEditorForm, RoomBatchCreationForm, RoomForm
-from AKModel.models import Event, AK, AKSlot, Room, AKTrack, AKCategory, AKOwner, AKOrgaMessage, AKRequirement, \
-    ConstraintViolation, DefaultSlot
-from AKModel.serializers import AKSerializer, AKSlotSerializer, RoomSerializer, AKTrackSerializer, AKCategorySerializer, \
-    AKOwnerSerializer
-
-
-class EventSlugMixin:
-    """
-    Mixin to handle views with event slugs
-    """
-    event = None
-
-    def _load_event(self):
-        # Find event based on event slug
-        if self.event is None:
-            self.event = get_object_or_404(Event, slug=self.kwargs.get("event_slug", None))
-
-    def get(self, request, *args, **kwargs):
-        self._load_event()
-        return super().get(request, *args, **kwargs)
-
-    def post(self, request, *args, **kwargs):
-        self._load_event()
-        return super().post(request, *args, **kwargs)
-
-    def list(self, request, *args, **kwargs):
-        self._load_event()
-        return super().list(request, *args, **kwargs)
-
-    def create(self, request, *args, **kwargs):
-        self._load_event()
-        return super().create(request, *args, **kwargs)
-
-    def dispatch(self, request, *args, **kwargs):
-        if self.event is None:
-            self._load_event()
-        return super().dispatch(request, *args, **kwargs)
-
-    def get_context_data(self, *, object_list=None, **kwargs):
-        context = super().get_context_data(object_list=object_list, **kwargs)
-        # Add event to context (to make it accessible in templates)
-        context["event"] = self.event
-        return context
-
-
-class FilterByEventSlugMixin(EventSlugMixin):
-    """
-    Mixin to filter different querysets based on a event slug from the request url
-    """
-
-    def get_queryset(self):
-        # Filter current queryset based on url event slug or return 404 if event slug is invalid
-        return super().get_queryset().filter(event=self.event)
-
-
-class AdminViewMixin:
-    site_url = ''
-    title = ''
-
-    def get_context_data(self, **kwargs):
-        extra = admin.site.each_context(self.request)
-        extra.update(super().get_context_data(**kwargs))
-
-        if self.site_url != '':
-            extra["site_url"] = self.site_url
-        if self.title != '':
-            extra["title"] = self.title
-
-        return extra
-
-
-class AKOwnerViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
-    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
-    serializer_class = AKOwnerSerializer
-
-    def get_queryset(self):
-        return AKOwner.objects.filter(event=self.event)
-
-
-class AKCategoryViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
-    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
-    serializer_class = AKCategorySerializer
-
-    def get_queryset(self):
-        return AKCategory.objects.filter(event=self.event)
-
-
-class AKTrackViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin,
-                     mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
-    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
-    serializer_class = AKTrackSerializer
-
-    def get_queryset(self):
-        return AKTrack.objects.filter(event=self.event)
-
-
-class AKViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin,
-                viewsets.GenericViewSet):
-    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
-    serializer_class = AKSerializer
-
-    def get_queryset(self):
-        return AK.objects.filter(event=self.event)
-
-
-class RoomViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
-    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
-    serializer_class = RoomSerializer
-
-    def get_queryset(self):
-        return Room.objects.filter(event=self.event)
-
-
-class AKSlotViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin,
-                    mixins.ListModelMixin, viewsets.GenericViewSet):
-    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
-    serializer_class = AKSlotSerializer
-
-    def get_queryset(self):
-        return AKSlot.objects.filter(event=self.event)
-
-
-class UserView(TemplateView):
-    template_name = "AKModel/user.html"
-
-
-class EventStatusView(AdminViewMixin, DetailView):
-    template_name = "admin/AKModel/status.html"
-    model = Event
-    context_object_name = "event"
-    title = _("Event Status")
-
-    def get_context_data(self, **kwargs):
-        context = super().get_context_data(**kwargs)
-        context["unscheduled_slots_count"] = context["event"].akslot_set.filter(start=None).count
-        context["site_url"] = reverse_lazy("dashboard:dashboard_event", kwargs={'slug': context["event"].slug})
-        context["ak_messages"] = AKOrgaMessage.objects.filter(ak__event=context["event"])
-        return context
-
-
-class AKRequirementOverview(AdminViewMixin, FilterByEventSlugMixin, ListView):
-    model = AKRequirement
-    context_object_name = "requirements"
-    title = _("Requirements for Event")
-    template_name = "admin/AKModel/requirements_overview.html"
-
-    def get_context_data(self, **kwargs):
-        context = super().get_context_data(**kwargs)
-        context["event"] = self.event
-        context["site_url"] = reverse_lazy("dashboard:dashboard_event", kwargs={'slug': context["event"].slug})
-        return context
-
-
-class AKCSVExportView(AdminViewMixin, FilterByEventSlugMixin, ListView):
-    template_name = "admin/AKModel/ak_csv_export.html"
-    model = AKSlot
-    context_object_name = "slots"
-    title = _("AK CSV Export")
-
-    def get_queryset(self):
-        return super().get_queryset().order_by("ak__track")
-
-    def get_context_data(self, **kwargs):
-        context = super().get_context_data(**kwargs)
-        return context
-
-
-class AKWikiExportView(AdminViewMixin, DetailView):
-    template_name = "admin/AKModel/wiki_export.html"
-    model = Event
-    context_object_name = "event"
-    title = _("AK Wiki Export")
-
-    def get_context_data(self, **kwargs):
-        context = super().get_context_data(**kwargs)
-
-        categories_with_aks, ak_wishes = context["event"].get_categories_with_aks(
-            wishes_seperately=True,
-            filter=lambda ak: ak.include_in_export
-        )
-
-        context["categories_with_aks"] = [(category.name, ak_list) for category, ak_list in categories_with_aks]
-        context["categories_with_aks"].append((_("Wishes"), ak_wishes))
-
-        return context
-
-
-class IntermediateAdminView(AdminViewMixin, FormView):
-    template_name = "admin/AKModel/action_intermediate.html"
-    form_class = AdminIntermediateForm
-
-    def get_preview(self):
-        return ""
-
-    def get_context_data(self, **kwargs):
-        context = super().get_context_data(**kwargs)
-        context["title"] = self.title
-        context["preview"] = self.get_preview()
-        return context
-
-
-class AKMessageDeleteView(EventSlugMixin, IntermediateAdminView):
-    template_name = "admin/AKModel/message_delete.html"
-    title = _("Delete AK Orga Messages")
-
-    def get_orga_messages_for_event(self, event):
-        return AKOrgaMessage.objects.filter(ak__event=event)
-
-    def get_success_url(self):
-        return reverse_lazy('admin:event_status', kwargs={'slug': self.event.slug})
-
-    def get_context_data(self, **kwargs):
-        context = super().get_context_data(**kwargs)
-        context["ak_messages"] = self.get_orga_messages_for_event(self.event)
-        return context
-
-    def form_valid(self, form):
-        self.get_orga_messages_for_event(self.event).delete()
-        messages.add_message(self.request, messages.SUCCESS, _("AK Orga Messages successfully deleted"))
-        return super().form_valid(form)
-
-
-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):
-        import_types = ["import_categories", "import_requirements"]
-        if apps.is_installed("AKDashboard"):
-            import_types.append("import_buttons")
-
-        for import_type in import_types:
-            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
-
-
-class ExportSlidesView(EventSlugMixin, IntermediateAdminView):
-    title = _('Export AK Slides')
-    form_class = SlideExportForm
-
-    def form_valid(self, form):
-        template_name = 'admin/AKModel/export/slides.tex'
-
-        NEXT_AK_LIST_LENGTH = form.cleaned_data['num_next']
-        RESULT_PRESENTATION_MODE = form.cleaned_data["presentation_mode"]
-        SPACE_FOR_NOTES_IN_WISHES = form.cleaned_data["wish_notes"]
-
-        translations = {
-            'symbols': _("Symbols"),
-            'who': _("Who?"),
-            'duration': _("Duration(s)"),
-            'reso': _("Reso intention?"),
-            'category': _("Category (for Wishes)"),
-            'wishes': _("Wishes"),
-        }
-
-        def build_ak_list_with_next_aks(ak_list):
-            next_aks_list = zip_longest(*[ak_list[i + 1:] for i in range(NEXT_AK_LIST_LENGTH)], fillvalue=None)
-            return [(ak, next_aks) for ak, next_aks in zip_longest(ak_list, next_aks_list, fillvalue=list())]
-
-        categories_with_aks, ak_wishes = self.event.get_categories_with_aks(wishes_seperately=True, filter=lambda
-            ak: not RESULT_PRESENTATION_MODE or (ak.present or (ak.present is None and ak.category.present_by_default)))
-
-        context = {
-            'title': self.event.name,
-            'categories_with_aks': [(category, build_ak_list_with_next_aks(ak_list)) for category, ak_list in
-                                    categories_with_aks],
-            'subtitle': _("AKs"),
-            "wishes": build_ak_list_with_next_aks(ak_wishes),
-            "translations": translations,
-            "result_presentation_mode": RESULT_PRESENTATION_MODE,
-            "space_for_notes_in_wishes": SPACE_FOR_NOTES_IN_WISHES,
-        }
-
-        source = render_template_with_context(template_name, context)
-
-        # Perform real compilation (run latex twice for correct page numbers)
-        with tempfile.TemporaryDirectory() as tempdir:
-            run_tex_in_directory(source, tempdir, template_name=self.template_name)
-            os.remove(f'{tempdir}/texput.tex')
-            pdf = run_tex_in_directory(source, tempdir, template_name=self.template_name)
-
-        timestamp = datetime.datetime.now(tz=self.event.timezone).strftime("%Y-%m-%d_%H_%M")
-        return PDFResponse(pdf, filename=f'{self.event.slug}_ak_slides_{timestamp}.pdf')
-
-
-class IntermediateAdminActionView(IntermediateAdminView, ABC):
-    form_class = AdminIntermediateActionForm
-    entities = None
-
-    def get_queryset(self, pks=None):
-        if pks is None:
-            pks = self.request.GET['pks']
-        return self.model.objects.filter(pk__in=pks.split(","))
-
-    def get_initial(self):
-        initial = super().get_initial()
-        initial['pks'] = self.request.GET['pks']
-        return initial
-
-    def get_preview(self):
-        self.entities = self.get_queryset()
-        joined_entities = '\n'.join(str(e) for e in self.entities)
-        return f"{self.confirmation_message}:\n\n {joined_entities}"
-
-    def get_success_url(self):
-        return reverse(f"admin:{self.model._meta.app_label}_{self.model._meta.model_name}_changelist")
-
-    @abstractmethod
-    def action(self, form):
-        pass
-
-    def form_valid(self, form):
-        self.entities = self.get_queryset(pks=form.cleaned_data['pks'])
-        self.action(form)
-        messages.add_message(self.request, messages.SUCCESS, self.success_message)
-        return super().form_valid(form)
-
-
-class LoopActionMixin(ABC):
-    def action(self, form):
-        self.pre_action()
-        for entity in self.entities:
-            self.perform_action(entity)
-            entity.save()
-        self.post_action()
-
-    @abstractmethod
-    def perform_action(self, entity):
-        pass
-
-    def pre_action(self):
-        pass
-
-    def post_action(self):
-        pass
-
-
-class CVMarkResolvedView(IntermediateAdminActionView):
-    title = _('Mark Constraint Violations as manually resolved')
-    model = ConstraintViolation
-    confirmation_message = _("The following Constraint Violations will be marked as manually resolved")
-    success_message = _("Constraint Violations marked as resolved")
-
-    def action(self, form):
-        self.entities.update(manually_resolved=True)
-
-
-class CVSetLevelViolationView(IntermediateAdminActionView):
-    title = _('Set Constraint Violations to level "violation"')
-    model = ConstraintViolation
-    confirmation_message = _("The following Constraint Violations will be set to level 'violation'")
-    success_message = _("Constraint Violations set to level 'violation'")
-
-    def action(self, form):
-        self.entities.update(level=ConstraintViolation.ViolationLevel.VIOLATION)
-
-
-class CVSetLevelWarningView(IntermediateAdminActionView):
-    title = _('Set Constraint Violations to level "warning"')
-    model = ConstraintViolation
-    confirmation_message = _("The following Constraint Violations will be set to level 'warning'")
-    success_message = _("Constraint Violations set to level 'warning'")
-
-    def action(self, form):
-        self.entities.update(level=ConstraintViolation.ViolationLevel.WARNING)
-
-
-class AKResetInterestView(IntermediateAdminActionView):
-    title = _("Reset interest in AKs")
-    model = AK
-    confirmation_message = _("Interest of the following AKs will be set to not filled (-1):")
-    success_message = _("Reset of interest in AKs successful.")
-
-    def action(self, form):
-        self.entities.update(interest=-1)
-
-
-class AKResetInterestCounterView(IntermediateAdminActionView):
-    title = _("Reset AKs' interest counters")
-    model = AK
-    confirmation_message = _("Interest counter of the following AKs will be set to 0:")
-    success_message = _("AKs' interest counters set back to 0.")
-
-    def action(self, form):
-        self.entities.update(interest_counter=0)
-
-
-class PlanPublishView(IntermediateAdminActionView):
-    title = _('Publish plan')
-    model = Event
-    confirmation_message = _('Publish the plan(s) of:')
-    success_message = _('Plan published')
-
-    def action(self, form):
-        self.entities.update(plan_published_at=Now(), plan_hidden=False)
-
-
-class PlanUnpublishView(IntermediateAdminActionView):
-    title = _('Unpublish plan')
-    model = Event
-    confirmation_message = _('Unpublish the plan(s) of:')
-    success_message = _('Plan unpublished')
-
-    def action(self, form):
-        self.entities.update(plan_published_at=None, plan_hidden=True)
-
-
-class DefaultSlotEditorView(EventSlugMixin, IntermediateAdminView):
-    template_name = "admin/AKModel/default_slot_editor.html"
-    form_class = DefaultSlotEditorForm
-    title = _("Edit Default Slots")
-
-    def get_success_url(self):
-        return self.request.path
-
-    def get_initial(self):
-        initial = super().get_initial()
-        default_slots = [
-            {"id": s.id, "start": s.start_iso, "end": s.end_iso, "allDay": False}
-            for s in self.event.defaultslot_set.all()
-        ]
-        initial['availabilities'] = json.dumps({
-            'availabilities': default_slots
-        })
-        return initial
-
-    def form_valid(self, form):
-        default_slots_raw = json.loads(form.cleaned_data['availabilities'])["availabilities"]
-        tz = self.event.timezone
-
-        created_count = 0
-        updated_count = 0
-
-        previous_slot_ids = set(s.id for s in self.event.defaultslot_set.all())
-
-        for slot in default_slots_raw:
-            start = parse_datetime(slot["start"]).astimezone(tz)
-            end = parse_datetime(slot["end"]).astimezone(tz)
-
-            if slot["id"] != '':
-                id = int(slot["id"])
-                if id not in previous_slot_ids:
-                    # Make sure only slots (currently) belonging to this event are edited
-                    # (user did not manipulate IDs and slots have not been deleted in another session in the meantime)
-                    messages.add_message(
-                        self.request,
-                        messages.WARNING,
-                        _("Could not update slot {id} since it does not belong to {event}")
-                        .format(id=slot['id'], event=self.event.name)
-                    )
-                else:
-                    # Update existing entries
-                    previous_slot_ids.remove(id)
-                    original_slot = DefaultSlot.objects.get(id=id)
-                    if original_slot.start != start or original_slot.end != end:
-                        original_slot.start = start
-                        original_slot.end = end
-                        original_slot.save()
-                        updated_count += 1
-            else:
-                # Create new entries
-                DefaultSlot.objects.create(
-                    start=start,
-                    end=end,
-                    event=self.event
-                )
-                created_count += 1
-
-        # Delete all slots not re-submitted by the user (and hence deleted in editor)
-        deleted_count = len(previous_slot_ids)
-        for d_id in previous_slot_ids:
-            DefaultSlot.objects.get(id=d_id).delete()
-
-        if created_count + updated_count + deleted_count > 0:
-            messages.add_message(
-                self.request,
-                messages.SUCCESS,
-                _("Updated {u} slot(s). created {c} new slot(s) and deleted {d} slot(s)")
-                .format(u=str(updated_count), c=str(created_count), d=str(deleted_count))
-            )
-        return super().form_valid(form)
-
-
-class RoomCreationView(AdminViewMixin, CreateView):
-    form_class = RoomForm
-    template_name = 'admin/AKModel/room_create.html'
-
-    def get_success_url(self):
-        print(self.request.POST['save_action'])
-        if self.request.POST['save_action'] == 'save_add_another':
-            return reverse_lazy('admin:room-new')
-        elif self.request.POST['save_action'] == 'save_continue':
-            return reverse_lazy('admin:AKModel_room_change', kwargs={'object_id': self.room.pk})
-        else:
-            return reverse_lazy('admin:AKModel_room_changelist')
-
-    def form_valid(self, form):
-        self.room = form.save()
-        messages.success(self.request, _("Created Room '%(room)s'" % {'room': self.room}))
-        return HttpResponseRedirect(self.get_success_url())
-
-
-class RoomBatchCreationView(EventSlugMixin, IntermediateAdminView):
-    form_class = RoomBatchCreationForm
-    title = _("Import Rooms from CSV")
-
-    def get_success_url(self):
-        return reverse_lazy('admin:event_status', kwargs={'slug': self.event.slug})
-
-    def form_valid(self, form):
-        virtual_rooms_support = False
-        created_count = 0
-
-        rooms_raw_dict: csv.DictReader = form.cleaned_data["rooms"]
-
-        if apps.is_installed("AKOnline") and "url" in rooms_raw_dict.fieldnames:
-            virtual_rooms_support = True
-            from AKOnline.models import VirtualRoom
-
-        for raw_room in rooms_raw_dict:
-            name = raw_room["name"]
-            location = raw_room["location"] if "location" in rooms_raw_dict.fieldnames else ""
-            capacity = raw_room["capacity"] if "capacity" in rooms_raw_dict.fieldnames else -1
-
-            try:
-                r = Room.objects.create(name=name,
-                                    location=location,
-                                    capacity=capacity,
-                                    event=self.event)
-                if virtual_rooms_support and raw_room["url"] != "":
-                    VirtualRoom.objects.create(room=r,
-                                               url=raw_room["url"])
-                created_count += 1
-            except django.db.Error as e:
-                messages.add_message(self.request, messages.WARNING,
-                                     _("Could not import room {name}: {e}").format(name=name, e=str(e)))
-
-        if created_count > 0:
-            messages.add_message(self.request, messages.SUCCESS,
-                                 _("Imported {count} room(s)").format(count=created_count))
-        else:
-            messages.add_message(self.request, messages.WARNING, _("No rooms imported"))
-        return super().form_valid(form)
diff --git a/AKModel/views/__init__.py b/AKModel/views/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/AKModel/views/ak.py b/AKModel/views/ak.py
new file mode 100644
index 00000000..640d398e
--- /dev/null
+++ b/AKModel/views/ak.py
@@ -0,0 +1,96 @@
+from django.contrib import messages
+from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
+from django.views.generic import ListView, DetailView
+
+from AKModel.metaviews.admin import AdminViewMixin, FilterByEventSlugMixin, EventSlugMixin, IntermediateAdminView, \
+    IntermediateAdminActionView
+from AKModel.models import AKRequirement, AKSlot, Event, AKOrgaMessage, AK
+
+
+class AKRequirementOverview(AdminViewMixin, FilterByEventSlugMixin, ListView):
+    model = AKRequirement
+    context_object_name = "requirements"
+    title = _("Requirements for Event")
+    template_name = "admin/AKModel/requirements_overview.html"
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["event"] = self.event
+        context["site_url"] = reverse_lazy("dashboard:dashboard_event", kwargs={'slug': context["event"].slug})
+        return context
+
+
+class AKCSVExportView(AdminViewMixin, FilterByEventSlugMixin, ListView):
+    template_name = "admin/AKModel/ak_csv_export.html"
+    model = AKSlot
+    context_object_name = "slots"
+    title = _("AK CSV Export")
+
+    def get_queryset(self):
+        return super().get_queryset().order_by("ak__track")
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        return context
+
+
+class AKWikiExportView(AdminViewMixin, DetailView):
+    template_name = "admin/AKModel/wiki_export.html"
+    model = Event
+    context_object_name = "event"
+    title = _("AK Wiki Export")
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+
+        categories_with_aks, ak_wishes = context["event"].get_categories_with_aks(
+            wishes_seperately=True,
+            filter=lambda ak: ak.include_in_export
+        )
+
+        context["categories_with_aks"] = [(category.name, ak_list) for category, ak_list in categories_with_aks]
+        context["categories_with_aks"].append((_("Wishes"), ak_wishes))
+
+        return context
+
+
+class AKMessageDeleteView(EventSlugMixin, IntermediateAdminView):
+    template_name = "admin/AKModel/message_delete.html"
+    title = _("Delete AK Orga Messages")
+
+    def get_orga_messages_for_event(self, event):
+        return AKOrgaMessage.objects.filter(ak__event=event)
+
+    def get_success_url(self):
+        return reverse_lazy('admin:event_status', kwargs={'slug': self.event.slug})
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["ak_messages"] = self.get_orga_messages_for_event(self.event)
+        return context
+
+    def form_valid(self, form):
+        self.get_orga_messages_for_event(self.event).delete()
+        messages.add_message(self.request, messages.SUCCESS, _("AK Orga Messages successfully deleted"))
+        return super().form_valid(form)
+
+
+class AKResetInterestView(IntermediateAdminActionView):
+    title = _("Reset interest in AKs")
+    model = AK
+    confirmation_message = _("Interest of the following AKs will be set to not filled (-1):")
+    success_message = _("Reset of interest in AKs successful.")
+
+    def action(self, form):
+        self.entities.update(interest=-1)
+
+
+class AKResetInterestCounterView(IntermediateAdminActionView):
+    title = _("Reset AKs' interest counters")
+    model = AK
+    confirmation_message = _("Interest counter of the following AKs will be set to 0:")
+    success_message = _("AKs' interest counters set back to 0.")
+
+    def action(self, form):
+        self.entities.update(interest_counter=0)
diff --git a/AKModel/views/api.py b/AKModel/views/api.py
new file mode 100644
index 00000000..abf4c261
--- /dev/null
+++ b/AKModel/views/api.py
@@ -0,0 +1,57 @@
+from rest_framework import mixins, viewsets, permissions
+
+from AKModel.metaviews.admin import EventSlugMixin
+from AKModel.models import AKOwner, AKCategory, AKTrack, AK, Room, AKSlot
+from AKModel.serializers import AKOwnerSerializer, AKCategorySerializer, AKTrackSerializer, AKSerializer, \
+    RoomSerializer, AKSlotSerializer
+
+
+class AKOwnerViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
+    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
+    serializer_class = AKOwnerSerializer
+
+    def get_queryset(self):
+        return AKOwner.objects.filter(event=self.event)
+
+
+class AKCategoryViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
+    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
+    serializer_class = AKCategorySerializer
+
+    def get_queryset(self):
+        return AKCategory.objects.filter(event=self.event)
+
+
+class AKTrackViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin,
+                     mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
+    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
+    serializer_class = AKTrackSerializer
+
+    def get_queryset(self):
+        return AKTrack.objects.filter(event=self.event)
+
+
+class AKViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin,
+                viewsets.GenericViewSet):
+    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
+    serializer_class = AKSerializer
+
+    def get_queryset(self):
+        return AK.objects.filter(event=self.event)
+
+
+class RoomViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
+    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
+    serializer_class = RoomSerializer
+
+    def get_queryset(self):
+        return Room.objects.filter(event=self.event)
+
+
+class AKSlotViewSet(EventSlugMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin,
+                    mixins.ListModelMixin, viewsets.GenericViewSet):
+    permission_classes = (permissions.DjangoModelPermissionsOrAnonReadOnly,)
+    serializer_class = AKSlotSerializer
+
+    def get_queryset(self):
+        return AKSlot.objects.filter(event=self.event)
diff --git a/AKModel/views/event_wizard.py b/AKModel/views/event_wizard.py
new file mode 100644
index 00000000..2aca3660
--- /dev/null
+++ b/AKModel/views/event_wizard.py
@@ -0,0 +1,90 @@
+from django.apps import apps
+from django.contrib import messages
+from django.shortcuts import redirect
+from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
+from django.views.generic import CreateView, FormView, UpdateView, DetailView
+
+from AKModel.forms import NewEventWizardStartForm, NewEventWizardSettingsForm, NewEventWizardPrepareImportForm, \
+    NewEventWizardImportForm, NewEventWizardActivateForm
+from AKModel.metaviews.admin import AdminViewMixin, WizardViewMixin, EventSlugMixin
+from AKModel.models import Event
+
+
+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):
+        import_types = ["import_categories", "import_requirements"]
+        if apps.is_installed("AKDashboard"):
+            import_types.append("import_buttons")
+
+        for import_type in import_types:
+            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/AKModel/views/manage.py b/AKModel/views/manage.py
new file mode 100644
index 00000000..e4c72503
--- /dev/null
+++ b/AKModel/views/manage.py
@@ -0,0 +1,197 @@
+import datetime
+import json
+import os
+import tempfile
+from itertools import zip_longest
+
+from django.contrib import messages
+from django.db.models.functions import Now
+from django.utils.dateparse import parse_datetime
+from django.utils.translation import gettext_lazy as _
+from django.views.generic import TemplateView
+from django_tex.core import render_template_with_context, run_tex_in_directory
+from django_tex.response import PDFResponse
+
+from AKModel.forms import SlideExportForm, DefaultSlotEditorForm
+from AKModel.metaviews.admin import EventSlugMixin, IntermediateAdminView, IntermediateAdminActionView
+from AKModel.models import ConstraintViolation, Event, DefaultSlot
+
+
+class UserView(TemplateView):
+    template_name = "AKModel/user.html"
+
+
+class ExportSlidesView(EventSlugMixin, IntermediateAdminView):
+    title = _('Export AK Slides')
+    form_class = SlideExportForm
+
+    def form_valid(self, form):
+        template_name = 'admin/AKModel/export/slides.tex'
+
+        NEXT_AK_LIST_LENGTH = form.cleaned_data['num_next']
+        RESULT_PRESENTATION_MODE = form.cleaned_data["presentation_mode"]
+        SPACE_FOR_NOTES_IN_WISHES = form.cleaned_data["wish_notes"]
+
+        translations = {
+            'symbols': _("Symbols"),
+            'who': _("Who?"),
+            'duration': _("Duration(s)"),
+            'reso': _("Reso intention?"),
+            'category': _("Category (for Wishes)"),
+            'wishes': _("Wishes"),
+        }
+
+        def build_ak_list_with_next_aks(ak_list):
+            next_aks_list = zip_longest(*[ak_list[i + 1:] for i in range(NEXT_AK_LIST_LENGTH)], fillvalue=None)
+            return [(ak, next_aks) for ak, next_aks in zip_longest(ak_list, next_aks_list, fillvalue=list())]
+
+        categories_with_aks, ak_wishes = self.event.get_categories_with_aks(wishes_seperately=True, filter=lambda
+            ak: not RESULT_PRESENTATION_MODE or (ak.present or (ak.present is None and ak.category.present_by_default)))
+
+        context = {
+            'title': self.event.name,
+            'categories_with_aks': [(category, build_ak_list_with_next_aks(ak_list)) for category, ak_list in
+                                    categories_with_aks],
+            'subtitle': _("AKs"),
+            "wishes": build_ak_list_with_next_aks(ak_wishes),
+            "translations": translations,
+            "result_presentation_mode": RESULT_PRESENTATION_MODE,
+            "space_for_notes_in_wishes": SPACE_FOR_NOTES_IN_WISHES,
+        }
+
+        source = render_template_with_context(template_name, context)
+
+        # Perform real compilation (run latex twice for correct page numbers)
+        with tempfile.TemporaryDirectory() as tempdir:
+            run_tex_in_directory(source, tempdir, template_name=self.template_name)
+            os.remove(f'{tempdir}/texput.tex')
+            pdf = run_tex_in_directory(source, tempdir, template_name=self.template_name)
+
+        timestamp = datetime.datetime.now(tz=self.event.timezone).strftime("%Y-%m-%d_%H_%M")
+        return PDFResponse(pdf, filename=f'{self.event.slug}_ak_slides_{timestamp}.pdf')
+
+
+class CVMarkResolvedView(IntermediateAdminActionView):
+    title = _('Mark Constraint Violations as manually resolved')
+    model = ConstraintViolation
+    confirmation_message = _("The following Constraint Violations will be marked as manually resolved")
+    success_message = _("Constraint Violations marked as resolved")
+
+    def action(self, form):
+        self.entities.update(manually_resolved=True)
+
+
+class CVSetLevelViolationView(IntermediateAdminActionView):
+    title = _('Set Constraint Violations to level "violation"')
+    model = ConstraintViolation
+    confirmation_message = _("The following Constraint Violations will be set to level 'violation'")
+    success_message = _("Constraint Violations set to level 'violation'")
+
+    def action(self, form):
+        self.entities.update(level=ConstraintViolation.ViolationLevel.VIOLATION)
+
+
+class CVSetLevelWarningView(IntermediateAdminActionView):
+    title = _('Set Constraint Violations to level "warning"')
+    model = ConstraintViolation
+    confirmation_message = _("The following Constraint Violations will be set to level 'warning'")
+    success_message = _("Constraint Violations set to level 'warning'")
+
+    def action(self, form):
+        self.entities.update(level=ConstraintViolation.ViolationLevel.WARNING)
+
+
+class PlanPublishView(IntermediateAdminActionView):
+    title = _('Publish plan')
+    model = Event
+    confirmation_message = _('Publish the plan(s) of:')
+    success_message = _('Plan published')
+
+    def action(self, form):
+        self.entities.update(plan_published_at=Now(), plan_hidden=False)
+
+
+class PlanUnpublishView(IntermediateAdminActionView):
+    title = _('Unpublish plan')
+    model = Event
+    confirmation_message = _('Unpublish the plan(s) of:')
+    success_message = _('Plan unpublished')
+
+    def action(self, form):
+        self.entities.update(plan_published_at=None, plan_hidden=True)
+
+
+class DefaultSlotEditorView(EventSlugMixin, IntermediateAdminView):
+    template_name = "admin/AKModel/default_slot_editor.html"
+    form_class = DefaultSlotEditorForm
+    title = _("Edit Default Slots")
+
+    def get_success_url(self):
+        return self.request.path
+
+    def get_initial(self):
+        initial = super().get_initial()
+        default_slots = [
+            {"id": s.id, "start": s.start_iso, "end": s.end_iso, "allDay": False}
+            for s in self.event.defaultslot_set.all()
+        ]
+        initial['availabilities'] = json.dumps({
+            'availabilities': default_slots
+        })
+        return initial
+
+    def form_valid(self, form):
+        default_slots_raw = json.loads(form.cleaned_data['availabilities'])["availabilities"]
+        tz = self.event.timezone
+
+        created_count = 0
+        updated_count = 0
+
+        previous_slot_ids = set(s.id for s in self.event.defaultslot_set.all())
+
+        for slot in default_slots_raw:
+            start = parse_datetime(slot["start"]).astimezone(tz)
+            end = parse_datetime(slot["end"]).astimezone(tz)
+
+            if slot["id"] != '':
+                id = int(slot["id"])
+                if id not in previous_slot_ids:
+                    # Make sure only slots (currently) belonging to this event are edited
+                    # (user did not manipulate IDs and slots have not been deleted in another session in the meantime)
+                    messages.add_message(
+                        self.request,
+                        messages.WARNING,
+                        _("Could not update slot {id} since it does not belong to {event}")
+                        .format(id=slot['id'], event=self.event.name)
+                    )
+                else:
+                    # Update existing entries
+                    previous_slot_ids.remove(id)
+                    original_slot = DefaultSlot.objects.get(id=id)
+                    if original_slot.start != start or original_slot.end != end:
+                        original_slot.start = start
+                        original_slot.end = end
+                        original_slot.save()
+                        updated_count += 1
+            else:
+                # Create new entries
+                DefaultSlot.objects.create(
+                    start=start,
+                    end=end,
+                    event=self.event
+                )
+                created_count += 1
+
+        # Delete all slots not re-submitted by the user (and hence deleted in editor)
+        deleted_count = len(previous_slot_ids)
+        for d_id in previous_slot_ids:
+            DefaultSlot.objects.get(id=d_id).delete()
+
+        if created_count + updated_count + deleted_count > 0:
+            messages.add_message(
+                self.request,
+                messages.SUCCESS,
+                _("Updated {u} slot(s). created {c} new slot(s) and deleted {d} slot(s)")
+                .format(u=str(updated_count), c=str(created_count), d=str(deleted_count))
+            )
+        return super().form_valid(form)
diff --git a/AKModel/views/room.py b/AKModel/views/room.py
new file mode 100644
index 00000000..94c16b89
--- /dev/null
+++ b/AKModel/views/room.py
@@ -0,0 +1,75 @@
+import csv
+
+import django.db
+from django.apps import apps
+from django.contrib import messages
+from django.http import HttpResponseRedirect
+from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
+from django.views.generic import CreateView
+
+from AKModel.forms import RoomForm, RoomBatchCreationForm
+from AKModel.metaviews.admin import AdminViewMixin, EventSlugMixin, IntermediateAdminView
+from AKModel.models import Room
+
+
+class RoomCreationView(AdminViewMixin, CreateView):
+    form_class = RoomForm
+    template_name = 'admin/AKModel/room_create.html'
+
+    def get_success_url(self):
+        print(self.request.POST['save_action'])
+        if self.request.POST['save_action'] == 'save_add_another':
+            return reverse_lazy('admin:room-new')
+        elif self.request.POST['save_action'] == 'save_continue':
+            return reverse_lazy('admin:AKModel_room_change', kwargs={'object_id': self.room.pk})
+        else:
+            return reverse_lazy('admin:AKModel_room_changelist')
+
+    def form_valid(self, form):
+        self.room = form.save()
+        messages.success(self.request, _("Created Room '%(room)s'" % {'room': self.room}))
+        return HttpResponseRedirect(self.get_success_url())
+
+
+class RoomBatchCreationView(EventSlugMixin, IntermediateAdminView):
+    form_class = RoomBatchCreationForm
+    title = _("Import Rooms from CSV")
+
+    def get_success_url(self):
+        return reverse_lazy('admin:event_status', kwargs={'slug': self.event.slug})
+
+    def form_valid(self, form):
+        virtual_rooms_support = False
+        created_count = 0
+
+        rooms_raw_dict: csv.DictReader = form.cleaned_data["rooms"]
+
+        if apps.is_installed("AKOnline") and "url" in rooms_raw_dict.fieldnames:
+            virtual_rooms_support = True
+            from AKOnline.models import VirtualRoom
+
+        for raw_room in rooms_raw_dict:
+            name = raw_room["name"]
+            location = raw_room["location"] if "location" in rooms_raw_dict.fieldnames else ""
+            capacity = raw_room["capacity"] if "capacity" in rooms_raw_dict.fieldnames else -1
+
+            try:
+                r = Room.objects.create(name=name,
+                                    location=location,
+                                    capacity=capacity,
+                                    event=self.event)
+                if virtual_rooms_support and raw_room["url"] != "":
+                    VirtualRoom.objects.create(room=r,
+                                               url=raw_room["url"])
+                created_count += 1
+            except django.db.Error as e:
+                messages.add_message(self.request, messages.WARNING,
+                                     _("Could not import room {name}: {e}").format(name=name, e=str(e)))
+
+        if created_count > 0:
+            messages.add_message(self.request, messages.SUCCESS,
+                                 _("Imported {count} room(s)").format(count=created_count))
+        else:
+            messages.add_message(self.request, messages.WARNING, _("No rooms imported"))
+        return super().form_valid(form)
diff --git a/AKModel/views/status.py b/AKModel/views/status.py
new file mode 100644
index 00000000..460c13af
--- /dev/null
+++ b/AKModel/views/status.py
@@ -0,0 +1,163 @@
+from django.apps import apps
+from django.urls import reverse_lazy
+from django.utils.html import format_html
+from django.utils.translation import gettext_lazy as _
+
+from AKModel.metaviews import status_manager
+from AKModel.metaviews.admin import EventSlugMixin, AdminViewMixin
+from AKModel.metaviews.status import TemplateStatusWidget, StatusView
+
+
+@status_manager.register(name="event_overview")
+class EventOverviewWidget(TemplateStatusWidget):
+    required_context_type = "event"
+    title = _("Overview")
+    template_name = "admin/AKModel/status/event_overview.html"
+
+    def render_status(self, context: {}) -> str:
+        return "success" if not context["event"].plan_hidden else "primary"
+
+
+@status_manager.register(name="event_categories")
+class EventCategoriesWidget(TemplateStatusWidget):
+    required_context_type = "event"
+    title = _("Categories")
+    template_name = "admin/AKModel/status/event_categories.html"
+    actions = [
+        {
+            "text": _("Add category"),
+            "url": reverse_lazy("admin:AKModel_akcategory_add"),
+         }
+    ]
+
+    def render_title(self, context: {}) -> str:
+        self.category_count = context['event'].akcategory_set.count()
+        return f"{super().render_title(context)} ({self.category_count})"
+
+    def render_status(self, context: {}) -> str:
+        return "danger" if self.category_count == 0 else "primary"
+
+
+@status_manager.register(name="event_rooms")
+class EventRoomsWidget(TemplateStatusWidget):
+    required_context_type = "event"
+    title = _("Rooms")
+    template_name = "admin/AKModel/status/event_rooms.html"
+    actions = [
+        {
+            "text": _("Add Room"),
+            "url": reverse_lazy("admin:AKModel_room_add"),
+         }
+    ]
+
+    def render_title(self, context: {}) -> str:
+        self.room_count = context['event'].room_set.count()
+        return f"{super().render_title(context)} ({self.room_count})"
+
+    def render_status(self, context: {}) -> str:
+        return "danger" if self.room_count == 0 else "primary"
+
+    def render_actions(self, context: {}) -> list[dict]:
+        actions = super().render_actions(context)
+        actions.append(
+            {
+                "text": _("Import Rooms from CSV"),
+                "url": reverse_lazy("admin:room-import", kwargs={"event_slug": context["event"].slug}),
+            }
+        )
+        return actions
+
+
+@status_manager.register(name="event_aks")
+class EventAKsWidget(TemplateStatusWidget):
+    required_context_type = "event"
+    title = _("AKs")
+    template_name = "admin/AKModel/status/event_aks.html"
+
+    def get_context_data(self, context) -> dict:
+        context["ak_count"] = context["event"].ak_set.count()
+        context["unscheduled_slots_count"] = context["event"].akslot_set.filter(start=None).count
+        return context
+
+    def render_actions(self, context: {}) -> list[dict]:
+        actions = [
+            {
+                "text": _("Scheduling"),
+                "url": reverse_lazy("admin:schedule", kwargs={"event_slug": context["event"].slug}),
+            },
+        ]
+        if apps.is_installed("AKScheduling"):
+            actions.extend([
+                {
+                    "text": format_html('{} <span class="badge bg-secondary">{}</span>',
+                                        _("Constraint Violations"),
+                                        context["event"].constraintviolation_set.count()),
+                    "url": reverse_lazy("admin:constraint-violations", kwargs={"slug": context["event"].slug}),
+                },
+                {
+                    "text": _("AKs requiring special attention"),
+                    "url": reverse_lazy("admin:special-attention", kwargs={"slug": context["event"].slug}),
+                },
+                {
+                    "text": _("Enter Interest"),
+                    "url": reverse_lazy("admin:enter-interest",
+                            kwargs={"event_slug": context["event"].slug, "pk": context["event"].ak_set.all().first().pk}),
+                },
+            ])
+        actions.extend([
+                {
+                    "text": _("Edit Default Slots"),
+                    "url": reverse_lazy("admin:default-slots-editor", kwargs={"event_slug": context["event"].slug}),
+                },
+                {
+                    "text": _("Manage ak tracks"),
+                    "url": reverse_lazy("admin:tracks_manage", kwargs={"event_slug": context["event"].slug}),
+                },
+                {
+                    "text": _("Export AKs as CSV"),
+                    "url": reverse_lazy("admin:ak_csv_export", kwargs={"event_slug": context["event"].slug}),
+                },
+                {
+                    "text": _("Export AKs for Wiki"),
+                    "url": reverse_lazy("admin:ak_wiki_export", kwargs={"slug": context["event"].slug}),
+                },
+                {
+                    "text": _("Export AK Slides"),
+                    "url": reverse_lazy("admin:ak_slide_export", kwargs={"event_slug": context["event"].slug}),
+                },
+            ]
+        )
+        return actions
+
+
+@status_manager.register(name="event_requirements")
+class EventRequirementsWidget(TemplateStatusWidget):
+    required_context_type = "event"
+    title = _("Requirements")
+    template_name = "admin/AKModel/status/event_requirements.html"
+
+    def render_title(self, context: {}) -> str:
+        self.requirements_count = context['event'].akrequirement_set.count()
+        return f"{super().render_title(context)} ({self.requirements_count})"
+
+    def render_actions(self, context: {}) -> list[dict]:
+        return [
+            {
+                "text": _("Show AKs for requirements"),
+                "url": reverse_lazy("admin:event_requirement_overview", kwargs={"event_slug": context["event"].slug}),
+            },
+            {
+                "text": _("Add Requirement"),
+                "url": reverse_lazy("admin:AKModel_akrequirement_add"),
+            },
+        ]
+
+
+class EventStatusView(EventSlugMixin, StatusView):
+    title = _("Event Status")
+    provided_context_type = "event"
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["site_url"] = reverse_lazy("dashboard:dashboard_event", kwargs={'slug': context["event"].slug})
+        return context
diff --git a/AKOnline/locale/de_DE/LC_MESSAGES/django.po b/AKOnline/locale/de_DE/LC_MESSAGES/django.po
index 94047231..cf4c442e 100644
--- a/AKOnline/locale/de_DE/LC_MESSAGES/django.po
+++ b/AKOnline/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-03-24 18:01+0100\n"
+"POT-Creation-Date: 2023-03-26 19:51+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -34,7 +34,7 @@ msgstr "Raum"
 msgid "Virtual Room"
 msgstr "Virtueller Raum"
 
-#: AKOnline/models.py:17
+#: AKOnline/models.py:17 AKOnline/views.py:27
 msgid "Virtual Rooms"
 msgstr "Virtuelle Räume"
 
@@ -42,12 +42,12 @@ msgstr "Virtuelle Räume"
 msgid "Leave empty if that room is not virtual/hybrid."
 msgstr "Leer lassen wenn der Raum nicht virtuell/hybrid ist"
 
-#: AKOnline/views.py:16
+#: AKOnline/views.py:18
 #, python-format
 msgid "Created Room '%(room)s'"
 msgstr "Raum '%(room)s' angelegt"
 
-#: AKOnline/views.py:18
+#: AKOnline/views.py:20
 #, python-format
 msgid "Created related Virtual Room '%(vroom)s'"
 msgstr "Verbundenen virtuellen Raum '%(vroom)s' angelegt"
diff --git a/AKOnline/templates/admin/AKOnline/status/event_virtual_rooms.html b/AKOnline/templates/admin/AKOnline/status/event_virtual_rooms.html
new file mode 100644
index 00000000..a68526c3
--- /dev/null
+++ b/AKOnline/templates/admin/AKOnline/status/event_virtual_rooms.html
@@ -0,0 +1,11 @@
+{% load i18n %}
+
+<ul>
+    {% for room in event.room_set.all %}
+        {% if room.virtual and room.virtual.url %}
+        <li>
+            <a href="{% url 'admin:AKOnline_virtualroom_change' room.pk %}">{{ room }} ({{ room.virtual.url | truncatechars:30 }})</a>
+        </li>
+        {% endif %}
+    {% endfor %}
+</ul>
diff --git a/AKOnline/views.py b/AKOnline/views.py
index 44855eb4..13f089a8 100644
--- a/AKOnline/views.py
+++ b/AKOnline/views.py
@@ -2,7 +2,9 @@ from django.contrib import messages
 from django.http import HttpResponseRedirect
 from django.utils.translation import gettext_lazy as _
 
-from AKModel.views import AdminViewMixin, RoomCreationView
+from AKModel.metaviews import status_manager
+from AKModel.metaviews.status import TemplateStatusWidget
+from AKModel.views.room import RoomCreationView
 from AKOnline.forms import RoomWithVirtualForm
 
 
@@ -17,3 +19,10 @@ class RoomCreationWithVirtualView(RoomCreationView):
         if objects['virtual'] is not None:
             messages.success(self.request, _("Created related Virtual Room '%(vroom)s'" % {'vroom': objects['virtual']}))
         return HttpResponseRedirect(self.get_success_url())
+
+
+@status_manager.register(name="event_virtual_rooms")
+class EventVirtualRoomsWidget(TemplateStatusWidget):
+    required_context_type = "event"
+    title = _("Virtual Rooms")
+    template_name = "admin/AKOnline/status/event_virtual_rooms.html"
diff --git a/AKPlan/views.py b/AKPlan/views.py
index 828e5e58..513bca31 100644
--- a/AKPlan/views.py
+++ b/AKPlan/views.py
@@ -7,7 +7,7 @@ from django.utils.datetime_safe import datetime
 from django.views.generic import ListView, DetailView
 
 from AKModel.models import AKSlot, Room, AKTrack
-from AKModel.views import FilterByEventSlugMixin
+from AKModel.metaviews.admin import FilterByEventSlugMixin
 
 
 class PlanIndexView(FilterByEventSlugMixin, ListView):
diff --git a/AKScheduling/api.py b/AKScheduling/api.py
index 98838e0f..7155e6fe 100644
--- a/AKScheduling/api.py
+++ b/AKScheduling/api.py
@@ -8,7 +8,7 @@ from rest_framework import viewsets, mixins, serializers, permissions
 
 from AKModel.availability.models import Availability
 from AKModel.models import Room, AKSlot, ConstraintViolation, DefaultSlot
-from AKModel.views import EventSlugMixin
+from AKModel.metaviews.admin import EventSlugMixin
 
 
 class ResourceSerializer(serializers.ModelSerializer):
diff --git a/AKScheduling/views.py b/AKScheduling/views.py
index 9d0302cf..7174287f 100644
--- a/AKScheduling/views.py
+++ b/AKScheduling/views.py
@@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
 from django.views.generic import ListView, DetailView, UpdateView
 
 from AKModel.models import AKSlot, AKTrack, Event, AK, AKCategory
-from AKModel.views import AdminViewMixin, FilterByEventSlugMixin, EventSlugMixin, IntermediateAdminView
+from AKModel.metaviews.admin import EventSlugMixin, FilterByEventSlugMixin, AdminViewMixin, IntermediateAdminView
 from AKScheduling.forms import AKInterestForm
 from AKSubmission.forms import AKAddSlotForm
 
diff --git a/AKSubmission/locale/de_DE/LC_MESSAGES/django.po b/AKSubmission/locale/de_DE/LC_MESSAGES/django.po
index c0d16bb1..871d5d9c 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: 2023-01-01 20:05+0100\n"
+"POT-Creation-Date: 2023-03-26 19:51+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -22,11 +22,11 @@ msgstr ""
 msgid "\"%(duration)s\" is not a valid duration"
 msgstr "\"%(duration)s\" ist keine gültige Dauer"
 
-#: AKSubmission/forms.py:122
+#: AKSubmission/forms.py:117
 msgid "Duration(s)"
 msgstr "Dauer(n)"
 
-#: AKSubmission/forms.py:124
+#: AKSubmission/forms.py:119
 msgid ""
 "Enter at least one planned duration (in hours). If your AK should have "
 "multiple slots, use multiple lines"
@@ -34,28 +34,28 @@ msgstr ""
 "Mindestens eine geplante Dauer (in Stunden) angeben. Wenn der AK mehrere "
 "Slots haben soll, mehrere Zeilen verwenden"
 
-#: AKSubmission/forms.py:179
+#: AKSubmission/forms.py:170
 #: AKSubmission/templates/AKSubmission/ak_detail.html:309
 msgid "Start"
 msgstr "Start"
 
-#: AKSubmission/forms.py:180
+#: AKSubmission/forms.py:171
 #: AKSubmission/templates/AKSubmission/ak_detail.html:310
 msgid "End"
 msgstr "Ende"
 
-#: AKSubmission/forms.py:181
+#: AKSubmission/forms.py:172
 #: AKSubmission/templates/AKSubmission/ak_detail.html:239
 #: AKSubmission/templates/AKSubmission/akslot_delete.html:35
 msgid "Duration"
 msgstr "Dauer"
 
-#: AKSubmission/forms.py:182
+#: AKSubmission/forms.py:173
 #: AKSubmission/templates/AKSubmission/ak_detail.html:241
 msgid "Room"
 msgstr "Raum"
 
-#: AKSubmission/forms.py:186
+#: AKSubmission/forms.py:177
 #: AKSubmission/templates/AKSubmission/ak_history.html:11
 #: AKSubmission/templates/AKSubmission/akslot_delete.html:31
 msgid "AK"
@@ -73,8 +73,8 @@ msgstr "AK"
 #: AKSubmission/templates/AKSubmission/submission_not_configured.html:11
 #: AKSubmission/templates/AKSubmission/submission_overview.html:7
 #: AKSubmission/templates/AKSubmission/submission_overview.html:11
-#: AKSubmission/templates/AKSubmission/submission_overview.html:41
-#: AKSubmission/templates/AKSubmission/submit_new.html:34
+#: AKSubmission/templates/AKSubmission/submission_overview.html:36
+#: AKSubmission/templates/AKSubmission/submit_new.html:31
 #: AKSubmission/templates/AKSubmission/submit_new_wish.html:13
 msgid "AK Submission"
 msgstr "AK-Eintragung"
@@ -242,7 +242,7 @@ msgstr "Mögliche Zeiten"
 #: AKSubmission/templates/AKSubmission/akslot_delete.html:7
 #: AKSubmission/templates/AKSubmission/submission_not_configured.html:7
 #: AKSubmission/templates/AKSubmission/submission_overview.html:7
-#: AKSubmission/templates/AKSubmission/submission_overview.html:45
+#: AKSubmission/templates/AKSubmission/submission_overview.html:40
 #: AKSubmission/templates/AKSubmission/submit_new.html:9
 #: AKSubmission/templates/AKSubmission/submit_new_wish.html:7
 msgid "AKs"
@@ -283,7 +283,7 @@ msgstr "Die Ergebnisse dieses AKs vorstellen"
 msgid "Intends to submit a resolution"
 msgstr "Beabsichtigt eine Resolution einzureichen"
 
-#: AKSubmission/templates/AKSubmission/ak_list.html:6 AKSubmission/views.py:40
+#: AKSubmission/templates/AKSubmission/ak_list.html:6 AKSubmission/views.py:42
 msgid "All AKs"
 msgstr "Alle AKs"
 
@@ -307,22 +307,22 @@ msgstr "Details"
 msgid "There are no AKs in this category yet"
 msgstr "Es gibt noch keine AKs in dieser Kategorie"
 
-#: AKSubmission/templates/AKSubmission/akmessage_add.html:28
+#: AKSubmission/templates/AKSubmission/akmessage_add.html:27
 msgid "Send"
 msgstr "Senden"
 
-#: AKSubmission/templates/AKSubmission/akmessage_add.html:32
-#: AKSubmission/templates/AKSubmission/akowner_create_update.html:27
-#: AKSubmission/templates/AKSubmission/akslot_add_update.html:30
-#: AKSubmission/templates/AKSubmission/submit_new.html:56
+#: AKSubmission/templates/AKSubmission/akmessage_add.html:31
+#: AKSubmission/templates/AKSubmission/akowner_create_update.html:26
+#: AKSubmission/templates/AKSubmission/akslot_add_update.html:29
+#: AKSubmission/templates/AKSubmission/submit_new.html:52
 msgid "Reset Form"
 msgstr "Formular leeren"
 
-#: AKSubmission/templates/AKSubmission/akmessage_add.html:36
-#: AKSubmission/templates/AKSubmission/akowner_create_update.html:31
-#: AKSubmission/templates/AKSubmission/akslot_add_update.html:34
-#: AKSubmission/templates/AKSubmission/akslot_delete.html:46
-#: AKSubmission/templates/AKSubmission/submit_new.html:60
+#: AKSubmission/templates/AKSubmission/akmessage_add.html:35
+#: AKSubmission/templates/AKSubmission/akowner_create_update.html:30
+#: AKSubmission/templates/AKSubmission/akslot_add_update.html:33
+#: AKSubmission/templates/AKSubmission/akslot_delete.html:45
+#: AKSubmission/templates/AKSubmission/submit_new.html:56
 msgid "Cancel"
 msgstr "Abbrechen"
 
@@ -332,8 +332,8 @@ msgstr "Abbrechen"
 msgid "AK Owner"
 msgstr "AK-Leitung"
 
-#: AKSubmission/templates/AKSubmission/akowner_create_update.html:24
-#: AKSubmission/templates/AKSubmission/akslot_add_update.html:26
+#: AKSubmission/templates/AKSubmission/akowner_create_update.html:23
+#: AKSubmission/templates/AKSubmission/akslot_add_update.html:25
 msgid "Continue"
 msgstr "Weiter"
 
@@ -350,7 +350,7 @@ msgstr "AK-Dauer(n)"
 msgid "Do you really want to delete this AK Slot?"
 msgstr "Willst du diesen AK-Slot wirklich löschen?"
 
-#: AKSubmission/templates/AKSubmission/akslot_delete.html:42
+#: AKSubmission/templates/AKSubmission/akslot_delete.html:41
 msgid "Confirm"
 msgstr "Bestätigen"
 
@@ -366,109 +366,117 @@ msgstr ""
 "Das System ist bisher nicht für Eintragen und Anzeige von AKs konfiguriert. "
 "Bitte versuche es später wieder."
 
-#: AKSubmission/templates/AKSubmission/submission_overview.html:49
+#: AKSubmission/templates/AKSubmission/submission_overview.html:44
 msgid ""
 "On this page you can see a list of current AKs, change them and add new ones."
 msgstr ""
 "Auf dieser Seite kannst du eine Liste von aktuellen AKs sehen, diese "
 "bearbeiten und neue hinzufügen."
 
-#: AKSubmission/templates/AKSubmission/submission_overview.html:56
+#: AKSubmission/templates/AKSubmission/submission_overview.html:52
 #: AKSubmission/templates/AKSubmission/submit_new_wish.html:7
 #: AKSubmission/templates/AKSubmission/submit_new_wish.html:14
 #: AKSubmission/templates/AKSubmission/submit_new_wish.html:18
 msgid "New AK Wish"
 msgstr "Neuer AK-Wunsch"
 
-#: AKSubmission/templates/AKSubmission/submission_overview.html:60
+#: AKSubmission/templates/AKSubmission/submission_overview.html:56
 msgid "Who"
 msgstr "Wer"
 
-#: AKSubmission/templates/AKSubmission/submission_overview.html:63
+#: AKSubmission/templates/AKSubmission/submission_overview.html:59
 msgid "I do not own AKs yet"
 msgstr "Ich leite bisher keine AKs"
 
-#: AKSubmission/templates/AKSubmission/submission_overview.html:71
+#: AKSubmission/templates/AKSubmission/submission_overview.html:67
 #: AKSubmission/templates/AKSubmission/submit_new.html:9
-#: AKSubmission/templates/AKSubmission/submit_new.html:37
-#: AKSubmission/templates/AKSubmission/submit_new.html:44
+#: AKSubmission/templates/AKSubmission/submit_new.html:34
+#: AKSubmission/templates/AKSubmission/submit_new.html:41
 msgid "New AK"
 msgstr "Neuer AK"
 
-#: AKSubmission/templates/AKSubmission/submission_overview.html:77
+#: AKSubmission/templates/AKSubmission/submission_overview.html:73
 msgid "Edit Person Info"
 msgstr "Personen-Info bearbeiten"
 
-#: AKSubmission/templates/AKSubmission/submission_overview.html:84
+#: AKSubmission/templates/AKSubmission/submission_overview.html:81
 msgid "This event is not active. You cannot add or change AKs"
 msgstr ""
 "Dieses Event is nicht aktiv. Es können keine AKs hinzugefügt oder bearbeitet "
 "werden"
 
-#: AKSubmission/templates/AKSubmission/submit_new.html:52
+#: AKSubmission/templates/AKSubmission/submit_new.html:48
 msgid "Submit"
 msgstr "Eintragen"
 
-#: AKSubmission/views.py:71
+#: AKSubmission/views.py:73
 msgid "Wishes"
 msgstr "Wünsche"
 
-#: AKSubmission/views.py:71
+#: AKSubmission/views.py:73
 msgid "AKs one would like to have"
 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:91
+#: AKSubmission/views.py:93
 msgid "Currently planned AKs"
 msgstr "Aktuell geplante AKs"
 
-#: AKSubmission/views.py:181
+#: AKSubmission/views.py:186
 msgid "Event inactive. Cannot create or update."
 msgstr "Event inaktiv. Hinzufügen/Bearbeiten nicht möglich."
 
-#: AKSubmission/views.py:197
+#: AKSubmission/views.py:202
 msgid "AK successfully created"
 msgstr "AK erfolgreich angelegt"
 
-#: AKSubmission/views.py:247
+#: AKSubmission/views.py:252
 msgid "AK successfully updated"
 msgstr "AK erfolgreich aktualisiert"
 
-#: AKSubmission/views.py:285
+#: AKSubmission/views.py:290
 #, 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:326
+#: AKSubmission/views.py:331
 msgid "Person Info successfully updated"
 msgstr "Personen-Info erfolgreich aktualisiert"
 
-#: AKSubmission/views.py:346
+#: AKSubmission/views.py:351
 msgid "No user selected"
 msgstr "Keine Person ausgewählt"
 
-#: AKSubmission/views.py:373
+#: AKSubmission/views.py:378
 msgid "AK Slot successfully added"
 msgstr "AK-Slot erfolgreich angelegt"
 
-#: AKSubmission/views.py:387
+#: AKSubmission/views.py:391
 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:397
+#: AKSubmission/views.py:401
 msgid "AK Slot successfully updated"
 msgstr "AK-Slot erfolgreich aktualisiert"
 
-#: AKSubmission/views.py:410
+#: AKSubmission/views.py:413
 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:420
+#: AKSubmission/views.py:423
 msgid "AK Slot successfully deleted"
 msgstr "AK-Slot erfolgreich angelegt"
 
-#: AKSubmission/views.py:442
+#: AKSubmission/views.py:430
+msgid "Messages"
+msgstr "Nachrichten"
+
+#: AKSubmission/views.py:440
+msgid "Delete all messages"
+msgstr "Alle Nachrichten löschen"
+
+#: AKSubmission/views.py:463
 msgid "Message to organizers successfully saved"
 msgstr "Nachricht an die Organisator*innen erfolgreich gespeichert"
 
diff --git a/AKSubmission/views.py b/AKSubmission/views.py
index 1b865843..d62762e1 100644
--- a/AKSubmission/views.py
+++ b/AKSubmission/views.py
@@ -13,9 +13,10 @@ from django.views import View
 from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
 
 from AKModel.availability.models import Availability
+from AKModel.metaviews import status_manager
+from AKModel.metaviews.status import TemplateStatusWidget
 from AKModel.models import AK, AKCategory, AKOwner, AKSlot, AKTrack, AKOrgaMessage
-from AKModel.views import EventSlugMixin
-from AKModel.views import FilterByEventSlugMixin
+from AKModel.metaviews.admin import EventSlugMixin, FilterByEventSlugMixin
 from AKSubmission.api import ak_interest_indication_active
 from AKSubmission.forms import AKWishForm, AKOwnerForm, AKSubmissionForm, AKDurationForm, AKOrgaMessageForm, \
     AKForm
@@ -423,6 +424,25 @@ class AKSlotDeleteView(EventSlugMixin, EventInactiveRedirectMixin, DeleteView):
         return self.object.ak.detail_url
 
 
+@status_manager.register(name="event_ak_messages")
+class EventAKMessagesWidget(TemplateStatusWidget):
+    required_context_type = "event"
+    title = _("Messages")
+    template_name = "admin/AKModel/render_ak_messages.html"
+
+    def get_context_data(self, context) -> dict:
+        context["ak_messages"] = AKOrgaMessage.objects.filter(ak__event=context["event"])
+        return context
+
+    def render_actions(self, context: {}) -> list[dict]:
+        return [
+            {
+                "text": _("Delete all messages"),
+                "url": reverse_lazy("admin:ak_delete_orga_messages", kwargs={"event_slug": context["event"].slug}),
+            },
+        ]
+
+
 class AKAddOrgaMessageView(EventSlugMixin, CreateView):
     model = AKOrgaMessage
     form_class = AKOrgaMessageForm
-- 
GitLab


From bbfe8d7d23276a4907b30e6a0e7e34bcc4d25653 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20H=C3=A4ttasch?=
 <benjamin.haettasch@fachschaft.informatik.tu-darmstadt.de>
Date: Sun, 26 Mar 2023 23:51:12 +0200
Subject: [PATCH 2/2] Minor design improvements for status views

---
 AKModel/templates/admin/AKModel/status/status.html | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/AKModel/templates/admin/AKModel/status/status.html b/AKModel/templates/admin/AKModel/status/status.html
index 5918aaf3..0a883762 100644
--- a/AKModel/templates/admin/AKModel/status/status.html
+++ b/AKModel/templates/admin/AKModel/status/status.html
@@ -15,13 +15,13 @@
                     <div class="card-header">
                         {% if widget.actions %}
                             <div class="float-end">
-                                <a class="" data-bs-toggle="dropdown" aria-expanded="false">
-                                    {% fa6_icon "ellipsis-vertical" %}
+                                <a style="cursor: pointer;" data-bs-toggle="dropdown" aria-expanded="false">
+                                    &nbsp;{% fa6_icon "ellipsis-vertical" %}&nbsp;
                                 </a>
                                 <ul class="dropdown-menu dropdown-menu-end">
                                     {% for action in widget.actions %}
-                                    <li>
-                                        <a class="dropdown-item" href="{{ action.url }}">{{ action.text }}</a>
+                                    <li class="dropdown-item">
+                                        <a href="{{ action.url }}">{{ action.text }}</a>
                                     </li>
                                     {% endfor %}
                                 </ul>
-- 
GitLab