Merge pull request #3985 from ostcar/cleanup_access_permission
Refactor assess_permission
This commit is contained in:
commit
5fc868cbee
@ -12,7 +12,9 @@ def check(args=None):
|
||||
"""
|
||||
Checks for pep8 and other code styling conventions.
|
||||
"""
|
||||
return call('flake8 --max-line-length=150 --statistics openslides tests')
|
||||
value = call('flake8 --max-line-length=150 --statistics openslides tests')
|
||||
value += call('python -m mypy openslides/ tests/')
|
||||
return value
|
||||
|
||||
|
||||
@command('travis', help='Runs the code that travis does')
|
||||
|
@ -10,17 +10,8 @@ class ItemAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'agenda.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import ItemSerializer
|
||||
|
||||
return ItemSerializer
|
||||
|
||||
# TODO: In the following method we use full_data['is_hidden'] and
|
||||
# full_data['is_internal'] but this can be out of date.
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
|
@ -22,6 +22,7 @@ class AgendaAppConfig(AppConfig):
|
||||
listen_to_related_object_post_delete,
|
||||
listen_to_related_object_post_save)
|
||||
from .views import ItemViewSet
|
||||
from . import serializers # noqa
|
||||
from ..utils.access_permissions import required_user
|
||||
|
||||
# Define projector elements.
|
||||
|
@ -1,7 +1,7 @@
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from ..utils.access_permissions import BaseAccessPermissions
|
||||
from ..utils.auth import async_has_perm, has_perm
|
||||
from ..utils.auth import async_has_perm
|
||||
|
||||
|
||||
class AssignmentAccessPermissions(BaseAccessPermissions):
|
||||
@ -10,18 +10,6 @@ class AssignmentAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'assignments.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns different serializer classes according to users permissions.
|
||||
"""
|
||||
from .serializers import AssignmentFullSerializer, AssignmentShortSerializer
|
||||
|
||||
if user is None or (has_perm(user, 'assignments.can_see') and has_perm(user, 'assignments.can_manage')):
|
||||
serializer_class = AssignmentFullSerializer
|
||||
else:
|
||||
serializer_class = AssignmentShortSerializer
|
||||
return serializer_class
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
|
@ -15,11 +15,12 @@ class AssignmentsAppConfig(AppConfig):
|
||||
def ready(self):
|
||||
# Import all required stuff.
|
||||
from ..core.signals import permission_change
|
||||
from ..utils.access_permissions import required_user
|
||||
from ..utils.rest_api import router
|
||||
from . import serializers # noqa
|
||||
from .projector import get_projector_elements
|
||||
from .signals import get_permission_change_data
|
||||
from .views import AssignmentViewSet, AssignmentPollViewSet
|
||||
from ..utils.access_permissions import required_user
|
||||
|
||||
# Define projector elements.
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
@ -238,31 +238,3 @@ class AssignmentFullSerializer(ModelSerializer):
|
||||
assignment.agenda_item_update_information['parent_id'] = agenda_parent_id
|
||||
assignment.save()
|
||||
return assignment
|
||||
|
||||
|
||||
class AssignmentShortSerializer(AssignmentFullSerializer):
|
||||
"""
|
||||
Serializer for assignment.models.Assignment objects. Without unpublished poll.
|
||||
"""
|
||||
assignment_related_users = AssignmentRelatedUserSerializer(many=True, read_only=True)
|
||||
polls = AssignmentShortPollSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Assignment
|
||||
fields = (
|
||||
'id',
|
||||
'title',
|
||||
'description',
|
||||
'open_posts',
|
||||
'phase',
|
||||
'assignment_related_users',
|
||||
'poll_description_default',
|
||||
'polls',
|
||||
'agenda_item_id',
|
||||
'tags',)
|
||||
validators = (posts_validator,)
|
||||
|
||||
def validate(self, data):
|
||||
if 'description' in data:
|
||||
data['description'] = validate_html(data['description'])
|
||||
return data
|
||||
|
@ -8,28 +8,12 @@ class ProjectorAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'core.can_see_projector'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import ProjectorSerializer
|
||||
|
||||
return ProjectorSerializer
|
||||
|
||||
|
||||
class TagAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
Access permissions container for Tag and TagViewSet.
|
||||
"""
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import TagSerializer
|
||||
|
||||
return TagSerializer
|
||||
|
||||
|
||||
class ChatMessageAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -37,14 +21,6 @@ class ChatMessageAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'core.can_use_chat'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import ChatMessageSerializer
|
||||
|
||||
return ChatMessageSerializer
|
||||
|
||||
|
||||
class ProjectorMessageAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -52,14 +28,6 @@ class ProjectorMessageAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'core.can_see_projector'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import ProjectorMessageSerializer
|
||||
|
||||
return ProjectorMessageSerializer
|
||||
|
||||
|
||||
class CountdownAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -67,14 +35,6 @@ class CountdownAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'core.can_see_projector'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import CountdownSerializer
|
||||
|
||||
return CountdownSerializer
|
||||
|
||||
|
||||
class ConfigAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -82,14 +42,6 @@ class ConfigAccessPermissions(BaseAccessPermissions):
|
||||
ConfigViewSet).
|
||||
"""
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import ConfigSerializer
|
||||
|
||||
return ConfigSerializer
|
||||
|
||||
|
||||
class HistoryAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -102,11 +54,3 @@ class HistoryAccessPermissions(BaseAccessPermissions):
|
||||
model instances.
|
||||
"""
|
||||
return await async_in_some_groups(user_id, [GROUP_ADMIN_PK])
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import HistorySerializer
|
||||
|
||||
return HistorySerializer
|
||||
|
@ -22,6 +22,7 @@ class CoreAppConfig(AppConfig):
|
||||
from ..utils.rest_api import router
|
||||
from ..utils.cache import element_cache
|
||||
from .projector import get_projector_elements
|
||||
from . import serializers # noqa
|
||||
from .signals import (
|
||||
delete_django_app_permissions,
|
||||
get_permission_change_data,
|
||||
|
@ -10,14 +10,6 @@ class MediafileAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'mediafiles.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import MediafileSerializer
|
||||
|
||||
return MediafileSerializer
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
|
@ -18,6 +18,7 @@ class MediafilesAppConfig(AppConfig):
|
||||
from .projector import get_projector_elements
|
||||
from .signals import get_permission_change_data
|
||||
from .views import MediafileViewSet
|
||||
from . import serializers # noqa
|
||||
from ..utils.access_permissions import required_user
|
||||
|
||||
# Define projector elements.
|
||||
|
@ -11,14 +11,6 @@ class MotionAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'motions.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import MotionSerializer
|
||||
|
||||
return MotionSerializer
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
@ -71,14 +63,6 @@ class MotionChangeRecommendationAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'motions.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import MotionChangeRecommendationSerializer
|
||||
|
||||
return MotionChangeRecommendationSerializer
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
@ -107,14 +91,6 @@ class MotionCommentSectionAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'motions.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import MotionCommentSectionSerializer
|
||||
|
||||
return MotionCommentSectionSerializer
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
@ -140,14 +116,6 @@ class StatuteParagraphAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'motions.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import StatuteParagraphSerializer
|
||||
|
||||
return StatuteParagraphSerializer
|
||||
|
||||
|
||||
class CategoryAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -155,14 +123,6 @@ class CategoryAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'motions.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import CategorySerializer
|
||||
|
||||
return CategorySerializer
|
||||
|
||||
|
||||
class MotionBlockAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -170,25 +130,9 @@ class MotionBlockAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
base_permission = 'motions.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import MotionBlockSerializer
|
||||
|
||||
return MotionBlockSerializer
|
||||
|
||||
|
||||
class WorkflowAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
Access permissions container for Workflow and WorkflowViewSet.
|
||||
"""
|
||||
base_permission = 'motions.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import WorkflowSerializer
|
||||
|
||||
return WorkflowSerializer
|
||||
|
@ -21,6 +21,7 @@ class MotionsAppConfig(AppConfig):
|
||||
create_builtin_workflows,
|
||||
get_permission_change_data,
|
||||
)
|
||||
from . import serializers # noqa
|
||||
from .views import (
|
||||
CategoryViewSet,
|
||||
StatuteParagraphViewSet,
|
||||
|
@ -6,11 +6,3 @@ class TopicAccessPermissions(BaseAccessPermissions):
|
||||
Access permissions container for Topic and TopicViewSet.
|
||||
"""
|
||||
base_permission = 'agenda.can_see'
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import TopicSerializer
|
||||
|
||||
return TopicSerializer
|
||||
|
@ -16,6 +16,7 @@ class TopicsAppConfig(AppConfig):
|
||||
from .projector import get_projector_elements
|
||||
from .signals import get_permission_change_data
|
||||
from .views import TopicViewSet
|
||||
from . import serializers # noqa
|
||||
|
||||
# Define projector elements.
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
@ -10,14 +10,6 @@ class UserAccessPermissions(BaseAccessPermissions):
|
||||
Access permissions container for User and UserViewSet.
|
||||
"""
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns different serializer classes with respect user's permissions.
|
||||
"""
|
||||
from .serializers import UserFullSerializer
|
||||
|
||||
return UserFullSerializer
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
@ -95,14 +87,6 @@ class GroupAccessPermissions(BaseAccessPermissions):
|
||||
Access permissions container for Groups. Everyone can see them
|
||||
"""
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import GroupSerializer
|
||||
|
||||
return GroupSerializer
|
||||
|
||||
|
||||
class PersonalNoteAccessPermissions(BaseAccessPermissions):
|
||||
"""
|
||||
@ -110,14 +94,6 @@ class PersonalNoteAccessPermissions(BaseAccessPermissions):
|
||||
can handle personal notes.
|
||||
"""
|
||||
|
||||
def get_serializer_class(self, user=None):
|
||||
"""
|
||||
Returns serializer class.
|
||||
"""
|
||||
from .serializers import PersonalNoteSerializer
|
||||
|
||||
return PersonalNoteSerializer
|
||||
|
||||
async def get_restricted_data(
|
||||
self,
|
||||
full_data: List[Dict[str, Any]],
|
||||
|
@ -1,8 +1,6 @@
|
||||
from typing import Any, Callable, Dict, List, Set
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from django.db.models import Model
|
||||
from rest_framework.serializers import Serializer
|
||||
|
||||
from .auth import async_anonymous_is_enabled, async_has_perm, user_to_user_id
|
||||
from .cache import element_cache
|
||||
@ -41,25 +39,6 @@ class BaseAccessPermissions:
|
||||
else:
|
||||
return bool(user_id) or await async_anonymous_is_enabled()
|
||||
|
||||
def get_serializer_class(self, user_id: int = 0) -> Serializer:
|
||||
"""
|
||||
Returns different serializer classes according to users permissions.
|
||||
|
||||
This should return the serializer for full data access if user is
|
||||
None. See get_full_data().
|
||||
"""
|
||||
# TODO: Rewrite me by using an serializer_class attribute and removing
|
||||
# the user_id argument.
|
||||
raise NotImplementedError(
|
||||
"You have to add the method 'get_serializer_class' to your "
|
||||
"access permissions class.".format(self))
|
||||
|
||||
def get_full_data(self, instance: Model) -> Dict[str, Any]:
|
||||
"""
|
||||
Returns all possible serialized data for the given instance.
|
||||
"""
|
||||
return self.get_serializer_class()(instance).data
|
||||
|
||||
async def get_restricted_data(
|
||||
self, full_data: List[Dict[str, Any]],
|
||||
user_id: int) -> List[Dict[str, Any]]:
|
||||
@ -71,11 +50,6 @@ class BaseAccessPermissions:
|
||||
the return is the same. Returns an empty list if the user has no read
|
||||
access. Returns reduced data if the user has limited access. Default:
|
||||
Returns full data if the user has read access to model instances.
|
||||
|
||||
Hint: You should override this method if your get_serializer_class()
|
||||
method returns different serializers for different users or if you
|
||||
have access restrictions in your view or viewset in methods like
|
||||
retrieve() or list().
|
||||
"""
|
||||
return full_data if await self.async_check_permissions(user_id) else []
|
||||
|
||||
|
@ -4,6 +4,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db import models
|
||||
|
||||
from .access_permissions import BaseAccessPermissions
|
||||
from .rest_api import model_serializer_classes
|
||||
from .utils import convert_camel_case_to_pseudo_snake_case
|
||||
|
||||
|
||||
@ -134,4 +135,5 @@ class RESTModelMixin:
|
||||
"""
|
||||
Returns the full_data of the instance.
|
||||
"""
|
||||
return self.get_access_permissions().get_full_data(self)
|
||||
serializer_class = model_serializer_classes[type(self)]
|
||||
return serializer_class(self).data
|
||||
|
@ -2,6 +2,7 @@ from collections import OrderedDict
|
||||
from typing import Any, Dict, Iterable, Optional, Type
|
||||
|
||||
from asgiref.sync import async_to_sync
|
||||
from django.db.models import Model
|
||||
from django.http import Http404
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import detail_route, list_route
|
||||
@ -32,6 +33,7 @@ from rest_framework.serializers import (
|
||||
PrimaryKeyRelatedField,
|
||||
RelatedField,
|
||||
Serializer,
|
||||
SerializerMetaclass,
|
||||
SerializerMethodField,
|
||||
ValidationError,
|
||||
)
|
||||
@ -152,17 +154,44 @@ class PermissionMixin:
|
||||
|
||||
def get_serializer_class(self) -> Type[Serializer]:
|
||||
"""
|
||||
Overridden method to return the serializer class given by the
|
||||
access permissions container.
|
||||
Overridden method to return the serializer class for the model.
|
||||
"""
|
||||
if self.get_access_permissions() is not None:
|
||||
serializer_class = self.get_access_permissions().get_serializer_class(self.request.user) # type: ignore
|
||||
model = self.get_queryset().model # type: ignore
|
||||
try:
|
||||
return model_serializer_classes[model]
|
||||
except AttributeError:
|
||||
# If there is no known serializer class for the model, return the
|
||||
# default serializer class.
|
||||
return super().get_serializer_class() # type: ignore
|
||||
|
||||
|
||||
model_serializer_classes: Dict[Type[Model], Serializer] = {}
|
||||
|
||||
|
||||
class ModelSerializerRegisterer(SerializerMetaclass):
|
||||
"""
|
||||
Meta class for model serializer that detects the corresponding model
|
||||
and saves it.
|
||||
"""
|
||||
|
||||
def __new__(cls, name, bases, attrs): # type: ignore
|
||||
"""
|
||||
Detects the corresponding model from the ModelSerializer by
|
||||
looking into the Meta-class.
|
||||
|
||||
Does nothing, if the Meta-class does not have the model attribute.
|
||||
"""
|
||||
serializer_class = super().__new__(cls, name, bases, attrs)
|
||||
try:
|
||||
model = serializer_class.Meta.model
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
serializer_class = super().get_serializer_class() # type: ignore
|
||||
model_serializer_classes[model] = serializer_class
|
||||
return serializer_class
|
||||
|
||||
|
||||
class ModelSerializer(_ModelSerializer):
|
||||
class ModelSerializer(_ModelSerializer, metaclass=ModelSerializerRegisterer):
|
||||
"""
|
||||
ModelSerializer that changes the field names of related fields to
|
||||
FIELD_NAME_id.
|
||||
|
Loading…
Reference in New Issue
Block a user