Projet

Général

Profil

0002-django_rbac-annotate-roles-with-actual-auth-level-gi.patch

Valentin Deniaud, 05 juin 2019 14:30

Télécharger (3,25 ko)

Voir les différences:

Subject: [PATCH 2/3] django_rbac: annotate roles with actual auth level given
 context
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Example when this is useful :
A user has role R1 with an auth level of 2. R1 inherits from R2 (ie R1
is child, R2 is parent). When looking for the roles of the user
(Roles.objects.for_user(user)), we will get R1 and R2. Then we might
want to know which authentication level the user has to get in order to
be allowed to use R2. The good answer is 2, although R2.auth_level is 1.
This commit adds a way to find out the good answer.

Note : il y a un cas limite où ça devrait ne pas marcher, pourtant si,
et je sais pas pourquoi.
Si un utilisateur a R1 et R2, deux rôles de niv 2.
R1 hérite de R3 (niv 1) et R2 hérite de R4 (niv 1).
Jusque là la solution fonctionne.
Et maintenant si R3 hérite de R4 ? Pour déterminer le needed_auth_level
de R4, je pensais qu'on se retrouverait à faire :
min(niv(fils_de_R4)) = min(niv(R2, R3)) = min(2, 1) = 1
Ce qui serait bien sûr faux.
Ben dans mes tests set_needed_auth_level lui met un needed_auth_level de
2, mais je sais pas ce qui le fait marcher exactement !
À confirmer par un test très clair, quand on en sera à écrire des tests.
 src/django_rbac/managers.py | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)
src/django_rbac/managers.py
2 2
import threading
3 3

  
4 4
from django.db import models
5
from django.db.models import query
5
from django.db.models import query, Min, Case, When
6 6
from django.contrib.contenttypes.models import ContentType
7 7
from django.db.models.query import Q, Prefetch
8 8
from django.contrib.auth import get_user_model
......
103 103

  
104 104

  
105 105
class RoleQuerySet(query.QuerySet):
106
    def for_user(self, user, max_auth_level=None):
106
    def for_user(self, user, max_auth_level=None, annotate=False):
107 107
        qs = self.filter(members=user)
108 108
        if max_auth_level:
109 109
            qs = qs.filter(auth_level__lte=max_auth_level)
110 110
        qs = qs.parents()
111 111
        if max_auth_level:
112 112
            qs = qs.filter(auth_level__lte=max_auth_level)
113
        return qs.distinct()
113
        qs = qs.distinct()
114
        if annotate:
115
            qs = qs.set_needed_auth_levels(user)
116
        return qs
114 117

  
115 118
    def parents(self, include_self=True, annotate=False):
116 119
        qs = self.model.objects.filter(child_relation__child__in=self)
......
121 124
            qs = qs.annotate(direct=models.Max(IntCast('child_relation__direct')))
122 125
        return qs
123 126

  
127
    def set_needed_auth_levels(self, user):
128
        return self.annotate(needed_auth_level=Case(
129
            When(~Q(members=user), then=Min('child_relation__child__auth_level')),
130
            default='auth_level'
131
        ))
132

  
124 133
    def children(self, include_self=True, annotate=False):
125 134
        qs = self.model.objects.filter(parent_relation__parent__in=self)
126 135
        if include_self:
127
-