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

Handle public instances in the ACL mixin

parent adbf5946
No related branches found
No related tags found
No related merge requests found
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.db.models import Q, functions
from django.db.models import IntegerField, Q, Value, functions
from django.shortcuts import get_object_or_404
from django.views.decorators.cache import cache_page
from rest_framework.exceptions import APIException, ValidationError
......@@ -28,43 +28,48 @@ class ACLMixin(object):
def user(self):
return self._user or self.request.user
def get_public_instances(self, model, default_level):
return model.objects \
.filter(public=True) \
.annotate(max_level=Value(default_level, IntegerField()))
def rights_filter(self, model, level, public=False):
"""
Return a model queryset matching a given access level for this user
Return a model queryset matching a given access level for this user.
"""
# Handle specific cases (i.e. admin or anonymous user)
if self.user.is_admin or self.user.is_internal:
return model.objects.all()
elif user.is_anonymous:
if level > Role.Guest.value or not public:
return model.objects.all().annotate(max_level=Value(Role.Admin.value))
elif self.user.is_anonymous:
if not public:
return model.objects.none()
else:
return model.objects.filter(public=True)
return self.get_public_instances(model, Role.Guest.value)
# Filter users rights and annotate the resulting level for those rights
queryset = model.objects \
.filter(
# Filter instances with direct and groups rights for this user (They may be duplicated)
# Filter instances with rights concerning this user. This may create duplicates
Q(memberships__user=self.user)
| Q(memberships__group__memberships__user=self.user)
) \
.annotate(
# Keep only the lowest level for each right via group
max_level=functions.Least(
# In case of direct right, group level will be skipped (Null value)
'memberships__level',
# In case of direct right, the group level will be skipped (Null value)
'memberships__group__memberships__level'
)
) \
.filter(
# Ensure one of the right has an adequate level
max_level__gte=level
)
# Ensure one of the right has an adequate level
queryset = queryset.filter(max_level__gte=level)
if (public):
# Allow access to public instances if the public parameter is set
queryset = queryset | model.objects.filter(public=True)
# Use a join to add public instances as this is the more elegant solution
if public and level <= Role.Guest.value:
queryset = queryset.union(self.get_public_instances(model, Role.Guest.value))
return queryset.distinct()
# Return distinct corpus with the max right level among matching rights
return queryset.order_by('id', '-max_level').distinct('id')
def has_access(self, instance, level):
if self.user.is_admin or self.user.is_internal:
......@@ -86,11 +91,13 @@ class ACLMixin(object):
class RepositoryACLMixin(ACLMixin):
@property
def readable_repositories(self):
return self.rights_filter(Repository, Role.Guest.value, public=False)
return self.rights_filter(Repository, Role.Guest.value)
@property
def executable_repositories(self):
return self.rights_filter(Repository, Role.Contributor.value, public=False)
return self.rights_filter(Repository, Role.Contributor.value)
def has_read_access(self, repo):
return self.has_access(repo, Role.Guest.value)
......@@ -103,12 +110,16 @@ class RepositoryACLMixin(ACLMixin):
class NewCorpusACLMixin(ACLMixin):
@property
def readable_corpora(self):
return self.rights_filter(Corpus, Role.Guest.value, public=True)
@property
def writable_corpora(self):
return self.rights_filter(Corpus, Role.Contributor.value)
@property
def administrable_corpora(self):
return self.rights_filter(Corpus, Role.Admin.value)
......
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