diff --git a/CHANGELOG b/CHANGELOG
index 92014d0d3..07534dc4f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -8,6 +8,9 @@ Version 2.0.1 (unreleased)
==========================
[https://github.com/OpenSlides/OpenSlides/milestones/2.0.1]
+Other:
+- Remove config cache to support multiple threads or processes.
+
Version 2.0 (2016-04-18)
========================
diff --git a/openslides/agenda/apps.py b/openslides/agenda/apps.py
index a0c573577..6cd114997 100644
--- a/openslides/agenda/apps.py
+++ b/openslides/agenda/apps.py
@@ -15,16 +15,18 @@ class AgendaAppConfig(AppConfig):
# Import all required stuff.
from django.db.models.signals import pre_delete, post_save
- from openslides.core.signals import config_signal
+ from openslides.core.config import config
from openslides.utils.rest_api import router
+ from .config_variables import get_config_variables
from .signals import (
- setup_agenda_config,
listen_to_related_object_post_delete,
listen_to_related_object_post_save)
from .views import ItemViewSet
+ # Define config varialbes
+ config.update_config_varialbes(get_config_variables())
+
# Connect signals.
- config_signal.connect(setup_agenda_config, dispatch_uid='setup_agenda_config')
post_save.connect(
listen_to_related_object_post_save,
dispatch_uid='listen_to_related_object_post_save')
diff --git a/openslides/agenda/config_variables.py b/openslides/agenda/config_variables.py
new file mode 100644
index 000000000..5b5ba9994
--- /dev/null
+++ b/openslides/agenda/config_variables.py
@@ -0,0 +1,88 @@
+from datetime import datetime
+
+from django.core.exceptions import ValidationError as DjangoValidationError
+from django.core.validators import MaxLengthValidator, MinValueValidator
+from django.utils.translation import ugettext as _
+from django.utils.translation import ugettext_lazy
+
+from openslides.core.config import ConfigVariable
+
+
+def validate_start_time(value):
+ try:
+ datetime.strptime(value, '%d.%m.%Y %H:%M')
+ except ValueError:
+ raise DjangoValidationError(_('Invalid input.'))
+
+
+def get_config_variables():
+ """
+ Generator which yields all config variables of this app.
+
+ It has to be evaluated during app loading (see apps.py).
+ """
+ yield ConfigVariable(
+ name='agenda_number_prefix',
+ default_value='',
+ label=ugettext_lazy('Numbering prefix for agenda items'),
+ help_text=ugettext_lazy('This prefix will be set if you run the automatic agenda numbering.'),
+ weight=210,
+ group=ugettext_lazy('Agenda'),
+ subgroup=ugettext_lazy('General'),
+ validators=(MaxLengthValidator(20),))
+
+ yield ConfigVariable(
+ name='agenda_numeral_system',
+ default_value='arabic',
+ input_type='choice',
+ label=ugettext_lazy('Numeral system for agenda items'),
+ choices=(
+ {'value': 'arabic', 'display_name': ugettext_lazy('Arabic')},
+ {'value': 'roman', 'display_name': ugettext_lazy('Roman')}),
+ weight=215,
+ group=ugettext_lazy('Agenda'),
+ subgroup=ugettext_lazy('General'))
+
+ # TODO: Use an input type with generic datetime support.
+ yield ConfigVariable(
+ name='agenda_start_event_date_time',
+ default_value='',
+ label=ugettext_lazy('Begin of event'),
+ help_text=ugettext_lazy('Input format: DD.MM.YYYY HH:MM'),
+ weight=220,
+ group=ugettext_lazy('Agenda'),
+ subgroup=ugettext_lazy('General'),
+ validators=(validate_start_time,))
+
+ # List of speakers
+
+ yield ConfigVariable(
+ name='agenda_show_last_speakers',
+ default_value=1,
+ input_type='integer',
+ label=ugettext_lazy('Number of last speakers to be shown on the projector'),
+ weight=230,
+ group=ugettext_lazy('Agenda'),
+ subgroup=ugettext_lazy('List of speakers'),
+ validators=(MinValueValidator(0),))
+
+ yield ConfigVariable(
+ name='agenda_countdown_warning_time',
+ default_value=0,
+ input_type='integer',
+ label=ugettext_lazy('Show orange countdown in the last x seconds of speaking time'),
+ help_text=ugettext_lazy('Enter duration in seconds. Choose 0 to disable warning color.'),
+ weight=235,
+ group=ugettext_lazy('Agenda'),
+ subgroup=ugettext_lazy('List of speakers'),
+ validators=(MinValueValidator(0),))
+
+ yield ConfigVariable(
+ name='agenda_couple_countdown_and_speakers',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Couple countdown with the list of speakers'),
+ help_text=ugettext_lazy('[Begin speech] starts the countdown, [End speech] stops the countdown.'),
+ weight=240,
+ group=ugettext_lazy('Agenda'),
+ subgroup=ugettext_lazy('List of speakers'))
diff --git a/openslides/agenda/signals.py b/openslides/agenda/signals.py
index be46e16f5..ff8694774 100644
--- a/openslides/agenda/signals.py
+++ b/openslides/agenda/signals.py
@@ -1,97 +1,10 @@
-from datetime import datetime
-
from django.contrib.contenttypes.models import ContentType
-from django.core.exceptions import ValidationError as DjangoValidationError
-from django.core.validators import MaxLengthValidator, MinValueValidator
-from django.utils.translation import ugettext as _
-from django.utils.translation import ugettext_lazy
-from openslides.core.config import ConfigVariable
from openslides.utils.autoupdate import inform_changed_data
from .models import Item
-def validate_start_time(value):
- try:
- datetime.strptime(value, '%d.%m.%Y %H:%M')
- except ValueError:
- raise DjangoValidationError(_('Invalid input.'))
-
-
-def setup_agenda_config(sender, **kwargs):
- """
- Receiver function to setup all agenda config variables.
- This function connected to the signal openslides.core.signals.config_signal
- during app loading.
- """
- yield ConfigVariable(
- name='agenda_number_prefix',
- default_value='',
- label=ugettext_lazy('Numbering prefix for agenda items'),
- help_text=ugettext_lazy('This prefix will be set if you run the automatic agenda numbering.'),
- weight=210,
- group=ugettext_lazy('Agenda'),
- subgroup=ugettext_lazy('General'),
- validators=(MaxLengthValidator(20),))
-
- yield ConfigVariable(
- name='agenda_numeral_system',
- default_value='arabic',
- input_type='choice',
- label=ugettext_lazy('Numeral system for agenda items'),
- choices=(
- {'value': 'arabic', 'display_name': ugettext_lazy('Arabic')},
- {'value': 'roman', 'display_name': ugettext_lazy('Roman')}),
- weight=215,
- group=ugettext_lazy('Agenda'),
- subgroup=ugettext_lazy('General'))
-
- # TODO: Use an input type with generic datetime support.
- yield ConfigVariable(
- name='agenda_start_event_date_time',
- default_value='',
- label=ugettext_lazy('Begin of event'),
- help_text=ugettext_lazy('Input format: DD.MM.YYYY HH:MM'),
- weight=220,
- group=ugettext_lazy('Agenda'),
- subgroup=ugettext_lazy('General'),
- validators=(validate_start_time,))
-
- # List of speakers
-
- yield ConfigVariable(
- name='agenda_show_last_speakers',
- default_value=1,
- input_type='integer',
- label=ugettext_lazy('Number of last speakers to be shown on the projector'),
- weight=230,
- group=ugettext_lazy('Agenda'),
- subgroup=ugettext_lazy('List of speakers'),
- validators=(MinValueValidator(0),))
-
- yield ConfigVariable(
- name='agenda_countdown_warning_time',
- default_value=0,
- input_type='integer',
- label=ugettext_lazy('Show orange countdown in the last x seconds of speaking time'),
- help_text=ugettext_lazy('Enter duration in seconds. Choose 0 to disable warning color.'),
- weight=235,
- group=ugettext_lazy('Agenda'),
- subgroup=ugettext_lazy('List of speakers'),
- validators=(MinValueValidator(0),))
-
- yield ConfigVariable(
- name='agenda_couple_countdown_and_speakers',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Couple countdown with the list of speakers'),
- help_text=ugettext_lazy('[Begin speech] starts the countdown, [End speech] stops the countdown.'),
- weight=240,
- group=ugettext_lazy('Agenda'),
- subgroup=ugettext_lazy('List of speakers'))
-
-
def listen_to_related_object_post_save(sender, instance, created, **kwargs):
"""
Receiver function to create agenda items. It is connected to the signal
diff --git a/openslides/assignments/apps.py b/openslides/assignments/apps.py
index 67a455495..7228e4f89 100644
--- a/openslides/assignments/apps.py
+++ b/openslides/assignments/apps.py
@@ -14,13 +14,13 @@ class AssignmentsAppConfig(AppConfig):
from . import projector # noqa
# Import all required stuff.
- from openslides.core.signals import config_signal
+ from openslides.core.config import config
from openslides.utils.rest_api import router
- from .signals import setup_assignment_config
+ from .config_variables import get_config_variables
from .views import AssignmentViewSet, AssignmentPollViewSet
- # Connect signals.
- config_signal.connect(setup_assignment_config, dispatch_uid='setup_assignment_config')
+ # Define config variables
+ config.update_config_varialbes(get_config_variables())
# Register viewsets.
router.register(self.get_model('Assignment').get_collection_string(), AssignmentViewSet)
diff --git a/openslides/assignments/signals.py b/openslides/assignments/config_variables.py
similarity index 92%
rename from openslides/assignments/signals.py
rename to openslides/assignments/config_variables.py
index 17f920948..e4e3412b3 100644
--- a/openslides/assignments/signals.py
+++ b/openslides/assignments/config_variables.py
@@ -6,15 +6,14 @@ from openslides.core.config import ConfigVariable
from openslides.poll.models import PERCENT_BASE_CHOICES
-def setup_assignment_config(sender, **kwargs):
+def get_config_variables():
"""
- Receiver function to setup all assignment config variables. They are
- grouped in 'Ballot and ballot papers' and 'PDF'. This function is
- connected to the signal openslides.core.signals.config_signal during
- app loading.
+ Generator which yields all config variables of this app.
+
+ They are grouped in 'Ballot and ballot papers' and 'PDF'. The generator has
+ to be evaluated during app loading (see apps.py).
"""
# Ballot and ballot papers
-
yield ConfigVariable(
name='assignments_poll_vote_values',
default_value='auto',
diff --git a/openslides/core/apps.py b/openslides/core/apps.py
index 456d08552..569c3d72c 100644
--- a/openslides/core/apps.py
+++ b/openslides/core/apps.py
@@ -15,11 +15,13 @@ class CoreAppConfig(AppConfig):
# Import all required stuff.
from django.db.models import signals
- from openslides.core.signals import config_signal, post_permission_creation
+ from openslides.core.config import config
+ from openslides.core.signals import post_permission_creation
from openslides.utils.autoupdate import inform_changed_data_receiver, inform_deleted_data_receiver
from openslides.utils.rest_api import router
from openslides.utils.search import index_add_instance, index_del_instance
- from .signals import delete_django_app_permissions, setup_general_config
+ from .config_variables import get_config_variables
+ from .signals import delete_django_app_permissions
from .views import (
ChatMessageViewSet,
ConfigViewSet,
@@ -28,10 +30,10 @@ class CoreAppConfig(AppConfig):
TagViewSet,
)
+ # Define config variables
+ config.update_config_varialbes(get_config_variables())
+
# Connect signals.
- config_signal.connect(
- setup_general_config,
- dispatch_uid='setup_general_config')
post_permission_creation.connect(
delete_django_app_permissions,
dispatch_uid='delete_django_app_permissions')
diff --git a/openslides/core/config.py b/openslides/core/config.py
index d4d52113d..b0ad57e4f 100644
--- a/openslides/core/config.py
+++ b/openslides/core/config.py
@@ -19,33 +19,35 @@ class ConfigHandler:
object. To get a config variable use x = config[...], to set it use
config[...] = x.
"""
+
+ def __init__(self):
+ # Dict, that keeps all ConfigVariable objects. Has to be set at statup.
+ # See the run method in openslides.core.apps.
+ self.config_variables = {}
+
def __getitem__(self, key):
"""
- Returns the value of the config variable. Builds the cache if it
- does not exist.
+ Returns the value of the config variable. Returns the default value, if
+ not value exists in the database.
"""
try:
- return self._cache[key]
+ default_value = self.config_variables[key].default_value
except KeyError:
- raise ConfigNotFound(_('The config variable %s was not found.') % key)
- except AttributeError:
- self.setup_cache()
- return self[key]
+ raise ConfigNotFound(_('The config variable {} was not found.').format(key))
- def setup_cache(self):
- """
- Creates a cache of all config variables with their current value.
- """
- self._cache = {}
- for key, config_variable in self.get_config_variables().items():
- self._cache[key] = config_variable.default_value
- for config_object in ConfigStore.objects.all():
- self._cache[config_object.key] = config_object.value
+ try:
+ db_value = ConfigStore.objects.get(key=key)
+ except ConfigStore.DoesNotExist:
+ return default_value
+ return db_value.value
def __contains__(self, key):
+ """
+ Returns True, if the config varialbe exists.
+ """
try:
- config[key]
- except ConfigNotFound:
+ self.config_variables[key]
+ except KeyError:
return False
else:
return True
@@ -56,9 +58,9 @@ class ConfigHandler:
"""
# Check if the variable is defined.
try:
- config_variable = config.get_config_variables()[key]
+ config_variable = self.config_variables[key]
except KeyError:
- raise ConfigNotFound(_('The config variable %s was not found.') % key)
+ raise ConfigNotFound(_('The config variable {} was not found.').format(key))
# Validate datatype and run validators.
expected_type = INPUT_TYPE_MAPPING[config_variable.input_type]
@@ -69,8 +71,15 @@ class ConfigHandler:
except ValueError:
raise ConfigError(_('Wrong datatype. Expected %(expected_type)s, got %(got_type)s.') % {
'expected_type': expected_type, 'got_type': type(value)})
- if config_variable.input_type == 'choice' and value not in map(lambda choice: choice['value'], config_variable.choices):
- raise ConfigError(_('Invalid input. Choice does not match.'))
+
+ if config_variable.input_type == 'choice':
+ # Choices can be a callable. In this case call it at this place
+ if callable(config_variable.choices):
+ choices = config_variable.choices()
+ else:
+ choices = config_variable.choices
+ if value not in map(lambda choice: choice['value'], choices):
+ raise ConfigError(_('Invalid input. Choice does not match.'))
for validator in config_variable.validators:
try:
validator(value)
@@ -78,50 +87,45 @@ class ConfigHandler:
raise ConfigError(e.messages[0])
# Save the new value to the database.
- config_store, created = ConfigStore.objects.get_or_create(key=key, defaults={'value': value})
- if not created:
- config_store.value = value
- config_store.save()
-
- # Update cache.
- if hasattr(self, '_cache'):
- self._cache[key] = value
+ ConfigStore.objects.update_or_create(key=key, defaults={'value': value})
# Call on_change callback.
if config_variable.on_change:
config_variable.on_change()
+ def update_config_varialbes(self, items):
+ """
+ Updates the config_variables dict.
+
+ items has to be an iterator over ConfigVariable objects.
+ """
+ new_items = dict((variable.name, variable) for variable in items)
+ # Check that all ConfigVariables are unique. So no key from items can
+ # be in already in self.config_variables
+ for key in new_items.keys():
+ if key in self.config_variables:
+ raise ConfigError(_('Too many values for config variable {} found.').format(key))
+
+ self.config_variables.update(new_items)
+
def items(self):
"""
- Returns key-value pairs of all config variables.
+ Iterates over key-value pairs of all config variables.
"""
- if not hasattr(self, '_cache'):
- self.setup_cache()
- return self._cache.items()
+ # Create a dict with the default values of each ConfigVariable
+ config_items = dict((key, variable.default_value) for key, variable in self.config_variables.items())
- def get_config_variables(self):
- """
- Returns a dictionary with all ConfigVariable instances of all
- signal receivers. The key is the name of the config variable.
- """
- # config_signal can not be imported at global space, because
- # core.signals imports this file
- from .signals import config_signal
-
- result = {}
- for receiver, config_collection in config_signal.send(sender='get_config_variables'):
- for config_variable in config_collection:
- if config_variable.name in result:
- raise ConfigError(_('Too many values for config variable %s found.') % config_variable.name)
- result[config_variable.name] = config_variable
- return result
+ # Update the dict with all values, which are in the db
+ for db_value in ConfigStore.objects.all():
+ config_items[db_value.key] = db_value.value
+ return config_items.items()
def get_all_translatable(self):
"""
Generator to get all config variables as strings when their values are
intended to be translated.
"""
- for config_variable in self.get_config_variables().values():
+ for config_variable in self.config_variables.values():
if config_variable.translatable:
yield config_variable.name
diff --git a/openslides/core/config_variables.py b/openslides/core/config_variables.py
new file mode 100644
index 000000000..affaeee7b
--- /dev/null
+++ b/openslides/core/config_variables.py
@@ -0,0 +1,160 @@
+from django.core.validators import MaxLengthValidator
+from django.utils.translation import ugettext as _
+from django.utils.translation import ugettext_lazy
+
+from openslides.core.config import ConfigVariable
+
+
+def get_config_variables():
+ """
+ Generator which yields all config variables of this app.
+
+ There are two main groups: 'General' and 'Projector'. The group 'General'
+ has subgroups. The generator has to be evaluated during app loading
+ (see apps.py).
+ """
+ yield ConfigVariable(
+ name='general_event_name',
+ default_value='OpenSlides',
+ label=ugettext_lazy('Event name'),
+ weight=110,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'),
+ validators=(MaxLengthValidator(50),))
+
+ yield ConfigVariable(
+ name='general_event_description',
+ default_value=_('Presentation and assembly system'),
+ label=ugettext_lazy('Short description of event'),
+ weight=115,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'),
+ validators=(MaxLengthValidator(100),),
+ translatable=True)
+
+ yield ConfigVariable(
+ name='general_event_date',
+ default_value='',
+ label=ugettext_lazy('Event date'),
+ weight=120,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'))
+
+ yield ConfigVariable(
+ name='general_event_location',
+ default_value='',
+ label=ugettext_lazy('Event location'),
+ weight=125,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'))
+
+ yield ConfigVariable(
+ name='general_event_organizer',
+ default_value='',
+ label=ugettext_lazy('Event organizer'),
+ weight=130,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'))
+
+ yield ConfigVariable(
+ name='general_event_legal_notice',
+ default_value=_(
+ 'OpenSlides is a free web based '
+ 'presentation and assembly system for visualizing and controlling agenda, '
+ 'motions and elections of an assembly.'),
+ input_type='text',
+ label=ugettext_lazy('Legal notice'),
+ weight=132,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'),
+ translatable=True)
+
+ yield ConfigVariable(
+ name='general_event_welcome_title',
+ default_value=_('Welcome to OpenSlides'),
+ label=ugettext_lazy('Front page title'),
+ weight=134,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'),
+ translatable=True)
+
+ yield ConfigVariable(
+ name='general_event_welcome_text',
+ default_value=_('[Space for your welcome text.]'),
+ input_type='text',
+ label=ugettext_lazy('Front page text'),
+ weight=136,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('Event'),
+ translatable=True)
+
+ # General System
+
+ yield ConfigVariable(
+ name='general_system_enable_anonymous',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Allow access for anonymous guest users'),
+ weight=138,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('System'))
+
+ yield ConfigVariable(
+ name='general_login_info_text',
+ default_value='',
+ label=ugettext_lazy('Show this text on the login page.'),
+ weight=140,
+ group=ugettext_lazy('General'),
+ subgroup=ugettext_lazy('System'))
+
+ # Projector
+
+ yield ConfigVariable(
+ name='projector_enable_logo',
+ default_value=True,
+ input_type='boolean',
+ label=ugettext_lazy('Show logo on projector'),
+ help_text=ugettext_lazy(
+ 'You can replace the logo. Just copy a file to '
+ '"static/img/logo-projector.png" in your OpenSlides data path.'),
+ weight=150,
+ group=ugettext_lazy('Projector'))
+
+ yield ConfigVariable(
+ name='projector_enable_title',
+ default_value=True,
+ input_type='boolean',
+ label=ugettext_lazy('Show title and description of event on projector'),
+ weight=155,
+ group=ugettext_lazy('Projector'))
+
+ yield ConfigVariable(
+ name='projector_header_backgroundcolor',
+ default_value='#317796',
+ input_type='colorpicker',
+ label=ugettext_lazy('Background color of projector header and footer'),
+ weight=160,
+ group=ugettext_lazy('Projector'))
+
+ yield ConfigVariable(
+ name='projector_header_fontcolor',
+ default_value='#F5F5F5',
+ input_type='colorpicker',
+ label=ugettext_lazy('Font color of projector header and footer'),
+ weight=165,
+ group=ugettext_lazy('Projector'))
+
+ yield ConfigVariable(
+ name='projector_h1_fontcolor',
+ default_value='#317796',
+ input_type='colorpicker',
+ label=ugettext_lazy('Font color of projector headline'),
+ weight=170,
+ group=ugettext_lazy('Projector'))
+
+ yield ConfigVariable(
+ name='projector_default_countdown',
+ default_value=60,
+ label=ugettext_lazy('Default countdown'),
+ weight=185,
+ group=ugettext_lazy('Projector'))
diff --git a/openslides/core/middleware.py b/openslides/core/middleware.py
deleted file mode 100644
index d4bc03a21..000000000
--- a/openslides/core/middleware.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from .config import config
-
-
-class ConfigCacheMiddleware(object):
- """
- Middleware to refresh the config cache before processing any view.
- """
- def process_request(self, request):
- config.setup_cache()
diff --git a/openslides/core/signals.py b/openslides/core/signals.py
index 2f8bc101d..dc4490f5c 100644
--- a/openslides/core/signals.py
+++ b/openslides/core/signals.py
@@ -1,12 +1,7 @@
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
-from django.core.validators import MaxLengthValidator
from django.db.models import Q
from django.dispatch import Signal
-from django.utils.translation import ugettext as _
-from django.utils.translation import ugettext_lazy
-
-from openslides.core.config import ConfigVariable
# This signal is sent when the migrate command is done. That means it is sent
# after post_migrate sending and creating all Permission objects. Don't use it
@@ -25,163 +20,3 @@ def delete_django_app_permissions(sender, **kwargs):
Q(app_label='sessions'))
for permission in Permission.objects.filter(content_type__in=contenttypes):
permission.delete()
-
-
-def setup_general_config(sender, **kwargs):
- """
- Receiver function to setup general config variables for OpenSlides.
- There are two main groups: 'General' and 'Projector'. The group
- 'General' has subgroups. This function is connected to the signal
- openslides.core.signals.config_signal during app loading.
- """
- # General Event
-
- yield ConfigVariable(
- name='general_event_name',
- default_value='OpenSlides',
- label=ugettext_lazy('Event name'),
- weight=110,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'),
- validators=(MaxLengthValidator(50),))
-
- yield ConfigVariable(
- name='general_event_description',
- default_value=_('Presentation and assembly system'),
- label=ugettext_lazy('Short description of event'),
- weight=115,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'),
- validators=(MaxLengthValidator(100),),
- translatable=True)
-
- yield ConfigVariable(
- name='general_event_date',
- default_value='',
- label=ugettext_lazy('Event date'),
- weight=120,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'))
-
- yield ConfigVariable(
- name='general_event_location',
- default_value='',
- label=ugettext_lazy('Event location'),
- weight=125,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'))
-
- yield ConfigVariable(
- name='general_event_organizer',
- default_value='',
- label=ugettext_lazy('Event organizer'),
- weight=130,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'))
-
- yield ConfigVariable(
- name='general_event_legal_notice',
- default_value=_(
- 'OpenSlides is a free web based '
- 'presentation and assembly system for visualizing and controlling agenda, '
- 'motions and elections of an assembly.'),
- input_type='text',
- label=ugettext_lazy('Legal notice'),
- weight=132,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'),
- translatable=True)
-
- yield ConfigVariable(
- name='general_event_welcome_title',
- default_value=_('Welcome to OpenSlides'),
- label=ugettext_lazy('Front page title'),
- weight=134,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'),
- translatable=True)
-
- yield ConfigVariable(
- name='general_event_welcome_text',
- default_value=_('[Space for your welcome text.]'),
- input_type='text',
- label=ugettext_lazy('Front page text'),
- weight=136,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('Event'),
- translatable=True)
-
- # General System
-
- yield ConfigVariable(
- name='general_system_enable_anonymous',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Allow access for anonymous guest users'),
- weight=138,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('System'))
-
- yield ConfigVariable(
- name='general_login_info_text',
- default_value='',
- label=ugettext_lazy('Show this text on the login page.'),
- weight=140,
- group=ugettext_lazy('General'),
- subgroup=ugettext_lazy('System'))
-
- # Projector
-
- yield ConfigVariable(
- name='projector_enable_logo',
- default_value=True,
- input_type='boolean',
- label=ugettext_lazy('Show logo on projector'),
- help_text=ugettext_lazy(
- 'You can replace the logo. Just copy a file to '
- '"static/img/logo-projector.png" in your OpenSlides data path.'),
- weight=150,
- group=ugettext_lazy('Projector'))
-
- yield ConfigVariable(
- name='projector_enable_title',
- default_value=True,
- input_type='boolean',
- label=ugettext_lazy('Show title and description of event on projector'),
- weight=155,
- group=ugettext_lazy('Projector'))
-
- yield ConfigVariable(
- name='projector_header_backgroundcolor',
- default_value='#317796',
- input_type='colorpicker',
- label=ugettext_lazy('Background color of projector header and footer'),
- weight=160,
- group=ugettext_lazy('Projector'))
-
- yield ConfigVariable(
- name='projector_header_fontcolor',
- default_value='#F5F5F5',
- input_type='colorpicker',
- label=ugettext_lazy('Font color of projector header and footer'),
- weight=165,
- group=ugettext_lazy('Projector'))
-
- yield ConfigVariable(
- name='projector_h1_fontcolor',
- default_value='#317796',
- input_type='colorpicker',
- label=ugettext_lazy('Font color of projector headline'),
- weight=170,
- group=ugettext_lazy('Projector'))
-
- yield ConfigVariable(
- name='projector_default_countdown',
- default_value=60,
- label=ugettext_lazy('Default countdown'),
- weight=185,
- group=ugettext_lazy('Projector'))
-
-
-config_signal = Signal(providing_args=[])
-"""Signal to get all config tabs from all apps."""
diff --git a/openslides/core/views.py b/openslides/core/views.py
index b76183d1b..ac6ee5412 100644
--- a/openslides/core/views.py
+++ b/openslides/core/views.py
@@ -415,12 +415,9 @@ class ConfigMetadata(SimpleMetadata):
Custom metadata class to add config info to responses on OPTIONS requests.
"""
def determine_metadata(self, request, view):
- # Sort config variables by weight.
- config_variables = sorted(config.get_config_variables().values(), key=attrgetter('weight'))
-
# Build tree.
config_groups = []
- for config_variable in config_variables:
+ for config_variable in sorted(config.config_variables.values(), key=attrgetter('weight')):
if config_variable.is_hidden():
# Skip hidden config variables. Do not even check groups and subgroups.
continue
diff --git a/openslides/global_settings.py b/openslides/global_settings.py
index f913e79ab..9b6ba6090 100644
--- a/openslides/global_settings.py
+++ b/openslides/global_settings.py
@@ -60,7 +60,6 @@ MIDDLEWARE_CLASSES = (
'django.middleware.csrf.CsrfViewMiddleware',
'openslides.users.auth.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
- 'openslides.core.middleware.ConfigCacheMiddleware',
)
ROOT_URLCONF = 'openslides.urls'
diff --git a/openslides/motions/apps.py b/openslides/motions/apps.py
index 582090fb5..38ad8e34f 100644
--- a/openslides/motions/apps.py
+++ b/openslides/motions/apps.py
@@ -15,13 +15,16 @@ class MotionsAppConfig(AppConfig):
from . import projector # noqa
# Import all required stuff.
- from openslides.core.signals import config_signal
+ from openslides.core.config import config
from openslides.utils.rest_api import router
- from .signals import create_builtin_workflows, setup_motion_config
+ from .config_variables import get_config_variables
+ from .signals import create_builtin_workflows
from .views import CategoryViewSet, MotionViewSet, MotionPollViewSet, WorkflowViewSet
+ # Define config varialbes
+ config.update_config_varialbes(get_config_variables())
+
# Connect signals.
- config_signal.connect(setup_motion_config, dispatch_uid='setup_motion_config')
post_migrate.connect(create_builtin_workflows, dispatch_uid='motion_create_builtin_workflows')
# Register viewsets.
diff --git a/openslides/motions/config_variables.py b/openslides/motions/config_variables.py
new file mode 100644
index 000000000..74cf3dc8c
--- /dev/null
+++ b/openslides/motions/config_variables.py
@@ -0,0 +1,183 @@
+from django.core.validators import MinValueValidator
+from django.utils.translation import ugettext as _
+from django.utils.translation import pgettext, ugettext_lazy
+
+from openslides.core.config import ConfigVariable
+from openslides.poll.models import PERCENT_BASE_CHOICES
+
+from .models import Workflow
+
+
+def get_workflow_choices():
+ """
+ Returns a list of all workflows to be used as choices for the config variable
+ 'motions_workflow'. Each list item contains the pk and the display name.
+ """
+ return [{'value': str(workflow.pk), 'display_name': ugettext_lazy(workflow.name)}
+ for workflow in Workflow.objects.all()]
+
+
+def get_config_variables():
+ """
+ Generator which yields all config variables of this app.
+
+ They are grouped in 'General', 'Amendments', 'Supporters', 'Voting and ballot
+ papers' and 'PDF'. The generator has to be evaluated during app loading
+ (see apps.py).
+ """
+ # General
+ yield ConfigVariable(
+ name='motions_workflow',
+ default_value='1',
+ input_type='choice',
+ label=ugettext_lazy('Workflow of new motions'),
+ choices=get_workflow_choices,
+ weight=310,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('General'))
+
+ yield ConfigVariable(
+ name='motions_identifier',
+ default_value='per_category',
+ input_type='choice',
+ label=ugettext_lazy('Identifier'),
+ choices=(
+ {'value': 'per_category', 'display_name': ugettext_lazy('Numbered per category')},
+ {'value': 'serially_numbered', 'display_name': ugettext_lazy('Serially numbered')},
+ {'value': 'manually', 'display_name': ugettext_lazy('Set it manually')}),
+ weight=315,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('General'))
+
+ yield ConfigVariable(
+ name='motions_preamble',
+ default_value=_('The assembly may decide,'),
+ label=ugettext_lazy('Motion preamble'),
+ weight=320,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('General'),
+ translatable=True)
+
+ yield ConfigVariable(
+ name='motions_stop_submitting',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Stop submitting new motions by non-staff users'),
+ weight=325,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('General'))
+
+ yield ConfigVariable(
+ name='motions_allow_disable_versioning',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Allow to disable versioning'),
+ weight=330,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('General'))
+
+ # Amendments
+ # Amendments currently not implemented. (TODO: Implement it like in OpenSlides 1.7.)
+ yield ConfigVariable(
+ name='motions_amendments_enabled',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Activate amendments'),
+ hidden=True,
+ weight=335,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('Amendments'))
+
+ yield ConfigVariable(
+ name='motions_amendments_prefix',
+ default_value=pgettext('Prefix for the identifier for amendments', 'A'),
+ label=ugettext_lazy('Prefix for the identifier for amendments'),
+ hidden=True,
+ weight=340,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('Amendments'))
+
+ # Supporters
+
+ yield ConfigVariable(
+ name='motions_min_supporters',
+ default_value=0,
+ input_type='integer',
+ label=ugettext_lazy('Number of (minimum) required supporters for a motion'),
+ help_text=ugettext_lazy('Choose 0 to disable the supporting system.'),
+ weight=345,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('Supporters'),
+ validators=(MinValueValidator(0),))
+
+ yield ConfigVariable(
+ name='motions_remove_supporters',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Remove all supporters of a motion if a submitter edits his motion in early state'),
+ weight=350,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('Supporters'))
+
+ # Voting and ballot papers
+
+ yield ConfigVariable(
+ name='motions_poll_100_percent_base',
+ default_value='WITHOUT_INVALID',
+ input_type='choice',
+ label=ugettext_lazy('The 100 % base of a voting result consists of'),
+ choices=PERCENT_BASE_CHOICES,
+ weight=355,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('Voting and ballot papers'))
+
+ yield ConfigVariable(
+ name='motions_pdf_ballot_papers_selection',
+ default_value='CUSTOM_NUMBER',
+ input_type='choice',
+ label=ugettext_lazy('Number of ballot papers (selection)'),
+ choices=(
+ {'value': 'NUMBER_OF_DELEGATES', 'display_name': ugettext_lazy('Number of all delegates')},
+ {'value': 'NUMBER_OF_ALL_PARTICIPANTS', 'display_name': ugettext_lazy('Number of all participants')},
+ {'value': 'CUSTOM_NUMBER', 'display_name': ugettext_lazy('Use the following custom number')}),
+ weight=360,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('Voting and ballot papers'))
+
+ yield ConfigVariable(
+ name='motions_pdf_ballot_papers_number',
+ default_value=8,
+ input_type='integer',
+ label=ugettext_lazy('Custom number of ballot papers'),
+ weight=365,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('Voting and ballot papers'),
+ validators=(MinValueValidator(1),))
+
+ # PDF
+
+ yield ConfigVariable(
+ name='motions_pdf_title',
+ default_value=_('Motions'),
+ label=ugettext_lazy('Title for PDF document (all motions)'),
+ weight=370,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('PDF'),
+ translatable=True)
+
+ yield ConfigVariable(
+ name='motions_pdf_preamble',
+ default_value='',
+ label=ugettext_lazy('Preamble text for PDF document (all motions)'),
+ weight=375,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('PDF'))
+
+ yield ConfigVariable(
+ name='motions_pdf_paragraph_numbering',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Show paragraph numbering (only in PDF)'),
+ weight=380,
+ group=ugettext_lazy('Motions'),
+ subgroup=ugettext_lazy('PDF'))
diff --git a/openslides/motions/signals.py b/openslides/motions/signals.py
index 782c94e8e..15cc0fa78 100644
--- a/openslides/motions/signals.py
+++ b/openslides/motions/signals.py
@@ -1,179 +1,8 @@
-from django.core.validators import MinValueValidator
-from django.utils.translation import ugettext as _
-from django.utils.translation import pgettext, ugettext_lazy, ugettext_noop
-
-from openslides.core.config import ConfigVariable
-from openslides.poll.models import PERCENT_BASE_CHOICES
+from django.utils.translation import ugettext_noop
from .models import State, Workflow
-def setup_motion_config(sender, **kwargs):
- """
- Receiver function to setup all motion config variables. They are
- grouped in 'General', 'Amendments', 'Supporters', 'Voting and ballot
- papers' and 'PDF'. This function connected to the signal
- openslides.core.signals.config_signal during app loading.
- """
- # General
-
- yield ConfigVariable(
- name='motions_workflow',
- default_value='1',
- input_type='choice',
- label=ugettext_lazy('Workflow of new motions'),
- choices=({'value': str(workflow.pk), 'display_name': ugettext_lazy(workflow.name)} for workflow in Workflow.objects.all()),
- weight=310,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('General'))
-
- yield ConfigVariable(
- name='motions_identifier',
- default_value='per_category',
- input_type='choice',
- label=ugettext_lazy('Identifier'),
- choices=(
- {'value': 'per_category', 'display_name': ugettext_lazy('Numbered per category')},
- {'value': 'serially_numbered', 'display_name': ugettext_lazy('Serially numbered')},
- {'value': 'manually', 'display_name': ugettext_lazy('Set it manually')}),
- weight=315,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('General'))
-
- yield ConfigVariable(
- name='motions_preamble',
- default_value=_('The assembly may decide,'),
- label=ugettext_lazy('Motion preamble'),
- weight=320,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('General'),
- translatable=True)
-
- yield ConfigVariable(
- name='motions_stop_submitting',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Stop submitting new motions by non-staff users'),
- weight=325,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('General'))
-
- yield ConfigVariable(
- name='motions_allow_disable_versioning',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Allow to disable versioning'),
- weight=330,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('General'))
-
- # Amendments
- # Amendments currently not implemented. (TODO: Implement it like in OpenSlides 1.7.)
- yield ConfigVariable(
- name='motions_amendments_enabled',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Activate amendments'),
- hidden=True,
- weight=335,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('Amendments'))
-
- yield ConfigVariable(
- name='motions_amendments_prefix',
- default_value=pgettext('Prefix for the identifier for amendments', 'A'),
- label=ugettext_lazy('Prefix for the identifier for amendments'),
- hidden=True,
- weight=340,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('Amendments'))
-
- # Supporters
-
- yield ConfigVariable(
- name='motions_min_supporters',
- default_value=0,
- input_type='integer',
- label=ugettext_lazy('Number of (minimum) required supporters for a motion'),
- help_text=ugettext_lazy('Choose 0 to disable the supporting system.'),
- weight=345,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('Supporters'),
- validators=(MinValueValidator(0),))
-
- yield ConfigVariable(
- name='motions_remove_supporters',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Remove all supporters of a motion if a submitter edits his motion in early state'),
- weight=350,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('Supporters'))
-
- # Voting and ballot papers
-
- yield ConfigVariable(
- name='motions_poll_100_percent_base',
- default_value='WITHOUT_INVALID',
- input_type='choice',
- label=ugettext_lazy('The 100 % base of a voting result consists of'),
- choices=PERCENT_BASE_CHOICES,
- weight=355,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('Voting and ballot papers'))
-
- yield ConfigVariable(
- name='motions_pdf_ballot_papers_selection',
- default_value='CUSTOM_NUMBER',
- input_type='choice',
- label=ugettext_lazy('Number of ballot papers (selection)'),
- choices=(
- {'value': 'NUMBER_OF_DELEGATES', 'display_name': ugettext_lazy('Number of all delegates')},
- {'value': 'NUMBER_OF_ALL_PARTICIPANTS', 'display_name': ugettext_lazy('Number of all participants')},
- {'value': 'CUSTOM_NUMBER', 'display_name': ugettext_lazy('Use the following custom number')}),
- weight=360,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('Voting and ballot papers'))
-
- yield ConfigVariable(
- name='motions_pdf_ballot_papers_number',
- default_value=8,
- input_type='integer',
- label=ugettext_lazy('Custom number of ballot papers'),
- weight=365,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('Voting and ballot papers'),
- validators=(MinValueValidator(1),))
-
- # PDF
-
- yield ConfigVariable(
- name='motions_pdf_title',
- default_value=_('Motions'),
- label=ugettext_lazy('Title for PDF document (all motions)'),
- weight=370,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('PDF'),
- translatable=True)
-
- yield ConfigVariable(
- name='motions_pdf_preamble',
- default_value='',
- label=ugettext_lazy('Preamble text for PDF document (all motions)'),
- weight=375,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('PDF'))
-
- yield ConfigVariable(
- name='motions_pdf_paragraph_numbering',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Show paragraph numbering (only in PDF)'),
- weight=380,
- group=ugettext_lazy('Motions'),
- subgroup=ugettext_lazy('PDF'))
-
-
def create_builtin_workflows(sender, **kwargs):
"""
Receiver function to create a simple and a complex workflow. It is
diff --git a/openslides/users/apps.py b/openslides/users/apps.py
index 623adc8f0..bbd2663e3 100644
--- a/openslides/users/apps.py
+++ b/openslides/users/apps.py
@@ -14,15 +14,17 @@ class UsersAppConfig(AppConfig):
from . import projector # noqa
# Import all required stuff.
- from ..core.signals import config_signal, post_permission_creation
+ from ..core.config import config
+ from ..core.signals import post_permission_creation
from ..utils.rest_api import router
- from .signals import create_builtin_groups_and_admin, setup_users_config
+ from .config_variables import get_config_variables
+ from .signals import create_builtin_groups_and_admin
from .views import GroupViewSet, UserViewSet
+ # Define config variables
+ config.update_config_varialbes(get_config_variables())
+
# Connect signals.
- config_signal.connect(
- setup_users_config,
- dispatch_uid='setup_users_config')
post_permission_creation.connect(
create_builtin_groups_and_admin,
dispatch_uid='create_builtin_groups_and_admin')
diff --git a/openslides/users/config_variables.py b/openslides/users/config_variables.py
new file mode 100644
index 000000000..171f313a7
--- /dev/null
+++ b/openslides/users/config_variables.py
@@ -0,0 +1,86 @@
+from django.utils.translation import ugettext as _
+from django.utils.translation import ugettext_lazy
+
+from openslides.core.config import ConfigVariable
+
+
+def get_config_variables():
+ """
+ Generator which yields all config variables of this app.
+
+ They are grouped in 'Sorting' and 'PDF'. The generator has to be evaluated
+ during app loading (see apps.py).
+ """
+ # Sorting
+ yield ConfigVariable(
+ name='users_sort_users_by_first_name',
+ default_value=False,
+ input_type='boolean',
+ label=ugettext_lazy('Sort users by first name'),
+ help_text=ugettext_lazy('Disable for sorting by last name'),
+ weight=510,
+ group=ugettext_lazy('Users'),
+ subgroup=ugettext_lazy('Sorting'))
+
+ # PDF
+
+ yield ConfigVariable(
+ name='users_pdf_welcometitle',
+ default_value=_('Welcome to OpenSlides!'),
+ label=ugettext_lazy('Title for access data and welcome PDF'),
+ weight=520,
+ group=ugettext_lazy('Users'),
+ subgroup=ugettext_lazy('PDF'),
+ translatable=True)
+
+ yield ConfigVariable(
+ name='users_pdf_welcometext',
+ default_value=_('[Place for your welcome and help text.]'),
+ label=ugettext_lazy('Help text for access data and welcome PDF'),
+ weight=530,
+ group=ugettext_lazy('Users'),
+ subgroup=ugettext_lazy('PDF'),
+ translatable=True)
+
+ # TODO: Use Django's URLValidator here.
+ yield ConfigVariable(
+ name='users_pdf_url',
+ default_value='http://example.com:8000',
+ label=ugettext_lazy('System URL'),
+ help_text=ugettext_lazy('Used for QRCode in PDF of access data.'),
+ weight=540,
+ group=ugettext_lazy('Users'),
+ subgroup=ugettext_lazy('PDF'))
+
+ yield ConfigVariable(
+ name='users_pdf_wlan_ssid',
+ default_value='',
+ label=ugettext_lazy('WLAN name (SSID)'),
+ help_text=ugettext_lazy('Used for WLAN QRCode in PDF of access data.'),
+ weight=550,
+ group=ugettext_lazy('Users'),
+ subgroup=ugettext_lazy('PDF'))
+
+ yield ConfigVariable(
+ name='users_pdf_wlan_password',
+ default_value='',
+ label=ugettext_lazy('WLAN password'),
+ help_text=ugettext_lazy('Used for WLAN QRCode in PDF of access data.'),
+ weight=560,
+ group=ugettext_lazy('Users'),
+ subgroup=ugettext_lazy('PDF'))
+
+ yield ConfigVariable(
+ name='users_pdf_wlan_encryption',
+ default_value='',
+ input_type='choice',
+ label=ugettext_lazy('WLAN encryption'),
+ help_text=ugettext_lazy('Used for WLAN QRCode in PDF of access data.'),
+ choices=(
+ {'value': '', 'display_name': '---------'},
+ {'value': 'WEP', 'display_name': ugettext_lazy('WEP')},
+ {'value': 'WPA', 'display_name': ugettext_lazy('WPA/WPA2')},
+ {'value': 'nopass', 'display_name': ugettext_lazy('No encryption')}),
+ weight=570,
+ group=ugettext_lazy('Users'),
+ subgroup=ugettext_lazy('PDF'))
diff --git a/openslides/users/signals.py b/openslides/users/signals.py
index 34bd75ad5..8192fa28e 100644
--- a/openslides/users/signals.py
+++ b/openslides/users/signals.py
@@ -1,95 +1,9 @@
from django.contrib.auth.models import Permission
from django.db.models import Q
-from django.utils.translation import ugettext as _
-from django.utils.translation import ugettext_lazy
-from ..core.config import ConfigVariable
from .models import Group, User
-def setup_users_config(sender, **kwargs):
- """
- Receiver function to setup all users config variables. They are grouped
- in 'Sorting' and 'PDF'. This function is connected to the signal
- openslides.core.signals.config_signal during app loading.
- """
-
- # Sorting
-
- yield ConfigVariable(
- name='users_sort_users_by_first_name',
- default_value=False,
- input_type='boolean',
- label=ugettext_lazy('Sort users by first name'),
- help_text=ugettext_lazy('Disable for sorting by last name'),
- weight=510,
- group=ugettext_lazy('Users'),
- subgroup=ugettext_lazy('Sorting'))
-
- # PDF
-
- yield ConfigVariable(
- name='users_pdf_welcometitle',
- default_value=_('Welcome to OpenSlides!'),
- label=ugettext_lazy('Title for access data and welcome PDF'),
- weight=520,
- group=ugettext_lazy('Users'),
- subgroup=ugettext_lazy('PDF'),
- translatable=True)
-
- yield ConfigVariable(
- name='users_pdf_welcometext',
- default_value=_('[Place for your welcome and help text.]'),
- label=ugettext_lazy('Help text for access data and welcome PDF'),
- weight=530,
- group=ugettext_lazy('Users'),
- subgroup=ugettext_lazy('PDF'),
- translatable=True)
-
- # TODO: Use Django's URLValidator here.
- yield ConfigVariable(
- name='users_pdf_url',
- default_value='http://example.com:8000',
- label=ugettext_lazy('System URL'),
- help_text=ugettext_lazy('Used for QRCode in PDF of access data.'),
- weight=540,
- group=ugettext_lazy('Users'),
- subgroup=ugettext_lazy('PDF'))
-
- yield ConfigVariable(
- name='users_pdf_wlan_ssid',
- default_value='',
- label=ugettext_lazy('WLAN name (SSID)'),
- help_text=ugettext_lazy('Used for WLAN QRCode in PDF of access data.'),
- weight=550,
- group=ugettext_lazy('Users'),
- subgroup=ugettext_lazy('PDF'))
-
- yield ConfigVariable(
- name='users_pdf_wlan_password',
- default_value='',
- label=ugettext_lazy('WLAN password'),
- help_text=ugettext_lazy('Used for WLAN QRCode in PDF of access data.'),
- weight=560,
- group=ugettext_lazy('Users'),
- subgroup=ugettext_lazy('PDF'))
-
- yield ConfigVariable(
- name='users_pdf_wlan_encryption',
- default_value='',
- input_type='choice',
- label=ugettext_lazy('WLAN encryption'),
- help_text=ugettext_lazy('Used for WLAN QRCode in PDF of access data.'),
- choices=(
- {'value': '', 'display_name': '---------'},
- {'value': 'WEP', 'display_name': ugettext_lazy('WEP')},
- {'value': 'WPA', 'display_name': ugettext_lazy('WPA/WPA2')},
- {'value': 'nopass', 'display_name': ugettext_lazy('No encryption')}),
- weight=570,
- group=ugettext_lazy('Users'),
- subgroup=ugettext_lazy('PDF'))
-
-
def create_builtin_groups_and_admin(**kwargs):
"""
Creates the builtin groups: Anonymous, Registered, Delegates and Staff.
diff --git a/openslides/utils/test.py b/openslides/utils/test.py
index 75cb0b9ff..c9f90c6de 100644
--- a/openslides/utils/test.py
+++ b/openslides/utils/test.py
@@ -1,8 +1,6 @@
from django.test import TestCase as _TestCase
from django.test.runner import DiscoverRunner
-from openslides.core.config import config
-
class OpenSlidesDiscoverRunner(DiscoverRunner):
def run_tests(self, test_labels, extra_tests=None, **kwargs):
@@ -28,15 +26,8 @@ class OpenSlidesDiscoverRunner(DiscoverRunner):
class TestCase(_TestCase):
"""
- Overwrites Django's TestCase class to refreshs the config cache.
- """
+ Does nothing at the moment.
- def _post_teardown(self, *args, **kwargs):
- return_value = super(TestCase, self)._post_teardown(*args, **kwargs)
- # Resets the config object by deleting the cache
- try:
- del config._cache
- except AttributeError:
- # The cache has only to be deleted if it exists.
- pass
- return return_value
+ Could be used in the future. Use this this for the integration test suit.
+ """
+ pass
diff --git a/tests/integration/core/test_views.py b/tests/integration/core/test_views.py
index 7545f2bac..31143ca9a 100644
--- a/tests/integration/core/test_views.py
+++ b/tests/integration/core/test_views.py
@@ -1,17 +1,18 @@
import json
+from unittest.mock import patch
from django.core.urlresolvers import reverse
-from django.dispatch import receiver
from rest_framework import status
from rest_framework.test import APIClient
from openslides import __version__ as version
-from openslides.core.config import ConfigVariable, config
+from openslides.core.config import ConfigHandler, ConfigVariable
from openslides.core.models import CustomSlide, Projector
-from openslides.core.signals import config_signal
from openslides.utils.rest_api import ValidationError
from openslides.utils.test import TestCase
+config = ConfigHandler()
+
class ProjectorAPI(TestCase):
"""
@@ -74,10 +75,19 @@ class VersionView(TestCase):
'version': 'unknown'}]})
+@patch('openslides.core.config.config', config)
+@patch('openslides.core.views.config', config)
class ConfigViewSet(TestCase):
"""
Tests requests to deal with config variables.
"""
+ def setUp(self):
+ config.update_config_varialbes(set_simple_config_view_integration_config_test())
+
+ def tearDown(self):
+ # Reset the config variables
+ config.config_variables = {}
+
def test_retrieve(self):
self.client.login(username='admin', password='admin')
config['test_var_aeW3Quahkah1phahCheo'] = 'test_value_Oovoojieme7eephaed2A'
@@ -178,8 +188,7 @@ def validator_for_testing(value):
raise ValidationError({'detail': 'Invalid input.'})
-@receiver(config_signal, dispatch_uid='set_simple_config_view_integration_config_test')
-def set_simple_config_view_integration_config_test(sender, **kwargs):
+def set_simple_config_view_integration_config_test():
"""
Sets a simple config view with some config variables but without
grouping.
diff --git a/tests/integration/motions/test_viewset.py b/tests/integration/motions/test_viewset.py
index 32399ca7c..96465bdc3 100644
--- a/tests/integration/motions/test_viewset.py
+++ b/tests/integration/motions/test_viewset.py
@@ -150,7 +150,7 @@ class RetrieveMotion(TestCase):
self.motion.create_poll()
def test_number_of_queries(self):
- with self.assertNumQueries(17):
+ with self.assertNumQueries(16):
self.client.get(reverse('motion-detail', args=[self.motion.pk]))
diff --git a/tests/old/config/test_config.py b/tests/old/config/test_config.py
index 2ba3b33c8..ed4c11a53 100644
--- a/tests/old/config/test_config.py
+++ b/tests/old/config/test_config.py
@@ -1,12 +1,28 @@
-from django.dispatch import receiver
+from unittest.mock import patch
-from openslides.core.config import ConfigVariable, config
+from openslides.core.config import ConfigHandler, ConfigVariable
from openslides.core.exceptions import ConfigError, ConfigNotFound
-from openslides.core.signals import config_signal
from openslides.utils.test import TestCase
+class TestConfigException(Exception):
+ pass
+
+config = ConfigHandler()
+
+
+@patch('openslides.core.config.config', config)
class HandleConfigTest(TestCase):
+ def setUp(self):
+ config.update_config_varialbes(set_grouped_config_view())
+ config.update_config_varialbes(set_simple_config_view())
+ config.update_config_varialbes(set_simple_config_view_multiple_vars())
+ config.update_config_varialbes(set_simple_config_collection_disabled_view())
+ config.update_config_varialbes(set_simple_config_collection_with_callback())
+
+ def tearDown(self):
+ # Reset the config variables
+ config.config_variables = {}
def get_config_var(self, key):
return config[key]
@@ -26,24 +42,10 @@ class HandleConfigTest(TestCase):
self.get_config_var('unknown_config_var')
def test_get_multiple_config_var_error(self):
- config_signal.connect(
- set_simple_config_view_multiple_vars,
- dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
-
with self.assertRaisesMessage(
ConfigError,
'Too many values for config variable multiple_config_var found.'):
- config.setup_cache()
- config_signal.disconnect(
- set_simple_config_view_multiple_vars,
- dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
-
- def test_database_queries(self):
- """
- Test that no database queries are send, after the cache was created.
- """
- config.setup_cache()
- self.assertNumQueries(0, self.get_config_var, key='string_var')
+ config.update_config_varialbes(set_simple_config_view_multiple_vars())
def test_setup_config_var(self):
self.assertRaises(TypeError, ConfigVariable)
@@ -73,9 +75,8 @@ class HandleConfigTest(TestCase):
Tests that the special callback is called and raises a special
message.
"""
- # TODO: use right exception
with self.assertRaisesMessage(
- Exception,
+ TestConfigException,
'Change callback dhcnfg34dlg06kdg successfully called.'):
self.set_config_var(
key='var_with_callback_ghvnfjd5768gdfkwg0hm2',
@@ -86,8 +87,7 @@ class HandleConfigTest(TestCase):
'new_string_kbmbnfhdgibkdjshg452bc')
-@receiver(config_signal, dispatch_uid='set_grouped_config_view_for_testing')
-def set_grouped_config_view(sender, **kwargs):
+def set_grouped_config_view():
"""
Sets a grouped config collection. There are some variables, one variable
with a string as default value, one with a boolean as default value,
@@ -128,8 +128,7 @@ def set_grouped_config_view(sender, **kwargs):
subgroup='Group 2 Toongai7ahyahy7B')
-@receiver(config_signal, dispatch_uid='set_simple_config_view_for_testing')
-def set_simple_config_view(sender, **kwargs):
+def set_simple_config_view():
"""
Sets a simple config view with some config variables but without
grouping.
@@ -139,8 +138,7 @@ def set_simple_config_view(sender, **kwargs):
yield ConfigVariable(name='none_config_var', default_value=None)
-# Do not connect to the signal now but later inside the test.
-def set_simple_config_view_multiple_vars(sender, **kwargs):
+def set_simple_config_view_multiple_vars():
"""
Sets a bad config view with some multiple config vars.
"""
@@ -148,15 +146,13 @@ def set_simple_config_view_multiple_vars(sender, **kwargs):
yield ConfigVariable(name='multiple_config_var', default_value='foobar2')
-@receiver(config_signal, dispatch_uid='set_simple_config_collection_disabled_view_for_testing')
-def set_simple_config_collection_disabled_view(sender, **kwargs):
+def set_simple_config_collection_disabled_view():
yield ConfigVariable(name='hidden_config_var_2', default_value='')
-@receiver(config_signal, dispatch_uid='set_simple_config_collection_with_callback_for_testing')
-def set_simple_config_collection_with_callback(sender, **kwargs):
+def set_simple_config_collection_with_callback():
def callback():
- raise Exception('Change callback dhcnfg34dlg06kdg successfully called.')
+ raise TestConfigException('Change callback dhcnfg34dlg06kdg successfully called.')
yield ConfigVariable(
name='var_with_callback_ghvnfjd5768gdfkwg0hm2',
default_value='',
diff --git a/tests/unit/config/test_api.py b/tests/unit/config/test_api.py
index ef061efa2..d059401bc 100644
--- a/tests/unit/config/test_api.py
+++ b/tests/unit/config/test_api.py
@@ -1,7 +1,7 @@
from unittest import TestCase
from unittest.mock import patch
-from openslides.core.config import ConfigHandler, ConfigVariable, config
+from openslides.core.config import ConfigVariable, config
from openslides.core.exceptions import ConfigNotFound
@@ -26,12 +26,7 @@ class TestConfigVariable(TestCase):
class TestConfigHandler(TestCase):
- def test_get_from_cache(self):
- ConfigHandler._cache = {'key_eeshah4Sho6zailee4ko': 'value_chies7aCohZoo9umieph'}
- self.assertEqual(config['key_eeshah4Sho6zailee4ko'], 'value_chies7aCohZoo9umieph')
-
def test_get_not_found(self):
- ConfigHandler._cache = {}
self.assertRaises(
ConfigNotFound,
config.__getitem__,