From a5df2c078f616cbcd93d030ade0213773278c8f1 Mon Sep 17 00:00:00 2001 From: Jonathan Weth <git@jonathanweth.de> Date: Sun, 11 Aug 2024 17:20:37 +0200 Subject: [PATCH] Update AutomaticPlan to work with new models --- aleksis/apps/chronos/models.py | 13 +- aleksis/apps/chronos/util/change_tracker.py | 126 +------------------- 2 files changed, 11 insertions(+), 128 deletions(-) diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py index 35f4e011..a5457a88 100644 --- a/aleksis/apps/chronos/models.py +++ b/aleksis/apps/chronos/models.py @@ -1209,7 +1209,7 @@ class AutomaticPlan(LiveDocument): @property def current_start_day(self) -> date: """Get first day which should be shown in the PDF.""" - return TimePeriod.get_next_relevant_day(timezone.now().date(), datetime.now().time()) + return timezone.now().date() @property def current_end_day(self) -> date: @@ -1248,11 +1248,16 @@ class AutomaticPlan(LiveDocument): continue # Check if the changed object is relevant for the time period of the PDF file - if isinstance(version.object, Event): + if not version.object.amends: + return + + if version.object.datetime_start: + date_start = version.object.datetime_start.date() + date_end = version.object.datetime_end.date() + else: date_start = version.object.date_start date_end = version.object.date_end - else: - date_start = date_end = version.object.date + if date_start <= self.current_end_day and date_end >= self.current_start_day: update = True break diff --git a/aleksis/apps/chronos/util/change_tracker.py b/aleksis/apps/chronos/util/change_tracker.py index c9b8afb1..669f5c4e 100644 --- a/aleksis/apps/chronos/util/change_tracker.py +++ b/aleksis/apps/chronos/util/change_tracker.py @@ -1,9 +1,4 @@ -from typing import Any, Optional - from django.contrib.contenttypes.models import ContentType -from django.db import transaction -from django.db.models import Model -from django.db.models.signals import m2m_changed, post_save, pre_delete from django.dispatch import Signal, receiver from celery import shared_task @@ -11,126 +6,9 @@ from reversion.models import Revision def _get_substitution_models(): - from aleksis.apps.chronos.models import ( - Event, - ExtraLesson, - LessonSubstitution, - SupervisionSubstitution, - ) - - return [LessonSubstitution, Event, ExtraLesson, SupervisionSubstitution] - - -class TimetableChange: - """A change to timetable models.""" - - def __init__( - self, - instance: Model, - changed_fields: Optional[dict[str, Any]] = None, - created: bool = False, - deleted: bool = False, - ): - self.instance = instance - self.changed_fields = changed_fields or {} - self.created = created - self.deleted = deleted - - -class TimetableDataChangeTracker: - """Helper class for tracking changes in timetable models by using signals.""" - - @classmethod - def get_models(cls) -> list[type[Model]]: - """Return all models that should be tracked.""" - from aleksis.apps.chronos.models import ( - Event, - ExtraLesson, - LessonSubstitution, - SupervisionSubstitution, - ) - - return [LessonSubstitution, Event, ExtraLesson, SupervisionSubstitution] - - def __init__(self): - self.changes = {} - self.m2m_fields = {} - - if transaction.get_autocommit(): - raise RuntimeError("Cannot use change tracker outside of transaction") - - for model in self.get_models(): - post_save.connect(self._handle_save, sender=model, weak=False) - pre_delete.connect(self._handle_delete, sender=model, weak=False) - - # Register signals for all relevant m2m fields - m2m_fields = { - getattr(model, f.name).through: f - for f in model._meta.get_fields() - if f.many_to_many - } - self.m2m_fields.update(m2m_fields) - for through_model, _field in m2m_fields.items(): - m2m_changed.connect(self._handle_m2m_changed, sender=through_model, weak=False) - - transaction.on_commit(self.close) - - def get_instance_key(self, instance: Model) -> str: - """Get unique string key for an instance.""" - return f"{instance._meta.model_name}_{instance.id}" - - def _add_change(self, change: TimetableChange): - """Add a change to the list of changes and update, if necessary.""" - key = self.get_instance_key(change.instance) - if key not in self.changes or change.deleted or change.created: - self.changes[key] = change - else: - self.changes[key].changed_fields.update(change.changed_fields) - - def _handle_save(self, sender: type[Model], instance: Model, created: bool, **kwargs): - """Handle the save signal.""" - change = TimetableChange(instance, created=created) - if not created: - change.changed_fields = instance.tracker.changed() - self._add_change(change) - - def _handle_delete(self, sender: type[Model], instance: Model, **kwargs): - """Handle the delete signal.""" - change = TimetableChange(instance, deleted=True) - self._add_change(change) - - def _handle_m2m_changed( - self, - sender: type[Model], - instance: Model, - action: str, - model: type[Model], - pk_set: set, - **kwargs, - ): - """Handle the m2m_changed signal.""" - if action in ["pre_add", "pre_remove", "pre_clear"]: - field_name = self.m2m_fields[sender].name - current_value = list(getattr(instance, field_name).all()) - if self.get_instance_key(instance) in self.changes: - change = self.changes[self.get_instance_key(instance)] - if field_name in change.changed_fields: - current_value = None - - if current_value is not None: - change = TimetableChange(instance, changed_fields={field_name: current_value}) - self._add_change(change) - - def close(self): - """Disconnect signals and send change signal.""" - for model in self.get_models(): - post_save.disconnect(self._handle_save, sender=model) - pre_delete.disconnect(self._handle_delete, sender=model) - - for through_model, _field in self.m2m_fields.items(): - m2m_changed.disconnect(self._handle_m2m_changed, sender=through_model) + from aleksis.apps.chronos.models import LessonEvent, SupervisionEvent - timetable_data_changed.send(sender=self, changes=self.changes) + return [LessonEvent, SupervisionEvent] chronos_revision_created = Signal() -- GitLab