8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-27 07:02:26 +00:00

Add can_list acl, move views autocomplete mixins to re2o/views.py

This commit is contained in:
chirac 2020-12-30 19:06:09 +01:00 committed by Gabriel Detraz
parent b418719ef7
commit 4df53ca902
7 changed files with 63 additions and 13 deletions

View file

@ -37,7 +37,7 @@ from .models import (
Banque Banque
) )
from re2o.mixins import AutocompleteViewMixin from re2o.views import AutocompleteViewMixin
from re2o.acl import ( from re2o.acl import (
can_view_all, can_view_all,

View file

@ -369,6 +369,15 @@ def can_view_all(*targets):
return acl_base_decorator("can_view_all", *targets, on_instance=False) return acl_base_decorator("can_view_all", *targets, on_instance=False)
def can_list(*targets):
"""Decorator to check if an user can list a class of model.
It runs `acl_base_decorator` with the flag `on_instance=False` and the
method 'can_list'. See `acl_base_decorator` documentation for further
details.
"""
return acl_base_decorator("can_list", *targets, on_instance=False)
def can_view_app(*apps_name): def can_view_app(*apps_name):
"""Decorator to check if an user can view the applications.""" """Decorator to check if an user can view the applications."""
for app_name in apps_name: for app_name in apps_name:

View file

@ -29,6 +29,7 @@ from django.utils.translation import ugettext as _
from dal import autocomplete from dal import autocomplete
class RevMixin(object): class RevMixin(object):
"""A mixin to subclass the save and delete function of a model """A mixin to subclass the save and delete function of a model
to enforce the versioning of the object before those actions to enforce the versioning of the object before those actions
@ -80,6 +81,8 @@ class AclMixin(object):
:can_view: Applied on an instance, return if the user can view the :can_view: Applied on an instance, return if the user can view the
instance instance
:can_view_all: Applied on a class, return if the user can view all :can_view_all: Applied on a class, return if the user can view all
instances
:can_list: Applied on a class, return if the user can list all
instances""" instances"""
@classmethod @classmethod
@ -209,6 +212,28 @@ class AclMixin(object):
(permission,), (permission,),
) )
@classmethod
def can_list(cls, user_request, *_args, **_kwargs):
"""Check if a user can list all instances of an object
Parameters:
user_request: User calling for this action
Returns:
Boolean: True if user_request has the right access to do it, else
false with reason for reject authorization
"""
permission = cls.get_modulename() + ".view_" + cls.get_classname()
can = user_request.has_perm(permission)
return (
can,
_("You don't have the right to list every %s object.") % cls.get_classname()
if not can
else None,
(permission,),
cls.objects.all() if can else None,
)
def can_view(self, user_request, *_args, **_kwargs): def can_view(self, user_request, *_args, **_kwargs):
"""Check if a user can view an instance of an object """Check if a user can view an instance of an object
@ -272,13 +297,3 @@ class AutocompleteMultipleModelMixin(autocomplete.ModelSelect2Multiple):
attrs["data-minimum-results-for-search"] = attrs.get("data-minimum-results-for-search", 10) attrs["data-minimum-results-for-search"] = attrs.get("data-minimum-results-for-search", 10)
return attrs return attrs
class AutocompleteViewMixin(autocomplete.Select2QuerySetView):
obj_type = None # This MUST be overridden by child class
query_filter = "name__icontains" # Override this if necessary
def get_queryset(self):
query_set = self.obj_type.objects.all()
if self.q:
query_set = query_set.filter(**{ self.query_filter: self.q})
return query_set

View file

@ -141,6 +141,8 @@ def get_callback(tag_name, obj=None):
return acl_fct(obj.can_view_all, False) return acl_fct(obj.can_view_all, False)
if tag_name == "cannot_view_all": if tag_name == "cannot_view_all":
return acl_fct(obj.can_view_all, True) return acl_fct(obj.can_view_all, True)
if tag_name == "can_list":
return acl_fct(obj.can_list, False)
if tag_name == "can_view_app": if tag_name == "can_view_app":
return acl_fct( return acl_fct(
lambda x: ( lambda x: (
@ -296,6 +298,7 @@ def acl_change_filter(parser, token):
@register.tag("cannot_delete_all") @register.tag("cannot_delete_all")
@register.tag("can_view_all") @register.tag("can_view_all")
@register.tag("cannot_view_all") @register.tag("cannot_view_all")
@register.tag("can_list")
def acl_model_filter(parser, token): def acl_model_filter(parser, token):
"""Generic definition of an acl templatetag for acl based on model""" """Generic definition of an acl templatetag for acl based on model"""

View file

@ -33,6 +33,10 @@ from django.template.context_processors import csrf
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.views.decorators.cache import cache_page from django.views.decorators.cache import cache_page
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.decorators import method_decorator
from dal import autocomplete
from preferences.models import ( from preferences.models import (
Service, Service,
@ -43,6 +47,7 @@ from preferences.models import (
Mandate, Mandate,
) )
from .acl import can_list
from .contributors import CONTRIBUTORS from .contributors import CONTRIBUTORS
from importlib import import_module from importlib import import_module
from re2o.settings_local import OPTIONNAL_APPS_RE2O from re2o.settings_local import OPTIONNAL_APPS_RE2O
@ -169,3 +174,21 @@ def handler500(request):
def handler404(request): def handler404(request):
"""The handler view for a 404 error""" """The handler view for a 404 error"""
return render(request, "errors/404.html", status=404) return render(request, "errors/404.html", status=404)
class AutocompleteViewMixin(LoginRequiredMixin, autocomplete.Select2QuerySetView):
obj_type = None # This MUST be overridden by child class
query_set = None
query_filter = "name__icontains" # Override this if necessary
def get_queryset(self):
can, reason, _permission, query_set = self.obj_type.can_list(self.request.user)
self.query_set = query_set
if hasattr(self, "filter_results"):
self.filter_results()
else:
if self.q:
self.query_set = self.query_set.filter(**{ self.query_filter: self.q})
return self.query_set

View file

@ -44,7 +44,7 @@ from .models import (
SwitchBay, SwitchBay,
) )
from re2o.mixins import AutocompleteViewMixin from re2o.views import AutocompleteViewMixin
from re2o.acl import ( from re2o.acl import (
can_view_all, can_view_all,

View file

@ -45,7 +45,7 @@ from .models import (
EMailAddress, EMailAddress,
) )
from re2o.mixins import AutocompleteViewMixin from re2o.views import AutocompleteViewMixin
from re2o.acl import ( from re2o.acl import (
can_view_all, can_view_all,