Merge pull request #2175 from ostcar/config
Redesign of the config variables.
This commit is contained in:
commit
f2570551a1
@ -8,6 +8,9 @@ Version 2.0.1 (unreleased)
|
|||||||
==========================
|
==========================
|
||||||
[https://github.com/OpenSlides/OpenSlides/milestones/2.0.1]
|
[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)
|
Version 2.0 (2016-04-18)
|
||||||
========================
|
========================
|
||||||
|
@ -15,16 +15,18 @@ class AgendaAppConfig(AppConfig):
|
|||||||
|
|
||||||
# Import all required stuff.
|
# Import all required stuff.
|
||||||
from django.db.models.signals import pre_delete, post_save
|
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 openslides.utils.rest_api import router
|
||||||
|
from .config_variables import get_config_variables
|
||||||
from .signals import (
|
from .signals import (
|
||||||
setup_agenda_config,
|
|
||||||
listen_to_related_object_post_delete,
|
listen_to_related_object_post_delete,
|
||||||
listen_to_related_object_post_save)
|
listen_to_related_object_post_save)
|
||||||
from .views import ItemViewSet
|
from .views import ItemViewSet
|
||||||
|
|
||||||
|
# Define config varialbes
|
||||||
|
config.update_config_varialbes(get_config_variables())
|
||||||
|
|
||||||
# Connect signals.
|
# Connect signals.
|
||||||
config_signal.connect(setup_agenda_config, dispatch_uid='setup_agenda_config')
|
|
||||||
post_save.connect(
|
post_save.connect(
|
||||||
listen_to_related_object_post_save,
|
listen_to_related_object_post_save,
|
||||||
dispatch_uid='listen_to_related_object_post_save')
|
dispatch_uid='listen_to_related_object_post_save')
|
||||||
|
88
openslides/agenda/config_variables.py
Normal file
88
openslides/agenda/config_variables.py
Normal file
@ -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'))
|
@ -1,97 +1,10 @@
|
|||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
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 openslides.utils.autoupdate import inform_changed_data
|
||||||
|
|
||||||
from .models import Item
|
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):
|
def listen_to_related_object_post_save(sender, instance, created, **kwargs):
|
||||||
"""
|
"""
|
||||||
Receiver function to create agenda items. It is connected to the signal
|
Receiver function to create agenda items. It is connected to the signal
|
||||||
|
@ -14,13 +14,13 @@ class AssignmentsAppConfig(AppConfig):
|
|||||||
from . import projector # noqa
|
from . import projector # noqa
|
||||||
|
|
||||||
# Import all required stuff.
|
# 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 openslides.utils.rest_api import router
|
||||||
from .signals import setup_assignment_config
|
from .config_variables import get_config_variables
|
||||||
from .views import AssignmentViewSet, AssignmentPollViewSet
|
from .views import AssignmentViewSet, AssignmentPollViewSet
|
||||||
|
|
||||||
# Connect signals.
|
# Define config variables
|
||||||
config_signal.connect(setup_assignment_config, dispatch_uid='setup_assignment_config')
|
config.update_config_varialbes(get_config_variables())
|
||||||
|
|
||||||
# Register viewsets.
|
# Register viewsets.
|
||||||
router.register(self.get_model('Assignment').get_collection_string(), AssignmentViewSet)
|
router.register(self.get_model('Assignment').get_collection_string(), AssignmentViewSet)
|
||||||
|
@ -6,15 +6,14 @@ from openslides.core.config import ConfigVariable
|
|||||||
from openslides.poll.models import PERCENT_BASE_CHOICES
|
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
|
Generator which yields all config variables of this app.
|
||||||
grouped in 'Ballot and ballot papers' and 'PDF'. This function is
|
|
||||||
connected to the signal openslides.core.signals.config_signal during
|
They are grouped in 'Ballot and ballot papers' and 'PDF'. The generator has
|
||||||
app loading.
|
to be evaluated during app loading (see apps.py).
|
||||||
"""
|
"""
|
||||||
# Ballot and ballot papers
|
# Ballot and ballot papers
|
||||||
|
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
name='assignments_poll_vote_values',
|
name='assignments_poll_vote_values',
|
||||||
default_value='auto',
|
default_value='auto',
|
@ -15,11 +15,13 @@ class CoreAppConfig(AppConfig):
|
|||||||
|
|
||||||
# Import all required stuff.
|
# Import all required stuff.
|
||||||
from django.db.models import signals
|
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.autoupdate import inform_changed_data_receiver, inform_deleted_data_receiver
|
||||||
from openslides.utils.rest_api import router
|
from openslides.utils.rest_api import router
|
||||||
from openslides.utils.search import index_add_instance, index_del_instance
|
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 (
|
from .views import (
|
||||||
ChatMessageViewSet,
|
ChatMessageViewSet,
|
||||||
ConfigViewSet,
|
ConfigViewSet,
|
||||||
@ -28,10 +30,10 @@ class CoreAppConfig(AppConfig):
|
|||||||
TagViewSet,
|
TagViewSet,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Define config variables
|
||||||
|
config.update_config_varialbes(get_config_variables())
|
||||||
|
|
||||||
# Connect signals.
|
# Connect signals.
|
||||||
config_signal.connect(
|
|
||||||
setup_general_config,
|
|
||||||
dispatch_uid='setup_general_config')
|
|
||||||
post_permission_creation.connect(
|
post_permission_creation.connect(
|
||||||
delete_django_app_permissions,
|
delete_django_app_permissions,
|
||||||
dispatch_uid='delete_django_app_permissions')
|
dispatch_uid='delete_django_app_permissions')
|
||||||
|
@ -19,33 +19,35 @@ class ConfigHandler:
|
|||||||
object. To get a config variable use x = config[...], to set it use
|
object. To get a config variable use x = config[...], to set it use
|
||||||
config[...] = x.
|
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):
|
def __getitem__(self, key):
|
||||||
"""
|
"""
|
||||||
Returns the value of the config variable. Builds the cache if it
|
Returns the value of the config variable. Returns the default value, if
|
||||||
does not exist.
|
not value exists in the database.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self._cache[key]
|
default_value = self.config_variables[key].default_value
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ConfigNotFound(_('The config variable %s was not found.') % key)
|
raise ConfigNotFound(_('The config variable {} was not found.').format(key))
|
||||||
except AttributeError:
|
|
||||||
self.setup_cache()
|
|
||||||
return self[key]
|
|
||||||
|
|
||||||
def setup_cache(self):
|
try:
|
||||||
"""
|
db_value = ConfigStore.objects.get(key=key)
|
||||||
Creates a cache of all config variables with their current value.
|
except ConfigStore.DoesNotExist:
|
||||||
"""
|
return default_value
|
||||||
self._cache = {}
|
return db_value.value
|
||||||
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
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
|
"""
|
||||||
|
Returns True, if the config varialbe exists.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
config[key]
|
self.config_variables[key]
|
||||||
except ConfigNotFound:
|
except KeyError:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
@ -56,9 +58,9 @@ class ConfigHandler:
|
|||||||
"""
|
"""
|
||||||
# Check if the variable is defined.
|
# Check if the variable is defined.
|
||||||
try:
|
try:
|
||||||
config_variable = config.get_config_variables()[key]
|
config_variable = self.config_variables[key]
|
||||||
except KeyError:
|
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.
|
# Validate datatype and run validators.
|
||||||
expected_type = INPUT_TYPE_MAPPING[config_variable.input_type]
|
expected_type = INPUT_TYPE_MAPPING[config_variable.input_type]
|
||||||
@ -69,7 +71,14 @@ class ConfigHandler:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
raise ConfigError(_('Wrong datatype. Expected %(expected_type)s, got %(got_type)s.') % {
|
raise ConfigError(_('Wrong datatype. Expected %(expected_type)s, got %(got_type)s.') % {
|
||||||
'expected_type': expected_type, 'got_type': type(value)})
|
'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):
|
|
||||||
|
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.'))
|
raise ConfigError(_('Invalid input. Choice does not match.'))
|
||||||
for validator in config_variable.validators:
|
for validator in config_variable.validators:
|
||||||
try:
|
try:
|
||||||
@ -78,50 +87,45 @@ class ConfigHandler:
|
|||||||
raise ConfigError(e.messages[0])
|
raise ConfigError(e.messages[0])
|
||||||
|
|
||||||
# Save the new value to the database.
|
# Save the new value to the database.
|
||||||
config_store, created = ConfigStore.objects.get_or_create(key=key, defaults={'value': value})
|
ConfigStore.objects.update_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
|
|
||||||
|
|
||||||
# Call on_change callback.
|
# Call on_change callback.
|
||||||
if config_variable.on_change:
|
if config_variable.on_change:
|
||||||
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):
|
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'):
|
# Create a dict with the default values of each ConfigVariable
|
||||||
self.setup_cache()
|
config_items = dict((key, variable.default_value) for key, variable in self.config_variables.items())
|
||||||
return self._cache.items()
|
|
||||||
|
|
||||||
def get_config_variables(self):
|
# Update the dict with all values, which are in the db
|
||||||
"""
|
for db_value in ConfigStore.objects.all():
|
||||||
Returns a dictionary with all ConfigVariable instances of all
|
config_items[db_value.key] = db_value.value
|
||||||
signal receivers. The key is the name of the config variable.
|
return config_items.items()
|
||||||
"""
|
|
||||||
# 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
|
|
||||||
|
|
||||||
def get_all_translatable(self):
|
def get_all_translatable(self):
|
||||||
"""
|
"""
|
||||||
Generator to get all config variables as strings when their values are
|
Generator to get all config variables as strings when their values are
|
||||||
intended to be translated.
|
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:
|
if config_variable.translatable:
|
||||||
yield config_variable.name
|
yield config_variable.name
|
||||||
|
|
||||||
|
160
openslides/core/config_variables.py
Normal file
160
openslides/core/config_variables.py
Normal file
@ -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=_(
|
||||||
|
'<a href="http://www.openslides.org">OpenSlides</a> 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'))
|
@ -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()
|
|
@ -1,12 +1,7 @@
|
|||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.validators import MaxLengthValidator
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.dispatch import Signal
|
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
|
# 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
|
# 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'))
|
Q(app_label='sessions'))
|
||||||
for permission in Permission.objects.filter(content_type__in=contenttypes):
|
for permission in Permission.objects.filter(content_type__in=contenttypes):
|
||||||
permission.delete()
|
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=_(
|
|
||||||
'<a href="http://www.openslides.org">OpenSlides</a> 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."""
|
|
||||||
|
@ -415,12 +415,9 @@ class ConfigMetadata(SimpleMetadata):
|
|||||||
Custom metadata class to add config info to responses on OPTIONS requests.
|
Custom metadata class to add config info to responses on OPTIONS requests.
|
||||||
"""
|
"""
|
||||||
def determine_metadata(self, request, view):
|
def determine_metadata(self, request, view):
|
||||||
# Sort config variables by weight.
|
|
||||||
config_variables = sorted(config.get_config_variables().values(), key=attrgetter('weight'))
|
|
||||||
|
|
||||||
# Build tree.
|
# Build tree.
|
||||||
config_groups = []
|
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():
|
if config_variable.is_hidden():
|
||||||
# Skip hidden config variables. Do not even check groups and subgroups.
|
# Skip hidden config variables. Do not even check groups and subgroups.
|
||||||
continue
|
continue
|
||||||
|
@ -60,7 +60,6 @@ MIDDLEWARE_CLASSES = (
|
|||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'openslides.users.auth.AuthenticationMiddleware',
|
'openslides.users.auth.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'openslides.core.middleware.ConfigCacheMiddleware',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ROOT_URLCONF = 'openslides.urls'
|
ROOT_URLCONF = 'openslides.urls'
|
||||||
|
@ -15,13 +15,16 @@ class MotionsAppConfig(AppConfig):
|
|||||||
from . import projector # noqa
|
from . import projector # noqa
|
||||||
|
|
||||||
# Import all required stuff.
|
# 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 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
|
from .views import CategoryViewSet, MotionViewSet, MotionPollViewSet, WorkflowViewSet
|
||||||
|
|
||||||
|
# Define config varialbes
|
||||||
|
config.update_config_varialbes(get_config_variables())
|
||||||
|
|
||||||
# Connect signals.
|
# 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')
|
post_migrate.connect(create_builtin_workflows, dispatch_uid='motion_create_builtin_workflows')
|
||||||
|
|
||||||
# Register viewsets.
|
# Register viewsets.
|
||||||
|
183
openslides/motions/config_variables.py
Normal file
183
openslides/motions/config_variables.py
Normal file
@ -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'))
|
@ -1,179 +1,8 @@
|
|||||||
from django.core.validators import MinValueValidator
|
from django.utils.translation import ugettext_noop
|
||||||
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 .models import State, Workflow
|
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):
|
def create_builtin_workflows(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Receiver function to create a simple and a complex workflow. It is
|
Receiver function to create a simple and a complex workflow. It is
|
||||||
|
@ -14,15 +14,17 @@ class UsersAppConfig(AppConfig):
|
|||||||
from . import projector # noqa
|
from . import projector # noqa
|
||||||
|
|
||||||
# Import all required stuff.
|
# 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 ..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
|
from .views import GroupViewSet, UserViewSet
|
||||||
|
|
||||||
|
# Define config variables
|
||||||
|
config.update_config_varialbes(get_config_variables())
|
||||||
|
|
||||||
# Connect signals.
|
# Connect signals.
|
||||||
config_signal.connect(
|
|
||||||
setup_users_config,
|
|
||||||
dispatch_uid='setup_users_config')
|
|
||||||
post_permission_creation.connect(
|
post_permission_creation.connect(
|
||||||
create_builtin_groups_and_admin,
|
create_builtin_groups_and_admin,
|
||||||
dispatch_uid='create_builtin_groups_and_admin')
|
dispatch_uid='create_builtin_groups_and_admin')
|
||||||
|
86
openslides/users/config_variables.py
Normal file
86
openslides/users/config_variables.py
Normal file
@ -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'))
|
@ -1,95 +1,9 @@
|
|||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
from django.db.models import Q
|
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
|
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):
|
def create_builtin_groups_and_admin(**kwargs):
|
||||||
"""
|
"""
|
||||||
Creates the builtin groups: Anonymous, Registered, Delegates and Staff.
|
Creates the builtin groups: Anonymous, Registered, Delegates and Staff.
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
from django.test import TestCase as _TestCase
|
from django.test import TestCase as _TestCase
|
||||||
from django.test.runner import DiscoverRunner
|
from django.test.runner import DiscoverRunner
|
||||||
|
|
||||||
from openslides.core.config import config
|
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesDiscoverRunner(DiscoverRunner):
|
class OpenSlidesDiscoverRunner(DiscoverRunner):
|
||||||
def run_tests(self, test_labels, extra_tests=None, **kwargs):
|
def run_tests(self, test_labels, extra_tests=None, **kwargs):
|
||||||
@ -28,15 +26,8 @@ class OpenSlidesDiscoverRunner(DiscoverRunner):
|
|||||||
|
|
||||||
class TestCase(_TestCase):
|
class TestCase(_TestCase):
|
||||||
"""
|
"""
|
||||||
Overwrites Django's TestCase class to refreshs the config cache.
|
Does nothing at the moment.
|
||||||
"""
|
|
||||||
|
|
||||||
def _post_teardown(self, *args, **kwargs):
|
Could be used in the future. Use this this for the integration test suit.
|
||||||
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
|
pass
|
||||||
return return_value
|
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
import json
|
import json
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.dispatch import receiver
|
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.test import APIClient
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
from openslides import __version__ as version
|
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.models import CustomSlide, Projector
|
||||||
from openslides.core.signals import config_signal
|
|
||||||
from openslides.utils.rest_api import ValidationError
|
from openslides.utils.rest_api import ValidationError
|
||||||
from openslides.utils.test import TestCase
|
from openslides.utils.test import TestCase
|
||||||
|
|
||||||
|
config = ConfigHandler()
|
||||||
|
|
||||||
|
|
||||||
class ProjectorAPI(TestCase):
|
class ProjectorAPI(TestCase):
|
||||||
"""
|
"""
|
||||||
@ -74,10 +75,19 @@ class VersionView(TestCase):
|
|||||||
'version': 'unknown'}]})
|
'version': 'unknown'}]})
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openslides.core.config.config', config)
|
||||||
|
@patch('openslides.core.views.config', config)
|
||||||
class ConfigViewSet(TestCase):
|
class ConfigViewSet(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests requests to deal with config variables.
|
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):
|
def test_retrieve(self):
|
||||||
self.client.login(username='admin', password='admin')
|
self.client.login(username='admin', password='admin')
|
||||||
config['test_var_aeW3Quahkah1phahCheo'] = 'test_value_Oovoojieme7eephaed2A'
|
config['test_var_aeW3Quahkah1phahCheo'] = 'test_value_Oovoojieme7eephaed2A'
|
||||||
@ -178,8 +188,7 @@ def validator_for_testing(value):
|
|||||||
raise ValidationError({'detail': 'Invalid input.'})
|
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():
|
||||||
def set_simple_config_view_integration_config_test(sender, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Sets a simple config view with some config variables but without
|
Sets a simple config view with some config variables but without
|
||||||
grouping.
|
grouping.
|
||||||
|
@ -150,7 +150,7 @@ class RetrieveMotion(TestCase):
|
|||||||
self.motion.create_poll()
|
self.motion.create_poll()
|
||||||
|
|
||||||
def test_number_of_queries(self):
|
def test_number_of_queries(self):
|
||||||
with self.assertNumQueries(17):
|
with self.assertNumQueries(16):
|
||||||
self.client.get(reverse('motion-detail', args=[self.motion.pk]))
|
self.client.get(reverse('motion-detail', args=[self.motion.pk]))
|
||||||
|
|
||||||
|
|
||||||
|
@ -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.exceptions import ConfigError, ConfigNotFound
|
||||||
from openslides.core.signals import config_signal
|
|
||||||
from openslides.utils.test import TestCase
|
from openslides.utils.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class TestConfigException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
config = ConfigHandler()
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openslides.core.config.config', config)
|
||||||
class HandleConfigTest(TestCase):
|
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):
|
def get_config_var(self, key):
|
||||||
return config[key]
|
return config[key]
|
||||||
@ -26,24 +42,10 @@ class HandleConfigTest(TestCase):
|
|||||||
self.get_config_var('unknown_config_var')
|
self.get_config_var('unknown_config_var')
|
||||||
|
|
||||||
def test_get_multiple_config_var_error(self):
|
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(
|
with self.assertRaisesMessage(
|
||||||
ConfigError,
|
ConfigError,
|
||||||
'Too many values for config variable multiple_config_var found.'):
|
'Too many values for config variable multiple_config_var found.'):
|
||||||
config.setup_cache()
|
config.update_config_varialbes(set_simple_config_view_multiple_vars())
|
||||||
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')
|
|
||||||
|
|
||||||
def test_setup_config_var(self):
|
def test_setup_config_var(self):
|
||||||
self.assertRaises(TypeError, ConfigVariable)
|
self.assertRaises(TypeError, ConfigVariable)
|
||||||
@ -73,9 +75,8 @@ class HandleConfigTest(TestCase):
|
|||||||
Tests that the special callback is called and raises a special
|
Tests that the special callback is called and raises a special
|
||||||
message.
|
message.
|
||||||
"""
|
"""
|
||||||
# TODO: use right exception
|
|
||||||
with self.assertRaisesMessage(
|
with self.assertRaisesMessage(
|
||||||
Exception,
|
TestConfigException,
|
||||||
'Change callback dhcnfg34dlg06kdg successfully called.'):
|
'Change callback dhcnfg34dlg06kdg successfully called.'):
|
||||||
self.set_config_var(
|
self.set_config_var(
|
||||||
key='var_with_callback_ghvnfjd5768gdfkwg0hm2',
|
key='var_with_callback_ghvnfjd5768gdfkwg0hm2',
|
||||||
@ -86,8 +87,7 @@ class HandleConfigTest(TestCase):
|
|||||||
'new_string_kbmbnfhdgibkdjshg452bc')
|
'new_string_kbmbnfhdgibkdjshg452bc')
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='set_grouped_config_view_for_testing')
|
def set_grouped_config_view():
|
||||||
def set_grouped_config_view(sender, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Sets a grouped config collection. There are some variables, one variable
|
Sets a grouped config collection. There are some variables, one variable
|
||||||
with a string as default value, one with a boolean as default value,
|
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')
|
subgroup='Group 2 Toongai7ahyahy7B')
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='set_simple_config_view_for_testing')
|
def set_simple_config_view():
|
||||||
def set_simple_config_view(sender, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Sets a simple config view with some config variables but without
|
Sets a simple config view with some config variables but without
|
||||||
grouping.
|
grouping.
|
||||||
@ -139,8 +138,7 @@ def set_simple_config_view(sender, **kwargs):
|
|||||||
yield ConfigVariable(name='none_config_var', default_value=None)
|
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():
|
||||||
def set_simple_config_view_multiple_vars(sender, **kwargs):
|
|
||||||
"""
|
"""
|
||||||
Sets a bad config view with some multiple config 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')
|
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():
|
||||||
def set_simple_config_collection_disabled_view(sender, **kwargs):
|
|
||||||
yield ConfigVariable(name='hidden_config_var_2', default_value='')
|
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():
|
||||||
def set_simple_config_collection_with_callback(sender, **kwargs):
|
|
||||||
def callback():
|
def callback():
|
||||||
raise Exception('Change callback dhcnfg34dlg06kdg successfully called.')
|
raise TestConfigException('Change callback dhcnfg34dlg06kdg successfully called.')
|
||||||
yield ConfigVariable(
|
yield ConfigVariable(
|
||||||
name='var_with_callback_ghvnfjd5768gdfkwg0hm2',
|
name='var_with_callback_ghvnfjd5768gdfkwg0hm2',
|
||||||
default_value='',
|
default_value='',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch
|
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
|
from openslides.core.exceptions import ConfigNotFound
|
||||||
|
|
||||||
|
|
||||||
@ -26,12 +26,7 @@ class TestConfigVariable(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestConfigHandler(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):
|
def test_get_not_found(self):
|
||||||
ConfigHandler._cache = {}
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
ConfigNotFound,
|
ConfigNotFound,
|
||||||
config.__getitem__,
|
config.__getitem__,
|
||||||
|
Loading…
Reference in New Issue
Block a user