Merge pull request #3382 from ostcar/remove_dispatch
Rewrite projector_element without dispatch
This commit is contained in:
commit
71e154ec6d
@ -1,6 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
from ..utils.collection import Collection
|
||||
from ..utils.projector import register_projector_elements
|
||||
|
||||
|
||||
class AgendaAppConfig(AppConfig):
|
||||
@ -10,16 +11,13 @@ class AgendaAppConfig(AppConfig):
|
||||
angular_projector_module = True
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Do this by just importing all from these files.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from django.db.models.signals import pre_delete, post_save
|
||||
from openslides.core.config import config
|
||||
from openslides.core.signals import permission_change, user_data_required
|
||||
from openslides.utils.rest_api import router
|
||||
from ..core.config import config
|
||||
from ..core.signals import permission_change, user_data_required
|
||||
from ..utils.rest_api import router
|
||||
from .config_variables import get_config_variables
|
||||
from .projector import get_projector_elements
|
||||
from .signals import (
|
||||
get_permission_change_data,
|
||||
listen_to_related_object_post_delete,
|
||||
@ -27,8 +25,9 @@ class AgendaAppConfig(AppConfig):
|
||||
required_users)
|
||||
from .views import ItemViewSet
|
||||
|
||||
# Define config variables
|
||||
# Define config variables and projector elements.
|
||||
config.update_config_variables(get_config_variables())
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
||||
# Connect signals.
|
||||
post_save.connect(
|
||||
|
@ -1,3 +1,5 @@
|
||||
from typing import Generator, Type
|
||||
|
||||
from ..core.config import config
|
||||
from ..core.exceptions import ProjectorException
|
||||
from ..core.models import Projector
|
||||
@ -136,3 +138,9 @@ class CurrentListOfSpeakersSlide(ProjectorElement):
|
||||
output.extend(self.get_requirements_as_collection_elements(config_entry))
|
||||
break
|
||||
return output
|
||||
|
||||
|
||||
def get_projector_elements() -> Generator[Type[ProjectorElement], None, None]:
|
||||
yield ItemListSlide
|
||||
yield ListOfSpeakersSlide
|
||||
yield CurrentListOfSpeakersSlide
|
||||
|
@ -4,6 +4,7 @@ from django.apps import AppConfig
|
||||
from mypy_extensions import TypedDict
|
||||
|
||||
from ..utils.collection import Collection
|
||||
from ..utils.projector import register_projector_elements
|
||||
|
||||
|
||||
class AssignmentsAppConfig(AppConfig):
|
||||
@ -13,20 +14,18 @@ class AssignmentsAppConfig(AppConfig):
|
||||
angular_projector_module = True
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Do this by just importing all from these files.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from openslides.core.config import config
|
||||
from openslides.core.signals import permission_change, user_data_required
|
||||
from openslides.utils.rest_api import router
|
||||
from ..core.config import config
|
||||
from ..core.signals import permission_change, user_data_required
|
||||
from ..utils.rest_api import router
|
||||
from .config_variables import get_config_variables
|
||||
from .projector import get_projector_elements
|
||||
from .signals import get_permission_change_data, required_users
|
||||
from .views import AssignmentViewSet, AssignmentPollViewSet
|
||||
|
||||
# Define config variables
|
||||
# Define config variables and projector elements.
|
||||
config.update_config_variables(get_config_variables())
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
||||
# Connect signals.
|
||||
permission_change.connect(
|
||||
|
@ -1,3 +1,5 @@
|
||||
from typing import Generator, Type
|
||||
|
||||
from ..core.exceptions import ProjectorException
|
||||
from ..utils.projector import ProjectorElement
|
||||
from .models import Assignment, AssignmentPoll
|
||||
@ -64,3 +66,7 @@ class AssignmentSlide(ProjectorElement):
|
||||
else:
|
||||
data = {'agenda_item_id': assignment.agenda_item_id}
|
||||
return data
|
||||
|
||||
|
||||
def get_projector_elements() -> Generator[Type[ProjectorElement], None, None]:
|
||||
yield AssignmentSlide
|
||||
|
@ -3,6 +3,7 @@ from django.conf import settings
|
||||
from django.db.models.signals import post_migrate
|
||||
|
||||
from ..utils.collection import Collection
|
||||
from ..utils.projector import register_projector_elements
|
||||
|
||||
|
||||
class CoreAppConfig(AppConfig):
|
||||
@ -12,15 +13,12 @@ class CoreAppConfig(AppConfig):
|
||||
angular_projector_module = True
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Do this by just importing all from these files.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from .config import config
|
||||
from .signals import post_permission_creation
|
||||
from ..utils.rest_api import router
|
||||
from .config_variables import get_config_variables
|
||||
from .projector import get_projector_elements
|
||||
from .signals import (
|
||||
delete_django_app_permissions,
|
||||
get_permission_change_data,
|
||||
@ -36,8 +34,9 @@ class CoreAppConfig(AppConfig):
|
||||
TagViewSet,
|
||||
)
|
||||
|
||||
# Define config variables
|
||||
# Define config variables and projector elements.
|
||||
config.update_config_variables(get_config_variables())
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
||||
# Connect signals.
|
||||
post_permission_creation.connect(
|
||||
|
@ -5,7 +5,7 @@ from jsonfield import JSONField
|
||||
|
||||
from ..utils.collection import CollectionElement
|
||||
from ..utils.models import RESTModelMixin
|
||||
from ..utils.projector import ProjectorElement
|
||||
from ..utils.projector import get_all_projector_elements
|
||||
from .access_permissions import (
|
||||
ChatMessageAccessPermissions,
|
||||
ConfigAccessPermissions,
|
||||
@ -110,9 +110,7 @@ class Projector(RESTModelMixin, models.Model):
|
||||
result is also used.
|
||||
"""
|
||||
# Get all elements from all apps.
|
||||
elements = {}
|
||||
for element in ProjectorElement.get_all(): # type: ignore
|
||||
elements[element.name] = element
|
||||
elements = get_all_projector_elements()
|
||||
|
||||
# Parse result
|
||||
result = {}
|
||||
@ -137,9 +135,7 @@ class Projector(RESTModelMixin, models.Model):
|
||||
Generator which returns all instances that are shown on this projector.
|
||||
"""
|
||||
# Get all elements from all apps.
|
||||
elements = {}
|
||||
for element in ProjectorElement.get_all(): # type: ignore
|
||||
elements[element.name] = element
|
||||
elements = get_all_projector_elements()
|
||||
|
||||
# Generator
|
||||
for key, value in self.config.items():
|
||||
@ -166,11 +162,8 @@ class Projector(RESTModelMixin, models.Model):
|
||||
# It is necessary to parse all active projector elements to check whether they require some data.
|
||||
this_projector = collection_element.collection_string == self.get_collection_string() and collection_element.id == self.pk
|
||||
collection_element.information['this_projector'] = this_projector
|
||||
elements = {}
|
||||
|
||||
# Build projector elements.
|
||||
for element in ProjectorElement.get_all(): # type: ignore
|
||||
elements[element.name] = element
|
||||
elements = get_all_projector_elements()
|
||||
|
||||
# Iterate over all active projector elements.
|
||||
for key, value in self.config.items():
|
||||
|
@ -1,3 +1,5 @@
|
||||
from typing import Generator, Type
|
||||
|
||||
from ..utils.projector import ProjectorElement
|
||||
from .exceptions import ProjectorException
|
||||
from .models import Countdown, ProjectorMessage
|
||||
@ -48,3 +50,9 @@ class ProjectorMessageElement(ProjectorElement):
|
||||
pass
|
||||
else:
|
||||
yield message
|
||||
|
||||
|
||||
def get_projector_elements() -> Generator[Type[ProjectorElement], None, None]:
|
||||
yield Clock
|
||||
yield CountdownElement
|
||||
yield ProjectorMessageElement
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
from ..utils.collection import Collection
|
||||
from ..utils.projector import register_projector_elements
|
||||
|
||||
|
||||
class MediafilesAppConfig(AppConfig):
|
||||
@ -10,16 +11,16 @@ class MediafilesAppConfig(AppConfig):
|
||||
angular_projector_module = True
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Do this by just importing all from these files.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from openslides.core.signals import permission_change, user_data_required
|
||||
from openslides.utils.rest_api import router
|
||||
from .projector import get_projector_elements
|
||||
from .signals import get_permission_change_data, required_users
|
||||
from .views import MediafileViewSet
|
||||
|
||||
# Define projector elements.
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
||||
# Connect signals.
|
||||
permission_change.connect(
|
||||
get_permission_change_data,
|
||||
|
@ -1,3 +1,5 @@
|
||||
from typing import Generator, Type
|
||||
|
||||
from ..core.exceptions import ProjectorException
|
||||
from ..utils.projector import ProjectorElement
|
||||
from .models import Mediafile
|
||||
@ -21,3 +23,7 @@ class MediafileSlide(ProjectorElement):
|
||||
pass
|
||||
else:
|
||||
yield mediafile
|
||||
|
||||
|
||||
def get_projector_elements() -> Generator[Type[ProjectorElement], None, None]:
|
||||
yield MediafileSlide
|
||||
|
@ -2,6 +2,7 @@ from django.apps import AppConfig
|
||||
from django.db.models.signals import post_migrate
|
||||
|
||||
from ..utils.collection import Collection
|
||||
from ..utils.projector import register_projector_elements
|
||||
|
||||
|
||||
class MotionsAppConfig(AppConfig):
|
||||
@ -11,20 +12,18 @@ class MotionsAppConfig(AppConfig):
|
||||
angular_projector_module = True
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Do this by just importing all from these files.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from openslides.core.config import config
|
||||
from openslides.core.signals import permission_change, user_data_required
|
||||
from openslides.utils.rest_api import router
|
||||
from .config_variables import get_config_variables
|
||||
from .projector import get_projector_elements
|
||||
from .signals import create_builtin_workflows, get_permission_change_data, required_users
|
||||
from .views import CategoryViewSet, MotionViewSet, MotionBlockViewSet, MotionPollViewSet, MotionChangeRecommendationViewSet, WorkflowViewSet
|
||||
|
||||
# Define config variables
|
||||
# Define config variables and projector elements.
|
||||
config.update_config_variables(get_config_variables())
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
||||
# Connect signals.
|
||||
post_migrate.connect(create_builtin_workflows, dispatch_uid='motion_create_builtin_workflows')
|
||||
|
@ -1,3 +1,5 @@
|
||||
from typing import Generator, Type
|
||||
|
||||
from ..core.exceptions import ProjectorException
|
||||
from ..utils.projector import ProjectorElement
|
||||
from .models import Motion, MotionBlock, MotionChangeRecommendation, Workflow
|
||||
@ -90,3 +92,8 @@ class MotionBlockSlide(ProjectorElement):
|
||||
else:
|
||||
data = {'agenda_item_id': motion_block.agenda_item_id}
|
||||
return data
|
||||
|
||||
|
||||
def get_projector_elements() -> Generator[Type[ProjectorElement], None, None]:
|
||||
yield MotionSlide
|
||||
yield MotionBlockSlide
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
from ..utils.collection import Collection
|
||||
from ..utils.projector import register_projector_elements
|
||||
|
||||
|
||||
class TopicsAppConfig(AppConfig):
|
||||
@ -10,16 +11,16 @@ class TopicsAppConfig(AppConfig):
|
||||
angular_projector_module = True
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Do this by just importing all from these files.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from openslides.core.signals import permission_change
|
||||
from ..utils.rest_api import router
|
||||
from .projector import get_projector_elements
|
||||
from .signals import get_permission_change_data
|
||||
from .views import TopicViewSet
|
||||
|
||||
# Define projector elements.
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
||||
# Connect signals.
|
||||
permission_change.connect(
|
||||
get_permission_change_data,
|
||||
|
@ -1,3 +1,5 @@
|
||||
from typing import Generator, Type
|
||||
|
||||
from ..core.exceptions import ProjectorException
|
||||
from ..utils.projector import ProjectorElement
|
||||
from .models import Topic
|
||||
@ -33,3 +35,7 @@ class TopicSlide(ProjectorElement):
|
||||
else:
|
||||
data = {'agenda_item_id': topic.agenda_item_id}
|
||||
return data
|
||||
|
||||
|
||||
def get_projector_elements() -> Generator[Type[ProjectorElement], None, None]:
|
||||
yield TopicSlide
|
||||
|
@ -1,6 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
from ..utils.collection import Collection
|
||||
from ..utils.projector import register_projector_elements
|
||||
|
||||
|
||||
class UsersAppConfig(AppConfig):
|
||||
@ -10,20 +11,18 @@ class UsersAppConfig(AppConfig):
|
||||
angular_projector_module = True
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Just import this file.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from ..core.config import config
|
||||
from ..core.signals import post_permission_creation, permission_change
|
||||
from ..utils.rest_api import router
|
||||
from .config_variables import get_config_variables
|
||||
from .projector import get_projector_elements
|
||||
from .signals import create_builtin_groups_and_admin, get_permission_change_data
|
||||
from .views import GroupViewSet, PersonalNoteViewSet, UserViewSet
|
||||
|
||||
# Define config variables
|
||||
# Define config variables and projector elements.
|
||||
config.update_config_variables(get_config_variables())
|
||||
register_projector_elements(get_projector_elements())
|
||||
|
||||
# Connect signals.
|
||||
post_permission_creation.connect(
|
||||
|
@ -1,3 +1,5 @@
|
||||
from typing import Generator, Type
|
||||
|
||||
from ..core.exceptions import ProjectorException
|
||||
from ..utils.projector import ProjectorElement
|
||||
from .models import User
|
||||
@ -21,3 +23,7 @@ class UserSlide(ProjectorElement):
|
||||
pass
|
||||
else:
|
||||
yield user
|
||||
|
||||
|
||||
def get_projector_elements() -> Generator[Type[ProjectorElement], None, None]:
|
||||
yield UserSlide
|
||||
|
@ -1,112 +0,0 @@
|
||||
class SignalConnectMetaClass(type):
|
||||
"""
|
||||
Metaclass to connect the children of a base class to a Django signal.
|
||||
|
||||
Classes must have a signal argument and a get_dispatch_uid classmethod.
|
||||
The signal argument must be the Django signal the class should be
|
||||
connected to. The get_dispatch_uid classmethod must return a unique
|
||||
value for each child class and None for base classes because they will
|
||||
not be connected to the signal.
|
||||
|
||||
The classmethod get_all is added to every class using this metaclass.
|
||||
Calling this on a base class or on child classes will retrieve all
|
||||
connected children, one instance for each child class.
|
||||
|
||||
These instances will have a check_permission method which returns True
|
||||
by default. You can override this method to return False on runtime if
|
||||
you want to filter some children.
|
||||
|
||||
They will also have a get_default_weight method which returns the value
|
||||
of the default_weight attribute which is 0 by default. You can override
|
||||
the attribute or the method to sort the children.
|
||||
|
||||
Don't forget to set up the __init__ method so that it is able to receive
|
||||
wildcard keyword arguments (see example below). This is necessary
|
||||
because of Django's signal API.
|
||||
|
||||
Example:
|
||||
|
||||
class Base(object, metaclass=SignalConnectMetaClass):
|
||||
signal = django.dispatch.Signal()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_dispatch_uid(cls):
|
||||
if not cls.__name__ == 'Base':
|
||||
return cls.__name__
|
||||
|
||||
class Child(Base):
|
||||
pass
|
||||
|
||||
child = Base.get_all(request)[0]
|
||||
assert Child == type(child)
|
||||
"""
|
||||
def __new__(metaclass, class_name, class_parents, class_attributes):
|
||||
"""
|
||||
Creates the class and connects it to the signal if so. Adds all
|
||||
default attributes and methods.
|
||||
"""
|
||||
class_attributes['get_all'] = get_all
|
||||
new_class = super().__new__(
|
||||
metaclass, class_name, class_parents, class_attributes)
|
||||
try:
|
||||
dispatch_uid = new_class.get_dispatch_uid()
|
||||
except AttributeError:
|
||||
raise NotImplementedError('Your class %s must have a get_dispatch_uid classmethod.' % class_name)
|
||||
if dispatch_uid is not None:
|
||||
try:
|
||||
signal = new_class.signal
|
||||
except AttributeError:
|
||||
raise NotImplementedError('Your class %s must have a signal argument, which must be a Django Signal instance.' % class_name)
|
||||
else:
|
||||
signal.connect(new_class, dispatch_uid=dispatch_uid)
|
||||
attributes = {'check_permission': check_permission,
|
||||
'get_default_weight': get_default_weight,
|
||||
'default_weight': 0}
|
||||
for name, attribute in attributes.items():
|
||||
if not hasattr(new_class, name):
|
||||
setattr(new_class, name, attribute)
|
||||
return new_class
|
||||
|
||||
|
||||
@classmethod # type: ignore
|
||||
def get_all(cls, request=None):
|
||||
"""
|
||||
Collects all objects of the class created by the SignalConnectMetaClass
|
||||
from all apps via signal. They are sorted using the get_default_weight
|
||||
method. Does not return objects where check_permission returns False.
|
||||
|
||||
A django.http.HttpRequest object can optionally be given.
|
||||
|
||||
This classmethod is added as get_all classmethod to every class using
|
||||
the SignalConnectMetaClass.
|
||||
"""
|
||||
kwargs = {'sender': cls}
|
||||
if request is not None:
|
||||
kwargs['request'] = request
|
||||
all_objects = [obj for __, obj in cls.signal.send(**kwargs) if obj.check_permission()]
|
||||
all_objects.sort(key=lambda obj: obj.get_default_weight())
|
||||
return all_objects
|
||||
|
||||
|
||||
def check_permission(self):
|
||||
"""
|
||||
Returns True by default. Override this to filter some children on runtime.
|
||||
|
||||
This method is added to every instance of classes using the
|
||||
SignalConnectMetaClass.
|
||||
"""
|
||||
return True
|
||||
|
||||
|
||||
def get_default_weight(self):
|
||||
"""
|
||||
Returns the value of the default_weight attribute by default. Override
|
||||
this to sort some children on runtime.
|
||||
|
||||
This method is added to every instance of classes using the
|
||||
SignalConnectMetaClass.
|
||||
"""
|
||||
return self.default_weight
|
@ -1,42 +1,17 @@
|
||||
from typing import Any, Dict, Iterable, List, Optional # noqa
|
||||
|
||||
from django.dispatch import Signal
|
||||
from typing import Any, Dict, Generator, Iterable, List, Type
|
||||
|
||||
from .collection import CollectionElement
|
||||
from .dispatch import SignalConnectMetaClass
|
||||
|
||||
|
||||
class ProjectorElement(object, metaclass=SignalConnectMetaClass):
|
||||
class ProjectorElement:
|
||||
"""
|
||||
Base class for an element on the projector.
|
||||
|
||||
Every app which wants to add projector elements has to create classes
|
||||
subclassing from this base class with different names. The name attribute
|
||||
has to be set. The metaclass (SignalConnectMetaClass) does the rest of the
|
||||
magic.
|
||||
has to be set.
|
||||
"""
|
||||
signal = Signal()
|
||||
name = None # type: Optional[str]
|
||||
|
||||
def __init__(self, **kwargs: str) -> None:
|
||||
"""
|
||||
Initializes the projector element 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) -> Optional[str]:
|
||||
"""
|
||||
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__ == 'ProjectorElement':
|
||||
return cls.__name__
|
||||
return None
|
||||
name = None # type: str
|
||||
|
||||
def check_and_update_data(self, projector_object: Any, config_entry: Any) -> Any:
|
||||
"""
|
||||
@ -107,3 +82,25 @@ class ProjectorElement(object, metaclass=SignalConnectMetaClass):
|
||||
else:
|
||||
output = []
|
||||
return output
|
||||
|
||||
|
||||
projector_elements = {} # type: Dict[str, ProjectorElement]
|
||||
|
||||
|
||||
def register_projector_elements(elements: Generator[Type[ProjectorElement], None, None]) -> None:
|
||||
"""
|
||||
Registers projector elements for later use.
|
||||
|
||||
Has to be called in the app.ready method.
|
||||
"""
|
||||
for Element in elements:
|
||||
element = Element()
|
||||
projector_elements[element.name] = element
|
||||
|
||||
|
||||
def get_all_projector_elements() -> Dict[str, ProjectorElement]:
|
||||
"""
|
||||
Returns all projector elements that where registered with
|
||||
register_projector_elements()
|
||||
"""
|
||||
return projector_elements
|
||||
|
@ -19,9 +19,6 @@ ignore_missing_imports = true
|
||||
strict_optional = true
|
||||
check_untyped_defs = true
|
||||
|
||||
[mypy-openslides.utils.dispatch]
|
||||
ignore_errors = true
|
||||
|
||||
[mypy-openslides.utils.*]
|
||||
disallow_any = unannotated
|
||||
|
||||
|
@ -4,6 +4,9 @@ from . import __description__, __verbose_name__
|
||||
|
||||
|
||||
class TestPluginAppConfig(AppConfig):
|
||||
"""
|
||||
Test Plugin for the test tests.integration.core.test_views.VersionView
|
||||
"""
|
||||
name = 'tests.integration.test_plugin'
|
||||
label = 'tests.integration.test_plugin'
|
||||
verbose_name = __verbose_name__
|
||||
|
@ -1,28 +0,0 @@
|
||||
from django.db import models
|
||||
|
||||
from openslides.projector.models import SlideMixin
|
||||
|
||||
|
||||
class RelatedItem(SlideMixin, models.Model):
|
||||
slide_callback_name = 'test_related_item'
|
||||
name = models.CharField(max_length='255')
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Related Item CHFNGEJ5634DJ34F'
|
||||
|
||||
def get_agenda_title(self):
|
||||
return self.name
|
||||
|
||||
def get_agenda_title_supplement(self):
|
||||
return 'test item'
|
||||
|
||||
def get_absolute_url(self, link=None):
|
||||
if link is None:
|
||||
value = '/absolute-url-here/'
|
||||
else:
|
||||
value = super(RelatedItem, self).get_absolute_url(link)
|
||||
return value
|
||||
|
||||
|
||||
class BadRelatedItem(models.Model):
|
||||
name = models.CharField(max_length='255')
|
@ -1,26 +0,0 @@
|
||||
from django.test.client import Client
|
||||
|
||||
from openslides.assignments.models import Assignment
|
||||
from openslides.users.models import User
|
||||
from openslides.utils.test import TestCase
|
||||
|
||||
|
||||
class AssignmentPDFTest(TestCase):
|
||||
"""
|
||||
Tests for assignment PDF.
|
||||
"""
|
||||
def setUp(self):
|
||||
# Admin
|
||||
self.admin = User.objects.get(pk=1)
|
||||
self.admin_client = Client()
|
||||
self.admin_client.login(username='admin', password='admin')
|
||||
|
||||
def test_render_pdf(self):
|
||||
Assignment.objects.create(title='assignment_name_ith8qua1Eiferoqu5ju2', description="test", open_posts=1)
|
||||
response = self.admin_client.get('/assignments/print/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_render_many_posts(self):
|
||||
Assignment.objects.create(title='assignment_name_cohZ9shaipee3Phaing4', description="test", open_posts=20)
|
||||
response = self.admin_client.get('/assignments/print/')
|
||||
self.assertEqual(response.status_code, 200)
|
@ -1,263 +0,0 @@
|
||||
import os
|
||||
import tempfile
|
||||
from unittest import skip
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.test.client import Client
|
||||
|
||||
from openslides.mediafiles.models import Mediafile
|
||||
from openslides.users.models import User
|
||||
from openslides.utils.test import TestCase
|
||||
|
||||
|
||||
class MediafileTest(TestCase):
|
||||
"""
|
||||
Unit test for the mediafile model.
|
||||
"""
|
||||
def setUp(self):
|
||||
# Setup the three permissions
|
||||
ct = ContentType.objects.get(app_label='mediafiles', model='mediafile')
|
||||
perm_1 = Permission.objects.get(content_type=ct, codename='can_see')
|
||||
perm_2 = Permission.objects.get(content_type=ct, codename='can_upload')
|
||||
|
||||
# Setup three different users
|
||||
self.manager = User.objects.get(pk=1)
|
||||
self.vip_user = User.objects.create_user('mediafile_test_vip_user', 'default')
|
||||
self.vip_user.user_permissions.add(perm_1, perm_2)
|
||||
self.normal_user = User.objects.create_user('mediafile_test_normal_user', 'default')
|
||||
|
||||
# Setup a mediafile object
|
||||
self.tmp_dir = settings.MEDIA_ROOT
|
||||
tmpfile_no, mediafile_path = tempfile.mkstemp(prefix='tmp_openslides_test_', dir=self.tmp_dir)
|
||||
self.object = Mediafile.objects.create(title='Title File 1', mediafile=mediafile_path, uploader=self.normal_user)
|
||||
os.close(tmpfile_no)
|
||||
|
||||
def tearDown(self):
|
||||
self.object.mediafile.delete(save=False)
|
||||
super().tearDown()
|
||||
|
||||
def test_str(self):
|
||||
self.assertEqual(str(self.object), 'Title File 1')
|
||||
|
||||
@skip
|
||||
def test_absolute_url(self):
|
||||
self.assertEqual(self.object.get_absolute_url(), '/mediafiles/1/edit/')
|
||||
self.assertEqual(self.object.get_absolute_url('update'), '/mediafiles/1/edit/')
|
||||
self.assertEqual(self.object.get_absolute_url(link='delete'), '/mediafiles/1/del/')
|
||||
|
||||
def login_clients(self):
|
||||
"""
|
||||
Helper function to login all three test users.
|
||||
"""
|
||||
client_manager = Client()
|
||||
client_manager.login(username='admin', password='admin')
|
||||
client_vip_user = Client()
|
||||
client_vip_user.login(username='mediafile_test_vip_user', password='default')
|
||||
client_normal_user = Client()
|
||||
client_normal_user.login(username='mediafile_test_normal_user', password='default')
|
||||
return {'client_manager': client_manager,
|
||||
'client_vip_user': client_vip_user,
|
||||
'client_normal_user': client_normal_user}
|
||||
|
||||
@skip
|
||||
def test_see_mediafilelist(self):
|
||||
for client in self.login_clients().values():
|
||||
response = client.get('/mediafiles/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'mediafiles/mediafile_list.html')
|
||||
|
||||
@skip
|
||||
def test_upload_mediafile_get_request(self):
|
||||
clients = self.login_clients()
|
||||
response = clients['client_manager'].get('/mediafiles/new/')
|
||||
self.assertContains(response, '---------', status_code=200)
|
||||
self.assertContains(response, '<option value="1" selected="selected">Administrator</option>', status_code=200)
|
||||
self.assertTemplateUsed(response, 'mediafiles/mediafile_form.html')
|
||||
|
||||
response = clients['client_vip_user'].get('/mediafiles/new/')
|
||||
self.assertNotContains(response, '<select id="id_uploader" name="uploader">', status_code=200)
|
||||
self.assertTemplateUsed(response, 'mediafiles/mediafile_form.html')
|
||||
|
||||
response = clients['client_normal_user'].get('/mediafiles/new/')
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
@skip
|
||||
def test_upload_mediafile_post_request(self):
|
||||
# Test first user
|
||||
client_1 = self.login_clients()['client_manager']
|
||||
new_file_1 = SimpleUploadedFile(name='new_test_file.txt', content=bytes('test content hello manager', 'UTF-8'))
|
||||
response_1 = client_1.post('/mediafiles/new/',
|
||||
{'title': 'new_test_file_title_1',
|
||||
'mediafile': new_file_1,
|
||||
'uploader': self.normal_user.pk})
|
||||
self.assertRedirects(response_1, expected_url='/mediafiles/', status_code=302, target_status_code=200)
|
||||
object_1 = Mediafile.objects.latest('timestamp')
|
||||
self.assertEqual(object_1.mediafile.url, '/media/file/new_test_file.txt')
|
||||
self.assertEqual(object_1.uploader, self.normal_user)
|
||||
path_1 = object_1.mediafile.path
|
||||
object_1.mediafile.delete()
|
||||
self.assertFalse(os.path.exists(path_1))
|
||||
|
||||
# Test second user
|
||||
client_2 = self.login_clients()['client_vip_user']
|
||||
new_file_2 = SimpleUploadedFile(name='new_test_file.txt', content=bytes('test content hello vip_user', 'UTF-8'))
|
||||
response_2 = client_2.post('/mediafiles/new/',
|
||||
{'title': 'new_test_file_title_2',
|
||||
'mediafile': new_file_2})
|
||||
self.assertEqual(response_2.status_code, 302)
|
||||
# TODO: Check, why this does not work.
|
||||
# self.assertRedirects(response_2, expected_url='/mediafiles/', status_code=302, target_status_code=200)
|
||||
object_2 = Mediafile.objects.latest('timestamp')
|
||||
self.assertEqual(object_2.mediafile.url, '/media/file/new_test_file.txt')
|
||||
self.assertEqual(object_2.uploader, self.vip_user)
|
||||
path_2 = object_2.mediafile.path
|
||||
object_2.mediafile.delete()
|
||||
self.assertFalse(os.path.exists(path_2))
|
||||
|
||||
# Test third user
|
||||
client_3 = self.login_clients()['client_normal_user']
|
||||
new_file_3 = SimpleUploadedFile(name='new_test_file.txt', content=bytes('test content hello vip_user', 'UTF-8'))
|
||||
response_3 = client_3.post('/mediafiles/new/',
|
||||
{'title': 'new_test_file_title_2',
|
||||
'mediafile': new_file_3})
|
||||
self.assertEqual(response_3.status_code, 403)
|
||||
|
||||
@skip
|
||||
def test_edit_mediafile_get_request(self):
|
||||
clients = self.login_clients()
|
||||
response = clients['client_manager'].get('/mediafiles/1/edit/')
|
||||
self.assertContains(response, '---------', status_code=200)
|
||||
self.assertContains(response, '<option value="3" selected="selected">mediafile_test_normal_user</option>', status_code=200)
|
||||
self.assertTemplateUsed(response, 'mediafiles/mediafile_form.html')
|
||||
|
||||
response = clients['client_vip_user'].get('/mediafiles/1/edit/')
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
response = clients['client_normal_user'].get('/mediafiles/1/edit/')
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
@skip
|
||||
def test_edit_mediafile_get_request_own_file(self):
|
||||
clients = self.login_clients()
|
||||
self.object.uploader = self.vip_user
|
||||
self.object.save()
|
||||
response = clients['client_vip_user'].get('/mediafiles/1/edit/')
|
||||
self.assertNotContains(response, '---------', status_code=200)
|
||||
self.assertNotContains(response, '<option value="2" selected="selected">mediafile_test_vip_user</option>', status_code=200)
|
||||
self.assertTemplateUsed(response, 'mediafiles/mediafile_form.html')
|
||||
|
||||
@skip
|
||||
def test_edit_mediafile_post_request(self):
|
||||
# Test only one user
|
||||
tmpfile_no, mediafile_2_path = tempfile.mkstemp(prefix='tmp_openslides_test_', dir=self.tmp_dir)
|
||||
os.close(tmpfile_no)
|
||||
object_2 = Mediafile.objects.create(title='Title File 2', mediafile=mediafile_2_path, uploader=self.vip_user)
|
||||
client_1 = self.login_clients()['client_manager']
|
||||
new_file_1 = SimpleUploadedFile(name='new_test_file.txt', content=bytes('test content hello manager', 'UTF-8'))
|
||||
response_1 = client_1.post('/mediafiles/2/edit/',
|
||||
{'title': 'new_test_file_title_1',
|
||||
'mediafile': new_file_1,
|
||||
'uploader': self.manager.pk})
|
||||
self.assertEqual(response_1.status_code, 302)
|
||||
object_2 = Mediafile.objects.get(pk=2)
|
||||
self.assertEqual(object_2.mediafile.url, '/media/file/new_test_file.txt')
|
||||
self.assertEqual(object_2.uploader, self.manager)
|
||||
path_2 = object_2.mediafile.path
|
||||
object_2.mediafile.delete()
|
||||
self.assertFalse(os.path.exists(path_2))
|
||||
|
||||
@skip
|
||||
def test_edit_mediafile_post_request_own_file(self):
|
||||
tmpfile_no, mediafile_2_path = tempfile.mkstemp(prefix='tmp_openslides_test_', dir=self.tmp_dir)
|
||||
os.close(tmpfile_no)
|
||||
object_2 = Mediafile.objects.create(title='Title File 2b', mediafile=mediafile_2_path, uploader=self.vip_user)
|
||||
client = self.login_clients()['client_vip_user']
|
||||
new_file_1 = SimpleUploadedFile(name='new_test_file.txt', content=bytes('test content hello vip user', 'UTF-8'))
|
||||
response_1 = client.post('/mediafiles/2/edit/',
|
||||
{'title': 'new_test_file_title_2b',
|
||||
'mediafile': new_file_1})
|
||||
self.assertEqual(response_1.status_code, 302)
|
||||
object_2 = Mediafile.objects.get(pk=2)
|
||||
self.assertEqual(object_2.mediafile.url, '/media/file/new_test_file.txt')
|
||||
self.assertEqual(object_2.uploader, self.vip_user)
|
||||
path_2 = object_2.mediafile.path
|
||||
object_2.mediafile.delete()
|
||||
self.assertFalse(os.path.exists(path_2))
|
||||
|
||||
@skip
|
||||
def test_edit_mediafile_post_request_another_file(self):
|
||||
client = self.login_clients()['client_vip_user']
|
||||
new_file_1 = SimpleUploadedFile(name='new_test_file.txt', content=bytes('test content hello vip user', 'UTF-8'))
|
||||
response = client.post('/mediafiles/1/edit/',
|
||||
{'title': 'new_test_file_title_2c',
|
||||
'mediafile': new_file_1})
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
@skip
|
||||
def test_delete_mediafile_get_request(self):
|
||||
clients = self.login_clients()
|
||||
response = clients['client_manager'].get('/mediafiles/1/del/')
|
||||
self.assertRedirects(response, expected_url='/mediafiles/1/edit/', status_code=302, target_status_code=200)
|
||||
response = clients['client_vip_user'].get('/mediafiles/1/del/')
|
||||
self.assertEqual(response.status_code, 403)
|
||||
response = clients['client_normal_user'].get('/mediafiles/1/del/')
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
@skip
|
||||
def test_delete_mediafile_get_request_own_file(self):
|
||||
self.object.uploader = self.vip_user
|
||||
self.object.save()
|
||||
response = self.login_clients()['client_vip_user'].get('/mediafiles/1/del/')
|
||||
self.assertRedirects(response, expected_url='/mediafiles/1/edit/', status_code=302, target_status_code=200)
|
||||
|
||||
@skip
|
||||
def test_delete_mediafile_post_request(self):
|
||||
tmpfile_no, mediafile_3_path = tempfile.mkstemp(prefix='tmp_openslides_test_', dir=self.tmp_dir)
|
||||
os.close(tmpfile_no)
|
||||
object_3 = Mediafile.objects.create(title='Title File 3', mediafile=mediafile_3_path)
|
||||
client_1 = self.login_clients()['client_manager']
|
||||
response_1 = client_1.post('/mediafiles/2/del/', {'yes': 'foo'})
|
||||
self.assertRedirects(response_1, expected_url='/mediafiles/', status_code=302, target_status_code=200)
|
||||
self.assertFalse(os.path.exists(object_3.mediafile.path))
|
||||
|
||||
@skip
|
||||
def test_delete_mediafile_post_request_own_file(self):
|
||||
tmpfile_no, mediafile_3_path = tempfile.mkstemp(prefix='tmp_openslides_test_', dir=self.tmp_dir)
|
||||
os.close(tmpfile_no)
|
||||
object_3 = Mediafile.objects.create(title='Title File 3b', mediafile=mediafile_3_path, uploader=self.vip_user)
|
||||
client_1 = self.login_clients()['client_vip_user']
|
||||
response_1 = client_1.post('/mediafiles/2/del/', {'yes': 'foo'})
|
||||
self.assertRedirects(response_1, expected_url='/mediafiles/', status_code=302, target_status_code=200)
|
||||
self.assertFalse(os.path.exists(object_3.mediafile.path))
|
||||
|
||||
@skip
|
||||
def test_delete_mediafile_post_request_another_file(self):
|
||||
tmpfile_no, mediafile_3_path = tempfile.mkstemp(prefix='tmp_openslides_test_', dir=self.tmp_dir)
|
||||
os.close(tmpfile_no)
|
||||
object_3 = Mediafile.objects.create(title='Title File 3c', mediafile=mediafile_3_path, uploader=self.normal_user)
|
||||
client_1 = self.login_clients()['client_vip_user']
|
||||
response = client_1.post('/mediafiles/2/del/', {'yes': 'foo'})
|
||||
self.assertEqual(response.status_code, 403)
|
||||
path_3 = object_3.mediafile.path
|
||||
self.assertTrue(os.path.exists(path_3))
|
||||
object_3.mediafile.delete()
|
||||
self.assertFalse(os.path.exists(path_3))
|
||||
|
||||
def test_filesize(self):
|
||||
tmpfile_no, mediafile_4_path = tempfile.mkstemp(prefix='tmp_openslides_test_', dir=self.tmp_dir)
|
||||
os.close(tmpfile_no)
|
||||
object_4 = Mediafile.objects.create(title='Title File 4', mediafile=mediafile_4_path)
|
||||
self.assertEqual(object_4.get_filesize(), '< 1 kB')
|
||||
with open(object_4.mediafile.path, 'wb') as bigfile:
|
||||
bigfile.seek(2047)
|
||||
bigfile.write(b'0')
|
||||
self.assertEqual(object_4.get_filesize(), '2 kB')
|
||||
with open(object_4.mediafile.path, 'wb') as bigfile:
|
||||
bigfile.seek(1048575)
|
||||
bigfile.write(b'0')
|
||||
self.assertEqual(object_4.get_filesize(), '1 MB')
|
||||
os.remove(mediafile_4_path)
|
||||
self.assertEqual(object_4.get_filesize(), 'unknown')
|
@ -1 +0,0 @@
|
||||
default_app_config = 'tests.old.utils.apps.TestPluginAppConfig'
|
@ -1,6 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class TestPluginAppConfig(AppConfig):
|
||||
name = 'tests.old.utils'
|
||||
label = 'tests.old.utils'
|
@ -1,76 +0,0 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.dispatch import Signal
|
||||
from django.test.client import RequestFactory
|
||||
|
||||
from openslides.utils.dispatch import SignalConnectMetaClass
|
||||
from openslides.utils.test import TestCase
|
||||
|
||||
|
||||
class TestBaseOne(object, metaclass=SignalConnectMetaClass):
|
||||
signal = Signal()
|
||||
|
||||
@classmethod
|
||||
def get_dispatch_uid(cls):
|
||||
if not cls.__name__ == 'TestBaseOne':
|
||||
return 'test_vieM1eingi6luish5Sei'
|
||||
|
||||
|
||||
class TestBaseTwo(object, metaclass=SignalConnectMetaClass):
|
||||
signal = Signal()
|
||||
|
||||
@classmethod
|
||||
def get_dispatch_uid(cls):
|
||||
pass
|
||||
|
||||
|
||||
class TestSignalConnectMetaClass(TestCase):
|
||||
request_factory = RequestFactory()
|
||||
|
||||
@patch('tests.old.utils.test_dispatch.TestBaseOne.signal')
|
||||
def test_call_signal_send(self, mock_signal):
|
||||
TestBaseOne.get_all(self.request_factory.request)
|
||||
self.assertTrue(mock_signal.send.called)
|
||||
|
||||
@patch('tests.old.utils.test_dispatch.TestBaseOne.signal')
|
||||
def test_call_signal_connect(self, mock_signal):
|
||||
class TestChildOne(TestBaseOne):
|
||||
pass
|
||||
|
||||
self.assertTrue(mock_signal.connect.called)
|
||||
self.assertEqual(mock_signal.connect.call_args[0][0], TestChildOne)
|
||||
self.assertEqual(mock_signal.connect.call_args[1], dict(dispatch_uid='test_vieM1eingi6luish5Sei'))
|
||||
|
||||
def test_bad_base_class(self):
|
||||
def wrapper():
|
||||
class BadClass1(object, metaclass=SignalConnectMetaClass):
|
||||
pass
|
||||
|
||||
self.assertRaisesMessage(
|
||||
NotImplementedError,
|
||||
'Your class BadClass1 must have a get_dispatch_uid classmethod.',
|
||||
wrapper)
|
||||
|
||||
def test_bad_base_class_without_signal(self):
|
||||
def wrapper():
|
||||
class BadClass2(object, metaclass=SignalConnectMetaClass):
|
||||
@classmethod
|
||||
def get_dispatch_uid(cls):
|
||||
return True
|
||||
|
||||
self.assertRaisesMessage(
|
||||
NotImplementedError,
|
||||
'Your class BadClass2 must have a signal argument, which must be a Django Signal instance.',
|
||||
wrapper)
|
||||
|
||||
def test_receive_signal(self):
|
||||
class TestChildTwo(TestBaseTwo):
|
||||
def __init__(self, sender, **kwargs):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_dispatch_uid(self):
|
||||
return 'test_leeve5eighahT3zooxe5'
|
||||
|
||||
childtwo = TestBaseTwo.get_all(self.request_factory.request)[0]
|
||||
self.assertEqual(type(childtwo), TestChildTwo)
|
Loading…
Reference in New Issue
Block a user