From 4089ec54a9340ac903ad942209379e3fa375377a Mon Sep 17 00:00:00 2001
From: Michael Bauer <michael-bauer@posteo.de>
Date: Wed, 8 May 2024 13:34:55 +0200
Subject: [PATCH] Refactor parse_dummy & create_from_lesson_event

& use in DocumentationBatchCreateOrUpdateMutation & AbsencesBatchCreateMutation.
---
 aleksis/apps/alsijil/models.py               | 86 ++++++++++++++++++++
 aleksis/apps/alsijil/schema/absences.py      | 18 ++--
 aleksis/apps/alsijil/schema/documentation.py | 68 +---------------
 3 files changed, 97 insertions(+), 75 deletions(-)

diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 4f7e90a06..dfae4a372 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -2,6 +2,7 @@ from datetime import date, datetime
 from typing import Optional, Union
 from urllib.parse import urlparse
 
+from django.core.exceptions import PermissionDenied
 from django.db import models
 from django.db.models import QuerySet
 from django.db.models.constraints import CheckConstraint
@@ -10,6 +11,7 @@ from django.http import HttpRequest
 from django.urls import reverse
 from django.utils.formats import date_format
 from django.utils.translation import gettext_lazy as _
+from django.contrib.auth.models import User
 
 from calendarweek import CalendarWeek
 from colorfield.fields import ColorField
@@ -595,6 +597,90 @@ class Documentation(CalendarEvent):
 
         return Documentation.get_documentations_for_events(events, incomplete)
 
+    @classmethod
+    def parse_dummy(
+            cls,
+            id: string,
+    ) -> tuple:
+        """Parse dummy id string into lesson_event, datetime_start, datetime_end.
+        """
+        dummy, lesson_event_id, datetime_start_iso, datetime_end_iso = _id.split(";")
+        lesson_event = LessonEvent.objects.get(id=lesson_event_id)
+
+        datetime_start = datetime.fromisoformat(datetime_start_iso).astimezone(
+            lesson_event.timezone
+        )
+        datetime_end = datetime.fromisoformat(datetime_end_iso).astimezone(
+            lesson_event.timezone
+        )
+        return (lesson_event, datetime_start, datetime_end)
+
+    @classmethod
+    def create_from_lesson_event(
+            cls,
+            user: User,
+            lesson_event: LessonEvent,
+            datetime_start: datetime,
+            datetime_end: datetime,
+    ) -> Documentation:
+        """ Create a documentation from a lesson_event with start and end datetime.
+        User is needed for permission checking.
+        """
+        if user.has_perm(
+                "alsijil.add_documentation_for_lesson_event_rule", lesson_event
+            ) and (
+                get_site_preferences()["alsijil__allow_edit_future_documentations"] == "all"
+                or (
+                    get_site_preferences()["alsijil__allow_edit_future_documentations"]
+                    == "current_day"
+                    and datetime_start.date() <= localdate()
+                )
+                or (
+                    get_site_preferences()["alsijil__allow_edit_future_documentations"]
+                    == "current_time"
+                    and datetime_start <= localtime()
+                )
+            ):
+                if lesson_event.amends:
+                    if lesson_event.course:
+                        course = lesson_event.course
+                    else:
+                        course = lesson_event.amends.course
+
+                    if lesson_event.subject:
+                        subject = lesson_event.subject
+                    else:
+                        subject = lesson_event.amends.subject
+
+                    if lesson_event.teachers:
+                        teachers = lesson_event.teachers
+                    else:
+                        teachers = lesson_event.amends.teachers
+                else:
+                    course, subject, teachers = (
+                        lesson_event.course,
+                        lesson_event.subject,
+                        lesson_event.teachers,
+                    )
+
+                obj = cls.objects.create(
+                    datetime_start=datetime_start,
+                    datetime_end=datetime_end,
+                    amends=lesson_event,
+                    course=course,
+                    subject=subject,
+                    topic=doc.topic or "",
+                    homework=doc.homework or "",
+                    group_note=doc.group_note or "",
+                )
+                if doc.teachers is not None:
+                    obj.teachers.add(*doc.teachers)
+                else:
+                    obj.teachers.set(teachers.all())
+                obj.save()
+                return obj
+            raise PermissionDenied()
+
 
 class ParticipationStatus(CalendarEvent):
     """A participation or absence record about a single person.
diff --git a/aleksis/apps/alsijil/schema/absences.py b/aleksis/apps/alsijil/schema/absences.py
index 55aa8ecf5..bb02c4bb2 100644
--- a/aleksis/apps/alsijil/schema/absences.py
+++ b/aleksis/apps/alsijil/schema/absences.py
@@ -37,19 +37,17 @@ class AbsencesBatchCreateMutation(graphene.Mutation):
             # Create doc for dummies that are already in the past
             future = false
             for dummy in dummies:
-                # TODO/MAYBE: This in past logic could be somewhere else OR shared.
-                # The next 5 lines are shared with DocumentationBatchCreateOrUpdateMutation
-                # & could be deduplicated
-                dummy, lesson_event_id, datetime_start_iso, datetime_end_iso = _id.split(";")
-                lesson_event = LessonEvent.objects.get(id=lesson_event_id)
-                start = datetime.fromisoformat(datetime_start_iso).astimezone(
-                    lesson_event.timezone
-                )
+                lesson_event, dummy_start, dummy_end = Documentation.parse_dummy(dummy.id)
 
-                if start < datetime.now():
+                if dummy_start < datetime.now():
                     # In the past -> Create a Documentation
                     docs.append(
-                        DocumentationBatchCreateOrUpdateMutation.create_or_update(info, dummy)
+                        Documentation.create_from_lesson_event(
+                            info.context.user,
+                            lesson_event,
+                            dummy_start,
+                            dummy_end,
+                        )
                     )
                 else:
                     future = true
diff --git a/aleksis/apps/alsijil/schema/documentation.py b/aleksis/apps/alsijil/schema/documentation.py
index 3225db34e..9d3ea2b4b 100644
--- a/aleksis/apps/alsijil/schema/documentation.py
+++ b/aleksis/apps/alsijil/schema/documentation.py
@@ -9,7 +9,6 @@ from guardian.shortcuts import get_objects_for_user
 from reversion import create_revision, set_comment, set_user
 
 from aleksis.apps.alsijil.util.predicates import can_edit_documentation, is_in_allowed_time_range
-from aleksis.apps.chronos.models import LessonEvent
 from aleksis.apps.chronos.schema import LessonEventType
 from aleksis.apps.cursus.models import Subject
 from aleksis.apps.cursus.schema import CourseType, SubjectType
@@ -18,7 +17,6 @@ from aleksis.core.schema.base import (
     DjangoFilterMixin,
     PermissionsTypeMixin,
 )
-from aleksis.core.util.core_helpers import get_site_preferences
 
 from ..models import Documentation
 
@@ -100,70 +98,10 @@ class DocumentationBatchCreateOrUpdateMutation(graphene.Mutation):
         # Sadly, we can't use the update_or_create method since create_defaults
         # is only introduced in Django 5.0
         if _id.startswith("DUMMY"):
-            dummy, lesson_event_id, datetime_start_iso, datetime_end_iso = _id.split(";")
-            lesson_event = LessonEvent.objects.get(id=lesson_event_id)
-
-            datetime_start = datetime.fromisoformat(datetime_start_iso).astimezone(
-                lesson_event.timezone
-            )
-            datetime_end = datetime.fromisoformat(datetime_end_iso).astimezone(
-                lesson_event.timezone
+            return Documentation.create_from_lesson_event(
+                info.context.user,
+                *Documentation.parse_dummy(_id),
             )
-
-            if info.context.user.has_perm(
-                "alsijil.add_documentation_for_lesson_event_rule", lesson_event
-            ) and (
-                get_site_preferences()["alsijil__allow_edit_future_documentations"] == "all"
-                or (
-                    get_site_preferences()["alsijil__allow_edit_future_documentations"]
-                    == "current_day"
-                    and datetime_start.date() <= localdate()
-                )
-                or (
-                    get_site_preferences()["alsijil__allow_edit_future_documentations"]
-                    == "current_time"
-                    and datetime_start <= localtime()
-                )
-            ):
-                if lesson_event.amends:
-                    if lesson_event.course:
-                        course = lesson_event.course
-                    else:
-                        course = lesson_event.amends.course
-
-                    if lesson_event.subject:
-                        subject = lesson_event.subject
-                    else:
-                        subject = lesson_event.amends.subject
-
-                    if lesson_event.teachers:
-                        teachers = lesson_event.teachers
-                    else:
-                        teachers = lesson_event.amends.teachers
-                else:
-                    course, subject, teachers = (
-                        lesson_event.course,
-                        lesson_event.subject,
-                        lesson_event.teachers,
-                    )
-
-                obj = Documentation.objects.create(
-                    datetime_start=datetime_start,
-                    datetime_end=datetime_end,
-                    amends=lesson_event,
-                    course=course,
-                    subject=subject,
-                    topic=doc.topic or "",
-                    homework=doc.homework or "",
-                    group_note=doc.group_note or "",
-                )
-                if doc.teachers is not None:
-                    obj.teachers.add(*doc.teachers)
-                else:
-                    obj.teachers.set(teachers.all())
-                obj.save()
-                return obj
-            raise PermissionDenied()
         else:
             obj = Documentation.objects.get(id=_id)
 
-- 
GitLab