"durchstich" for autoupdate optimization
This commit is contained in:
parent
e598b308f0
commit
3db2f2fc16
9
openslides/agenda/access_permissions.py
Normal file
9
openslides/agenda/access_permissions.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class AccessPermissions:
|
||||||
|
def get_serializer_class(self, user):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def can_retrieve(self, user):
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
return user.has_perm('assignments.can_see')
|
@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy
|
|||||||
from reportlab.platypus import Paragraph
|
from reportlab.platypus import Paragraph
|
||||||
|
|
||||||
from openslides.core.config import config
|
from openslides.core.config import config
|
||||||
|
from openslides.agenda.access_permissions import AccessPermissions
|
||||||
from openslides.utils.exceptions import OpenSlidesError
|
from openslides.utils.exceptions import OpenSlidesError
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from openslides.utils.rest_api import (
|
from openslides.utils.rest_api import (
|
||||||
@ -36,12 +37,15 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
|
|||||||
"""
|
"""
|
||||||
queryset = Item.objects.all()
|
queryset = Item.objects.all()
|
||||||
serializer_class = ItemSerializer
|
serializer_class = ItemSerializer
|
||||||
|
access_permissions = AccessPermissions()
|
||||||
|
|
||||||
def check_view_permissions(self):
|
def check_view_permissions(self):
|
||||||
"""
|
"""
|
||||||
Returns True if the user has required permissions.
|
Returns True if the user has required permissions.
|
||||||
"""
|
"""
|
||||||
if self.action in ('metadata', 'list', 'retrieve', 'manage_speaker', 'tree'):
|
if self.action == 'retrieve':
|
||||||
|
result = self.access_permissions.can_retrieve(self.request.user)
|
||||||
|
elif self.action in ('metadata', 'list', 'manage_speaker', 'tree'):
|
||||||
result = self.request.user.has_perm('agenda.can_see')
|
result = self.request.user.has_perm('agenda.can_see')
|
||||||
# For manage_speaker and tree requests the rest of the check is
|
# For manage_speaker and tree requests the rest of the check is
|
||||||
# done in the specific method. See below.
|
# done in the specific method. See below.
|
||||||
|
18
openslides/assignments/access_permissions.py
Normal file
18
openslides/assignments/access_permissions.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
class AccessPermissions:
|
||||||
|
def get_serializer_class(self, user):
|
||||||
|
"""
|
||||||
|
Returns different serializer classes according to users permissions.
|
||||||
|
"""
|
||||||
|
from openslides.assignments.serializers import AssignmentFullSerializer, AssignmentShortSerializer
|
||||||
|
if user.has_perm('assignments.can_manage'):
|
||||||
|
serializer_class = AssignmentFullSerializer
|
||||||
|
else:
|
||||||
|
serializer_class = AssignmentShortSerializer
|
||||||
|
return serializer_class
|
||||||
|
|
||||||
|
def can_retrieve(self, user):
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
return user.has_perm('agenda.can_see')
|
@ -12,7 +12,6 @@ class AssignmentsAppConfig(AppConfig):
|
|||||||
# Load projector elements.
|
# Load projector elements.
|
||||||
# Do this by just importing all from these files.
|
# Do this by just importing all from these files.
|
||||||
from . import projector # noqa
|
from . import projector # noqa
|
||||||
|
|
||||||
# Import all required stuff.
|
# Import all required stuff.
|
||||||
from openslides.core.signals import config_signal
|
from openslides.core.signals import config_signal
|
||||||
from openslides.utils.rest_api import router
|
from openslides.utils.rest_api import router
|
||||||
@ -23,5 +22,5 @@ class AssignmentsAppConfig(AppConfig):
|
|||||||
config_signal.connect(setup_assignment_config, dispatch_uid='setup_assignment_config')
|
config_signal.connect(setup_assignment_config, dispatch_uid='setup_assignment_config')
|
||||||
|
|
||||||
# Register viewsets.
|
# Register viewsets.
|
||||||
router.register('assignments/assignment', AssignmentViewSet)
|
router.register(self.get_model('Assignment').get_collection_name(), AssignmentViewSet)
|
||||||
router.register('assignments/poll', AssignmentPollViewSet)
|
router.register('assignments/poll', AssignmentPollViewSet)
|
||||||
|
@ -7,6 +7,7 @@ from django.utils.translation import ugettext as _
|
|||||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||||
|
|
||||||
from openslides.agenda.models import Item, Speaker
|
from openslides.agenda.models import Item, Speaker
|
||||||
|
from openslides.assignments.access_permissions import AccessPermissions
|
||||||
from openslides.core.config import config
|
from openslides.core.config import config
|
||||||
from openslides.core.models import Tag
|
from openslides.core.models import Tag
|
||||||
from openslides.poll.models import (
|
from openslides.poll.models import (
|
||||||
@ -49,6 +50,7 @@ class AssignmentRelatedUser(RESTModelMixin, models.Model):
|
|||||||
|
|
||||||
|
|
||||||
class Assignment(RESTModelMixin, models.Model):
|
class Assignment(RESTModelMixin, models.Model):
|
||||||
|
access_permissions = AccessPermissions()
|
||||||
|
|
||||||
PHASE_SEARCH = 0
|
PHASE_SEARCH = 0
|
||||||
PHASE_VOTING = 1
|
PHASE_VOTING = 1
|
||||||
|
@ -17,6 +17,7 @@ from reportlab.platypus import (
|
|||||||
TableStyle,
|
TableStyle,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from openslides.assignments.access_permissions import AccessPermissions
|
||||||
from openslides.core.config import config
|
from openslides.core.config import config
|
||||||
from openslides.utils.pdf import stylesheet
|
from openslides.utils.pdf import stylesheet
|
||||||
from openslides.utils.rest_api import (
|
from openslides.utils.rest_api import (
|
||||||
@ -49,12 +50,15 @@ class AssignmentViewSet(ModelViewSet):
|
|||||||
mark_elected and create_poll.
|
mark_elected and create_poll.
|
||||||
"""
|
"""
|
||||||
queryset = Assignment.objects.all()
|
queryset = Assignment.objects.all()
|
||||||
|
access_permissions = AccessPermissions()
|
||||||
|
|
||||||
def check_view_permissions(self):
|
def check_view_permissions(self):
|
||||||
"""
|
"""
|
||||||
Returns True if the user has required permissions.
|
Returns True if the user has required permissions.
|
||||||
"""
|
"""
|
||||||
if self.action in ('metadata', 'list', 'retrieve'):
|
if self.action == 'retrieve':
|
||||||
|
result = self.access_permissions.can_retrieve(self.request.user)
|
||||||
|
elif self.action in ('metadata', 'list'):
|
||||||
result = self.request.user.has_perm('assignments.can_see')
|
result = self.request.user.has_perm('assignments.can_see')
|
||||||
elif self.action in ('create', 'partial_update', 'update', 'destroy',
|
elif self.action in ('create', 'partial_update', 'update', 'destroy',
|
||||||
'mark_elected', 'create_poll'):
|
'mark_elected', 'create_poll'):
|
||||||
@ -70,16 +74,6 @@ class AssignmentViewSet(ModelViewSet):
|
|||||||
result = False
|
result = False
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_serializer_class(self):
|
|
||||||
"""
|
|
||||||
Returns different serializer classes according to users permissions.
|
|
||||||
"""
|
|
||||||
if self.request.user.has_perm('assignments.can_manage'):
|
|
||||||
serializer_class = AssignmentFullSerializer
|
|
||||||
else:
|
|
||||||
serializer_class = AssignmentShortSerializer
|
|
||||||
return serializer_class
|
|
||||||
|
|
||||||
@detail_route(methods=['post', 'delete'])
|
@detail_route(methods=['post', 'delete'])
|
||||||
def candidature_self(self, request, pk=None):
|
def candidature_self(self, request, pk=None):
|
||||||
"""
|
"""
|
||||||
|
9
openslides/core/access_permissions.py
Normal file
9
openslides/core/access_permissions.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
class AccessPermissions:
|
||||||
|
def get_serializer_class(self, user):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def can_retrieve(self, user):
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
return user.has_perm('core.can_see_projector')
|
@ -12,11 +12,11 @@ class CoreAppConfig(AppConfig):
|
|||||||
# Load projector elements.
|
# Load projector elements.
|
||||||
# Do this by just importing all from these files.
|
# Do this by just importing all from these files.
|
||||||
from . import projector # noqa
|
from . import projector # noqa
|
||||||
|
|
||||||
# Import all required stuff.
|
# Import all required stuff.
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
from openslides.core.signals import config_signal, post_permission_creation
|
from openslides.core.signals import config_signal, post_permission_creation
|
||||||
from openslides.utils.autoupdate import inform_changed_data_receiver
|
from openslides.utils.autoupdate import inform_changed_data_receiver
|
||||||
|
from openslides.utils.autoupdate import inform_deleted_data_receiver
|
||||||
from openslides.utils.rest_api import router
|
from openslides.utils.rest_api import router
|
||||||
from openslides.utils.search import index_add_instance, index_del_instance
|
from openslides.utils.search import index_add_instance, index_del_instance
|
||||||
from .signals import delete_django_app_permissions, setup_general_config
|
from .signals import delete_django_app_permissions, setup_general_config
|
||||||
@ -49,8 +49,8 @@ class CoreAppConfig(AppConfig):
|
|||||||
inform_changed_data_receiver,
|
inform_changed_data_receiver,
|
||||||
dispatch_uid='inform_changed_data_receiver')
|
dispatch_uid='inform_changed_data_receiver')
|
||||||
signals.post_delete.connect(
|
signals.post_delete.connect(
|
||||||
inform_changed_data_receiver,
|
inform_deleted_data_receiver,
|
||||||
dispatch_uid='inform_changed_data_receiver')
|
dispatch_uid='inform_deleted_data_receiver')
|
||||||
|
|
||||||
# Update the search when a model is saved or deleted
|
# Update the search when a model is saved or deleted
|
||||||
signals.post_save.connect(
|
signals.post_save.connect(
|
||||||
|
@ -13,6 +13,7 @@ from django.http import Http404, HttpResponse
|
|||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
|
||||||
from openslides import __version__ as version
|
from openslides import __version__ as version
|
||||||
|
from openslides.core.access_permissions import AccessPermissions
|
||||||
from openslides.utils import views as utils_views
|
from openslides.utils import views as utils_views
|
||||||
from openslides.utils.plugins import (
|
from openslides.utils.plugins import (
|
||||||
get_plugin_description,
|
get_plugin_description,
|
||||||
@ -154,12 +155,15 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
|||||||
"""
|
"""
|
||||||
queryset = Projector.objects.all()
|
queryset = Projector.objects.all()
|
||||||
serializer_class = ProjectorSerializer
|
serializer_class = ProjectorSerializer
|
||||||
|
access_permissions = AccessPermissions()
|
||||||
|
|
||||||
def check_view_permissions(self):
|
def check_view_permissions(self):
|
||||||
"""
|
"""
|
||||||
Returns True if the user has required permissions.
|
Returns True if the user has required permissions.
|
||||||
"""
|
"""
|
||||||
if self.action in ('metadata', 'list', 'retrieve'):
|
if self.action == 'retrieve':
|
||||||
|
result = self.access_permissions.can_retrieve(self.request.user)
|
||||||
|
elif self.action in ('metadata', 'list'):
|
||||||
result = self.request.user.has_perm('core.can_see_projector')
|
result = self.request.user.has_perm('core.can_see_projector')
|
||||||
elif self.action in ('activate_elements', 'prune_elements', 'update_elements',
|
elif self.action in ('activate_elements', 'prune_elements', 'update_elements',
|
||||||
'deactivate_elements', 'clear_elements', 'control_view'):
|
'deactivate_elements', 'clear_elements', 'control_view'):
|
||||||
|
@ -2,9 +2,10 @@ import json
|
|||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from openslides.users.auth import get_user
|
||||||
from django.core.wsgi import get_wsgi_application
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
from django.utils.importlib import import_module
|
||||||
from sockjs.tornado import SockJSConnection, SockJSRouter
|
from sockjs.tornado import SockJSConnection, SockJSRouter
|
||||||
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
||||||
from tornado.httpserver import HTTPServer
|
from tornado.httpserver import HTTPServer
|
||||||
@ -18,7 +19,6 @@ from tornado.web import (
|
|||||||
StaticFileHandler,
|
StaticFileHandler,
|
||||||
)
|
)
|
||||||
from tornado.wsgi import WSGIContainer
|
from tornado.wsgi import WSGIContainer
|
||||||
|
|
||||||
from .rest_api import get_collection_and_id_from_url
|
from .rest_api import get_collection_and_id_from_url
|
||||||
|
|
||||||
RUNNING_HOST = None
|
RUNNING_HOST = None
|
||||||
@ -59,6 +59,9 @@ class DjangoStaticFileHandler(StaticFileHandler):
|
|||||||
return absolute_path
|
return absolute_path
|
||||||
|
|
||||||
|
|
||||||
|
class FakeRequest:
|
||||||
|
pass
|
||||||
|
|
||||||
class OpenSlidesSockJSConnection(SockJSConnection):
|
class OpenSlidesSockJSConnection(SockJSConnection):
|
||||||
"""
|
"""
|
||||||
SockJS connection for OpenSlides.
|
SockJS connection for OpenSlides.
|
||||||
@ -72,78 +75,41 @@ class OpenSlidesSockJSConnection(SockJSConnection):
|
|||||||
def on_close(self):
|
def on_close(self):
|
||||||
OpenSlidesSockJSConnection.waiters.remove(self)
|
OpenSlidesSockJSConnection.waiters.remove(self)
|
||||||
|
|
||||||
def forward_rest_response(self, response):
|
|
||||||
"""
|
|
||||||
Sends data to the client of the connection instance.
|
|
||||||
|
|
||||||
This method is called after succesful response of AsyncHTTPClient().
|
|
||||||
See send_object().
|
|
||||||
"""
|
|
||||||
if response.code in (200, 404):
|
|
||||||
# Only send something to the client in case of one of these status
|
|
||||||
# codes. You have to change the client code (autoupdate.onMessage)
|
|
||||||
# if you want to handle some more codes.
|
|
||||||
collection, obj_id = get_collection_and_id_from_url(response.request.url)
|
|
||||||
data = {
|
|
||||||
'url': response.request.url,
|
|
||||||
'status_code': response.code,
|
|
||||||
'collection': collection,
|
|
||||||
'id': obj_id,
|
|
||||||
'data': json.loads(response.body.decode())}
|
|
||||||
self.send(data)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def send_object(cls, object_url):
|
def send_object(cls, instance, is_delete):
|
||||||
"""
|
"""
|
||||||
Sends an OpenSlides object to all connected clients (waiters).
|
Sends an OpenSlides object to all connected clients (waiters).
|
||||||
|
|
||||||
First, retrieve the object from the OpenSlides REST api using the given
|
|
||||||
object_url.
|
|
||||||
"""
|
"""
|
||||||
# Join network location with object URL.
|
|
||||||
if settings.OPENSLIDES_WSGI_NETWORK_LOCATION:
|
|
||||||
wsgi_network_location = settings.OPENSLIDES_WSGI_NETWORK_LOCATION
|
|
||||||
else:
|
|
||||||
if RUNNING_HOST == '0.0.0.0':
|
|
||||||
# Windows can not connect to 0.0.0.0, so connect to localhost instead.
|
|
||||||
wsgi_network_location = 'http://localhost:{}'.format(RUNNING_PORT)
|
|
||||||
else:
|
|
||||||
wsgi_network_location = 'http://{}:{}'.format(RUNNING_HOST, RUNNING_PORT)
|
|
||||||
url = ''.join((wsgi_network_location, object_url))
|
|
||||||
|
|
||||||
# Send out internal HTTP request to get data from the REST api.
|
# Send out internal HTTP request to get data from the REST api.
|
||||||
for waiter in cls.waiters:
|
for waiter in cls.waiters:
|
||||||
# Initiat new headers object.
|
|
||||||
headers = HTTPHeaders()
|
|
||||||
|
|
||||||
# Read waiter's former cookies and parse session cookie to new header object.
|
# Read waiter's former cookies and parse session cookie to new header object.
|
||||||
|
headers = HTTPHeaders()
|
||||||
try:
|
try:
|
||||||
session_cookie = waiter.connection_info.cookies[settings.SESSION_COOKIE_NAME]
|
session_cookie = waiter.connection_info.cookies[settings.SESSION_COOKIE_NAME]
|
||||||
|
engine = import_module(settings.SESSION_ENGINE)
|
||||||
|
session = engine.SessionStore(session_cookie)
|
||||||
|
|
||||||
|
request = FakeRequest()
|
||||||
|
request.session = session
|
||||||
|
|
||||||
|
user = get_user(request)
|
||||||
|
serializer_class = instance.access_permissions.get_serializer_class(user)
|
||||||
|
serialized_instance_data = serializer_class(instance).data
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'url': "foobar",
|
||||||
|
'status_code': 404 if is_delete else 200,
|
||||||
|
'collection': instance.get_collection_name(),
|
||||||
|
'id': instance.id,
|
||||||
|
'data': serialized_instance_data}
|
||||||
|
waiter.send(data)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# There is no session cookie
|
# There is no session cookie
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
headers.add('Cookie', '%s=%s' % (settings.SESSION_COOKIE_NAME, session_cookie.value))
|
headers.add('Cookie', '%s=%s' % (settings.SESSION_COOKIE_NAME, session_cookie.value))
|
||||||
|
|
||||||
# Read waiter's language header.
|
|
||||||
try:
|
|
||||||
languages = waiter.connection_info.headers['Accept-Language']
|
|
||||||
except KeyError:
|
|
||||||
# There is no language header
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
headers.parse_line('Accept-Language: ' + languages)
|
|
||||||
|
|
||||||
# Setup uncompressed request.
|
|
||||||
request = HTTPRequest(
|
|
||||||
url=url,
|
|
||||||
headers=headers,
|
|
||||||
decompress_response=False)
|
|
||||||
# Setup non-blocking HTTP client
|
|
||||||
http_client = AsyncHTTPClient()
|
|
||||||
# Executes the request, asynchronously returning an HTTPResponse
|
|
||||||
# and calling waiter's forward_rest_response() method.
|
|
||||||
http_client.fetch(request, waiter.forward_rest_response)
|
|
||||||
|
|
||||||
|
|
||||||
def run_tornado(addr, port, *args, **kwargs):
|
def run_tornado(addr, port, *args, **kwargs):
|
||||||
@ -182,23 +148,23 @@ def run_tornado(addr, port, *args, **kwargs):
|
|||||||
RUNNING_PORT = None
|
RUNNING_PORT = None
|
||||||
|
|
||||||
|
|
||||||
def inform_changed_data(*args):
|
def inform_changed_data(is_delete, *args):
|
||||||
"""
|
"""
|
||||||
Informs all users about changed data.
|
Informs all users about changed data.
|
||||||
|
|
||||||
The arguments are Django/OpenSlides models.
|
The arguments are Django/OpenSlides models.
|
||||||
"""
|
"""
|
||||||
rest_urls = set()
|
root_instances = set()
|
||||||
for instance in args:
|
for instance in args:
|
||||||
try:
|
try:
|
||||||
rest_urls.add(instance.get_root_rest_url())
|
root_instances.add(instance.get_root_rest_element())
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# Instance has no method get_root_rest_url. Just skip it.
|
# Instance has no method get_root_rest_url. Just skip it.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if settings.USE_TORNADO_AS_WSGI_SERVER:
|
if settings.USE_TORNADO_AS_WSGI_SERVER:
|
||||||
for url in rest_urls:
|
for root_instance in root_instances:
|
||||||
OpenSlidesSockJSConnection.send_object(url)
|
OpenSlidesSockJSConnection.send_object(root_instance, is_delete)
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
# TODO: Implement big varainte with Apache or Nginx as wsgi webserver.
|
# TODO: Implement big varainte with Apache or Nginx as wsgi webserver.
|
||||||
@ -208,4 +174,11 @@ def inform_changed_data_receiver(sender, instance, **kwargs):
|
|||||||
"""
|
"""
|
||||||
Receiver for the inform_changed_data function to use in a signal.
|
Receiver for the inform_changed_data function to use in a signal.
|
||||||
"""
|
"""
|
||||||
inform_changed_data(instance)
|
inform_changed_data(False, instance)
|
||||||
|
|
||||||
|
|
||||||
|
def inform_deleted_data_receiver(sender, instance, **kwargs):
|
||||||
|
"""
|
||||||
|
Receiver for the inform_changed_data function to use in a signal.
|
||||||
|
"""
|
||||||
|
inform_changed_data(True, instance)
|
||||||
|
@ -22,6 +22,12 @@ class RESTModelMixin:
|
|||||||
Mixin for django models which are used in our rest api.
|
Mixin for django models which are used in our rest api.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
access_permissions = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_collection_name(cls):
|
||||||
|
return "{0}/{1}".format(cls._meta.app_label.lower(), cls._meta.object_name.lower())
|
||||||
|
|
||||||
def get_root_rest_element(self):
|
def get_root_rest_element(self):
|
||||||
"""
|
"""
|
||||||
Returns the root rest instance.
|
Returns the root rest instance.
|
||||||
|
@ -95,28 +95,6 @@ class IdPrimaryKeyRelatedField(PrimaryKeyRelatedField):
|
|||||||
return IdManyRelatedField(**list_kwargs)
|
return IdManyRelatedField(**list_kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ModelSerializer(_ModelSerializer):
|
|
||||||
"""
|
|
||||||
ModelSerializer that changes the field names of related fields to
|
|
||||||
FIELD_NAME_id.
|
|
||||||
"""
|
|
||||||
serializer_related_field = IdPrimaryKeyRelatedField
|
|
||||||
|
|
||||||
def get_fields(self):
|
|
||||||
"""
|
|
||||||
Returns all fields of the serializer.
|
|
||||||
"""
|
|
||||||
fields = OrderedDict()
|
|
||||||
|
|
||||||
for field_name, field in super().get_fields().items():
|
|
||||||
try:
|
|
||||||
field_name += field.field_name_suffix
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
fields[field_name] = field
|
|
||||||
return fields
|
|
||||||
|
|
||||||
|
|
||||||
class PermissionMixin:
|
class PermissionMixin:
|
||||||
"""
|
"""
|
||||||
Mixin for subclasses of APIView like GenericViewSet and ModelViewSet.
|
Mixin for subclasses of APIView like GenericViewSet and ModelViewSet.
|
||||||
@ -126,6 +104,13 @@ class PermissionMixin:
|
|||||||
Django REST framework's permission system is disabled.
|
Django REST framework's permission system is disabled.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
serializer_class = self.access_permissions.get_serializer_class(self.request.user) if self.access_permissions is not None else None
|
||||||
|
return super().get_serializer_class() if serializer_class is None else serializer_class
|
||||||
|
|
||||||
def get_permissions(self):
|
def get_permissions(self):
|
||||||
"""
|
"""
|
||||||
Overriden method to check view and projector permissions. Returns an
|
Overriden method to check view and projector permissions. Returns an
|
||||||
@ -160,12 +145,34 @@ class PermissionMixin:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class ModelSerializer(_ModelSerializer):
|
||||||
|
"""
|
||||||
|
ModelSerializer that changes the field names of related fields to
|
||||||
|
FIELD_NAME_id.
|
||||||
|
"""
|
||||||
|
serializer_related_field = IdPrimaryKeyRelatedField
|
||||||
|
|
||||||
|
def get_fields(self):
|
||||||
|
"""
|
||||||
|
Returns all fields of the serializer.
|
||||||
|
"""
|
||||||
|
fields = OrderedDict()
|
||||||
|
|
||||||
|
for field_name, field in super().get_fields().items():
|
||||||
|
try:
|
||||||
|
field_name += field.field_name_suffix
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
fields[field_name] = field
|
||||||
|
return fields
|
||||||
|
|
||||||
|
|
||||||
class GenericViewSet(PermissionMixin, _GenericViewSet):
|
class GenericViewSet(PermissionMixin, _GenericViewSet):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ModelViewSet(PermissionMixin, _ModelViewSet):
|
class ModelViewSet(PermissionMixin, _ModelViewSet):
|
||||||
pass
|
access_permissions = None
|
||||||
|
|
||||||
|
|
||||||
class ReadOnlyModelViewSet(PermissionMixin, _ReadOnlyModelViewSet):
|
class ReadOnlyModelViewSet(PermissionMixin, _ReadOnlyModelViewSet):
|
||||||
|
@ -10,3 +10,7 @@ def to_roman(number):
|
|||||||
return roman.toRoman(number)
|
return roman.toRoman(number)
|
||||||
except (roman.NotIntegerError, roman.OutOfRangeError):
|
except (roman.NotIntegerError, roman.OutOfRangeError):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def collection_name(model_class):
|
||||||
|
return "{1}/{2}".format(model_class.Meta.app_label.lower(), model_class.Meta.object_name)
|
||||||
|
Loading…
Reference in New Issue
Block a user