diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
index f4799fc786ebe58f33511a5412a2004264f91fe4..93daceb115dee73ae67300e690ef7feb69c2e14e 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/Coursebook.vue
@@ -51,7 +51,7 @@
         </v-list-item-content>
       </v-list-item>
 
-      <coursebook-date-select :value="dateStart"/>
+      <coursebook-date-select :value="dateStart" />
     </template>
     <template #loading>
       <CoursebookLoader />
@@ -65,7 +65,9 @@
 
     <template #no-results>
       <CoursebookEmptyMessage icon="mdi-book-alert-outline">
-        {{ $t("alsijil.coursebook.no_results", { search: $refs.iterator.search }) }}
+        {{
+          $t("alsijil.coursebook.no_results", { search: $refs.iterator.search })
+        }}
       </CoursebookEmptyMessage>
     </template>
   </c-r-u-d-iterator>
@@ -74,8 +76,12 @@
 <script>
 import CRUDIterator from "aleksis.core/components/generic/CRUDIterator.vue";
 import DocumentationModal from "./documentation/DocumentationModal.vue";
-import {DateTime} from "luxon";
-import {coursesOfTeacher, documentationsForCoursebook, groupsByOwner,} from "./coursebook.graphql";
+import { DateTime } from "luxon";
+import {
+  coursesOfTeacher,
+  documentationsForCoursebook,
+  groupsByOwner,
+} from "./coursebook.graphql";
 import CoursebookLoader from "./CoursebookLoader.vue";
 import CoursebookEmptyMessage from "./CoursebookEmptyMessage.vue";
 import CoursebookDateSelect from "./CoursebookDateSelect.vue";
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookDateSelect.vue b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookDateSelect.vue
index 436c4ab9e094490dff7df54c484572d5b8b1b2e3..9a2d9c65c380711cc5ba6d23863b6d06c8c39cdb 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookDateSelect.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookDateSelect.vue
@@ -24,39 +24,39 @@ export default {
       required: false,
       default: false,
     },
-  }
-}
+  },
+};
 </script>
 
 <template>
-<v-bottom-sheet
+  <v-bottom-sheet
     :value="true"
     persistent
     hide-overlay
     ref="sheet"
     class="rounded-t-xl rounded-b-0"
   >
-  <v-card>
-    <v-card-title id="content">
-      <div class="d-flex align-center justify-space-between full-width">
-        <v-btn icon large class="me-4">
-          <v-icon>$prev</v-icon>
-        </v-btn>
-        <date-field
-          solo-inverted
-          flat
-          hide-details
-          :value="value"
-          :label="$t('alsijil.coursebook.date_select.label')"
-          :disabled="loading"
-        />
-        <v-btn icon large class="ms-4">
-          <v-icon>$next</v-icon>
-        </v-btn>
-      </div>
-    </v-card-title>
-  </v-card>
-</v-bottom-sheet>
+    <v-card>
+      <v-card-title id="content">
+        <div class="d-flex align-center justify-space-between full-width">
+          <v-btn icon large class="me-4">
+            <v-icon>$prev</v-icon>
+          </v-btn>
+          <date-field
+            solo-inverted
+            flat
+            hide-details
+            :value="value"
+            :label="$t('alsijil.coursebook.date_select.label')"
+            :disabled="loading"
+          />
+          <v-btn icon large class="ms-4">
+            <v-icon>$next</v-icon>
+          </v-btn>
+        </div>
+      </v-card-title>
+    </v-card>
+  </v-bottom-sheet>
 </template>
 
 <style scoped>
@@ -64,4 +64,4 @@ export default {
   margin: auto;
   max-width: 500px;
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookEmptyMessage.vue b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookEmptyMessage.vue
index 059d613c3b4fb0a1d6b8234ae0c74c2d7a673cec..346ecc63c272ab5c57a1da9f5e5f78b825739a79 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookEmptyMessage.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/CoursebookEmptyMessage.vue
@@ -14,12 +14,12 @@
 </template>
 <script>
 export default {
-  name: 'CoursebookEmptyMessage',
+  name: "CoursebookEmptyMessage",
   props: {
     icon: {
       type: String,
-      default: 'mdi-book-alert-outline',
+      default: "mdi-book-alert-outline",
     },
   },
-}
-</script>
\ No newline at end of file
+};
+</script>
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/Documentation.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/Documentation.vue
index 0891fab875b4e1ea2117cd1b246e4aad7565824e..07918bc166c5b0717b30f11a8d4cf8e252ebadcb 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/Documentation.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/Documentation.vue
@@ -6,10 +6,7 @@
       class="full-width d-flex flex-column align-stretch"
       :class="{ 'flex-md-row': 'compact' in $attrs }"
     >
-      <lesson-information
-        class="flex-grow-1"
-        :documentation="documentation"
-      />
+      <lesson-information class="flex-grow-1" :documentation="documentation" />
       <lesson-summary
         class="flex-grow-1"
         ref="summary"
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
index e67555bb1463f5fc375533801d5a3004d05df803..f5cb72e1b7195f4e14943599e76df5ab0365f332 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/documentation/LessonNotes.vue
@@ -1,19 +1,29 @@
 <template>
-  <v-card-text class="d-flex align-center justify-space-between justify-md-end flex-wrap gap">
+  <v-card-text
+    class="d-flex align-center justify-space-between justify-md-end flex-wrap gap"
+  >
     <v-chip dense color="success">
-      <v-chip small dense class="mr-2" color="green darken-3 white--text">26</v-chip>
+      <v-chip small dense class="mr-2" color="green darken-3 white--text"
+        >26</v-chip
+      >
       von 30 anwesend
     </v-chip>
     <v-chip dense color="warning">
-      <v-chip small dense class="mr-2" color="orange darken-3 white--text">3</v-chip>
+      <v-chip small dense class="mr-2" color="orange darken-3 white--text"
+        >3</v-chip
+      >
       entschuldigt
     </v-chip>
     <v-chip dense color="error">
-      <v-chip small dense class="mr-2" color="red darken-3 white--text">1</v-chip>
+      <v-chip small dense class="mr-2" color="red darken-3 white--text"
+        >1</v-chip
+      >
       unentschuldigt
     </v-chip>
     <v-chip dense color="grey lighten-1">
-      <v-chip small dense class="mr-2" color="grey darken-1 white--text">4</v-chip>
+      <v-chip small dense class="mr-2" color="grey darken-1 white--text"
+        >4</v-chip
+      >
       Hausaufgaben vergessen
     </v-chip>
   </v-card-text>
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 803efbfb8227c8f66597049f099c82b52411cb18..7356d23dad2949092bb31ab292c081c06fdb1e2b 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -1,7 +1,6 @@
 from datetime import date, datetime, timezone
 from typing import Optional, Union
 from urllib.parse import urlparse
-import json
 
 from django.db import models
 from django.db.models import QuerySet
@@ -536,10 +535,12 @@ class Documentation(CalendarEvent):
             "not_amended": True,
         }
         if obj_type is not None and obj_id is not None:
-            event_params.update({
-                "type": obj_type,
-                "id": obj_id,
-            })
+            event_params.update(
+                {
+                    "type": obj_type,
+                    "id": obj_id,
+                }
+            )
 
         events = LessonEvent.get_single_events(
             date_start,
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index 1cfc2ca6526dc921a6d349c39c950fc0fc0cc664..037bf93c3bbf5e9e081d95accb3f56469d2ededf 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -1,7 +1,8 @@
-from django.db.models.query_utils import Q
+from datetime import datetime
+
 from django.core.exceptions import PermissionDenied
+from django.db.models.query_utils import Q
 
-from datetime import datetime
 import graphene
 
 from aleksis.apps.cursus.models import Course
@@ -11,9 +12,9 @@ from aleksis.core.schema.base import FilterOrderList
 from ..models import Documentation
 from .documentation import (
     DocumentationBatchCreateMutation,
+    DocumentationBatchCreateOrUpdateMutation,
     DocumentationBatchPatchMutation,
     DocumentationCreateMutation,
-    DocumentationBatchCreateOrUpdateMutation,
     DocumentationDeleteMutation,
     DocumentationType,
 )
diff --git a/aleksis/apps/alsijil/schema/documentation.py b/aleksis/apps/alsijil/schema/documentation.py
index b72a7f50ffd3fd08fe5e013e7f3ac4687089e652..a2027c54d68deef8b765f3d1d381ba5fbc7f1858 100644
--- a/aleksis/apps/alsijil/schema/documentation.py
+++ b/aleksis/apps/alsijil/schema/documentation.py
@@ -1,4 +1,7 @@
 from datetime import datetime, timezone
+
+from django.core.exceptions import PermissionDenied
+
 import graphene
 from graphene_django.types import DjangoObjectType
 from graphene_django_cud.mutations import (
@@ -8,8 +11,6 @@ from graphene_django_cud.mutations import (
 )
 from guardian.shortcuts import get_objects_for_user
 
-from django.core.exceptions import PermissionDenied
-
 from aleksis.apps.chronos.models import LessonEvent
 from aleksis.core.schema.base import (
     DeleteMutation,
@@ -17,6 +18,7 @@ from aleksis.core.schema.base import (
     PermissionBatchPatchMixin,
     PermissionsTypeMixin,
 )
+
 from ..models import Documentation
 
 
@@ -137,11 +139,12 @@ class DocumentationBatchCreateOrUpdateMutation(graphene.Mutation):
 
     @classmethod
     def create_or_update(cls, info, doc):
-        id = doc.id
+        _id = doc.id
 
-        # 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, datetime_end = id.split(";")
+        # 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, datetime_end = _id.split(";")
             lesson_event = LessonEvent.objects.get(id=lesson_event_id)
 
             if not info.context.user.has_perm(
@@ -149,7 +152,8 @@ class DocumentationBatchCreateOrUpdateMutation(graphene.Mutation):
             ):
                 raise PermissionDenied()
 
-            # Timezone removal is necessary due to ISO style offsets are no valid timezones. Instead, we take the timezone from the lesson_event and save it in a dedicated field.
+            # Timezone removal is necessary due to ISO style offsets are no valid timezones.
+            # Instead, we take the timezone from the lesson_event and save it in a dedicated field.
             return Documentation.objects.create(
                 datetime_start=datetime.fromisoformat(datetime_start).replace(tzinfo=timezone.utc),
                 datetime_end=datetime.fromisoformat(datetime_end).replace(tzinfo=timezone.utc),
@@ -162,7 +166,7 @@ class DocumentationBatchCreateOrUpdateMutation(graphene.Mutation):
                 group_note=doc.group_note or "",
             )
         else:
-            obj = Documentation.objects.get(id=id)
+            obj = Documentation.objects.get(id=_id)
 
             if not info.context.user.has_perm("alsijil.edit_documentation_rule", obj):
                 raise PermissionDenied()
@@ -178,7 +182,7 @@ class DocumentationBatchCreateOrUpdateMutation(graphene.Mutation):
             return obj
 
     @classmethod
-    def mutate(cls, root, info, input):
+    def mutate(cls, root, info, input):  # noqa
         objs = [cls.create_or_update(info, doc) for doc in input]
 
         return DocumentationBatchCreateOrUpdateMutation(documentations=objs)
diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py
index dff299faf8809526a030c8787b189bee40bd61e7..b631299adfb24f07a17d68aff39e70d80de23266 100644
--- a/aleksis/apps/alsijil/util/predicates.py
+++ b/aleksis/apps/alsijil/util/predicates.py
@@ -333,7 +333,8 @@ def is_course_member(user: User, obj: Course):
 def is_course_group_owner(user: User, obj: Course):
     """Predicate for group owners of a course.
 
-    Checks whether the person linked to the user is a owner of any group (and their parent groups) linked to the course.
+    Checks whether the person linked to the user is a owner of any group
+    (or their respective parent groups) linked to the course.
     """
     if obj:
         for g in obj.groups.all():
@@ -366,8 +367,9 @@ def is_lesson_event_member(user: User, obj: LessonEvent):
 def is_lesson_event_group_owner(user: User, obj: LessonEvent):
     """Predicate for group owners of a lesson event.
 
-    Checks whether the person linked to the user is a owner of some group linked to the lesson event,
-    or a owner of some group linked to the course, if the lesson event has one.
+    Checks whether the person linked to the user is a owner of any group
+    (or their respective parent groups) linked to the lesson event,
+    or a owner of any group linked to the course, if the lesson event has one.
     """
     if obj:
         if obj.course and is_course_group_owner(user, obj.course):