mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
''' Custom Permission classes.
|
|
Hierarchy: Anyone -> User -> Editor -> Owner -> Admin
|
|
'''
|
|
from typing import Any, cast
|
|
|
|
from django.core.exceptions import PermissionDenied
|
|
from rest_framework.permissions import AllowAny as Anyone # pylint: disable=unused-import
|
|
from rest_framework.permissions import BasePermission as _Base
|
|
from rest_framework.permissions import \
|
|
IsAuthenticated as GlobalUser # pylint: disable=unused-import
|
|
from rest_framework.request import Request
|
|
from rest_framework.views import APIView
|
|
|
|
from apps.library.models import AccessPolicy, Editor, LibraryItem, Version
|
|
from apps.oss.models import Operation
|
|
from apps.rsform.models import Constituenta
|
|
from apps.users.models import User
|
|
|
|
|
|
def _extract_item(obj: Any) -> LibraryItem:
|
|
if isinstance(obj, LibraryItem):
|
|
return obj
|
|
elif isinstance(obj, Constituenta):
|
|
return cast(LibraryItem, obj.schema)
|
|
elif isinstance(obj, Operation):
|
|
return cast(LibraryItem, obj.oss)
|
|
elif isinstance(obj, (Version, Editor)):
|
|
return cast(LibraryItem, obj.item)
|
|
raise PermissionDenied({
|
|
'message': 'Invalid type error. Please contact developers',
|
|
'object_id': obj.pk
|
|
})
|
|
|
|
|
|
def can_edit_item(user, obj: Any) -> bool:
|
|
if user.is_anonymous:
|
|
return False
|
|
if hasattr(user, 'is_staff') and user.is_staff:
|
|
return True
|
|
|
|
item = _extract_item(obj)
|
|
if item.owner_id == user.pk:
|
|
return True
|
|
|
|
if Editor.objects.filter(
|
|
item=item,
|
|
editor=cast(User, user)
|
|
).exists() and item.access_policy != AccessPolicy.PRIVATE:
|
|
return True
|
|
return False
|
|
|
|
|
|
class GlobalAdmin(_Base):
|
|
''' Item permission: Admin or higher. '''
|
|
|
|
def has_permission(self, request: Request, view: APIView) -> bool:
|
|
if not hasattr(request.user, 'is_staff'):
|
|
return False
|
|
return request.user.is_staff # type: ignore
|
|
|
|
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
|
if not hasattr(request.user, 'is_staff'):
|
|
return False
|
|
return request.user.is_staff # type: ignore
|
|
|
|
|
|
class ItemOwner(GlobalAdmin):
|
|
''' Item permission: Owner or higher. '''
|
|
|
|
def has_permission(self, request: Request, view: APIView) -> bool:
|
|
return not request.user.is_anonymous
|
|
|
|
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
|
if request.user == _extract_item(obj).owner:
|
|
return True
|
|
return super().has_object_permission(request, view, obj)
|
|
|
|
|
|
class ItemEditor(ItemOwner):
|
|
''' Item permission: Editor or higher. '''
|
|
|
|
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
|
if request.user.is_anonymous:
|
|
return False
|
|
item = _extract_item(obj)
|
|
if Editor.objects.filter(
|
|
item=item,
|
|
editor=cast(User, request.user)
|
|
).exists() and item.access_policy != AccessPolicy.PRIVATE:
|
|
return True
|
|
return super().has_object_permission(request, view, obj)
|
|
|
|
|
|
class ItemAnyone(ItemEditor):
|
|
''' Item permission: Anyone if public. '''
|
|
|
|
def has_permission(self, request: Request, view: APIView) -> bool:
|
|
return True
|
|
|
|
def has_object_permission(self, request: Request, view: APIView, obj: Any) -> bool:
|
|
item = _extract_item(obj)
|
|
if item.access_policy == AccessPolicy.PUBLIC:
|
|
return True
|
|
return super().has_object_permission(request, view, obj)
|
|
|
|
|
|
class EditorMixin(APIView):
|
|
''' Editor permissions mixin for API views. '''
|
|
|
|
def get_permissions(self):
|
|
result = super().get_permissions()
|
|
if self.request.method.upper() == 'GET':
|
|
result.append(Anyone())
|
|
else:
|
|
result.append(ItemEditor())
|
|
return result
|