helper/permission_helper
This commit is contained in:
@ -1,20 +1,16 @@
|
|||||||
"""
|
"""
|
||||||
Source: https://djangosnippets.org/snippets/1703/
|
Source: https://djangosnippets.org/snippets/1703/
|
||||||
"""
|
"""
|
||||||
|
from cookbook.models import ShareLink
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse_lazy, reverse
|
from django.urls import reverse, reverse_lazy
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from rest_framework.permissions import SAFE_METHODS
|
from rest_framework.permissions import SAFE_METHODS
|
||||||
|
|
||||||
from cookbook.models import ShareLink
|
|
||||||
|
|
||||||
|
|
||||||
# Helper Functions
|
|
||||||
|
|
||||||
def get_allowed_groups(groups_required):
|
def get_allowed_groups(groups_required):
|
||||||
"""
|
"""
|
||||||
@ -34,8 +30,8 @@ def get_allowed_groups(groups_required):
|
|||||||
def has_group_permission(user, groups):
|
def has_group_permission(user, groups):
|
||||||
"""
|
"""
|
||||||
Tests if a given user is member of a certain group (or any higher group)
|
Tests if a given user is member of a certain group (or any higher group)
|
||||||
Superusers always bypass permission checks. Unauthenticated users cant be member of any
|
Superusers always bypass permission checks.
|
||||||
group thus always return false.
|
Unauthenticated users cant be member of any group thus always return false.
|
||||||
:param user: django auth user object
|
:param user: django auth user object
|
||||||
:param groups: list or tuple of groups the user should be checked for
|
:param groups: list or tuple of groups the user should be checked for
|
||||||
:return: True if user is in allowed groups, false otherwise
|
:return: True if user is in allowed groups, false otherwise
|
||||||
@ -44,7 +40,8 @@ def has_group_permission(user, groups):
|
|||||||
return False
|
return False
|
||||||
groups_allowed = get_allowed_groups(groups)
|
groups_allowed = get_allowed_groups(groups)
|
||||||
if user.is_authenticated:
|
if user.is_authenticated:
|
||||||
if user.is_superuser | bool(user.groups.filter(name__in=groups_allowed)):
|
if (user.is_superuser
|
||||||
|
| bool(user.groups.filter(name__in=groups_allowed))):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -52,13 +49,15 @@ def has_group_permission(user, groups):
|
|||||||
def is_object_owner(user, obj):
|
def is_object_owner(user, obj):
|
||||||
"""
|
"""
|
||||||
Tests if a given user is the owner of a given object
|
Tests if a given user is the owner of a given object
|
||||||
test performed by checking user against the objects user and create_by field (if exists)
|
test performed by checking user against the objects user
|
||||||
|
and create_by field (if exists)
|
||||||
superusers bypass all checks, unauthenticated users cannot own anything
|
superusers bypass all checks, unauthenticated users cannot own anything
|
||||||
:param user django auth user object
|
:param user django auth user object
|
||||||
:param obj any object that should be tested
|
:param obj any object that should be tested
|
||||||
:return: true if user is owner of object, false otherwise
|
:return: true if user is owner of object, false otherwise
|
||||||
"""
|
"""
|
||||||
# TODO this could be improved/cleaned up by adding get_owner methods to all models that allow owner checks
|
# TODO this could be improved/cleaned up by adding
|
||||||
|
# get_owner methods to all models that allow owner checks
|
||||||
if not user.is_authenticated:
|
if not user.is_authenticated:
|
||||||
return False
|
return False
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
@ -81,7 +80,8 @@ def is_object_shared(user, obj):
|
|||||||
:param obj any object that should be tested
|
:param obj any object that should be tested
|
||||||
:return: true if user is shared for object, false otherwise
|
:return: true if user is shared for object, false otherwise
|
||||||
"""
|
"""
|
||||||
# TODO this could be improved/cleaned up by adding share checks for relevant objects
|
# TODO this could be improved/cleaned up by adding
|
||||||
|
# share checks for relevant objects
|
||||||
if not user.is_authenticated:
|
if not user.is_authenticated:
|
||||||
return False
|
return False
|
||||||
if user.is_superuser:
|
if user.is_superuser:
|
||||||
@ -94,10 +94,14 @@ def share_link_valid(recipe, share):
|
|||||||
Verifies the validity of a share uuid
|
Verifies the validity of a share uuid
|
||||||
:param recipe: recipe object
|
:param recipe: recipe object
|
||||||
:param share: share uuid
|
:param share: share uuid
|
||||||
:return: true if a share link with the given recipe and uuid exists, false otherwise
|
:return: true if a share link with the given recipe and uuid exists
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return True if ShareLink.objects.filter(recipe=recipe, uuid=share).exists() else False
|
return (
|
||||||
|
True
|
||||||
|
if ShareLink.objects.filter(recipe=recipe, uuid=share).exists()
|
||||||
|
else False
|
||||||
|
)
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -106,8 +110,8 @@ def share_link_valid(recipe, share):
|
|||||||
|
|
||||||
def group_required(*groups_required):
|
def group_required(*groups_required):
|
||||||
"""
|
"""
|
||||||
Decorator that tests the requesting user to be member of at least one of the provided groups
|
Decorator that tests the requesting user to be member
|
||||||
or higher level groups
|
of at least one of the provided groups or higher level groups
|
||||||
:param groups_required: list of required groups
|
:param groups_required: list of required groups
|
||||||
:return: true if member of group, false otherwise
|
:return: true if member of group, false otherwise
|
||||||
"""
|
"""
|
||||||
@ -127,24 +131,40 @@ class GroupRequiredMixin(object):
|
|||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not has_group_permission(request.user, self.groups_required):
|
if not has_group_permission(request.user, self.groups_required):
|
||||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
messages.add_message(
|
||||||
|
request,
|
||||||
|
messages.ERROR,
|
||||||
|
_('You do not have the required permissions to view this page!') # noqa: E501
|
||||||
|
)
|
||||||
return HttpResponseRedirect(reverse_lazy('index'))
|
return HttpResponseRedirect(reverse_lazy('index'))
|
||||||
|
|
||||||
return super(GroupRequiredMixin, self).dispatch(request, *args, **kwargs)
|
return super(GroupRequiredMixin, self) \
|
||||||
|
.dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class OwnerRequiredMixin(object):
|
class OwnerRequiredMixin(object):
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
if not request.user.is_authenticated:
|
if not request.user.is_authenticated:
|
||||||
messages.add_message(request, messages.ERROR, _('You are not logged in and therefore cannot view this page!'))
|
messages.add_message(
|
||||||
return HttpResponseRedirect(reverse_lazy('login') + '?next=' + request.path)
|
request,
|
||||||
|
messages.ERROR,
|
||||||
|
_('You are not logged in and therefore cannot view this page!')
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(
|
||||||
|
reverse_lazy('login') + '?next=' + request.path
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if not is_object_owner(request.user, self.get_object()):
|
if not is_object_owner(request.user, self.get_object()):
|
||||||
messages.add_message(request, messages.ERROR, _('You cannot interact with this object as it is not owned by you!'))
|
messages.add_message(
|
||||||
|
request,
|
||||||
|
messages.ERROR,
|
||||||
|
_('You cannot interact with this object as it is not owned by you!') # noqa: E501
|
||||||
|
)
|
||||||
return HttpResponseRedirect(reverse('index'))
|
return HttpResponseRedirect(reverse('index'))
|
||||||
|
|
||||||
return super(OwnerRequiredMixin, self).dispatch(request, *args, **kwargs)
|
return super(OwnerRequiredMixin, self) \
|
||||||
|
.dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
# Django Rest Framework Permission classes
|
# Django Rest Framework Permission classes
|
||||||
@ -155,7 +175,7 @@ class CustomIsOwner(permissions.BasePermission):
|
|||||||
verifies user has ownership over object
|
verifies user has ownership over object
|
||||||
(either user or created_by or user is request user)
|
(either user or created_by or user is request user)
|
||||||
"""
|
"""
|
||||||
message = _('You cannot interact with this object as it is not owned by you!')
|
message = _('You cannot interact with this object as it is not owned by you!') # noqa: E501
|
||||||
|
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
return request.user.is_authenticated
|
return request.user.is_authenticated
|
||||||
@ -164,12 +184,13 @@ class CustomIsOwner(permissions.BasePermission):
|
|||||||
return is_object_owner(request.user, obj)
|
return is_object_owner(request.user, obj)
|
||||||
|
|
||||||
|
|
||||||
class CustomIsShared(permissions.BasePermission): # TODO function duplicate/too similar name
|
# TODO function duplicate/too similar name
|
||||||
|
class CustomIsShared(permissions.BasePermission):
|
||||||
"""
|
"""
|
||||||
Custom permission class for django rest framework views
|
Custom permission class for django rest framework views
|
||||||
verifies user is shared for the object he is trying to access
|
verifies user is shared for the object he is trying to access
|
||||||
"""
|
"""
|
||||||
message = _('You cannot interact with this object as it is not owned by you!')
|
message = _('You cannot interact with this object as it is not owned by you!') # noqa: E501
|
||||||
|
|
||||||
def has_permission(self, request, view):
|
def has_permission(self, request, view):
|
||||||
return request.user.is_authenticated
|
return request.user.is_authenticated
|
||||||
|
Reference in New Issue
Block a user