OpenSlides/openslides/utils/collection.py
Oskar Hahn 6abb0976c2 Change system for autoupdate on the projector (#2394)
* Second websocket channel for the projector

* Removed use of projector requirements for REST API requests.

Refactored data serializing for projector websocket connection.

* Refactor the way that the projector autoupdate get its data.

* Fixed missing assignment slide title for hidden items.

* Release all items for item list slide and list of speakers slide. Fixed error with motion workflow.

* Created CollectionElement class which helps to handle autoupdate.
2016-09-17 22:26:23 +02:00

155 lines
5.1 KiB
Python

from django.apps import apps
class CollectionElement:
@classmethod
def from_instance(cls, instance, is_deleted=False):
"""
Returns a collection element from a database instance.
"""
return cls(instance=instance, is_deleted=is_deleted)
@classmethod
def from_values(cls, collection_string, id, is_deleted=False):
"""
Returns a collection element from a collection_string and an id.
"""
return cls(collection_string=collection_string, id=id, is_deleted=is_deleted)
def __init__(self, instance=None, is_deleted=False, collection_string=None, id=None):
"""
Do not use this. Use the methods from_instance() or from_values().
"""
if instance is not None:
self.collection_string = instance.get_collection_string()
self.id = instance.pk
elif collection_string is not None and id is not None:
self.collection_string = collection_string
self.id = id
else:
raise RuntimeError(
'Invalid state. Use CollectionElement.from_instance() or '
'CollectionElement.from_values() but not CollectionElement() '
'directly.')
self.instance = instance
self.deleted = is_deleted
def as_channels_message(self):
"""
Returns a dictonary that can be used to send the object through the
channels system.
"""
return {
'collection_string': self.collection_string,
'id': self.id,
'is_deleted': self.is_deleted()}
def as_autoupdate_for_user(self, user):
"""
Returns a dict that can be sent through the autoupdate system for a site
user.
Returns None if the user can not see the element.
"""
output = {
'collection': self.collection_string,
'id': self.id,
'action': 'deleted' if self.is_deleted() else 'changed',
}
if not self.is_deleted():
data = self.get_access_permissions().get_restricted_data(
self.get_full_data(), user)
if data is None:
# The user is not allowed to see this element. Reset output to None.
output = None
else:
output['data'] = data
return output
def as_autoupdate_for_projector(self):
"""
Returns a dict that can be sent through the autoupdate system for the
projector.
Returns None if the projector can not see the element.
"""
output = {
'collection': self.collection_string,
'id': self.id,
'action': 'deleted' if self.is_deleted() else 'changed',
}
if not self.is_deleted():
data = self.get_access_permissions().get_projector_data(
self.get_full_data())
if data is None:
# The user is not allowed to see this element. Reset output to None.
output = None
else:
output['data'] = data
return output
def get_model(self):
"""
Returns the django model that is used for this collection.
"""
return get_model_from_collection_string(self.collection_string)
def get_instance(self):
"""
Returns the instance as django object.
May raise a DoesNotExist exception.
"""
if self.is_deleted():
raise RuntimeError("The collection element is deleted.")
if self.instance is None:
self.instance = self.get_model().objects.get(pk=self.id)
return self.instance
def get_access_permissions(self):
"""
Returns the get_access_permissions object for the this collection element.
"""
return self.get_model().get_access_permissions()
def get_full_data(self):
"""
Returns the full_data of this collection_element from with all other
dics can be generated.
"""
return self.get_access_permissions().get_full_data(self.get_instance())
def is_deleted(self):
"""
Returns Ture if the item is marked as deleted.
"""
return self.deleted
def get_model_from_collection_string(collection_string):
"""
Returns a model class which belongs to the argument collection_string.
"""
def model_generator():
"""
Yields all models of all apps.
"""
for app_config in apps.get_app_configs():
for model in app_config.get_models():
yield model
for model in model_generator():
try:
model_collection_string = model.get_collection_string()
except AttributeError:
# Skip models which do not have the method get_collection_string.
pass
else:
if model_collection_string == collection_string:
# The model was found.
break
else:
# No model was found in all apps.
raise ValueError('Invalid message. A valid collection_string is missing.')
return model