Merge pull request #1535 from normanjaeckel/RESTProjectorPermissions
Added permission check for objects required for active projector elem…
This commit is contained in:
commit
237b0630ca
@ -18,7 +18,7 @@ def add_default_projector(apps, schema_editor):
|
||||
weight=-500)
|
||||
Projector = apps.get_model('core', 'Projector')
|
||||
projector_config = [
|
||||
{'name': 'core/clock'},
|
||||
{'name': 'core/clock', 'stable': True},
|
||||
{'name': 'core/customslide', 'id': custom_slide.id}]
|
||||
Projector.objects.create(config=projector_config)
|
||||
|
||||
|
@ -52,7 +52,7 @@ class Projector(RESTModelMixin, models.Model):
|
||||
for element in ProjectorElement.get_all():
|
||||
elements[element.name] = element
|
||||
for config_entry in self.config:
|
||||
name = config_entry.get('name')
|
||||
name = config_entry['name']
|
||||
element = elements.get(name)
|
||||
data = {'name': name}
|
||||
if element is None:
|
||||
@ -66,6 +66,22 @@ class Projector(RESTModelMixin, models.Model):
|
||||
data['error'] = str(e)
|
||||
yield data
|
||||
|
||||
@classmethod
|
||||
def get_all_requirements(cls):
|
||||
"""
|
||||
Generator which returns all ProjectorRequirement instances of all
|
||||
active projector elements.
|
||||
"""
|
||||
elements = {}
|
||||
for element in ProjectorElement.get_all():
|
||||
elements[element.name] = element
|
||||
for projector in cls.objects.all():
|
||||
for config_entry in projector.config:
|
||||
element = elements.get(config_entry['name'])
|
||||
if element is not None:
|
||||
for requirement in element.get_requirements(config_entry):
|
||||
yield requirement
|
||||
|
||||
|
||||
class CustomSlide(RESTModelMixin, AbsoluteUrlMixin, models.Model):
|
||||
"""
|
||||
|
@ -1,10 +1,11 @@
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from openslides.utils.projector import ProjectorElement
|
||||
from openslides.utils.projector import ProjectorElement, ProjectorRequirement
|
||||
|
||||
from .exceptions import ProjectorException
|
||||
from .models import CustomSlide
|
||||
from .views import CustomSlideViewSet
|
||||
|
||||
|
||||
class CustomSlideSlide(ProjectorElement):
|
||||
@ -22,6 +23,19 @@ class CustomSlideSlide(ProjectorElement):
|
||||
'collection': 'core/customslide',
|
||||
'id': pk}]
|
||||
|
||||
def get_requirements(self, config_entry):
|
||||
self.config_entry = config_entry
|
||||
try:
|
||||
pk = self.get_context()[0]['id']
|
||||
except ProjectorException:
|
||||
# Custom slide does not exist so just do nothing.
|
||||
pass
|
||||
else:
|
||||
yield ProjectorRequirement(
|
||||
view_class=CustomSlideViewSet,
|
||||
view_action='retrieve',
|
||||
pk=str(pk))
|
||||
|
||||
|
||||
class Clock(ProjectorElement):
|
||||
"""
|
||||
|
@ -1,9 +1,10 @@
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from openslides.core.exceptions import ProjectorException
|
||||
from openslides.utils.projector import ProjectorElement
|
||||
from openslides.utils.projector import ProjectorElement, ProjectorRequirement
|
||||
|
||||
from .models import User
|
||||
from .views import GroupViewSet, UserViewSet
|
||||
|
||||
|
||||
class UserSlide(ProjectorElement):
|
||||
@ -27,3 +28,17 @@ class UserSlide(ProjectorElement):
|
||||
'collection': 'users/group',
|
||||
'id': group.pk})
|
||||
return result
|
||||
|
||||
def get_requirements(self, config_entry):
|
||||
self.config_entry = config_entry
|
||||
try:
|
||||
context = self.get_context()
|
||||
except ProjectorException:
|
||||
# User does not exist so just do nothing.
|
||||
pass
|
||||
else:
|
||||
for item in context:
|
||||
yield ProjectorRequirement(
|
||||
view_class=UserViewSet if item['collection'] == 'users/user' else GroupViewSet,
|
||||
view_action='retrieve',
|
||||
pk=str(item['id']))
|
||||
|
@ -64,3 +64,39 @@ class ProjectorElement(object, metaclass=SignalConnectMetaClass):
|
||||
Returns the context of the projector element.
|
||||
"""
|
||||
return None
|
||||
|
||||
def get_requirements(self, config_entry):
|
||||
"""
|
||||
Returns an iterable of ProjectorRequirement instances to setup
|
||||
which views should be accessable for projector clients if the
|
||||
projector element is active. The config_entry has to be given.
|
||||
"""
|
||||
return ()
|
||||
|
||||
|
||||
class ProjectorRequirement:
|
||||
"""
|
||||
Container for required views. Such a view is defined by its class, its
|
||||
action and its kwargs which come from the URL path.
|
||||
"""
|
||||
def __init__(self, view_class, view_action, **kwargs):
|
||||
self.view_class = view_class
|
||||
self.view_action = view_action
|
||||
self.kwargs = kwargs
|
||||
|
||||
def is_currently_required(self, view_instance):
|
||||
"""
|
||||
Returns True if the view_instance matches the initiated data of this
|
||||
requirement.
|
||||
"""
|
||||
if not type(view_instance) == self.view_class:
|
||||
result = False
|
||||
elif not view_instance.action == self.view_action:
|
||||
result = False
|
||||
else:
|
||||
result = True
|
||||
for key in view_instance.kwargs:
|
||||
if not self.kwargs[key] == view_instance.kwargs[key]:
|
||||
result = False
|
||||
break
|
||||
return result
|
||||
|
@ -19,7 +19,8 @@ from rest_framework.serializers import ( # 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.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet, ViewSet # noqa
|
||||
from rest_framework.viewsets import ModelViewSet as _ModelViewSet
|
||||
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet, ViewSet # noqa
|
||||
from rest_framework.decorators import list_route # noqa
|
||||
|
||||
from .exceptions import OpenSlidesError
|
||||
@ -51,6 +52,44 @@ class RESTModelMixin:
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user