diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 51ce9376e534d149ffa315c50524867e8ff4f1dc..681ce0705b25842c1f24f9789569a2d88115b72c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,8 +3,8 @@ include: file: /ci/general.yml - project: "AlekSIS/official/AlekSIS" file: /ci/prepare/lock.yml - # - project: "AlekSIS/official/AlekSIS" - # file: /ci/test.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/test/test.yml - project: "AlekSIS/official/AlekSIS" file: /ci/test/lint.yml - project: "AlekSIS/official/AlekSIS" diff --git a/aleksis/apps/lesrooster/models.py b/aleksis/apps/lesrooster/models.py index 23c44e615ab088cb811be2a1a8c884a207d28b50..1592ae3c9fc05b82cb6a2a7910fc43c12f328efa 100644 --- a/aleksis/apps/lesrooster/models.py +++ b/aleksis/apps/lesrooster/models.py @@ -211,6 +211,24 @@ class Slot(ExtensiblePolymorphicModel): def get_last_datetime(self) -> datetime: return self.get_datetime_end(self.time_grid.validity_range.date_end) + def build_recurrence(self, *args, **kwargs) -> recurrence.Recurrence: + """Build a recurrence for this slot respecting the validity range borders.""" + pattern = recurrence.Recurrence( + dtstart=timezone.make_aware( + datetime.combine(self.time_grid.validity_range.date_start, self.time_start) + ), + rrules=[ + recurrence.Rule( + *args, + **kwargs, + until=timezone.make_aware( + datetime.combine(self.time_grid.validity_range.date_end, self.time_end) + ), + ) + ], + ) + return pattern + class Meta: constraints = [ models.UniqueConstraint( @@ -305,6 +323,10 @@ class Lesson(TeacherPropertiesMixin, RoomPropertiesMixin, ExtensibleModel): if self.slot_start.time_grid != self.slot_end.time_grid: raise ValidationError(_("The slots must be in the same time grid.")) + def build_recurrence(self, *args, **kwargs) -> "recurrence.Recurrence": + """Build a recurrence for this lesson respecting the validity range borders.""" + return self.slot_start.build_recurrence(*args, **kwargs) + @property def real_recurrence(self) -> "recurrence.Recurrence": """Get the real recurrence adjusted to the validity range and including holidays.""" @@ -431,6 +453,10 @@ class Supervision(TeacherPropertiesMixin, RoomPropertiesMixin, ExtensibleModel): verbose_name = _("Supervision") verbose_name_plural = _("Supervisions") + def build_recurrence(self, *args, **kwargs) -> "recurrence.Recurrence": + """Build a recurrence for this supervision respecting the validity range borders.""" + return self.break_slot.build_recurrence(*args, **kwargs) + @property def real_recurrence(self) -> "recurrence.Recurrence": """Get the real recurrence adjusted to the validity range and including holidays.""" diff --git a/aleksis/apps/lesrooster/tests/test_recurrence.py b/aleksis/apps/lesrooster/tests/test_recurrence.py new file mode 100644 index 0000000000000000000000000000000000000000..78c204b385338c7d2f8c542a3d6e6189132e6876 --- /dev/null +++ b/aleksis/apps/lesrooster/tests/test_recurrence.py @@ -0,0 +1,79 @@ +from datetime import date, datetime, time +from pprint import pprint + +from django.utils.timezone import get_current_timezone + +import pytest +import recurrence + +from aleksis.apps.lesrooster.models import ( + BreakSlot, + Lesson, + Slot, + Supervision, + TimeGrid, + ValidityRange, +) +from aleksis.core.models import SchoolTerm + +pytestmark = pytest.mark.django_db + + +@pytest.fixture +def school_term(): + date_start = date(2024, 1, 1) + date_end = date(2024, 6, 1) + school_term = SchoolTerm.objects.create(name="Test", date_start=date_start, date_end=date_end) + return school_term + + +@pytest.fixture +def validity_range(school_term): + validity_range = ValidityRange.objects.create( + school_term=school_term, date_start=school_term.date_start, date_end=school_term.date_end + ) + return validity_range + + +@pytest.fixture +def time_grid(validity_range): + return TimeGrid.objects.get(validity_range=validity_range, group=None) + + +def test_slot_build_recurrence(time_grid): + slot = Slot.objects.create( + time_grid=time_grid, weekday=0, period=1, time_start=time(8, 0), time_end=time(9, 0) + ) + rec = slot.build_recurrence(recurrence.WEEKLY) + + pprint(rec.rrules[0].__dict__) + + assert rec.dtstart == datetime(2024, 1, 1, 8, 0, tzinfo=get_current_timezone()) + assert len(rec.rrules) == 1 + + rrule = rec.rrules[0] + assert rrule.until == datetime(2024, 6, 1, 9, 0, tzinfo=get_current_timezone()) + assert rrule.freq == 2 + assert rrule.interval == 1 + + +def test_lesson_recurrence(time_grid): + slot = Slot.objects.create( + time_grid=time_grid, weekday=0, period=1, time_start=time(8, 0), time_end=time(9, 0) + ) + break_slot = BreakSlot.objects.create( + time_grid=time_grid, weekday=0, time_start=time(9, 0), time_end=time(9, 15) + ) + + lesson = Lesson.objects.create( + slot_start=slot, + slot_end=slot, + ) + + assert lesson.build_recurrence(recurrence.WEEKLY) == slot.build_recurrence(recurrence.WEEKLY) + + supervision = Supervision.objects.create(break_slot=break_slot) + + assert supervision.build_recurrence(recurrence.WEEKLY) == break_slot.build_recurrence( + recurrence.WEEKLY + )