From d7034148c320d2fcb1748f09cb9afaa2746d9088 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Sun, 7 Mar 2021 18:07:42 +0100
Subject: [PATCH] Extend querysets for holidays and groups

---
 aleksis/apps/chronos/managers.py | 30 ++++++++++++++++++++++++++++--
 aleksis/apps/chronos/models.py   |  7 ++++++-
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py
index 8955a3f7..6d940948 100644
--- a/aleksis/apps/chronos/managers.py
+++ b/aleksis/apps/chronos/managers.py
@@ -1,10 +1,12 @@
 from datetime import date, datetime, timedelta
 from enum import Enum
-from typing import Optional, Union
+from typing import Iterable, Optional, Union
 
 from django.contrib.sites.managers import CurrentSiteManager as _CurrentSiteManager
 from django.db import models
-from django.db.models import Count, F, Q, QuerySet
+from django.db.models import Count, ExpressionWrapper, F, Func, Q, QuerySet, Value
+from django.db.models.fields import DateField
+from django.db.models.functions import Concat
 
 from calendarweek import CalendarWeek
 
@@ -298,6 +300,13 @@ class LessonDataQuerySet(models.QuerySet, WeekQuerySetMixin):
                 | Q(**{self._period_path + "lesson__groups__parent_groups": group})
             )
 
+    def filter_groups(self, groups: Iterable[Group]) -> QuerySet:
+        """Filter for all lessons one of the groups regularly attends."""
+        return self.filter(
+            Q(**{self._period_path + "lesson__groups__in": groups})
+            | Q(**{self._period_path + "lesson__groups__parent_groups__in": groups})
+        )
+
     def filter_teacher(self, teacher: Union[Person, int]):
         """Filter for all lessons given by a certain teacher."""
         qs1 = self.filter(**{self._period_path + "lesson__teachers": teacher})
@@ -589,6 +598,10 @@ class TimetableQuerySet(models.QuerySet):
         else:
             return self.filter(Q(groups=group) | Q(groups__parent_groups=group))
 
+    def filter_groups(self, groups: Iterable[Group]) -> QuerySet:
+        """Filter for all objects one of the groups attends."""
+        return self.filter(Q(groups__in=groups) | Q(groups__parent_groups__in=groups)).distinct()
+
     def filter_teacher(self, teacher: Union[Person, int]):
         """Filter for all lessons given by a certain teacher."""
         return self.filter(teachers=teacher)
@@ -663,6 +676,19 @@ class ExtraLessonQuerySet(TimetableQuerySet, SchoolTermRelatedQuerySet, GroupByP
         """Filter all extra lessons on a day."""
         return self.within_dates(day, day)
 
+    def annotate_day(self):
+        weekday_to_date = ExpressionWrapper(
+            Func(
+                Concat(F("year"), F("week")),
+                Value("IYYYIW"),
+                output_field=DateField(),
+                function="TO_DATE",
+            )
+            + F("period__weekday"),
+            output_field=DateField(),
+        )
+        return self.annotate(day=weekday_to_date)
+
 
 class GroupPropertiesMixin:
     """Mixin for common group properties.
diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py
index 3dc0c6ba..6326f80a 100644
--- a/aleksis/apps/chronos/models.py
+++ b/aleksis/apps/chronos/models.py
@@ -3,7 +3,7 @@
 from __future__ import annotations
 
 from datetime import date, datetime, time, timedelta
-from typing import Dict, List, Optional, Tuple, Union
+from typing import Dict, Iterator, List, Optional, Tuple, Union
 
 from django.core.exceptions import ValidationError
 from django.db import models
@@ -685,6 +685,11 @@ class Holiday(ExtensibleModel):
     date_end = models.DateField(verbose_name=_("End date"), null=True)
     comments = models.TextField(verbose_name=_("Comments"), blank=True, null=True)
 
+    def get_days(self) -> Iterator[date]:
+        delta = self.date_end - self.date_start
+        for i in range(delta.days + 1):
+            yield self.date_start + timedelta(days=i)
+
     @classmethod
     def on_day(cls, day: date) -> Optional["Holiday"]:
         holidays = cls.objects.on_day(day)
-- 
GitLab