Forwarding JSON instead of Django model instances to autoupdate loop.
- Used raw SQL for createing default projector during inital migration. - Removed default_password and hidden agenda items from autoupdate data for some users. - Removed old get_collection_and_id_from_url() function.
This commit is contained in:
parent
4daa61888f
commit
132c6e81ec
@ -11,10 +11,23 @@ class ItemAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('agenda.can_see')
|
return user.has_perm('agenda.can_see')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
from .serializers import ItemSerializer
|
from .serializers import ItemSerializer
|
||||||
|
|
||||||
return ItemSerializer
|
return ItemSerializer
|
||||||
|
|
||||||
|
def get_restricted_data(self, full_data, user):
|
||||||
|
"""
|
||||||
|
Returns the restricted serialized data for the instance prepared
|
||||||
|
for the user.
|
||||||
|
"""
|
||||||
|
if (self.can_retrieve(user) and
|
||||||
|
(not full_data['is_hidden'] or
|
||||||
|
user.has_perm('agenda.can_see_hidden_items'))):
|
||||||
|
data = full_data
|
||||||
|
else:
|
||||||
|
data = None
|
||||||
|
return data
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
from django.core.urlresolvers import reverse
|
from openslides.utils.rest_api import ModelSerializer, RelatedField
|
||||||
|
|
||||||
from openslides.utils.rest_api import (
|
|
||||||
ModelSerializer,
|
|
||||||
RelatedField,
|
|
||||||
get_collection_and_id_from_url,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .models import Item, Speaker
|
from .models import Item, Speaker
|
||||||
|
|
||||||
@ -34,10 +28,7 @@ class RelatedItemRelatedField(RelatedField):
|
|||||||
Returns info concerning the related object extracted from the api URL
|
Returns info concerning the related object extracted from the api URL
|
||||||
of this object.
|
of this object.
|
||||||
"""
|
"""
|
||||||
view_name = '%s-detail' % type(value)._meta.object_name.lower()
|
return {'collection': value.get_collection_string(), 'id': value.get_rest_pk()}
|
||||||
url = reverse(view_name, kwargs={'pk': value.pk})
|
|
||||||
collection, obj_id = get_collection_and_id_from_url(url)
|
|
||||||
return {'collection': collection, 'id': obj_id}
|
|
||||||
|
|
||||||
|
|
||||||
class ItemSerializer(ModelSerializer):
|
class ItemSerializer(ModelSerializer):
|
||||||
|
@ -63,7 +63,6 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
|
|||||||
Checks if the requesting user has permission to see also an
|
Checks if the requesting user has permission to see also an
|
||||||
organizational item if it is one.
|
organizational item if it is one.
|
||||||
"""
|
"""
|
||||||
#TODO
|
|
||||||
if obj.is_hidden() and not request.user.has_perm('agenda.can_see_hidden_items'):
|
if obj.is_hidden() and not request.user.has_perm('agenda.can_see_hidden_items'):
|
||||||
self.permission_denied(request)
|
self.permission_denied(request)
|
||||||
|
|
||||||
|
@ -11,14 +11,27 @@ class AssignmentAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('assignments.can_see')
|
return user.has_perm('assignments.can_see')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns different serializer classes according to users permissions.
|
Returns different serializer classes according to users permissions.
|
||||||
"""
|
"""
|
||||||
from .serializers import AssignmentFullSerializer, AssignmentShortSerializer
|
from .serializers import AssignmentFullSerializer, AssignmentShortSerializer
|
||||||
|
|
||||||
if user.has_perm('assignments.can_manage'):
|
if user is None or user.has_perm('assignments.can_manage'):
|
||||||
serializer_class = AssignmentFullSerializer
|
serializer_class = AssignmentFullSerializer
|
||||||
else:
|
else:
|
||||||
serializer_class = AssignmentShortSerializer
|
serializer_class = AssignmentShortSerializer
|
||||||
return serializer_class
|
return serializer_class
|
||||||
|
|
||||||
|
def get_restricted_data(self, full_data, user):
|
||||||
|
"""
|
||||||
|
Returns the restricted serialized data for the instance prepared
|
||||||
|
for the user. Removes unpublushed polls for non admins so that they
|
||||||
|
only get a result like the AssignmentShortSerializer would give them.
|
||||||
|
"""
|
||||||
|
if user.has_perm('assignments.can_manage'):
|
||||||
|
data = full_data
|
||||||
|
else:
|
||||||
|
data = full_data.copy()
|
||||||
|
data['polls'] = [poll for poll in data['polls'] if poll['published']]
|
||||||
|
return data
|
||||||
|
@ -12,6 +12,7 @@ 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
|
||||||
|
@ -11,7 +11,7 @@ class ProjectorAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('core.can_see_projector')
|
return user.has_perm('core.can_see_projector')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
@ -30,7 +30,7 @@ class CustomSlideAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('core.can_manage_projector')
|
return user.has_perm('core.can_manage_projector')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
@ -53,7 +53,7 @@ class TagAccessPermissions(BaseAccessPermissions):
|
|||||||
# so if they are enabled.
|
# so if they are enabled.
|
||||||
return user.is_authenticated() or config['general_system_enable_anonymous']
|
return user.is_authenticated() or config['general_system_enable_anonymous']
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
@ -74,7 +74,7 @@ class ChatMessageAccessPermissions(BaseAccessPermissions):
|
|||||||
# permission core.can_use_chat. But they can not use it. See views.py.
|
# permission core.can_use_chat. But they can not use it. See views.py.
|
||||||
return user.has_perm('core.can_use_chat')
|
return user.has_perm('core.can_use_chat')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
@ -98,12 +98,12 @@ class ConfigAccessPermissions(BaseAccessPermissions):
|
|||||||
# the config. Anonymous users can do so if they are enabled.
|
# the config. Anonymous users can do so if they are enabled.
|
||||||
return user.is_authenticated() or config['general_system_enable_anonymous']
|
return user.is_authenticated() or config['general_system_enable_anonymous']
|
||||||
|
|
||||||
def get_serialized_data(self, instance, user):
|
def get_full_data(self, instance):
|
||||||
"""
|
"""
|
||||||
Returns the serlialized config data or None if the user is not
|
Returns the serlialized config data.
|
||||||
allowed to see it.
|
|
||||||
"""
|
"""
|
||||||
from .config import config
|
from .config import config
|
||||||
|
|
||||||
if self.can_retrieve(user) is not None:
|
# Attention: The format of this response has to be the same as in
|
||||||
|
# the retrieve method of ConfigViewSet.
|
||||||
return {'key': instance.key, 'value': config[instance.key]}
|
return {'key': instance.key, 'value': config[instance.key]}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# Generated by Django 1.9.2 on 2016-03-02 01:22
|
# Generated by Django 1.9.2 on 2016-03-02 01:22
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@ -12,18 +13,15 @@ from django.db import migrations, models
|
|||||||
import openslides.utils.models
|
import openslides.utils.models
|
||||||
|
|
||||||
|
|
||||||
def add_default_projector(apps, schema_editor):
|
def add_default_projector_via_sql():
|
||||||
"""
|
"""
|
||||||
Adds default projector and activates clock.
|
Adds default projector and activates clock.
|
||||||
"""
|
"""
|
||||||
# We get the model from the versioned app registry;
|
|
||||||
# if we directly import it, it will be the wrong version.
|
|
||||||
Projector = apps.get_model('core', 'Projector')
|
|
||||||
projector_config = {}
|
projector_config = {}
|
||||||
projector_config[uuid.uuid4().hex] = {
|
projector_config[uuid.uuid4().hex] = {
|
||||||
'name': 'core/clock',
|
'name': 'core/clock',
|
||||||
'stable': True}
|
'stable': True}
|
||||||
Projector.objects.create(config=projector_config)
|
return ["INSERT INTO core_projector (config, scale, scroll) VALUES ('{}', 0, 0);".format(json.dumps(projector_config))]
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@ -107,9 +105,5 @@ class Migration(migrations.Migration):
|
|||||||
},
|
},
|
||||||
bases=(openslides.utils.models.RESTModelMixin, models.Model),
|
bases=(openslides.utils.models.RESTModelMixin, models.Model),
|
||||||
),
|
),
|
||||||
migrations.RunPython(
|
migrations.RunSQL(add_default_projector_via_sql()),
|
||||||
code=add_default_projector,
|
|
||||||
reverse_code=None,
|
|
||||||
atomic=True,
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
@ -485,7 +485,7 @@ class ConfigViewSet(ViewSet):
|
|||||||
except ConfigNotFound:
|
except ConfigNotFound:
|
||||||
raise Http404
|
raise Http404
|
||||||
# Attention: The format of this response has to be the same as in
|
# Attention: The format of this response has to be the same as in
|
||||||
# the get_serialized_data method of ConfigAccessPermissions.
|
# the get_full_data method of ConfigAccessPermissions.
|
||||||
return Response({'key': key, 'value': value})
|
return Response({'key': key, 'value': value})
|
||||||
|
|
||||||
def update(self, request, *args, **kwargs):
|
def update(self, request, *args, **kwargs):
|
||||||
|
@ -11,7 +11,7 @@ class MediafileAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('mediafiles.can_see')
|
return user.has_perm('mediafiles.can_see')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
|
@ -11,7 +11,7 @@ class MotionAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('motions.can_see')
|
return user.has_perm('motions.can_see')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
@ -30,7 +30,7 @@ class CategoryAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('motions.can_see')
|
return user.has_perm('motions.can_see')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
@ -49,7 +49,7 @@ class WorkflowAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('motions.can_see')
|
return user.has_perm('motions.can_see')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns serializer class.
|
Returns serializer class.
|
||||||
"""
|
"""
|
||||||
|
@ -11,16 +11,39 @@ class UserAccessPermissions(BaseAccessPermissions):
|
|||||||
"""
|
"""
|
||||||
return user.has_perm('users.can_see_name')
|
return user.has_perm('users.can_see_name')
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns different serializer classes with respect user's permissions.
|
Returns different serializer classes with respect user's permissions.
|
||||||
"""
|
"""
|
||||||
from .serializers import UserFullSerializer, UserShortSerializer
|
from .serializers import UserFullSerializer, UserShortSerializer
|
||||||
|
|
||||||
if user.has_perm('users.can_see_extra_data'):
|
if user is None or user.has_perm('users.can_see_extra_data'):
|
||||||
# Return the UserFullSerializer for requests of users with more
|
# Return the UserFullSerializer for requests of users with more
|
||||||
# permissions.
|
# permissions.
|
||||||
serializer_class = UserFullSerializer
|
serializer_class = UserFullSerializer
|
||||||
else:
|
else:
|
||||||
serializer_class = UserShortSerializer
|
serializer_class = UserShortSerializer
|
||||||
return serializer_class
|
return serializer_class
|
||||||
|
|
||||||
|
def get_restricted_data(self, full_data, user):
|
||||||
|
"""
|
||||||
|
Returns the restricted serialized data for the instance prepared
|
||||||
|
for the user. Removes several fields for non admins so that they do
|
||||||
|
not get the default_password or even get only the fields as the
|
||||||
|
UserShortSerializer would give them.
|
||||||
|
"""
|
||||||
|
from .serializers import USERSHORTSERIALIZER_FIELDS
|
||||||
|
|
||||||
|
if user.has_perm('users.can_manage'):
|
||||||
|
data = full_data
|
||||||
|
elif user.has_perm('users.can_see_extra_data'):
|
||||||
|
# Only remove default password from full data.
|
||||||
|
data = full_data.copy()
|
||||||
|
del data['default_password']
|
||||||
|
else:
|
||||||
|
# Let only fields as in the UserShortSerializer pass this method.
|
||||||
|
data = {}
|
||||||
|
for key in full_data.keys():
|
||||||
|
if key in USERSHORTSERIALIZER_FIELDS:
|
||||||
|
data[key] = full_data[key]
|
||||||
|
return data
|
||||||
|
@ -11,16 +11,7 @@ from ..utils.rest_api import (
|
|||||||
)
|
)
|
||||||
from .models import Group, User
|
from .models import Group, User
|
||||||
|
|
||||||
|
USERSHORTSERIALIZER_FIELDS = (
|
||||||
class UserShortSerializer(ModelSerializer):
|
|
||||||
"""
|
|
||||||
Serializer for users.models.User objects.
|
|
||||||
|
|
||||||
Serializes only name fields and about me field.
|
|
||||||
"""
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = (
|
|
||||||
'id',
|
'id',
|
||||||
'username',
|
'username',
|
||||||
'title',
|
'title',
|
||||||
@ -32,6 +23,17 @@ class UserShortSerializer(ModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class UserShortSerializer(ModelSerializer):
|
||||||
|
"""
|
||||||
|
Serializer for users.models.User objects.
|
||||||
|
|
||||||
|
Serializes only name fields and about me field.
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = USERSHORTSERIALIZER_FIELDS
|
||||||
|
|
||||||
|
|
||||||
class UserFullSerializer(ModelSerializer):
|
class UserFullSerializer(ModelSerializer):
|
||||||
"""
|
"""
|
||||||
Serializer for users.models.User objects.
|
Serializer for users.models.User objects.
|
||||||
|
@ -75,7 +75,6 @@ class UserViewSet(ModelViewSet):
|
|||||||
|
|
||||||
Hides the default_password for non admins.
|
Hides the default_password for non admins.
|
||||||
"""
|
"""
|
||||||
#TODO: Hide default_password also in case of autoupdate.
|
|
||||||
response = super().retrieve(request, *args, **kwargs)
|
response = super().retrieve(request, *args, **kwargs)
|
||||||
self.extract_default_password(response)
|
self.extract_default_password(response)
|
||||||
return response
|
return response
|
||||||
|
@ -1,30 +1,77 @@
|
|||||||
class BaseAccessPermissions:
|
from django.dispatch import Signal
|
||||||
|
|
||||||
|
from .dispatch import SignalConnectMetaClass
|
||||||
|
|
||||||
|
|
||||||
|
class BaseAccessPermissions(object, metaclass=SignalConnectMetaClass):
|
||||||
"""
|
"""
|
||||||
Base access permissions container.
|
Base access permissions container.
|
||||||
|
|
||||||
|
Every app which has autoupdate models has to create classes subclassing
|
||||||
|
from this base class for every autoupdate root model. Each subclass has
|
||||||
|
to have a globally unique name. The metaclass (SignalConnectMetaClass)
|
||||||
|
does the rest of the magic.
|
||||||
"""
|
"""
|
||||||
|
signal = Signal()
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
"""
|
||||||
|
Initializes the access permission instance. This is done when the
|
||||||
|
signal is sent.
|
||||||
|
|
||||||
|
Because of Django's signal API, we have to take wildcard keyword
|
||||||
|
arguments. But they are not used here.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_dispatch_uid(cls):
|
||||||
|
"""
|
||||||
|
Returns the classname as a unique string for each class. Returns None
|
||||||
|
for the base class so it will not be connected to the signal.
|
||||||
|
"""
|
||||||
|
if not cls.__name__ == 'BaseAccessPermissions':
|
||||||
|
return cls.__name__
|
||||||
|
|
||||||
def can_retrieve(self, user):
|
def can_retrieve(self, user):
|
||||||
"""
|
"""
|
||||||
Returns True if the user has read access model instances.
|
Returns True if the user has read access to model instances.
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_serializer_class(self, user):
|
def get_serializer_class(self, user=None):
|
||||||
"""
|
"""
|
||||||
Returns different serializer classes according to users permissions.
|
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().
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"You have to add the classmethod 'get_serializer_class' to your "
|
"You have to add the method 'get_serializer_class' to your "
|
||||||
"access permissions class.".format(self))
|
"access permissions class.".format(self))
|
||||||
|
|
||||||
def get_serialized_data(self, instance, user):
|
def get_full_data(self, instance):
|
||||||
"""
|
"""
|
||||||
Returns the serialized data for the instance prepared for the user.
|
Returns all possible serialized data for the given instance.
|
||||||
|
"""
|
||||||
|
return self.get_serializer_class(user=None)(instance).data
|
||||||
|
|
||||||
Returns None if the user has no read access.
|
def get_restricted_data(self, full_data, user):
|
||||||
|
"""
|
||||||
|
Returns the restricted serialized data for the instance prepared
|
||||||
|
for the user.
|
||||||
|
|
||||||
|
Returns None 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 may return different serializer for
|
||||||
|
different users or if you have access restrictions in your view or
|
||||||
|
viewset in methods like retrieve() or check_object_permissions().
|
||||||
"""
|
"""
|
||||||
if self.can_retrieve(user):
|
if self.can_retrieve(user):
|
||||||
serializer_class = self.get_serializer_class(user)
|
data = full_data
|
||||||
data = serializer_class(instance).data
|
|
||||||
else:
|
else:
|
||||||
data = None
|
data = None
|
||||||
return data
|
return data
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
@ -17,7 +18,8 @@ from tornado.web import (
|
|||||||
)
|
)
|
||||||
from tornado.wsgi import WSGIContainer
|
from tornado.wsgi import WSGIContainer
|
||||||
|
|
||||||
from openslides.users.auth import AnonymousUser, get_user
|
from ..users.auth import AnonymousUser, get_user
|
||||||
|
from .access_permissions import BaseAccessPermissions
|
||||||
|
|
||||||
RUNNING_HOST = None
|
RUNNING_HOST = None
|
||||||
RUNNING_PORT = None
|
RUNNING_PORT = None
|
||||||
@ -71,10 +73,21 @@ class OpenSlidesSockJSConnection(SockJSConnection):
|
|||||||
OpenSlidesSockJSConnection.waiters.remove(self)
|
OpenSlidesSockJSConnection.waiters.remove(self)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def send_object(cls, instance, is_delete):
|
def send_object(cls, json_container):
|
||||||
"""
|
"""
|
||||||
Sends an OpenSlides object to all connected clients (waiters).
|
Sends an OpenSlides object to all connected clients (waiters).
|
||||||
"""
|
"""
|
||||||
|
# Load JSON
|
||||||
|
container = json.loads(json_container)
|
||||||
|
|
||||||
|
# Search our AccessPermission class.
|
||||||
|
for access_permissions in BaseAccessPermissions.get_all():
|
||||||
|
if access_permissions.get_dispatch_uid() == container.get('dispatch_uid'):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid container. A valid dispatch_uid is missing.')
|
||||||
|
|
||||||
|
# Loop over all waiters
|
||||||
for waiter in cls.waiters:
|
for waiter in cls.waiters:
|
||||||
# Read waiter's former cookies and parse session cookie to get user instance.
|
# Read waiter's former cookies and parse session cookie to get user instance.
|
||||||
try:
|
try:
|
||||||
@ -89,15 +102,28 @@ class OpenSlidesSockJSConnection(SockJSConnection):
|
|||||||
fake_request = type('FakeRequest', (), {})()
|
fake_request = type('FakeRequest', (), {})()
|
||||||
fake_request.session = session
|
fake_request.session = session
|
||||||
user = get_user(fake_request)
|
user = get_user(fake_request)
|
||||||
# Fetch serialized data and send them out to the waiter (client).
|
|
||||||
serialized_instance_data = instance.get_access_permissions().get_serialized_data(instance, user)
|
# Two cases: models instance was changed or deleted
|
||||||
if serialized_instance_data is not None:
|
if container.get('action') == 'changed':
|
||||||
data = {
|
data = access_permissions.get_restricted_data(container.get('full_data'), user)
|
||||||
'status_code': 404 if is_delete else 200, # TODO: Refactor this. Use strings like 'change' or 'delete'.
|
if data is None:
|
||||||
'collection': instance.get_collection_string(),
|
# There are no data for the user so he can't see the object. Skip him.
|
||||||
'id': instance.get_rest_pk(),
|
break
|
||||||
'data': serialized_instance_data}
|
output = {
|
||||||
waiter.send(data)
|
'status_code': 200, # TODO: Refactor this. Use strings like 'change' or 'delete'.
|
||||||
|
'collection': container['collection_string'],
|
||||||
|
'id': container['rest_pk'],
|
||||||
|
'data': data}
|
||||||
|
elif container.get('action') == 'deleted':
|
||||||
|
output = {
|
||||||
|
'status_code': 404, # TODO: Refactor this. Use strings like 'change' or 'delete'.
|
||||||
|
'collection': container['collection_string'],
|
||||||
|
'id': container['rest_pk']}
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid container. A valid action is missing.')
|
||||||
|
|
||||||
|
# Send output to the waiter (client).
|
||||||
|
waiter.send(output)
|
||||||
|
|
||||||
|
|
||||||
def run_tornado(addr, port, *args, **kwargs):
|
def run_tornado(addr, port, *args, **kwargs):
|
||||||
@ -152,13 +178,20 @@ def inform_changed_data(is_delete, *args):
|
|||||||
# Instance has no method get_root_rest_element. Just skip it.
|
# Instance has no method get_root_rest_element. Just skip it.
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
access_permissions = root_instance.get_access_permissions()
|
||||||
|
container = {
|
||||||
|
'dispatch_uid': access_permissions.get_dispatch_uid(),
|
||||||
|
'collection_string': root_instance.get_collection_string(),
|
||||||
|
'rest_pk': root_instance.get_rest_pk()}
|
||||||
if is_delete and instance == root_instance:
|
if is_delete and instance == root_instance:
|
||||||
# A root instance is deleted.
|
# A root instance is deleted.
|
||||||
OpenSlidesSockJSConnection.send_object(root_instance, is_delete)
|
container['action'] = 'deleted'
|
||||||
else:
|
else:
|
||||||
# A non root instance is deleted or any instance is just changed.
|
# A non root instance is deleted or any instance is just changed.
|
||||||
|
container['action'] = 'changed'
|
||||||
root_instance.refresh_from_db()
|
root_instance.refresh_from_db()
|
||||||
OpenSlidesSockJSConnection.send_object(root_instance, False)
|
container['full_data'] = access_permissions.get_full_data(root_instance)
|
||||||
|
OpenSlidesSockJSConnection.send_object(json.dumps(container))
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
# TODO: Implement big variant with Apache or Nginx as WSGI webserver.
|
# TODO: Implement big variant with Apache or Nginx as WSGI webserver.
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import re
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
from rest_framework import status # noqa
|
from rest_framework import status # noqa
|
||||||
from rest_framework.decorators import detail_route, list_route # noqa
|
from rest_framework.decorators import detail_route, list_route # noqa
|
||||||
@ -35,8 +33,6 @@ from rest_framework.viewsets import \
|
|||||||
ReadOnlyModelViewSet as _ReadOnlyModelViewSet # noqa
|
ReadOnlyModelViewSet as _ReadOnlyModelViewSet # noqa
|
||||||
from rest_framework.viewsets import ViewSet as _ViewSet # noqa
|
from rest_framework.viewsets import ViewSet as _ViewSet # noqa
|
||||||
|
|
||||||
from .exceptions import OpenSlidesError
|
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
|
|
||||||
|
|
||||||
@ -198,21 +194,3 @@ class ReadOnlyModelViewSet(PermissionMixin, _ReadOnlyModelViewSet):
|
|||||||
|
|
||||||
class ViewSet(PermissionMixin, _ViewSet):
|
class ViewSet(PermissionMixin, _ViewSet):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
#TODO: Remove this method
|
|
||||||
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/rest/users/user/3/')
|
|
||||||
returns ('users/user', '3').
|
|
||||||
|
|
||||||
Raises OpenSlidesError if the URL is invalid.
|
|
||||||
"""
|
|
||||||
path = urlparse(url).path
|
|
||||||
match = re.match(r'^/rest/(?P<collection>[-\w]+/[-\w]+)/(?P<id>[-\w]+)/$', path)
|
|
||||||
if not match:
|
|
||||||
raise OpenSlidesError('Invalid REST API URL: %s' % url)
|
|
||||||
return match.group('collection'), match.group('id')
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from openslides.agenda.models import Item, Speaker
|
from openslides.agenda.models import Item, Speaker
|
||||||
|
from openslides.core.models import CustomSlide
|
||||||
from openslides.users.models import User
|
from openslides.users.models import User
|
||||||
from openslides.utils.exceptions import OpenSlidesError
|
from openslides.utils.exceptions import OpenSlidesError
|
||||||
from openslides.utils.test import TestCase
|
from openslides.utils.test import TestCase
|
||||||
@ -6,8 +7,8 @@ from openslides.utils.test import TestCase
|
|||||||
|
|
||||||
class ListOfSpeakerModelTests(TestCase):
|
class ListOfSpeakerModelTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.item1 = Item.objects.create(title='item1')
|
self.item1 = CustomSlide.objects.create(title='item1').agenda_item
|
||||||
self.item2 = Item.objects.create(title='item2')
|
self.item2 = CustomSlide.objects.create(title='item2').agenda_item
|
||||||
self.speaker1 = User.objects.create(username='user1')
|
self.speaker1 = User.objects.create(username='user1')
|
||||||
self.speaker2 = User.objects.create(username='user2')
|
self.speaker2 = User.objects.create(username='user2')
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class MediafileTest(TestCase):
|
|||||||
os.close(tmpfile_no)
|
os.close(tmpfile_no)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.object.mediafile.delete()
|
self.object.mediafile.delete(save=False)
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
self.assertEqual(str(self.object), 'Title File 1')
|
self.assertEqual(str(self.object), 'Title File 1')
|
||||||
|
Loading…
Reference in New Issue
Block a user