From f2045a9be35ccad4e08037c92482d00ac654a120 Mon Sep 17 00:00:00 2001 From: Hangzhi Yu <hangzhi@protonmail.com> Date: Tue, 21 May 2024 11:18:24 +0200 Subject: [PATCH] Fix permissions --- aleksis/apps/chronos/managers.py | 9 +++++++++ aleksis/apps/chronos/models.py | 9 +++++++++ aleksis/apps/chronos/rules.py | 12 +++++++++++- aleksis/apps/chronos/schema/__init__.py | 4 ++-- aleksis/apps/chronos/util/predicates.py | 25 ++++++++++++++++++++----- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/aleksis/apps/chronos/managers.py b/aleksis/apps/chronos/managers.py index dd63807a..532e49cc 100644 --- a/aleksis/apps/chronos/managers.py +++ b/aleksis/apps/chronos/managers.py @@ -885,6 +885,15 @@ class LessonEventQuerySet(PolymorphicQuerySet): Q(groups__members=person) | Q(pk__in=amended) ).distinct() + def for_owner(self, person: Union[int, Person]) -> "LessonEventQuerySet": + """Get all lesson events the person owns any group of (including amends).""" + amended = self.filter( + Q(amended_by__isnull=False) | Q(groups__owners=person) + ).values_list("amended_by__pk", flat=True) + return self.filter( + Q(groups__owners=person) | Q(pk__in=amended) + ).distinct() + def for_group(self, group: Union[int, Group]) -> "LessonEventQuerySet": """Get all lesson events for a certain group (including amends/as parent group).""" amended = self.filter( diff --git a/aleksis/apps/chronos/models.py b/aleksis/apps/chronos/models.py index d27e4c6a..815b312b 100644 --- a/aleksis/apps/chronos/models.py +++ b/aleksis/apps/chronos/models.py @@ -1567,6 +1567,8 @@ class LessonEvent(CalendarEvent): return objs.for_room(obj_id) elif type_ == "COURSE": return objs.for_course(obj_id) + elif type_ == "OWNER": + return objs.for_owner(obj_id) if "own" in params: return objs @@ -1601,6 +1603,13 @@ class LessonEvent(CalendarEvent): "id": obj_id, } ) + else: + event_params.update( + { + "type": "OWNER", + "id": request.user.person.id, + } + ) events = LessonEvent.get_single_events( date_start, date_end, request, event_params, with_reference_object=True diff --git a/aleksis/apps/chronos/rules.py b/aleksis/apps/chronos/rules.py index 03ef88c2..65659458 100644 --- a/aleksis/apps/chronos/rules.py +++ b/aleksis/apps/chronos/rules.py @@ -12,6 +12,7 @@ from .util.predicates import ( has_any_group_substitution_perm, has_any_timetable_object, has_group_substitution_perm, + has_substitution_perm_by_group, has_room_timetable_perm, has_timetable_perm, ) @@ -41,9 +42,18 @@ add_perm("chronos.view_substitution_overview_rule", view_substitution_overview_p manage_substitutions_for_group_predicate = has_person & has_group_substitution_perm add_perm("chronos.manage_substitutions_for_group_rule", manage_substitutions_for_group_predicate) +# Add substitution +add_substitution_predicate = has_person & ( + has_substitution_perm_by_group + | has_global_perm("chronos.add_lessonsubstitution") + | has_object_perm("chronos.add_lessonsubstitution") +) +add_perm("chronos.add_substitution_rule", add_substitution_predicate) + # Edit substition edit_substitution_predicate = has_person & ( - has_global_perm("chronos.change_lessonsubstitution") + has_substitution_perm_by_group + | has_global_perm("chronos.change_lessonsubstitution") | has_object_perm("chronos.change_lessonsubstitution") ) add_perm("chronos.edit_substitution_rule", edit_substitution_predicate) diff --git a/aleksis/apps/chronos/schema/__init__.py b/aleksis/apps/chronos/schema/__init__.py index f0beaf9d..d2f1c747 100644 --- a/aleksis/apps/chronos/schema/__init__.py +++ b/aleksis/apps/chronos/schema/__init__.py @@ -189,7 +189,7 @@ class SubstitutionBatchCreateOrUpdateMutation(graphene.Mutation): amended_lesson_event.timezone ) - if info.context.user.has_perm("chronos.change_lessonsubstitution"): + if info.context.user.has_perm("chronos.add_substitution_rule", amended_lesson_event): obj = LessonEvent.objects.create( datetime_start=datetime_start, datetime_end=datetime_end, @@ -208,7 +208,7 @@ class SubstitutionBatchCreateOrUpdateMutation(graphene.Mutation): else: obj = LessonEvent.objects.get(id=_id) - if not info.context.user.has_perm("chronos.edit_substitution_rule", obj): + if not info.context.user.has_perm("chronos.edit_substitution_rule", obj.amends): raise PermissionDenied() if substitution.subject is not None: diff --git a/aleksis/apps/chronos/util/predicates.py b/aleksis/apps/chronos/util/predicates.py index 8549177f..f9103c12 100644 --- a/aleksis/apps/chronos/util/predicates.py +++ b/aleksis/apps/chronos/util/predicates.py @@ -4,9 +4,11 @@ from django.db.models import Model from rules import predicate from aleksis.core.models import Group, Person, Room +from aleksis.core.util.core_helpers import queryset_rules_filter from aleksis.core.util.predicates import has_any_object, has_global_perm, has_object_perm from .chronos_helpers import get_groups, get_rooms, get_teachers +from ..models import LessonEvent @predicate @@ -44,13 +46,27 @@ def has_group_timetable_perm(user: User, obj: Group) -> bool: ) +@predicate +def has_substitution_perm_by_group(user: User, obj: LessonEvent) -> bool: + """ + Check if can create/edit substitution based on group. + + Predicate which checks whether the user is allowed + to create/edit the requested substitution. + """ + return ( + obj.groups.filter(pk__in=user.person.owner_of.values_list("id", flat=True)).exists() + or queryset_rules_filter(user, obj.groups.all(), "core.manage_group_substitutions").exists() + ) + + @predicate def has_group_substitution_perm(user: User, obj: Group) -> bool: """ - Check if can access/edit group substitutions. + Check if can access/edit substitutions of given group. Predicate which checks whether the user is allowed - to access/edit the requested group substitutions. + to access/edit the substitutions of the given group. """ return ( obj in user.person.owner_of.all() @@ -62,14 +78,13 @@ def has_group_substitution_perm(user: User, obj: Group) -> bool: @predicate def has_any_group_substitution_perm(user: User) -> bool: """ - Check if can access/edit any group substitutions. + Check if can create/edit substitutions of any group. Predicate which checks whether the user is allowed - to access/edit any group substitutions. + to create/edit any substitutions of any group. """ return ( user.person.owner_of.exists() - or has_global_perm("chronos.view_lessonsubstitution")(user) or has_any_object("core.manage_group_substitutions", Group)(user) ) -- GitLab