OpenSlides/openslides/utils/rest_api.py

113 lines
3.7 KiB
Python
Raw Normal View History

import re
from urllib.parse import urlparse
from django.core.urlresolvers import reverse
from rest_framework.decorators import detail_route # noqa
from rest_framework.decorators import list_route # noqa
from rest_framework.metadata import SimpleMetadata # noqa
from rest_framework.mixins import DestroyModelMixin, UpdateModelMixin # noqa
from rest_framework.response import Response # noqa
from rest_framework.routers import DefaultRouter
from rest_framework.serializers import ( # noqa
CharField,
DictField,
Field,
IntegerField,
ListField,
ListSerializer,
ModelSerializer,
PrimaryKeyRelatedField,
RelatedField,
SerializerMethodField,
ValidationError,
)
from rest_framework.viewsets import ModelViewSet as _ModelViewSet # noqa
from rest_framework.viewsets import ( # noqa
GenericViewSet,
ReadOnlyModelViewSet,
ViewSet,
)
2014-10-11 14:15:42 +02:00
from .exceptions import OpenSlidesError
router = DefaultRouter()
class RESTModelMixin:
"""
Mixin for django models which are used in our rest api.
"""
def get_root_rest_element(self):
"""
Returns the root rest instance.
Uses self as default.
"""
return self
def get_root_rest_url(self):
"""
Returns the detail url of the root model of this object.
"""
# Gets the default url-name in the same way as django rest framework
# does in relations.HyperlinkedModelSerializer
root_instance = self.get_root_rest_element()
rest_url = '%s-detail' % type(root_instance)._meta.object_name.lower()
return reverse(rest_url, args=[str(root_instance.pk)])
class ModelViewSet(_ModelViewSet):
"""
Viewset for models. Before the method check_permission is called we
check projector requirements. If access for projector client users is
not currently required, check_permission is called, else not.
"""
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Ensure that the incoming request is permitted
self.perform_authentication(request)
if not self.check_projector_requirements():
self.check_permissions(request)
self.check_throttles(request)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
def check_projector_requirements(self):
"""
Helper method which returns True if the current request (on this
view instance) is required for at least one active projector element.
"""
from openslides.core.models import Projector
result = False
if self.request.user.has_perm('core.can_see_projector'):
for requirement in Projector.get_all_requirements():
if requirement.is_currently_required(view_instance=self):
result = True
break
return result
def get_collection_and_id_from_url(url):
"""
Helper function. Returns a tuple containing the collection name and the id
extracted out of the given REST api URL.
For example get_collection_and_id_from_url('http://localhost/api/users/user/3/')
returns ('users/user', '3').
Raises OpenSlidesError if the URL is invalid.
"""
path = urlparse(url).path
2015-01-30 11:58:36 +01:00
match = re.match(r'^/rest/(?P<collection>[-\w]+/[-\w]+)/(?P<id>[-\w]+)/$', path)
if not match:
raise OpenSlidesError('Invalid REST api URL: %s' % url)
2015-01-30 11:58:36 +01:00
return match.group('collection'), match.group('id')