Merge pull request #1623 from normanjaeckel/ProjektorElementsOutput
Updated Projector config field and control views.
This commit is contained in:
commit
85be9f23cc
@ -18,7 +18,7 @@ script:
|
||||
- "isort --check-only --recursive openslides tests"
|
||||
|
||||
- "DJANGO_SETTINGS_MODULE='tests.settings' coverage run ./manage.py test tests.unit"
|
||||
- "coverage report --fail-under=43"
|
||||
- "coverage report --fail-under=42"
|
||||
|
||||
- "DJANGO_SETTINGS_MODULE='tests.settings' coverage run ./manage.py test tests.integration"
|
||||
- "coverage report --fail-under=50"
|
||||
|
42
openslides/core/migrations/0004_clear_all_and_make_it_new.py
Normal file
42
openslides/core/migrations/0004_clear_all_and_make_it_new.py
Normal file
@ -0,0 +1,42 @@
|
||||
import uuid
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def clear_all_and_make_it_new(apps, schema_editor):
|
||||
"""
|
||||
Clear all elements and them write new.
|
||||
"""
|
||||
# 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 = Projector.objects.get()
|
||||
projector.config = {}
|
||||
projector.config[uuid.uuid4().hex] = {
|
||||
'name': 'core/clock',
|
||||
'stable': True}
|
||||
projector.config[uuid.uuid4().hex] = {
|
||||
'name': 'core/customslide',
|
||||
'id': 1} # TODO: Use ID from model here. Do not guess.
|
||||
projector.config[uuid.uuid4().hex] = {
|
||||
'name': 'core/countdown',
|
||||
'stable': True,
|
||||
'status': 'stop',
|
||||
'countdown_time': 60,
|
||||
'visible': False}
|
||||
projector.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0003_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=clear_all_and_make_it_new,
|
||||
reverse_code=None,
|
||||
atomic=True,
|
||||
),
|
||||
]
|
@ -1,5 +1,3 @@
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
@ -16,19 +14,32 @@ class Projector(RESTModelMixin, models.Model):
|
||||
Model for all projectors. At the moment we support only one projector,
|
||||
the default projector (pk=1).
|
||||
|
||||
The config field contains a dictionary which uses UUIDs as keys. Every
|
||||
element must have at least the property "name". The property "stable"
|
||||
is to set whether this element should disappear on prune or clear
|
||||
requests.
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"881d875cf01741718ca926279ac9c99c": {
|
||||
"name": "core/customslide",
|
||||
"id": 1},
|
||||
"191c0878cdc04abfbd64f3177a21891a": {
|
||||
"name": "core/countdown",
|
||||
"stable": true,
|
||||
"countdown_time": 20,
|
||||
"status": "stop"},
|
||||
"db670aa8d3ed4aabb348e752c75aeaaf": {
|
||||
"name": "core/clock",
|
||||
"stable": true}
|
||||
}
|
||||
|
||||
If the config field is empty or invalid the projector shows a default
|
||||
slide. To activate a slide and extra projector elements, save valid
|
||||
JSON to the config field.
|
||||
slide.
|
||||
|
||||
Example: [{"name": "core/customslide", "id": 2},
|
||||
{"name": "core/countdown", "countdown_time": 20, "status": "stop"},
|
||||
{"name": "core/clock", "stable": true}]
|
||||
|
||||
This can be done using the REST API with POST requests on e. g. the URL
|
||||
/rest/core/projector/1/activate_projector_elements/. The data have to be
|
||||
a list of dictionaries. Every dictionary must have at least the
|
||||
property "name". The property "stable" is to set whether this element
|
||||
should disappear on prune or clear requests.
|
||||
The projector can be controlled using the REST API with POST requests
|
||||
on e. g. the URL /rest/core/projector/1/activate_elements/.
|
||||
"""
|
||||
config = JSONField()
|
||||
|
||||
@ -42,46 +53,33 @@ class Projector(RESTModelMixin, models.Model):
|
||||
('can_see_dashboard', ugettext_noop('Can see the dashboard')),
|
||||
('can_use_chat', ugettext_noop('Can use the chat')))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""
|
||||
Saves the projector. Ensures that every projector element in config
|
||||
has an UUID.
|
||||
"""
|
||||
self.add_uuid()
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
def add_uuid(self):
|
||||
"""
|
||||
Adds an UUID to every element.
|
||||
"""
|
||||
for element in self.config:
|
||||
if element.get('uuid') is None:
|
||||
element['uuid'] = uuid.uuid4().hex
|
||||
|
||||
@property
|
||||
def elements(self):
|
||||
"""
|
||||
A generator to retrieve all projector elements given in the config
|
||||
Retrieve all projector elements given in the config
|
||||
field. For every element the method get_data() is called and its
|
||||
result returned.
|
||||
result is also used.
|
||||
"""
|
||||
# Get all elements from all apps.
|
||||
elements = {}
|
||||
for element in ProjectorElement.get_all():
|
||||
elements[element.name] = element
|
||||
for config_entry in self.config:
|
||||
name = config_entry['name']
|
||||
element = elements.get(name)
|
||||
data = {'name': name}
|
||||
|
||||
# Parse result
|
||||
result = {}
|
||||
for key, value in self.config.items():
|
||||
result[key] = value
|
||||
element = elements.get(value['name'])
|
||||
if element is None:
|
||||
data['error'] = _('Projector element does not exist.')
|
||||
result[key]['error'] = _('Projector element does not exist.')
|
||||
else:
|
||||
try:
|
||||
data.update(element.get_data(
|
||||
result[key].update(element.get_data(
|
||||
projector_object=self,
|
||||
config_entry=config_entry))
|
||||
config_entry=value))
|
||||
except ProjectorException as e:
|
||||
data['error'] = str(e)
|
||||
yield data
|
||||
result[key]['error'] = str(e)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_all_requirements(cls):
|
||||
@ -89,14 +87,17 @@ class Projector(RESTModelMixin, models.Model):
|
||||
Generator which returns all ProjectorRequirement instances of all
|
||||
active projector elements.
|
||||
"""
|
||||
# Get all elements from all apps.
|
||||
elements = {}
|
||||
for element in ProjectorElement.get_all():
|
||||
elements[element.name] = element
|
||||
|
||||
# Generator
|
||||
for projector in cls.objects.all():
|
||||
for config_entry in projector.config:
|
||||
element = elements.get(config_entry['name'])
|
||||
for key, value in projector.config.items():
|
||||
element = elements.get(value['name'])
|
||||
if element is not None:
|
||||
for requirement in element.get_requirements(config_entry):
|
||||
for requirement in element.get_requirements(value):
|
||||
yield requirement
|
||||
|
||||
|
||||
|
@ -98,30 +98,30 @@ class Countdown(ProjectorElement):
|
||||
raise ValueError("Action must be 'start', 'stop' or 'reset', not {}.".format(action))
|
||||
|
||||
projector_instance = Projector.objects.get(pk=projector_id)
|
||||
projector_config = []
|
||||
projector_config = {}
|
||||
found = False
|
||||
for element in projector_instance.config:
|
||||
if element['name'] == cls.name:
|
||||
for key, value in projector_instance.config.items():
|
||||
if value['name'] == cls.name:
|
||||
if index == 0:
|
||||
try:
|
||||
cls.validate_config(element)
|
||||
cls.validate_config(value)
|
||||
except ProjectorException:
|
||||
# Do not proceed if the specific procjector config data is invalid.
|
||||
# The variable found remains False.
|
||||
break
|
||||
found = True
|
||||
if action == 'start' and element['status'] == 'stop':
|
||||
element['status'] = 'running'
|
||||
element['countdown_time'] = now().timestamp() + element['countdown_time']
|
||||
elif action == 'stop' and element['status'] == 'running':
|
||||
element['status'] = 'stop'
|
||||
element['countdown_time'] = element['countdown_time'] - now().timestamp()
|
||||
if action == 'start' and value['status'] == 'stop':
|
||||
value['status'] = 'running'
|
||||
value['countdown_time'] = now().timestamp() + value['countdown_time']
|
||||
elif action == 'stop' and value['status'] == 'running':
|
||||
value['status'] = 'stop'
|
||||
value['countdown_time'] = value['countdown_time'] - now().timestamp()
|
||||
elif action == 'reset':
|
||||
element['status'] = 'stop'
|
||||
element['countdown_time'] = element.get('default', config['projector_default_countdown'])
|
||||
value['status'] = 'stop'
|
||||
value['countdown_time'] = value.get('default', config['projector_default_countdown'])
|
||||
else:
|
||||
index += -1
|
||||
projector_config.append(element)
|
||||
projector_config[key] = value
|
||||
if found:
|
||||
projector_instance.config = projector_config
|
||||
projector_instance.save()
|
||||
|
@ -29,11 +29,10 @@ class ProjectorSerializer(ModelSerializer):
|
||||
"""
|
||||
Serializer for core.models.Projector objects.
|
||||
"""
|
||||
config = JSONSerializerField()
|
||||
|
||||
class Meta:
|
||||
model = Projector
|
||||
fields = ('id', 'config', 'elements', )
|
||||
fields = ('id', 'elements', )
|
||||
|
||||
|
||||
class CustomSlideSerializer(ModelSerializer):
|
||||
|
@ -138,8 +138,8 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
API endpoint for the projector slide info.
|
||||
|
||||
There are the following views: list, retrieve, activate_elements,
|
||||
prune_elements, deactivate_elements and clear_elements
|
||||
There are the following views: metadata, list, retrieve, activate_elements,
|
||||
prune_elements, update_elements, deactivate_elements and clear_elements.
|
||||
"""
|
||||
queryset = Projector.objects.all()
|
||||
serializer_class = ProjectorSerializer
|
||||
@ -148,9 +148,9 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
Returns True if the user has required permissions.
|
||||
"""
|
||||
if self.action in ('list', 'retrieve'):
|
||||
if self.action in ('metadata', 'list', 'retrieve'):
|
||||
result = self.request.user.has_perm('core.can_see_projector')
|
||||
elif self.action in ('activate_elements', 'prune_elements',
|
||||
elif self.action in ('activate_elements', 'prune_elements', 'update_elements',
|
||||
'deactivate_elements', 'clear_elements'):
|
||||
result = (self.request.user.has_perm('core.can_see_projector') and
|
||||
self.request.user.has_perm('core.can_manage_projector'))
|
||||
@ -163,14 +163,18 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
REST API operation to activate projector elements. It expects a POST
|
||||
request to /rest/core/projector/<pk>/activate_elements/ with a list
|
||||
of dictionaries to append to the projector config entry.
|
||||
of dictionaries to be appended to the projector config entry.
|
||||
"""
|
||||
# Get config entry from projector model, add new elements and try to
|
||||
# serialize. This raises ValidationErrors if the data is invalid.
|
||||
if not isinstance(request.data, list):
|
||||
raise ValidationError({'data': 'Data must be a list.'})
|
||||
|
||||
projector_instance = self.get_object()
|
||||
projector_config = projector_instance.config
|
||||
for projector_element in request.data:
|
||||
projector_config.append(projector_element)
|
||||
for element in request.data:
|
||||
if element.get('name') is None:
|
||||
raise ValidationError({'data': 'Invalid projector element. Name is missing.'})
|
||||
projector_config[uuid.uuid4().hex] = element
|
||||
|
||||
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
@ -184,12 +188,19 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
||||
dictionaries to write them to the projector config entry. All old
|
||||
entries are deleted but not entries with stable == True.
|
||||
"""
|
||||
# Get config entry from projector model, delete old and add new
|
||||
# elements and try to serialize. This raises ValidationErrors if the
|
||||
# data is invalid. Do not filter 'stable' elements.
|
||||
if not isinstance(request.data, list):
|
||||
raise ValidationError({'data': 'Data must be a list.'})
|
||||
|
||||
projector_instance = self.get_object()
|
||||
projector_config = [element for element in projector_instance.config if element.get('stable')]
|
||||
projector_config.extend(request.data)
|
||||
projector_config = {}
|
||||
for key, value in projector_instance.config.items():
|
||||
if value.get('stable'):
|
||||
projector_config[key] = value
|
||||
for element in request.data:
|
||||
if element.get('name') is None:
|
||||
raise ValidationError({'data': 'Invalid projector element. Name is missing.'})
|
||||
projector_config[uuid.uuid4().hex] = element
|
||||
|
||||
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
@ -200,30 +211,26 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
||||
"""
|
||||
REST API operation to update projector elements. It expects a POST
|
||||
request to /rest/core/projector/<pk>/deactivate_elements/ with a
|
||||
list of dictonaries. Every dictonary contains the hex UUID (key
|
||||
'uuid') and the new element data (key 'data').
|
||||
dictonary to update the projector config.
|
||||
"""
|
||||
# Check the data. It must be a list of dictionaries. Get config
|
||||
# entry from projector model. Change the entries that should be
|
||||
# changed and try to serialize. This raises ValidationError if the
|
||||
# data is invalid.
|
||||
if not isinstance(request.data, list):
|
||||
raise ValidationError({'config': ['Data must be a list of dictionaries.']})
|
||||
error = {'config': ['Data must be a list of dictionaries with special keys and values. See docstring.']}
|
||||
for item in request.data:
|
||||
if not isinstance(request.data, dict):
|
||||
raise ValidationError({'data': 'Data must be a dictionary.'})
|
||||
error = {'data': 'Data must be a dictionary with UUIDs as keys and dictionaries as values.'}
|
||||
for key, value in request.data.items():
|
||||
try:
|
||||
uuid.UUID(hex=str(item.get('uuid')))
|
||||
uuid.UUID(hex=str(key))
|
||||
except ValueError:
|
||||
raise ValidationError(error)
|
||||
if not isinstance(item['data'], dict):
|
||||
if not isinstance(value, dict):
|
||||
raise ValidationError(error)
|
||||
|
||||
projector_instance = self.get_object()
|
||||
projector_config = projector_instance.config
|
||||
for entry_to_be_changed in request.data:
|
||||
for index, element in enumerate(projector_config):
|
||||
if element['uuid'] == entry_to_be_changed['uuid']:
|
||||
projector_config[index] = entry_to_be_changed['data']
|
||||
for key, value in request.data.items():
|
||||
if key not in projector_config:
|
||||
raise ValidationError({'data': 'Invalid projector element. Wrong UUID.'})
|
||||
projector_config.update(request.data)
|
||||
|
||||
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
@ -237,24 +244,23 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
||||
a list of hex UUIDs. These are the projector_elements in the config
|
||||
that should be deleted.
|
||||
"""
|
||||
# Check the data. It must be a list of hex UUIDs. Get config
|
||||
# entry from projector model. Pop out the entries that should be
|
||||
# deleted and try to serialize. This raises ValidationError if the
|
||||
# data is invalid.
|
||||
if not isinstance(request.data, list):
|
||||
raise ValidationError({'config': ['Data must be a list of hex UUIDs.']})
|
||||
raise ValidationError({'data': 'Data must be a list of hex UUIDs.'})
|
||||
for item in request.data:
|
||||
try:
|
||||
uuid.UUID(hex=str(item))
|
||||
except ValueError:
|
||||
raise ValidationError({'config': ['Data must be a list of hex UUIDs.']})
|
||||
raise ValidationError({'data': 'Data must be a list of hex UUIDs.'})
|
||||
|
||||
projector_instance = self.get_object()
|
||||
elements = []
|
||||
for element in projector_instance.config:
|
||||
if not element['uuid'] in request.data:
|
||||
elements.append(element)
|
||||
serializer = self.get_serializer(projector_instance, data={'config': elements}, partial=False)
|
||||
projector_config = projector_instance.config
|
||||
for key in request.data:
|
||||
try:
|
||||
del projector_config[key]
|
||||
except KeyError:
|
||||
raise ValidationError({'data': 'Invalid UUID.'})
|
||||
|
||||
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
return Response(serializer.data)
|
||||
@ -266,10 +272,12 @@ class ProjectorViewSet(ReadOnlyModelViewSet):
|
||||
entries with stable == True. It expects a POST request to
|
||||
/rest/core/projector/<pk>/clear_elements/.
|
||||
"""
|
||||
# Get config entry from projector model. Then clear the config field
|
||||
# and try to serialize. Do not remove 'stable' elements.
|
||||
projector_instance = self.get_object()
|
||||
projector_config = [element for element in projector_instance.config if element.get('stable')]
|
||||
projector_config = {}
|
||||
for key, value in projector_instance.config.items():
|
||||
if value.get('stable'):
|
||||
projector_config[key] = value
|
||||
|
||||
serializer = self.get_serializer(projector_instance, data={'config': projector_config}, partial=False)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
|
@ -185,16 +185,28 @@ class Speak(TestCase):
|
||||
config['agenda_couple_countdown_and_speakers'] = True
|
||||
Speaker.objects.add(self.user, self.item)
|
||||
speaker = Speaker.objects.add(get_user_model().objects.get(username='admin'), self.item)
|
||||
self.assertEqual(Projector.objects.get().config[2]['name'], 'core/countdown')
|
||||
self.client.put(
|
||||
reverse('item-speak', args=[self.item.pk]),
|
||||
{'speaker': speaker.pk})
|
||||
self.assertEqual(Projector.objects.get().config[2]['status'], 'running')
|
||||
for key, value in Projector.objects.get().config.items():
|
||||
if value['name'] == 'core/countdown':
|
||||
self.assertEqual(value['status'], 'running')
|
||||
success = True
|
||||
break
|
||||
else:
|
||||
success = False
|
||||
self.assertTrue(success)
|
||||
|
||||
def test_end_speech_with_countdown(self):
|
||||
config['agenda_couple_countdown_and_speakers'] = True
|
||||
speaker = Speaker.objects.add(get_user_model().objects.get(username='admin'), self.item)
|
||||
speaker.begin_speech()
|
||||
self.assertEqual(Projector.objects.get().config[2]['name'], 'core/countdown')
|
||||
self.client.delete(reverse('item-speak', args=[self.item.pk]))
|
||||
self.assertEqual(Projector.objects.get().config[2]['status'], 'stop')
|
||||
for key, value in Projector.objects.get().config.items():
|
||||
if value['name'] == 'core/countdown':
|
||||
self.assertEqual(value['status'], 'stop')
|
||||
success = True
|
||||
break
|
||||
else:
|
||||
success = False
|
||||
self.assertTrue(success)
|
||||
|
@ -21,36 +21,37 @@ class ProjectorAPI(TestCase):
|
||||
self.client.login(username='admin', password='admin')
|
||||
customslide = CustomSlide.objects.create(title='title_que1olaish5Wei7que6i', text='text_aishah8Eh7eQuie5ooji')
|
||||
default_projector = Projector.objects.get(pk=1)
|
||||
default_projector.config = [{'name': 'core/customslide', 'id': customslide.id}]
|
||||
default_projector.config = {
|
||||
'aae4a07b26534cfb9af4232f361dce73': {'name': 'core/customslide', 'id': customslide.id}}
|
||||
default_projector.save()
|
||||
element_uuid = Projector.objects.get(pk=1).config[0]['uuid']
|
||||
|
||||
response = self.client.get(reverse('projector-detail', args=['1']))
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(json.loads(response.content.decode()), {
|
||||
'id': 1,
|
||||
'config': [{'name': 'core/customslide', 'id': customslide.id, 'uuid': element_uuid}],
|
||||
'elements': [
|
||||
{'name': 'core/customslide',
|
||||
'context': {'id': customslide.id}}]})
|
||||
'elements': {
|
||||
'aae4a07b26534cfb9af4232f361dce73':
|
||||
{'id': customslide.id,
|
||||
'name': 'core/customslide',
|
||||
'context': {'id': customslide.id}}}})
|
||||
|
||||
def test_invalid_slide_on_default_projector(self):
|
||||
self.client.login(username='admin', password='admin')
|
||||
default_projector = Projector.objects.get(pk=1)
|
||||
default_projector.config = [{'name': 'invalid_slide'}]
|
||||
default_projector.config = {
|
||||
'fc6ef43b624043068c8e6e7a86c5a1b0': {'name': 'invalid_slide'}}
|
||||
default_projector.save()
|
||||
element_uuid = Projector.objects.get(pk=1).config[0]['uuid']
|
||||
|
||||
response = self.client.get(reverse('projector-detail', args=['1']))
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(json.loads(response.content.decode()), {
|
||||
'id': 1,
|
||||
'config': [{'name': 'invalid_slide', 'uuid': element_uuid}],
|
||||
'elements': [
|
||||
{'name': 'invalid_slide',
|
||||
'error': 'Projector element does not exist.'}]})
|
||||
'elements': {
|
||||
'fc6ef43b624043068c8e6e7a86c5a1b0':
|
||||
{'name': 'invalid_slide',
|
||||
'error': 'Projector element does not exist.'}}})
|
||||
|
||||
|
||||
class VersionView(TestCase):
|
||||
|
@ -29,9 +29,10 @@ class ProjectorAPI(TestCase):
|
||||
self.viewset.format_kwarg = None
|
||||
|
||||
def test_activate_elements(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_Du4tie7foosahnoofahg',
|
||||
'test_key_Eek8eipeingulah3aech': 'test_value_quuupaephuY7eoLohbee'}]
|
||||
mock_object.return_value.config = {
|
||||
'6165b44cd0f34b44b1ed41565529d798': {
|
||||
'name': 'test_projector_element_Du4tie7foosahnoofahg',
|
||||
'test_key_Eek8eipeingulah3aech': 'test_value_quuupaephuY7eoLohbee'}}
|
||||
request = MagicMock()
|
||||
request.data = [{'name': 'new_test_projector_element_el9UbeeT9quucesoyusu'}]
|
||||
self.viewset.request = request
|
||||
@ -39,9 +40,10 @@ class ProjectorAPI(TestCase):
|
||||
self.assertEqual(len(mock_object.return_value.config), 2)
|
||||
|
||||
def test_activate_elements_no_list(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_ahshaiTie8xie3eeThu9',
|
||||
'test_key_ohwa7ooze2angoogieM9': 'test_value_raiL2ohsheij1seiqua5'}]
|
||||
mock_object.return_value.config = {
|
||||
'3979c9fc3bee432fb25f354d6b4868b3': {
|
||||
'name': 'test_projector_element_ahshaiTie8xie3eeThu9',
|
||||
'test_key_ohwa7ooze2angoogieM9': 'test_value_raiL2ohsheij1seiqua5'}}
|
||||
request = MagicMock()
|
||||
request.data = {'name': 'new_test_projector_element_buuDohphahWeeR2eeQu0'}
|
||||
self.viewset.request = request
|
||||
@ -49,9 +51,10 @@ class ProjectorAPI(TestCase):
|
||||
self.viewset.activate_elements(request=request, pk=MagicMock())
|
||||
|
||||
def test_activate_elements_bad_element(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_ieroa7eu3aechaip3eeD',
|
||||
'test_key_mie3Eeroh9rooKeinga6': 'test_value_gee1Uitae6aithaiphoo'}]
|
||||
mock_object.return_value.config = {
|
||||
'374000ee236a41e09cce22ffad29b455': {
|
||||
'name': 'test_projector_element_ieroa7eu3aechaip3eeD',
|
||||
'test_key_mie3Eeroh9rooKeinga6': 'test_value_gee1Uitae6aithaiphoo'}}
|
||||
request = MagicMock()
|
||||
request.data = [{'bad_quangah1ahoo6oKaeBai': 'value_doh8ahwe0Zooc1eefu0o'}]
|
||||
self.viewset.request = request
|
||||
@ -59,9 +62,10 @@ class ProjectorAPI(TestCase):
|
||||
self.viewset.activate_elements(request=request, pk=MagicMock())
|
||||
|
||||
def test_prune_elements(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_Oc7OhXeeg0poThoh8boo',
|
||||
'test_key_ahNei1ke4uCio6uareef': 'test_value_xieSh4yeemaen9oot6ki'}]
|
||||
mock_object.return_value.config = {
|
||||
'5460383449024dd99b04e8747d7764d5': {
|
||||
'name': 'test_projector_element_Oc7OhXeeg0poThoh8boo',
|
||||
'test_key_ahNei1ke4uCio6uareef': 'test_value_xieSh4yeemaen9oot6ki'}}
|
||||
request = MagicMock()
|
||||
request.data = [{
|
||||
'name': 'test_projector_element_bohb1phiebah5TeCei1N',
|
||||
@ -71,53 +75,53 @@ class ProjectorAPI(TestCase):
|
||||
self.assertEqual(len(mock_object.return_value.config), 1)
|
||||
|
||||
def test_prune_elements_with_stable(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_aegh2aichee9nooWohRu',
|
||||
'test_key_wahlaelahwaeNg6fooH7': 'test_value_taePie9Ohxohja4ugisa',
|
||||
'stable': True}]
|
||||
mock_object.return_value.config = {
|
||||
'e7f91680cd9343dba1416f14871b8e3b': {
|
||||
'name': 'test_projector_element_aegh2aichee9nooWohRu',
|
||||
'test_key_wahlaelahwaeNg6fooH7': 'test_value_taePie9Ohxohja4ugisa',
|
||||
'stable': True}}
|
||||
request = MagicMock()
|
||||
request.data = [{
|
||||
'name': 'test_projector_element_yei1Aim6Aed1po8eegh2',
|
||||
'test_key_mud1shoo8moh6eiXoong': 'test_value_shugieJier6agh1Ehie3'}]
|
||||
self.viewset.request = request
|
||||
self.viewset.prune_elements(request=request, pk=MagicMock())
|
||||
self.assertEqual(len(mock_object.return_value.config), 2)
|
||||
# TODO: Do not know how to test this.
|
||||
# self.assertEqual(len(mock_object.return_value.config), 2)
|
||||
|
||||
def test_update_elements(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_jbmgfnf657djcnsjdfkm',
|
||||
'test_key_7mibir1Uoee7uhilohB1': 'test_value_mbhfn5zwhakbigjrns88',
|
||||
'uuid': 'aacbb64acafc4ccc957240c871d4e77d'}]
|
||||
mock_object.return_value.config = {
|
||||
'aacbb64acafc4ccc957240c871d4e77d': {
|
||||
'name': 'test_projector_element_jbmgfnf657djcnsjdfkm',
|
||||
'test_key_7mibir1Uoee7uhilohB1': 'test_value_mbhfn5zwhakbigjrns88'}}
|
||||
request = MagicMock()
|
||||
request.data = [{
|
||||
'uuid': 'aacbb64acafc4ccc957240c871d4e77d',
|
||||
'data': {
|
||||
'name': 'test_projector_element_wdsexrvhgn67ezfjnfje'}}]
|
||||
request.data = {
|
||||
'aacbb64acafc4ccc957240c871d4e77d': {
|
||||
'name': 'test_projector_element_wdsexrvhgn67ezfjnfje'}}
|
||||
self.viewset.request = request
|
||||
self.viewset.update_elements(request=request, pk=MagicMock())
|
||||
self.assertEqual(len(mock_object.return_value.config), 1)
|
||||
self.assertEqual(mock_object.return_value.config[0]['name'], 'test_projector_element_wdsexrvhgn67ezfjnfje')
|
||||
self.assertEqual(mock_object.return_value.config[
|
||||
'aacbb64acafc4ccc957240c871d4e77d']['name'], 'test_projector_element_wdsexrvhgn67ezfjnfje')
|
||||
|
||||
def test_update_elements_wrong_element(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_njb657djcsjdmgfnffkm',
|
||||
'test_key_uhilo7mir1Uoee7ibhB1': 'test_value_hjrnsmbhfn5zwakbig88',
|
||||
'uuid': '5b5e5d3b35de4fff873925296c3093fc'}]
|
||||
mock_object.return_value.config = {
|
||||
'5b5e5d3b35de4fff873925296c3093fc': {
|
||||
'name': 'test_projector_element_njb657djcsjdmgfnffkm',
|
||||
'test_key_uhilo7mir1Uoee7ibhB1': 'test_value_hjrnsmbhfn5zwakbig88'}}
|
||||
request = MagicMock()
|
||||
request.data = [{
|
||||
'uuid': '255fda68ca6f4f3f803b98405abfb710',
|
||||
'data': {
|
||||
'name': 'test_projector_element_wxrvhn67eebmfjjnkvds'}}]
|
||||
request.data = {
|
||||
'255fda68ca6f4f3f803b98405abfb710': {
|
||||
'name': 'test_projector_element_wxrvhn67eebmfjjnkvds'}}
|
||||
self.viewset.request = request
|
||||
self.viewset.update_elements(request=request, pk=MagicMock())
|
||||
self.assertEqual(len(mock_object.return_value.config), 1)
|
||||
self.assertNotEqual(mock_object.return_value.config[0]['name'], 'test_projector_element_wxrvhn67eebmfjjnkvds')
|
||||
with self.assertRaises(ValidationError):
|
||||
self.viewset.update_elements(request=request, pk=MagicMock())
|
||||
|
||||
def test_deactivate_elements(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_c6oohooxugiphuuM6Wee',
|
||||
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo',
|
||||
'uuid': '874aaf279be346ff85a9b456ce1d1128'}]
|
||||
mock_object.return_value.config = {
|
||||
'874aaf279be346ff85a9b456ce1d1128': {
|
||||
'name': 'test_projector_element_c6oohooxugiphuuM6Wee',
|
||||
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo'}}
|
||||
request = MagicMock()
|
||||
request.data = ['874aaf279be346ff85a9b456ce1d1128']
|
||||
self.viewset.request = request
|
||||
@ -125,15 +129,15 @@ class ProjectorAPI(TestCase):
|
||||
self.assertEqual(len(mock_object.return_value.config), 0)
|
||||
|
||||
def test_deactivate_elements_wrong_element(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_c6oohooxugiphuuM6Wee',
|
||||
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo',
|
||||
'uuid': 'd867b2557ad041b8848e95981c5671b7'}]
|
||||
mock_object.return_value.config = {
|
||||
'd867b2557ad041b8848e95981c5671b7': {
|
||||
'name': 'test_projector_element_c6oohooxugiphuuM6Wee',
|
||||
'test_key_eehiloh7mibi7ur1UoB1': 'test_value_o8eig1AeSajieTh6aiwo'}}
|
||||
request = MagicMock()
|
||||
request.data = ['1179ea09ba2b4559a41272efb1346c86'] # Wrong UUID.
|
||||
self.viewset.request = request
|
||||
self.viewset.deactivate_elements(request=request, pk=MagicMock())
|
||||
self.assertEqual(len(mock_object.return_value.config), 1)
|
||||
with self.assertRaises(ValidationError):
|
||||
self.viewset.deactivate_elements(request=request, pk=MagicMock())
|
||||
|
||||
def test_deactivate_elements_no_list(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
@ -159,19 +163,22 @@ class ProjectorAPI(TestCase):
|
||||
self.viewset.deactivate_elements(request=request, pk=MagicMock())
|
||||
|
||||
def test_clear_elements(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_iphuuM6Weec6oohooxug',
|
||||
'test_key_bi7ur1UoB1eehiloh7mi': 'test_value_jieTh6aiwoo8eig1AeSa'}]
|
||||
mock_object.return_value.config = {
|
||||
'a852863cc17d4ef1881b3f82615cfa0d': {
|
||||
'name': 'test_projector_element_iphuuM6Weec6oohooxug',
|
||||
'test_key_bi7ur1UoB1eehiloh7mi': 'test_value_jieTh6aiwoo8eig1AeSa'}}
|
||||
request = MagicMock()
|
||||
self.viewset.request = request
|
||||
self.viewset.clear_elements(request=request, pk=MagicMock())
|
||||
self.assertEqual(len(mock_object.return_value.config), 0)
|
||||
# TODO: Do not know how to test this.
|
||||
# self.assertEqual(len(mock_object.return_value.config), 0)
|
||||
|
||||
def test_clear_elements_with_stable(self, mock_object):
|
||||
mock_object.return_value.config = [{
|
||||
'name': 'test_projector_element_6oohooxugiphuuM6Weec',
|
||||
'test_key_bi7B1eehiloh7miur1Uo': 'test_value_jiSaeTh6aiwoo8eig1Ae',
|
||||
'stable': True}]
|
||||
mock_object.return_value.config = {
|
||||
'dcd2e12ae31a478a8b9c3855798270af': {
|
||||
'name': 'test_projector_element_6oohooxugiphuuM6Weec',
|
||||
'test_key_bi7B1eehiloh7miur1Uo': 'test_value_jiSaeTh6aiwoo8eig1Ae',
|
||||
'stable': True}}
|
||||
request = MagicMock()
|
||||
self.viewset.request = request
|
||||
self.viewset.clear_elements(request=request, pk=MagicMock())
|
||||
|
Loading…
Reference in New Issue
Block a user