From ad65d9c6fcf0e858eb4cf671e1cb4084c1dc89cf Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Mon, 7 Aug 2023 13:57:08 +0200
Subject: [PATCH] Move LessonEvent queries to own queryset and drop dangerous
 attributes

---
 aleksis/apps/chronos/managers.py | 34 +++++++++++++++++++-
 aleksis/apps/chronos/models.py   | 53 ++++++++------------------------
 2 files changed, 45 insertions(+), 42 deletions(-)

diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py
index 80563bcd..d537dd45 100644
--- a/aleksis/apps/chronos/managers.py
+++ b/aleksis/apps/chronos/managers.py
@@ -12,7 +12,7 @@ from calendarweek import CalendarWeek
 
 from aleksis.apps.chronos.util.date import week_weekday_from_date, week_weekday_to_date
 from aleksis.core.managers import DateRangeQuerySetMixin, SchoolTermRelatedQuerySet
-from aleksis.core.models import Group, Person
+from aleksis.core.models import Group, Person, Room
 from aleksis.core.util.core_helpers import get_site_preferences
 
 
@@ -859,3 +859,35 @@ class RoomPropertiesMixin:
     @property
     def room_short_names(self, sep: str = ", ") -> str:
         return sep.join([room.short_name for room in self.get_rooms()])
+
+
+class LessonEventQuerySet(QuerySet):
+    """Queryset with special query methods for lesson events."""
+
+    def for_teacher(self, teacher: Union[int, Person]):
+        amended = objs.filter(Q(amended_by__isnull=False) & (Q(teachers=teacher))).values_list(
+            "amended_by__pk", flat=True
+        )
+        return objs.filter(Q(teachers=teacher) | Q(pk__in=amended)).distinct()
+
+    def for_group(self, group: Union[int, Group]):
+        amended = self.filter(
+            Q(amended_by__isnull=False) & (Q(groups=group) | Q(groups__parent_groups=group))
+        ).values_list("amended_by__pk", flat=True)
+        return self.filter(
+            Q(groups=group) | Q(groups__parent_groups=group) | Q(pk__in=amended)
+        ).distinct()
+
+    def for_room(self, room: Union[int, Room]):
+        amended = self.filter(Q(amended_by__isnull=False) & (Q(rooms=room))).values_list(
+            "amended_by__pk", flat=True
+        )
+        return self.filter(Q(rooms=room) | Q(pk__in=amended)).distinct()
+
+    def for_person(self, person: Union[int, Person]):
+        amended = self.filter(
+            Q(amended_by__isnull=False) & (Q(teachers=person) | Q(groups__members=person))
+        ).values_list("amended_by__pk", flat=True)
+        return self.filter(
+            Q(teachers=person) | Q(groups__members=person) | Q(pk__in=amended)
+        ).distinct()
diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 7cc450ef..ae323ccc 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -42,6 +42,7 @@ from aleksis.apps.chronos.managers import (
     ExtraLessonQuerySet,
     GroupPropertiesMixin,
     HolidayQuerySet,
+    LessonEventQuerySet,
     LessonPeriodManager,
     LessonPeriodQuerySet,
     LessonSubstitutionManager,
@@ -63,7 +64,10 @@ from aleksis.apps.chronos.util.format import format_m2m
 from aleksis.apps.cursus import models as cursus_models
 from aleksis.apps.cursus.models import Course
 from aleksis.apps.resint.models import LiveDocument
-from aleksis.core.managers import CurrentSiteManagerWithoutMigrations
+from aleksis.core.managers import (
+    AlekSISBaseManagerWithoutMigrations,
+    CurrentSiteManagerWithoutMigrations,
+)
 from aleksis.core.mixins import (
     ExtensibleModel,
     GlobalPermissionModel,
@@ -1370,6 +1374,8 @@ class LessonEvent(CalendarEvent):
     name = "lesson"
     verbose_name = _("Lessons")
 
+    objects = AlekSISBaseManagerWithoutMigrations.from_queryset(LessonEventQuerySet)()
+
     title = models.CharField(verbose_name=_("Name"), max_length=255, blank=True)
 
     course = models.ForeignKey(
@@ -1513,19 +1519,10 @@ class LessonEvent(CalendarEvent):
             return reference_object.real_amends.subject.colour_bg
         return super().value_color(reference_object, request)
 
-    @classmethod
-    def value_organizer(cls, reference_object: "LessonEvent", request) -> str:
-        """Get the organizer of the event."""
-        # TODO: Do not use the teachers as organizer, because only one organizer is allowed
-        return [t.get_vcal_address(role="CHAIR") for t in reference_object.teachers.all()]
-
     @classmethod
     def value_attendee(cls, reference_object: "LessonEvent", request) -> str:
         """Get the attendees of the event."""
-        # FIXME: Permissions
-        attendees = [t.get_vcal_address(role="CHAIR") for t in reference_object.teachers.all()] + [
-            g.get_vcal_address(role="REQ-PARTICIPANT") for g in reference_object.all_members
-        ]
+        attendees = [t.get_vcal_address(role="CHAIR") for t in reference_object.teachers.all()]
         return [a for a in attendees if a]
 
     @classmethod
@@ -1585,44 +1582,18 @@ class LessonEvent(CalendarEvent):
     def get_objects(cls, request, params=None) -> Iterable:
         """Return all objects that should be included in the calendar."""
         objs = super().get_objects(request, params)
-        print(params)
         if params:
             obj_id = int(params.get("id", 0))
             type = params.get("type", None)
-            print(obj_id, type)
 
             if type and obj_id:
                 if type == "TEACHER":
-                    amended = objs.filter(
-                        Q(amended_by__isnull=False) & (Q(teachers=obj_id))
-                    ).values_list("amended_by__pk", flat=True)
-                    return objs.filter(Q(teachers=obj_id) | Q(pk__in=amended)).distinct()
+                    return objs.for_teacher(obj_id)
                 elif type == "GROUP":
-                    amended = objs.filter(
-                        Q(amended_by__isnull=False) & (Q(groups=obj_id))
-                    ).values_list("amended_by__pk", flat=True)
-                    print(
-                        objs.filter(
-                            Q(groups=obj_id) | Q(groups__parent_groups=obj_id) | Q(pk__in=amended)
-                        ).distinct()
-                    )
-                    return objs.filter(
-                        Q(groups=obj_id) | Q(groups__parent_groups=obj_id) | Q(pk__in=amended)
-                    ).distinct()
+                    return objs.for_group(obj_id)
                 elif type == "ROOM":
-                    amended = objs.filter(
-                        Q(amended_by__isnull=False) & (Q(roms=obj_id))
-                    ).values_list("amended_by__pk", flat=True)
-                    return objs.filter(Q(rooms=obj_id) | Q(pk__in=amended)).distinct()
-        amended = objs.filter(
-            Q(amended_by__isnull=False)
-            & (Q(teachers=request.user.person) | Q(groups__members=request.user.person))
-        ).values_list("amended_by__pk", flat=True)
-        return objs.filter(
-            Q(teachers=request.user.person)
-            | Q(groups__members=request.user.person)
-            | Q(pk__in=amended)
-        ).distinct()
+                    return objs.for_room(obj_id)
+        return objs.for_person(request.user.person)
 
     class Meta:
         verbose_name = _("Lesson Event")
-- 
GitLab