diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py index 45aecf55b7553f0bd61c74cc4fee19e65f05b8d9..3b9d107346d823ccfd24761db78b28c949f3c0ac 100644 --- a/aleksis/apps/chronos/managers.py +++ b/aleksis/apps/chronos/managers.py @@ -946,3 +946,7 @@ class LessonEventQuerySet(RecurrencePolymorphicQuerySet): def not_amending(self) -> "LessonEventQuerySet": """Get all lesson events that are not amending other events.""" return self.filter(amends__isnull=True) + + def amending(self) -> "LessonEventQuerySet": + """Get all lesson events that are amending other events.""" + return self.filter(amends__isnull=False) diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py index 547978fc3759a83c54492d7b14fddcfc0c7e06b1..4d61b16c611de2dcee4a0f63e58cb52a2833d90e 100644 --- a/aleksis/apps/chronos/models.py +++ b/aleksis/apps/chronos/models.py @@ -1222,8 +1222,6 @@ class AutomaticPlan(LiveDocument): context = get_substitutions_context_data( wanted_day=date.today(), - request=None, - is_print=True, number_of_days=self.number_of_days, show_header_box=self.show_header_box, ) @@ -1562,6 +1560,7 @@ class LessonEvent(CalendarEvent): type_ = params.get("type", None) not_amended = params.get("not_amended", False) not_amending = params.get("not_amending", False) + amending = params.get("amending", False) own = params.get("own", False) if not_amended: @@ -1570,6 +1569,9 @@ class LessonEvent(CalendarEvent): if not_amending: objs = objs.not_amending() + if amending: + objs = objs.amending() + if request and "own" in params: if own: objs = objs.for_person(request.user.person) diff --git a/aleksis/apps/chronos/rules.py b/aleksis/apps/chronos/rules.py index 85a0d1c4a6b7e4bdef21edcaf1a294aa22d473c3..d814dd5b22adc24acdbbfc4c496875983bb1a626 100644 --- a/aleksis/apps/chronos/rules.py +++ b/aleksis/apps/chronos/rules.py @@ -44,7 +44,6 @@ add_perm("chronos.delete_substitution_rule", delete_substitution_predicate) # View substitutions view_substitutions_predicate = has_person & ( has_global_perm("chronos.view_lessonsubstitution") - | has_any_object("chronos.view_lessonsubstitution", LessonSubstitution) ) add_perm("chronos.view_substitutions_rule", view_substitutions_predicate) diff --git a/aleksis/apps/chronos/util/build.py b/aleksis/apps/chronos/util/build.py index 7946a3eaac461662fc34f57c454338dde7d52c00..62cdb0847a9707156975d681e603bae9e6429935 100644 --- a/aleksis/apps/chronos/util/build.py +++ b/aleksis/apps/chronos/util/build.py @@ -1,9 +1,8 @@ from collections import OrderedDict -from datetime import date +from datetime import date, datetime, time from typing import Union from django.apps import apps -from django.db.models import Q from calendarweek import CalendarWeek @@ -382,37 +381,37 @@ def build_timetable( return rows -def build_substitutions_list(wanted_day: date) -> list[dict]: +def build_substitutions_list(wanted_day: date) -> tuple[list[dict], set[Person], set[Group]]: rows = [] - - subs = ( - LessonEvent.objects.exclude(amends=None) - .filter(Q(datetime_start__date=wanted_day) | Q(date_start=wanted_day)) - .order_by("datetime_start", "date_start") + affected_teachers = set() + affected_groups = set() + + lesson_events = LessonEvent.get_single_events( + datetime.combine(wanted_day, time.min), + datetime.combine(wanted_day, time.max), + params={"amending": True}, + with_reference_object=True, ) - for i, sub in enumerate(subs): - sort_a = sub.group_names - - # FIXME? Looks hacky. sub.amends returns a CalendarEvent, but a LessonEvent is needed - sub.amends = LessonEvent.objects.get(pk=sub.amends.pk) + for lesson_event in lesson_events: + affected_teachers.update(lesson_event["REFERENCE_OBJECT"].teachers.all()) + affected_teachers.update(lesson_event["REFERENCE_OBJECT"].amends.teachers.all()) + affected_groups.update(lesson_event["REFERENCE_OBJECT"].groups.all()) + affected_groups.update(lesson_event["REFERENCE_OBJECT"].amends.groups.all()) row = { "type": "substitution", - "sort_a": sort_a, - "sort_b": str(sub.datetime_start if sub.datetime_start else sub.date_start), - "el": sub, + "sort_a": lesson_event["REFERENCE_OBJECT"].group_names, + "sort_b": str(lesson_event["DTSTART"]), + "el": lesson_event, } rows.append(row) - # Sort all items - def sorter(row: dict): - return row["sort_a"] + row["sort_b"] + rows.sort(key=lambda row: row["sort_a"] + row["sort_b"]) - rows.sort(key=sorter) - - return rows + print(rows) + return rows, affected_teachers, affected_groups def build_weekdays( diff --git a/aleksis/apps/chronos/util/chronos_helpers.py b/aleksis/apps/chronos/util/chronos_helpers.py index 81dc4fc9e979a1f09135c4a2eee08174ef8ac5fa..67e7626f65bbb4bfde2280e4aab64af236eb03f5 100644 --- a/aleksis/apps/chronos/util/chronos_helpers.py +++ b/aleksis/apps/chronos/util/chronos_helpers.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Optional from django.db.models import Count, Q from django.http import HttpRequest, HttpResponseNotFound from django.shortcuts import get_object_or_404 -from django.urls import reverse from guardian.core import ObjectPermissionChecker @@ -21,7 +20,6 @@ from ..models import ( SupervisionSubstitution, ) from .build import build_substitutions_list -from .js import date_unix if TYPE_CHECKING: from django.contrib.auth import get_user_model @@ -159,8 +157,6 @@ def get_rooms(user: "User"): def get_substitutions_context_data( wanted_day: date, - request: Optional[HttpRequest] = None, - is_print: bool = False, number_of_days: Optional[int] = None, show_header_box: Optional[bool] = None, ): @@ -177,33 +173,26 @@ def get_substitutions_context_data( ) day_contexts = {} - if is_print: - next_day = wanted_day - for _i in range(day_number): - day_contexts[next_day] = {"day": next_day} - next_day = next_day + timedelta(days=1) - else: - day_contexts = {wanted_day: {"day": wanted_day}} + day = wanted_day + for _i in range(day_number): + day_contexts[day] = {"day": day} - for day in day_contexts: - subs = build_substitutions_list(day) + subs, affected_teachers, affected_groups = build_substitutions_list(day) day_contexts[day]["substitutions"] = subs - day_contexts[day]["announcements"] = Announcement.for_timetables().on_date(day) + day_contexts[day]["announcements"] = Announcement.objects.on_date(day) if show_header_box: absences = Absence.objects.on_day(day) day_contexts[day]["absent_teachers"] = absences.absent_teachers() day_contexts[day]["absent_groups"] = absences.absent_groups() + day_contexts[day]["affected_teachers"] = sorted( + affected_teachers, key=lambda t: t.short_name or t.full_name + ) + day_contexts[day]["affected_groups"] = affected_groups - if not is_print: - context = day_contexts[wanted_day] - context["datepicker"] = { - "date": date_unix(wanted_day), - "dest": reverse("substitutions"), - } + day = day + timedelta(days=1) - else: - context["days"] = day_contexts + context["days"] = day_contexts return context