diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py index 89e0599844e282b9a07c6c80d13abb008f946d89..8955a3f798ce82f1286f68c500905ce37777d540 100644 --- a/aleksis/apps/chronos/managers.py +++ b/aleksis/apps/chronos/managers.py @@ -699,4 +699,8 @@ class TeacherPropertiesMixin: @property def teacher_names(self, sep: Optional[str] = ", ") -> str: - return sep.join([teacher.full_name for teacher in self.teachers.all()]) + return sep.join([teacher.full_name for teacher in self.get_teachers().all()]) + + @property + def teacher_short_names(self, sep: str = ", ") -> str: + return sep.join([teacher.short_name for teacher in self.get_teachers().all()]) diff --git a/aleksis/apps/chronos/mixins.py b/aleksis/apps/chronos/mixins.py index fc07ce29b92600bcd7ad7ac1e564d19db58360ab..5a784579b4ca7a1adbbc32ec2c54f44cc28f18b0 100644 --- a/aleksis/apps/chronos/mixins.py +++ b/aleksis/apps/chronos/mixins.py @@ -34,7 +34,8 @@ class ValidityRangeRelatedExtensibleModel(ExtensibleModel): class WeekRelatedMixin: @property def date(self) -> date: - return week_weekday_to_date(self.calendar_week, self.lesson_period.period.weekday) + period = self.lesson_period.period if hasattr(self, "lesson_period") else self.period + return week_weekday_to_date(self.calendar_week, period.weekday) @property def calendar_week(self) -> CalendarWeek: @@ -42,6 +43,11 @@ class WeekRelatedMixin: class WeekAnnotationMixin: + def annotate_week(self, week: CalendarWeek): + """Annotate this lesson with the number of the provided calendar week.""" + self._week = week.week + self._year = week.year + @property def week(self) -> Union[CalendarWeek, None]: """Get annotated week as `CalendarWeek`. diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py index 03788999f74feb384cb1780f09ebb32a92040d39..65fa31138895ada78af7fcbbd73e9061139a429c 100644 --- a/aleksis/apps/chronos/models.py +++ b/aleksis/apps/chronos/models.py @@ -217,6 +217,14 @@ class TimePeriod(ValidityRangeRelatedExtensibleModel): return url_prev, url_next + @classmethod + def from_period(cls, period: int, day: date) -> "TimePeriod": + """Get `TimePeriod` object for a period on a specific date. + + This will respect the relation to validity ranges. + """ + return cls.objects.on_day(day).filter(period=period).first() + @classproperty @cache_memoize(3600) def period_min(cls) -> int: @@ -344,6 +352,10 @@ class Lesson(ValidityRangeRelatedExtensibleModel, GroupPropertiesMixin, TeacherP return CalendarWeek(year=year, week=week) + def get_teachers(self) -> models.query.QuerySet: + """Get teachers relation.""" + return self.teachers + def __str__(self): return f"{format_m2m(self.groups)}, {self.subject.short_name}, {format_m2m(self.teachers)}" @@ -413,7 +425,7 @@ class LessonSubstitution(ExtensibleModel, WeekRelatedMixin): verbose_name_plural = _("Lesson substitutions") -class LessonPeriod(ExtensibleModel, WeekAnnotationMixin): +class LessonPeriod(WeekAnnotationMixin, TeacherPropertiesMixin, ExtensibleModel): label_ = "lesson_period" objects = LessonPeriodManager.from_queryset(LessonPeriodQuerySet)() @@ -458,9 +470,6 @@ class LessonPeriod(ExtensibleModel, WeekAnnotationMixin): else: return self.room - def get_teacher_names(self, sep: Optional[str] = ", ") -> str: - return sep.join([teacher.full_name for teacher in self.get_teachers().all()]) - def get_groups(self) -> models.query.QuerySet: return self.lesson.groups @@ -895,20 +904,70 @@ class Event(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, TeacherPrope return _(f"Event {self.pk}") @property - def period_from_on_day(self) -> int: + def raw_period_from_on_day(self) -> TimePeriod: + """Get start period on the annotated day (as TimePeriod object). + + If there is no date annotated, it will use the current date. + """ day = getattr(self, "_date", timezone.now().date()) if day != self.date_start: - return TimePeriod.period_min + return TimePeriod.from_period(TimePeriod.period_min, day) else: - return self.period_from.period + return self.period_from @property - def period_to_on_day(self) -> int: + def raw_period_to_on_day(self) -> TimePeriod: + """Get end period on the annotated day (as TimePeriod object). + + If there is no date annotated, it will use the current date. + """ day = getattr(self, "_date", timezone.now().date()) if day != self.date_end: - return TimePeriod.period_max + return TimePeriod.from_period(TimePeriod.period_max, day) else: - return self.period_to.period + return self.period_to + + @property + def period_from_on_day(self) -> int: + """Get start period on the annotated day (as period number). + + If there is no date annotated, it will use the current date. + """ + return self.raw_period_from_on_day.period + + @property + def period_to_on_day(self) -> int: + """Get end period on the annotated day (as period number). + + If there is no date annotated, it will use the current date. + """ + return self.raw_period_to_on_day.period + + def get_start_weekday(self, week: CalendarWeek) -> int: + """Get start date of an event in a specific week.""" + if self.date_start < week[TimePeriod.weekday_min]: + return TimePeriod.weekday_min + else: + return self.date_start.weekday() + + def get_end_weekday(self, week: CalendarWeek) -> int: + """Get end date of an event in a specific week.""" + if self.date_end > week[TimePeriod.weekday_max]: + return TimePeriod.weekday_max + else: + return self.date_end.weekday() + + def annotate_day(self, day: date): + """Annotate event with the provided date.""" + self._date = day + + def get_groups(self) -> models.query.QuerySet: + """Get groups relation.""" + return self.groups + + def get_teachers(self) -> models.query.QuerySet: + """Get teachers relation.""" + return self.teachers class Meta: ordering = ["date_start"] @@ -917,7 +976,9 @@ class Event(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, TeacherPrope verbose_name_plural = _("Events") -class ExtraLesson(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, WeekRelatedMixin): +class ExtraLesson( + GroupPropertiesMixin, TeacherPropertiesMixin, WeekRelatedMixin, SchoolTermRelatedExtensibleModel +): label_ = "extra_lesson" objects = ExtraLessonManager.from_queryset(ExtraLessonQuerySet)() @@ -949,6 +1010,18 @@ class ExtraLesson(SchoolTermRelatedExtensibleModel, GroupPropertiesMixin, WeekRe def __str__(self): return f"{self.week}, {self.period}, {self.subject}" + def get_groups(self) -> models.query.QuerySet: + """Get groups relation.""" + return self.groups + + def get_teachers(self) -> models.query.QuerySet: + """Get teachers relation.""" + return self.teachers + + def get_subject(self) -> Subject: + """Get subject.""" + return self.subject + class Meta: verbose_name = _("Extra lesson") verbose_name_plural = _("Extra lessons")