From 75ecb91f09e1f1dc1fa9d93f5d022928b75b9c20 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Sun, 23 Jun 2024 17:36:43 +0200
Subject: [PATCH] Introduce permissions for AbsenceCreationDialog

---
 .../absences/AbsenceCreationDialog.vue           |  6 ++++++
 .../coursebook/absences/absenceCreation.graphql  |  2 +-
 aleksis/apps/alsijil/models.py                   |  6 +++---
 aleksis/apps/alsijil/rules.py                    | 11 ++++-------
 aleksis/apps/alsijil/schema/__init__.py          |  7 +++++++
 aleksis/apps/alsijil/schema/absences.py          | 16 ++++++++++------
 aleksis/apps/alsijil/util/predicates.py          |  9 ++-------
 7 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
index 155433e44..e68d40980 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/AbsenceCreationDialog.vue
@@ -11,6 +11,9 @@
         bottom
         fixed
         right
+        :class="{
+          'd-none': !checkPermission('alsijil.view_register_absence_rule'),
+        }"
       >
         <v-icon>$plus</v-icon>
       </create-button>
@@ -106,6 +109,9 @@ export default {
       absenceReason: "",
     };
   },
+  mounted() {
+    this.addPermissions(["alsijil.view_register_absence_rule"]);
+  },
   methods: {
     cancel() {
       this.popup = false;
diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
index f808b469f..21ce30d0b 100644
--- a/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/absences/absenceCreation.graphql
@@ -1,6 +1,6 @@
 # Uses core persons query
 query persons {
-  allPersons: persons {
+  allPersons: absenceCreationPersons {
     id
     fullName
   }
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index b2c0a54fc..8dd46a5a8 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -798,11 +798,11 @@ class ParticipationStatus(CalendarEvent):
         qs = super().get_objects(request, params).select_related("person", "absence_reason")
         if params:
             if params.get("person"):
-                qs = qs.filter(person_id=params["person"])
+                qs = qs.filter(person=params["person"])
             elif params.get("persons"):
-                qs = qs.filter(person_id__in=params["persons"])
+                qs = qs.filter(person__in=params["persons"])
             elif params.get("group"):
-                qs = qs.filter(groups_of_person__id=params.get("group"))
+                qs = qs.filter(groups_of_person__in=params.get("group"))
         return qs
 
     @classmethod
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index 9045598fd..836c7383f 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -169,19 +169,16 @@ add_perm("alsijil.view_week_personalnote_rule", view_week_personal_notes_predica
 
 # Register absence
 view_register_absence_predicate = has_person & (
-    (
-        is_person_group_owner
-        & is_site_preference_set("alsijil", "register_absence_as_primary_group_owner")
-    )
-    | has_global_perm("alsijil.register_absence")
+    is_person_group_owner | has_global_perm("alsijil.register_absence")
 )
+add_perm("alsijil.view_register_absence_rule", view_register_absence_predicate)
 
 register_absence_predicate = has_person & (
-    view_register_absence_predicate
+    is_group_owner
+    | has_global_perm("alsijil.register_absence")
     | has_object_perm("core.register_absence_person")
     | has_person_group_object_perm("core.register_absence_group")
 )
-add_perm("alsijil.view_register_absence_rule", view_register_absence_predicate)
 add_perm("alsijil.register_absence_rule", register_absence_predicate)
 
 # View full register for group
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index 397834be0..2634a297d 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -44,6 +44,7 @@ class Query(graphene.ObjectType):
     groups_by_person = FilterOrderList(GroupType, person=graphene.ID())
     courses_of_person = FilterOrderList(CourseType, person=graphene.ID())
 
+    absence_creation_persons = graphene.List(PersonType)
     lessons_for_persons = graphene.List(
         LessonsForPersonType,
         persons=graphene.List(graphene.ID, required=True),
@@ -147,6 +148,12 @@ class Query(graphene.ObjectType):
             | Q(groups__parent_groups__owners=person)
         )
 
+    @staticmethod
+    def resolve_absence_creation_persons(root, info, **kwargs):
+        if not info.context.user.has_perm("alsijil.register_absence"):
+            return Person.objects.filter(member_of__owners=info.context.user.person)
+        return Person.objects.all()
+
     @staticmethod
     def resolve_lessons_for_persons(
         root,
diff --git a/aleksis/apps/alsijil/schema/absences.py b/aleksis/apps/alsijil/schema/absences.py
index ff7bf0376..8560ee73e 100644
--- a/aleksis/apps/alsijil/schema/absences.py
+++ b/aleksis/apps/alsijil/schema/absences.py
@@ -1,6 +1,11 @@
+from datetime import datetime
+
+from django.core.exceptions import PermissionDenied
+
 import graphene
 
 from aleksis.apps.kolego.models import Absence
+from aleksis.core.models import Person
 
 from ..models import ParticipationStatus
 from .participation_status import ParticipationStatusType
@@ -19,17 +24,18 @@ class AbsencesForPersonsCreateMutation(graphene.Mutation):
 
     @classmethod
     def mutate(cls, root, info, persons, start, end, comment, reason):  # noqa
-        # TODO: Check permissions for ParticipationStatus & KolegoAbsence
-        #       See MR 356
-
         participation_statuses = []
 
+        persons = Person.objects.filter(pk__in=persons)
+
         for person in persons:
+            if not info.context.user.has_perm("alsijil.register_absence_rule", person):
+                raise PermissionDenied()
             kolego_absence, __ = Absence.objects.get_or_create(
                 date_start=start,
                 date_end=end,
                 reason_id=reason,
-                person_id=person,
+                person=person,
                 comment=comment,
             )
 
@@ -41,14 +47,12 @@ class AbsencesForPersonsCreateMutation(graphene.Mutation):
                 with_reference_object=True,
             )
 
-            # Create a ParticipationStatus for each documentation
             for event in events:
                 participation_status = event["REFERENCE_OBJECT"]
                 participation_status.absence_reason_id = reason
                 participation_status.base_absence = kolego_absence
                 participation_status.save()
                 participation_statuses.append(participation_status)
-                # Set person & absence_reason directly from id
 
         return AbsencesForPersonsCreateMutation(
             ok=True, participation_statuses=participation_statuses
diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py
index 9f06195e2..6dea3844a 100644
--- a/aleksis/apps/alsijil/util/predicates.py
+++ b/aleksis/apps/alsijil/util/predicates.py
@@ -93,19 +93,14 @@ def is_group_owner(user: User, obj: Union[Group, Person]) -> bool:
 
 
 @predicate
-def is_person_group_owner(user: User, obj: Person) -> bool:
+def is_person_group_owner(user: User, obj) -> bool:
     """
     Predicate for group owners of any group.
 
     Checks whether the person linked to the user is
     the owner of any group of the given person.
     """
-    if obj:
-        for group in use_prefetched(obj, "member_of"):
-            if user.person in use_prefetched(group, "owners"):
-                return True
-        return False
-    return False
+    return Group.objects.filter(owners=user.person).exists()
 
 
 def use_prefetched(obj, attr):
-- 
GitLab