From f717a83a0488a77e911233de8fa30c6e01cd92b1 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Sun, 31 May 2020 12:32:33 +0200
Subject: [PATCH] Fix week view code

- Fix select form
- Fix names
- Fix URLs
---
 aleksis/apps/alsijil/forms.py | 27 +++++++++----
 aleksis/apps/alsijil/urls.py  |  2 +
 aleksis/apps/alsijil/views.py | 71 ++++++++++++++++++++++-------------
 3 files changed, 66 insertions(+), 34 deletions(-)

diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py
index 350bf018d..48c809cde 100644
--- a/aleksis/apps/alsijil/forms.py
+++ b/aleksis/apps/alsijil/forms.py
@@ -1,6 +1,8 @@
 from datetime import datetime
 
+from aleksis.apps.chronos.managers import TimetableType
 from django import forms
+from django.core.exceptions import ValidationError
 from django.db.models import Count
 from django.utils.translation import gettext_lazy as _
 
@@ -50,15 +52,24 @@ class SelectForm(forms.Form):
         required=False,
         widget=Select2Widget,
     )
-    room = forms.ModelChoiceField(
-        queryset=Room.objects.annotate(lessons_count=Count("lesson_periods")).filter(
-            lessons_count__gt=0
-        ),
-        label=_("Room"),
-        required=False,
-        widget=Select2Widget,
-    )
 
+    def clean(self) -> dict:
+        data = super().clean()
+
+        if data.get("group") and not data.get("teacher") :
+            type_ = TimetableType.GROUP
+            instance = data["group"]
+        elif data.get("teacher") and not data.get("group"):
+            type_ = TimetableType.TEACHER
+            instance = data["teacher"]
+        elif not data.get("teacher") and not data.get("group"):
+            return data
+        else:
+            raise ValidationError(_("You can't select a group and a teacher both."))
+
+        data["type_"] = type_
+        data["instance"] = instance
+        return data
 
 PersonalNoteFormSet = forms.modelformset_factory(
     PersonalNote, form=PersonalNoteForm, max_num=0, extra=0
diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py
index 20519ad4d..fe40f18ee 100644
--- a/aleksis/apps/alsijil/urls.py
+++ b/aleksis/apps/alsijil/urls.py
@@ -11,6 +11,8 @@ urlpatterns = [
     ),
     path("week", views.week_view, name="week_view"),
     path("week/<int:year>/<int:week>", views.week_view, name="week_view_by_week"),
+    path("week/<str:type_>/<int:id_>/", views.week_view, name="week_view"),
+    path("week/<int:year>/<int:week>/<str:type_>/<int:id_>/", views.week_view, name="week_view_by_week"),
     path("print/group/<int:id_>", views.full_register_group, name="full_register_group"),
     path("absence/new", views.register_absence, name="register_absence"),
     path("filters/list", views.list_personal_note_filters, name="list_personal_note_filters",),
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index b1e9f40bd..ee7c8d7e9 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -1,9 +1,11 @@
 from datetime import date, datetime, timedelta
 from typing import Optional
 
+from aleksis.apps.chronos.managers import TimetableType
+from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
 from django.core.exceptions import PermissionDenied
 from django.db.models import Count, Exists, OuterRef, Q, Sum
-from django.http import Http404, HttpRequest, HttpResponse
+from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse
 from django.utils.translation import ugettext as _
@@ -74,7 +76,7 @@ def lesson(
         lesson_period=lesson_period, week=wanted_week.week
     )
     lesson_documentation_form = LessonDocumentationForm(
-        request.POST or None, instance=lesson_documentation, prefix="leson_documentation",
+        request.POST or None, instance=lesson_documentation, prefix="lesson_documentation",
     )
 
     # Create a formset that holds all personal notes for all persons in this lesson
@@ -107,7 +109,7 @@ def lesson(
 
 
 def week_view(
-    request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None
+    request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None, type_: Optional[str] = None, id_: Optional[int] = None
 ) -> HttpResponse:
     context = {}
 
@@ -124,45 +126,62 @@ def week_view(
         )
     ).in_week(wanted_week)
 
-    group = None  # FIXME workaround for #38
-    if (
-        request.GET.get("group", None)
-        or request.GET.get("teacher", None)
-        or request.GET.get("room", None)
-    ):
-        lesson_periods = lesson_periods.filter_from_query(request.GET)
-        if "group" in request.GET and request.GET["group"]:
-            group = Group.objects.get(pk=request.GET["group"])
-        else:
-            group = None
+    group = None
+    if type_ and id_:
+        instance = get_el_by_pk(request, type_, id_)
+
+        if isinstance(instance, HttpResponseNotFound):
+            return HttpResponseNotFound()
+
+        type_ = TimetableType.from_string(type_)
+
+        if type_ == TimetableType.GROUP:
+            group = instance
+
+        lesson_periods = lesson_periods.filter_from_type(type_, instance)
     elif hasattr(request, "user") and hasattr(request.user, "person"):
-        group = request.user.person.owner_of.first()
-        if group:
-            lesson_periods = lesson_periods.filter_group(group)
-        elif request.user.person.lessons_as_teacher.exists():
+        instance = request.user.person
+        if request.user.person.lessons_as_teacher.exists():
             lesson_periods = lesson_periods.filter_teacher(request.user.person)
+            type_ = TimetableType.TEACHER
         else:
             lesson_periods = lesson_periods.filter_participant(request.user.person)
     else:
         lesson_periods = None
 
+    # Add a form to filter the view
+    if type_:
+        initial = {type_.value: instance}
+    else:
+        initial = {}
+    select_form = SelectForm(request.POST or None, initial=initial)
+
+    if request.method == "POST":
+        if select_form.is_valid():
+            if "type_" not in select_form.cleaned_data:
+                return redirect("week_view_by_week", wanted_week.year, wanted_week.week)
+            else:
+                return redirect("week_view_by_week", wanted_week.year, wanted_week.week,
+                                select_form.cleaned_data["type_"].value, select_form.cleaned_data["instance"].pk)
+
     if lesson_periods:
         # Aggregate all personal notes for this group and week
+        lesson_periods_pk = lesson_periods.values_list("pk", flat=True)
         persons = (
             Person.objects.filter(is_active=True)
-            .filter(member_of__lessons__lesson_periods__in=lesson_periods)
+            .filter(member_of__lessons__lesson_periods__in=lesson_periods_pk)
             .distinct()
             .prefetch_related("personal_notes")
             .annotate(
-                absences=Count(
+                absences_count=Count(
                     "personal_notes__absent",
                     filter=Q(
-                        personal_notes__lesson_period__in=lesson_periods,
+                        personal_notes__lesson_period__in=lesson_periods_pk,
                         personal_notes__week=wanted_week.week,
                         personal_notes__absent=True,
                     ),
                 ),
-                unexcused=Count(
+                unexcused_count=Count(
                     "personal_notes__absent",
                     filter=Q(
                         personal_notes__lesson_period__in=lesson_periods,
@@ -171,7 +190,7 @@ def week_view(
                         personal_notes__excused=False,
                     ),
                 ),
-                tardiness=Sum(
+                tardiness_sum=Sum(
                     "personal_notes__late",
                     filter=Q(
                         personal_notes__lesson_period__in=lesson_periods,
@@ -183,15 +202,15 @@ def week_view(
     else:
         persons = None
 
-    # Add a form to filter the view
-    select_form = SelectForm(request.GET or None)
+    # Resort lesson periods manually because an union queryset doesn't support order_by
+    lesson_periods = sorted(lesson_periods, key=lambda x: (x.period.weekday, x.period.period))
 
-    context["current_head"] = str(wanted_week)
     context["week"] = wanted_week
     context["lesson_periods"] = lesson_periods
     context["persons"] = persons
     context["group"] = group
     context["select_form"] = select_form
+    context["instance"] = instance
 
     week_prev = wanted_week - 1
     week_next = wanted_week + 1
-- 
GitLab