Skip to content
Snippets Groups Projects
Commit 189d571f authored by Valentin Rigal's avatar Valentin Rigal
Browse files

Implement the force approach

parent da402551
No related branches found
No related tags found
No related merge requests found
from django.conf import settings from django.conf import settings
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db.models import IntegerField, Q, Value, functions from django.db.models import Case, IntegerField, Q, Value, When, functions
from django.db.models.query_utils import DeferredAttribute from django.db.models.query_utils import DeferredAttribute
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.views.decorators.cache import cache_page from django.views.decorators.cache import cache_page
...@@ -44,7 +44,7 @@ class ACLMixin(object): ...@@ -44,7 +44,7 @@ class ACLMixin(object):
.filter(public=True) \ .filter(public=True) \
.annotate(max_level=Value(default_level, IntegerField())) .annotate(max_level=Value(default_level, IntegerField()))
def rights_filter(self, model, level, public=False): def rights_filter(self, model, level):
""" """
Return a model queryset matching a given access level for this user. Return a model queryset matching a given access level for this user.
""" """
...@@ -64,33 +64,52 @@ class ACLMixin(object): ...@@ -64,33 +64,52 @@ class ACLMixin(object):
.annotate(max_level=Value(Role.Admin.value, IntegerField())) \ .annotate(max_level=Value(Role.Admin.value, IntegerField())) \
.order_by(*self.mixin_order_by_fields, 'id') .order_by(*self.mixin_order_by_fields, 'id')
# Filter users rights and annotate the resulting level for those rights qs_filters = (
queryset = model.objects \ # Filter corpora with a right (direct or via a group)
.filter( Q(memberships__user=self.user)
# Filter instances with rights concerning this user. This may create duplicates # Note: in case of direct right, the group level will be skipped (Null value)
Q(memberships__user=self.user) | Q(memberships__group__memberships__user=self.user)
| Q(memberships__group__memberships__user=self.user) )
) \ if include_public:
.annotate( # Also match public corpora for which this user has no right
# Keep only the lowest level for each right via group qs_filters |= Q(
max_level=functions.Least( Q(public=True)
'memberships__level', & ~Q(memberships__user=self.user)
# In case of direct right, the group level will be skipped (Null value) & ~Q(memberships__group__memberships__user=self.user)
'memberships__group__memberships__level'
)
) )
# Order by decreasing max_level to make sure we keep the max among all rights # Annotate instances for each right. This may return duplicated instances
queryset = queryset.filter(max_level__gte=level) \ max_level_annotation = functions.Least(
.order_by(*self.mixin_order_by_fields, 'id', '-max_level') \ 'memberships__level',
.distinct(*self.mixin_order_by_fields, 'id') # In case of direct right, group level will be skipped (Null value)
'memberships__group__memberships__level'
# Use a join to add public instances as this is the more elegant solution )
if include_public: if include_public:
queryset = queryset.union(self.get_public_instances(model, Role.Guest.value)) # Also annotate public instances with no member right
max_level_annotation = Case(
When(
Q(
Q(public=True)
& ~Q(memberships__user=self.user)
& ~Q(memberships__group__memberships__user=self.user)
),
# Set the rôle to guest on public instances
then=Value(Role.Guest.value)
),
default=max_level_annotation,
output_field=IntegerField()
)
# Return distinct corpus with the max right level among matching rights # Return distinct corpus with the max right level among matching rights
return queryset.order_by(*self.mixin_order_by_fields, 'id') return model.objects \
.filter(qs_filters) \
.annotate(max_level=max_level_annotation) \
.filter(max_level__gte=level) \
.order_by(
# Order by decreasing max_level to make sure we keep the max among all rights
*self.mixin_order_by_fields, 'id', '-max_level'
) \
.distinct(*self.mixin_order_by_fields, 'id')
def has_access(self, instance, level): def has_access(self, instance, level):
self._check_level(level) self._check_level(level)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment