From 84e8b02594f5455d80c9c901d449d19dfd570a68 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 28 Jul 2020 15:25:08 +0200 Subject: [PATCH] :bug: Calculating permissions faster --- apps/activity/views.py | 3 +++ apps/member/views.py | 2 +- apps/permission/backends.py | 50 +++++++++++++------------------------ 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/apps/activity/views.py b/apps/activity/views.py index df3f00ea..7bc8def5 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -38,6 +38,9 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView table_class = ActivityTable ordering = ('-date_start',) + def get_queryset(self): + return super().get_queryset().distinct() + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) diff --git a/apps/member/views.py b/apps/member/views.py index 614c5bc1..9d6b34e5 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -642,7 +642,7 @@ class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): del form.fields['bank'] club = self.object.club - form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=isinstance(club, WEIClub)) + form.fields['roles'].queryset = Role.objects.filter(Q(weirole__isnull=not isinstance(club, WEIClub)) & (Q(for_club__isnull=True) | Q(for_club=club))).all() return form diff --git a/apps/permission/backends.py b/apps/permission/backends.py index 99f1b2da..374e67e6 100644 --- a/apps/permission/backends.py +++ b/apps/permission/backends.py @@ -36,27 +36,20 @@ class PermissionBackend(ModelBackend): # Unauthenticated users have no permissions return Permission.objects.none() - qs = Permission.objects.annotate( - club=F("role__membership__club"), - membership=F("role__membership"), - ).filter( - ( - Q( - role__membership__date_start__lte=timezone.now().today(), - role__membership__date_end__gte=timezone.now().today(), - ) - | Q(permanent=True) - ) - & Q(role__membership__user=user) - & Q(type=t) - & Q(mask__rank__lte=get_current_session().get("permission_mask", 0)) - ) + memberships = Membership.objects.filter(user=user).all() + + perms = [] + + for membership in memberships: + for role in membership.roles.all(): + for perm in role.permissions.filter(type=t, mask__rank__lte=get_current_session().get("permission_mask", 42)).all(): + if not perm.permanent: + if membership.date_start > timezone.now().date() or membership.date_end < timezone.now().date(): + continue + perm.membership = membership + perms.append(perm) + return perms - if settings.DATABASES[qs.db]["ENGINE"] == 'django.db.backends.postgresql_psycopg2': - qs = qs.distinct('pk', 'club') - else: # SQLite doesn't support distinct fields. - qs = qs.distinct() - return qs @staticmethod def permissions(user, model, type): @@ -67,22 +60,13 @@ class PermissionBackend(ModelBackend): :param type: The type of the permissions: view, change, add or delete :return: A generator of the requested permissions """ - clubs = {} - memberships = {} for permission in PermissionBackend.get_raw_permissions(user, type): - if not isinstance(model.model_class()(), permission.model.model_class()) or not permission.club: + if not isinstance(model.model_class()(), permission.model.model_class()) or not permission.membership: continue - if permission.club not in clubs: - clubs[permission.club] = club = Club.objects.get(pk=permission.club) - else: - club = clubs[permission.club] - - if permission.membership not in memberships: - memberships[permission.membership] = membership = Membership.objects.get(pk=permission.membership) - else: - membership = memberships[permission.membership] + membership = permission.membership + club = membership.club permission = permission.about( user=user, @@ -113,7 +97,6 @@ class PermissionBackend(ModelBackend): :param field: The field of the model to test, if concerned :return: A query that corresponds to the filter to give to a queryset """ - if user is None or isinstance(user, AnonymousUser): # Anonymous users can't do anything return Q(pk=-1) @@ -163,6 +146,7 @@ class PermissionBackend(ModelBackend): perm = perm.split('.')[-1].split('_', 2) perm_type = perm[0] perm_field = perm[2] if len(perm) == 3 else None + ct = ContentType.objects.get_for_model(obj) if any(permission.applies(obj, perm_type, perm_field) for permission in PermissionBackend.permissions(user_obj, ct, perm_type)):