Protect element fields from the projector model. Fixes creation of
projectors.
This commit is contained in:
parent
fc5f6f4e54
commit
5a1f638f8d
@ -148,11 +148,7 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
|
||||
public create(): void {
|
||||
if (this.createForm.valid && this.projectorToCreate) {
|
||||
this.projectorToCreate.patchValues(this.createForm.value as Projector);
|
||||
// TODO: the server shouldn't want to have element data..
|
||||
this.projectorToCreate.patchValues({
|
||||
elements: [{ name: 'core/clock', stable: true }],
|
||||
elements_preview: [],
|
||||
elements_history: [],
|
||||
reference_projector_id: this.projectors[0].reference_projector_id
|
||||
});
|
||||
this.repo.create(this.projectorToCreate).then(() => (this.projectorToCreate = null), this.raiseError);
|
||||
|
@ -91,7 +91,7 @@ class Projector(RESTModelMixin, models.Model):
|
||||
show_title = models.BooleanField(default=True)
|
||||
show_logo = models.BooleanField(default=True)
|
||||
|
||||
name = models.CharField(max_length=255, unique=True, blank=True)
|
||||
name = models.CharField(max_length=255, unique=True)
|
||||
|
||||
reference_projector = models.ForeignKey(
|
||||
"self",
|
||||
|
@ -1,7 +1,13 @@
|
||||
from typing import Any
|
||||
|
||||
from ..utils.projector import projector_slides
|
||||
from ..utils.rest_api import Field, IntegerField, ModelSerializer, ValidationError
|
||||
from ..utils.rest_api import (
|
||||
Field,
|
||||
IdPrimaryKeyRelatedField,
|
||||
IntegerField,
|
||||
ModelSerializer,
|
||||
ValidationError,
|
||||
)
|
||||
from ..utils.validate import validate_html
|
||||
from .models import (
|
||||
ChatMessage,
|
||||
@ -77,13 +83,17 @@ class ProjectorSerializer(ModelSerializer):
|
||||
Serializer for core.models.Projector objects.
|
||||
"""
|
||||
|
||||
elements = JSONSerializerField(validators=[elements_validator])
|
||||
elements_preview = JSONSerializerField(validators=[elements_validator])
|
||||
elements_history = JSONSerializerField(validators=[elements_array_validator])
|
||||
elements = JSONSerializerField(read_only=True)
|
||||
elements_preview = JSONSerializerField(read_only=True)
|
||||
elements_history = JSONSerializerField(read_only=True)
|
||||
|
||||
width = IntegerField(min_value=800, max_value=3840, required=False)
|
||||
height = IntegerField(min_value=340, max_value=2880, required=False)
|
||||
|
||||
projectiondefaults = IdPrimaryKeyRelatedField(
|
||||
many=True, required=False, queryset=ProjectionDefault.objects.all()
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Projector
|
||||
fields = (
|
||||
|
@ -57,6 +57,7 @@ from .models import (
|
||||
ProjectorMessage,
|
||||
Tag,
|
||||
)
|
||||
from .serializers import elements_array_validator, elements_validator
|
||||
|
||||
|
||||
# Special Django views
|
||||
@ -139,6 +140,11 @@ class ProjectorViewSet(ModelViewSet):
|
||||
result = False
|
||||
return result
|
||||
|
||||
def perform_create(self, serializer):
|
||||
projector = serializer.save()
|
||||
projector.elements = [{"name": "core/clock", "stable": True}]
|
||||
projector.save()
|
||||
|
||||
def destroy(self, *args, **kwargs):
|
||||
"""
|
||||
REST API operation for DELETE requests.
|
||||
@ -184,22 +190,24 @@ class ProjectorViewSet(ModelViewSet):
|
||||
"delete_last_history_element", False
|
||||
)
|
||||
|
||||
changed_data = {}
|
||||
if elements is not None:
|
||||
changed_data["elements"] = elements
|
||||
elements_validator(elements)
|
||||
projector.elements = elements
|
||||
|
||||
if preview is not None:
|
||||
changed_data["elements_preview"] = preview
|
||||
elements_validator(preview)
|
||||
projector.elements_preview = preview
|
||||
|
||||
elements_history = None
|
||||
if history_element is not None and delete_last_history_element is False:
|
||||
history = projector.elements_history + [history_element]
|
||||
changed_data["elements_history"] = history
|
||||
elements_history = projector.elements_history + [history_element]
|
||||
if history_element is None and delete_last_history_element is True:
|
||||
history = projector.elements_history[:-1]
|
||||
changed_data["elements_history"] = history
|
||||
|
||||
serializer = self.get_serializer(projector, data=changed_data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_update(serializer)
|
||||
elements_history = projector.elements_history[:-1]
|
||||
if elements_history is not None:
|
||||
elements_array_validator(elements_history)
|
||||
projector.elements_history = elements_history
|
||||
|
||||
projector.save()
|
||||
return Response()
|
||||
|
||||
@detail_route(methods=["post"])
|
||||
|
6
tests/common_groups.py
Normal file
6
tests/common_groups.py
Normal file
@ -0,0 +1,6 @@
|
||||
# In this file are the default group ids which should be used in all tests.
|
||||
|
||||
GROUP_DEFAULT_PK = 1
|
||||
GROUP_ADMIN_PK = 2
|
||||
GROUP_DELEGATE_PK = 3
|
||||
GROUP_STAFF_PK = 4
|
@ -1,11 +1,14 @@
|
||||
import pytest
|
||||
from django.urls import reverse
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from openslides.core.config import config
|
||||
from openslides.core.models import ChatMessage, Projector, Tag
|
||||
from openslides.users.models import User
|
||||
from openslides.utils.autoupdate import inform_changed_data
|
||||
from openslides.utils.test import TestCase
|
||||
from tests.common_groups import GROUP_ADMIN_PK, GROUP_DELEGATE_PK
|
||||
|
||||
from ..helpers import count_queries
|
||||
|
||||
@ -59,6 +62,146 @@ def test_config_db_queries():
|
||||
assert count_queries(Tag.get_elements) == 1
|
||||
|
||||
|
||||
class ProjectorViewSet(TestCase):
|
||||
"""
|
||||
Tests (currently just parts) of the ProjectorViewSet.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.client.login(username="admin", password="admin")
|
||||
|
||||
def test_create(self):
|
||||
response = self.client.post(
|
||||
reverse("projector-list"), {"name": "test_name_efIOLJHF32f&EF)NG3fw"}
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
# pk=1 should be the default projector and pk=2 the new one
|
||||
self.assertEqual(Projector.objects.all().count(), 2)
|
||||
self.assertTrue(Projector.objects.filter(pk=2).exists())
|
||||
projector = Projector.objects.get(pk=2)
|
||||
self.assertEqual(projector.name, "test_name_efIOLJHF32f&EF)NG3fw")
|
||||
self.assertEqual(projector.elements, [{"name": "core/clock", "stable": True}])
|
||||
|
||||
def test_create_no_data(self):
|
||||
response = self.client.post(reverse("projector-list"))
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertEqual(Projector.objects.all().count(), 1)
|
||||
|
||||
def test_no_permission(self):
|
||||
admin = User.objects.get(username="admin")
|
||||
admin.groups.add(GROUP_DELEGATE_PK)
|
||||
admin.groups.remove(GROUP_ADMIN_PK)
|
||||
inform_changed_data(admin)
|
||||
|
||||
response = self.client.post(reverse("projector-list"))
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||
self.assertEqual(Projector.objects.all().count(), 1)
|
||||
|
||||
|
||||
class Projection(TestCase):
|
||||
"""
|
||||
Tests the projection view.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.client.login(username="admin", password="admin")
|
||||
self.projector = Projector.objects.get(pk=1) # the default projector
|
||||
|
||||
def test_add_element(self):
|
||||
elements = [{"name": "core/clock"}]
|
||||
response = self.client.post(
|
||||
reverse("projector-project", args=[self.projector.pk]),
|
||||
{"elements": elements},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.projector = Projector.objects.get(pk=1)
|
||||
self.assertEqual(self.projector.elements, elements)
|
||||
self.assertEqual(self.projector.elements_preview, [])
|
||||
self.assertEqual(self.projector.elements_history, [])
|
||||
|
||||
def test_add_element_without_name(self):
|
||||
response = self.client.post(
|
||||
reverse("projector-project", args=[self.projector.pk]),
|
||||
{"elements": [{}]},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.projector = Projector.objects.get(pk=1)
|
||||
self.assertEqual(self.projector.elements, [])
|
||||
self.assertEqual(self.projector.elements_preview, [])
|
||||
self.assertEqual(self.projector.elements_history, [])
|
||||
|
||||
def test_no_permissions(self):
|
||||
admin = User.objects.get(username="admin")
|
||||
admin.groups.add(GROUP_DELEGATE_PK)
|
||||
admin.groups.remove(GROUP_ADMIN_PK)
|
||||
inform_changed_data(admin)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("projector-project", args=[self.projector.pk]), {}, format="json"
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||
|
||||
def test_remove_element(self):
|
||||
self.projector.elements = [{"name": "core/clock"}]
|
||||
self.projector.save()
|
||||
response = self.client.post(
|
||||
reverse("projector-project", args=[self.projector.pk]),
|
||||
{"elements": []},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.projector = Projector.objects.get(pk=1)
|
||||
self.assertEqual(self.projector.elements, [])
|
||||
self.assertEqual(self.projector.elements_preview, [])
|
||||
self.assertEqual(self.projector.elements_history, [])
|
||||
|
||||
def test_add_element_to_history(self):
|
||||
element = [{"name": "core/clock"}]
|
||||
response = self.client.post(
|
||||
reverse("projector-project", args=[self.projector.pk]),
|
||||
{"append_to_history": element},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.projector = Projector.objects.get(pk=1)
|
||||
self.assertEqual(self.projector.elements, [])
|
||||
self.assertEqual(self.projector.elements_preview, [])
|
||||
self.assertEqual(self.projector.elements_history, [element])
|
||||
|
||||
def test_remove_last_history_element(self):
|
||||
element1 = [{"name": "core/clock"}]
|
||||
element2 = [{"name": "motions/motion"}]
|
||||
self.projector.elements_history = [element1, element2]
|
||||
self.projector.save()
|
||||
response = self.client.post(
|
||||
reverse("projector-project", args=[self.projector.pk]),
|
||||
{"delete_last_history_element": True},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.projector = Projector.objects.get(pk=1)
|
||||
self.assertEqual(self.projector.elements, [])
|
||||
self.assertEqual(self.projector.elements_preview, [])
|
||||
self.assertEqual(self.projector.elements_history, [element1])
|
||||
|
||||
def test_set_preview(self):
|
||||
elements = [{"name": "core/clock"}]
|
||||
response = self.client.post(
|
||||
reverse("projector-project", args=[self.projector.pk]),
|
||||
{"preview": elements},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.projector = Projector.objects.get(pk=1)
|
||||
self.assertEqual(self.projector.elements, [])
|
||||
self.assertEqual(self.projector.elements_preview, elements)
|
||||
self.assertEqual(self.projector.elements_history, [])
|
||||
|
||||
|
||||
class ChatMessageViewSet(TestCase):
|
||||
"""
|
||||
Tests requests to deal with chat messages.
|
||||
|
@ -23,16 +23,16 @@ from openslides.motions.models import (
|
||||
from openslides.utils.auth import get_group_model
|
||||
from openslides.utils.autoupdate import inform_changed_data
|
||||
from openslides.utils.test import TestCase
|
||||
from tests.common_groups import (
|
||||
GROUP_ADMIN_PK,
|
||||
GROUP_DEFAULT_PK,
|
||||
GROUP_DELEGATE_PK,
|
||||
GROUP_STAFF_PK,
|
||||
)
|
||||
|
||||
from ..helpers import count_queries
|
||||
|
||||
|
||||
GROUP_DEFAULT_PK = 1
|
||||
GROUP_ADMIN_PK = 2
|
||||
GROUP_DELEGATE_PK = 3
|
||||
GROUP_STAFF_PK = 4
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=False)
|
||||
def test_motion_db_queries():
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user