From 3312ca427104c646e8ef639f1e3058a76b1a3396 Mon Sep 17 00:00:00 2001 From: Hangzhi Yu <hangzhi@protonmail.com> Date: Mon, 13 Jan 2025 12:06:32 +0100 Subject: [PATCH] Use annotation mechanism to make statistics page permission checking faster --- aleksis/apps/alsijil/schema/__init__.py | 122 +++++++++++++++++- .../alsijil/schema/participation_status.py | 4 + aleksis/apps/alsijil/schema/personal_note.py | 4 + 3 files changed, 127 insertions(+), 3 deletions(-) diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py index f337be4f..4c026343 100644 --- a/aleksis/apps/alsijil/schema/__init__.py +++ b/aleksis/apps/alsijil/schema/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime -from django.db.models import BooleanField, ExpressionWrapper, Q +from django.db.models import BooleanField, ExpressionWrapper, F, Q, Value import graphene import graphene_django_optimizer @@ -308,13 +308,71 @@ class Query(graphene.ObjectType): if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person): return [] school_term = get_active_school_term(info.context) + global_perm = info.context.user.has_perm("alsijil.change_participationstatus") return graphene_django_optimizer.query( ParticipationStatus.objects.filter( Q(absence_reason__isnull=False) | Q(tardiness__isnull=False), person=person, datetime_start__date__gte=school_term.date_start, datetime_end__date__lte=school_term.date_end, - ).order_by("-related_documentation__datetime_start"), + ) + .annotate( + can_edit=ExpressionWrapper( + Value(global_perm) + or ExpressionWrapper( + Q(related_documentation__isnull=False) + & ( + Q(related_documentation__amends__isnull=False) + | Q(related_documentation__amends__cancelled=False) + ) + & ( + Q(related_documentation__teachers__contains=info.context.user.person) + | ( + Q(related_documentation__amends__teachers__isnull=False) + & Q( + related_documentation__amends__teachers__contains=info.context.user.person + ) + ) + | ( + Q(related_documentation__amends__amends__teachers__isnull=False) + & Q( + related_documentation__amends__amends__teachers__contains=info.context.user.person + ) + ) + | ( + ( + Q(related_documentation__amends__isnull=False) + & ( + Q( + related_documentation__amends__groups__owners__contains=info.context.user.person + ) + | Q( + related_documentation__amends__groups__parent_groups__owners__contains=info.context.user.person + ) + ) + ) + | ( + Q(related_documentation__amends__amends__isnull=False) + & ( + Q( + related_documentation__amends__amends__groups__owners__contains=info.context.user.person + ) + | Q( + related_documentation__amends__amends__groups__parent_groups__owners__contains=info.context.user.person + ) + ) + ) + ) + ), + output_field=BooleanField(), + ), + output_field=BooleanField(), + ), + ) + .annotate( + can_delete=F("can_edit"), + ) + .order_by("-related_documentation__datetime_start"), info, ) @@ -324,6 +382,7 @@ class Query(graphene.ObjectType): if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person): return [] school_term = get_active_school_term(info.context) + global_perm = info.context.user.has_perm("alsijil.change_newpersonalnote") return graphene_django_optimizer.query( NewPersonalNote.objects.filter( person=person, @@ -331,7 +390,64 @@ class Query(graphene.ObjectType): datetime_start__date__gte=school_term.date_start, datetime_end__date__lte=school_term.date_end, ), - ).order_by("-documentation__datetime_start"), + ) + .annotate( + can_edit=ExpressionWrapper( + Value(global_perm) + or ExpressionWrapper( + Q(documentation__isnull=False) + & ( + Q(documentation__amends__isnull=False) + | Q(documentation__amends__cancelled=False) + ) + & ( + Q(documentation__teachers__contains=info.context.user.person) + | ( + Q(documentation__amends__teachers__isnull=False) + & Q( + documentation__amends__teachers__contains=info.context.user.person + ) + ) + | ( + Q(documentation__amends__amends__teachers__isnull=False) + & Q( + documentation__amends__amends__teachers__contains=info.context.user.person + ) + ) + | ( + ( + Q(documentation__amends__isnull=False) + & ( + Q( + documentation__amends__groups__owners__contains=info.context.user.person + ) + | Q( + documentation__amends__groups__parent_groups__owners__contains=info.context.user.person + ) + ) + ) + | ( + Q(documentation__amends__amends__isnull=False) + & ( + Q( + documentation__amends__amends__groups__owners__contains=info.context.user.person + ) + | Q( + documentation__amends__amends__groups__parent_groups__owners__contains=info.context.user.person + ) + ) + ) + ) + ), + output_field=BooleanField(), + ), + output_field=BooleanField(), + ), + ) + .annotate( + can_delete=F("can_edit"), + ) + .order_by("-documentation__datetime_start"), info, ) diff --git a/aleksis/apps/alsijil/schema/participation_status.py b/aleksis/apps/alsijil/schema/participation_status.py index bb90b9be..25df9ff3 100644 --- a/aleksis/apps/alsijil/schema/participation_status.py +++ b/aleksis/apps/alsijil/schema/participation_status.py @@ -70,10 +70,14 @@ class ParticipationStatusType( @staticmethod def resolve_can_edit(root: ParticipationStatus, info, **kwargs): + if hasattr(root, "can_edit"): + return root.can_edit return info.context.user.has_perm("alsijil.edit_participation_status_rule", root) @staticmethod def resolve_can_delete(root: ParticipationStatus, info, **kwargs): + if hasattr(root, "can_delete"): + return root.can_delete return info.context.user.has_perm("alsijil.edit_participation_status_rule", root) diff --git a/aleksis/apps/alsijil/schema/personal_note.py b/aleksis/apps/alsijil/schema/personal_note.py index f902639f..9598a277 100644 --- a/aleksis/apps/alsijil/schema/personal_note.py +++ b/aleksis/apps/alsijil/schema/personal_note.py @@ -28,10 +28,14 @@ class PersonalNoteType( @staticmethod def resolve_can_edit(root: NewPersonalNote, info, **kwargs): + if hasattr(root, "can_edit"): + return root.can_edit return info.context.user.has_perm("alsijil.edit_personal_note_rule", root) @staticmethod def resolve_can_delete(root: NewPersonalNote, info, **kwargs): + if hasattr(root, "can_delete"): + return root.can_delete return info.context.user.has_perm("alsijil.edit_personal_note_rule", root) -- GitLab