2013-03-01 17:13:12 +01:00
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
"""
|
|
|
|
|
openslides.config.api
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
Api for the config app.
|
|
|
|
|
|
|
|
|
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
|
|
|
|
:license: GNU GPL, see LICENSE for more details.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from .models import ConfigStore
|
|
|
|
|
from .exceptions import ConfigError, ConfigNotFound
|
|
|
|
|
from .signals import config_signal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigHandler(object):
|
|
|
|
|
"""
|
|
|
|
|
An simple object class to wrap the config variables. It is a container
|
|
|
|
|
object. To get a config variable use x = config[...], to set it use
|
|
|
|
|
config[...] = x.
|
|
|
|
|
"""
|
|
|
|
|
def __getitem__(self, key):
|
|
|
|
|
try:
|
|
|
|
|
return self._cache[key]
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise ConfigNotFound('The config variable %s was not found.' % key)
|
|
|
|
|
except AttributeError:
|
|
|
|
|
self.setup_cache()
|
|
|
|
|
return self[key]
|
|
|
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
2013-09-08 10:26:51 +02:00
|
|
|
|
# Save the new value to the database
|
2013-03-01 17:13:12 +01:00
|
|
|
|
updated_rows = ConfigStore.objects.filter(key=key).update(value=value)
|
|
|
|
|
if not updated_rows:
|
|
|
|
|
ConfigStore.objects.create(key=key, value=value)
|
2013-09-08 10:26:51 +02:00
|
|
|
|
|
|
|
|
|
# Update cache
|
2013-08-11 10:05:47 +02:00
|
|
|
|
try:
|
|
|
|
|
self._cache[key] = value
|
|
|
|
|
except AttributeError:
|
|
|
|
|
# This happens, when a config-var is set, before __getitem__ was
|
|
|
|
|
# called. In this case nothing should happen.
|
|
|
|
|
pass
|
2013-03-01 17:13:12 +01:00
|
|
|
|
|
2013-09-08 10:26:51 +02:00
|
|
|
|
# Call on_change callback
|
2013-09-25 09:43:09 +02:00
|
|
|
|
for receiver, config_page in config_signal.send(sender='set_value'):
|
2013-09-08 10:26:51 +02:00
|
|
|
|
for config_variable in config_page.variables:
|
|
|
|
|
if config_variable.name == key and config_variable.on_change:
|
|
|
|
|
config_variable.on_change()
|
|
|
|
|
break
|
|
|
|
|
|
2013-09-25 09:43:09 +02:00
|
|
|
|
def get_default(self, key):
|
|
|
|
|
"""
|
|
|
|
|
Returns the default value for 'key'.
|
|
|
|
|
"""
|
|
|
|
|
for receiver, config_page in config_signal.send(sender='get_default'):
|
|
|
|
|
for config_variable in config_page.variables:
|
|
|
|
|
if config_variable.name == key:
|
|
|
|
|
return config_variable.default_value
|
|
|
|
|
raise ConfigNotFound('The config variable %s was not found.' % key)
|
|
|
|
|
|
2013-03-01 17:13:12 +01:00
|
|
|
|
def setup_cache(self):
|
|
|
|
|
"""
|
|
|
|
|
Loads all config variables from the database and by sending a
|
|
|
|
|
signal to get the default into the cache.
|
|
|
|
|
"""
|
|
|
|
|
self._cache = {}
|
2013-09-25 09:43:09 +02:00
|
|
|
|
for receiver, config_page in config_signal.send(sender='setup_cache'):
|
2013-03-01 17:13:12 +01:00
|
|
|
|
for config_variable in config_page.variables:
|
|
|
|
|
if config_variable.name in self._cache:
|
|
|
|
|
raise ConfigError('Too many values for config variable %s found.' % config_variable.name)
|
|
|
|
|
self._cache[config_variable.name] = config_variable.default_value
|
|
|
|
|
for config_object in ConfigStore.objects.all():
|
|
|
|
|
self._cache[config_object.key] = config_object.value
|
|
|
|
|
|
|
|
|
|
def __contains__(self, key):
|
|
|
|
|
try:
|
|
|
|
|
config[key]
|
|
|
|
|
except ConfigNotFound:
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
config = ConfigHandler()
|
|
|
|
|
"""
|
|
|
|
|
Final entry point to get an set config variables. To get a config variable
|
|
|
|
|
use x = config[...], to set it use config[...] = x.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigBasePage(object):
|
|
|
|
|
"""
|
|
|
|
|
An abstract base class for simple and grouped config pages. The
|
|
|
|
|
attributes title and url are required. The attribute weight is used
|
|
|
|
|
for the order of the links in the submenu of the views. The attribute
|
|
|
|
|
extra_context can be used to insert extra css and js files into the
|
|
|
|
|
template.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, title, url, required_permission=None, weight=0, extra_context={}):
|
|
|
|
|
self.title = title
|
|
|
|
|
self.url = url
|
|
|
|
|
self.required_permission = required_permission
|
|
|
|
|
self.weight = weight
|
|
|
|
|
self.extra_context = extra_context
|
|
|
|
|
|
|
|
|
|
def is_shown(self):
|
|
|
|
|
"""
|
|
|
|
|
Returns True if at least one variable of the page has a form field.
|
|
|
|
|
"""
|
|
|
|
|
for variable in self.variables:
|
|
|
|
|
if variable.form_field is not None:
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigGroupedPage(ConfigBasePage):
|
|
|
|
|
"""
|
|
|
|
|
A simple object class for a grouped config page. Developers have to
|
|
|
|
|
set the groups attribute (tuple). The config variables are available
|
|
|
|
|
via the variables attribute. The page is shown as view in the config
|
|
|
|
|
tab, if there is at least one variable with a form field.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, groups, **kwargs):
|
|
|
|
|
self.groups = groups
|
|
|
|
|
super(ConfigGroupedPage, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def variables(self):
|
|
|
|
|
for group in self.groups:
|
|
|
|
|
for variable in group.variables:
|
|
|
|
|
yield variable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigPage(ConfigBasePage):
|
|
|
|
|
"""
|
|
|
|
|
A simple object class for a ungrouped config page. Developers have
|
|
|
|
|
to set the variables (tuple) directly. The page is shown as view in
|
|
|
|
|
the config tab, if there is at least one variable with a form field.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, variables, **kwargs):
|
|
|
|
|
self.variables = variables
|
|
|
|
|
super(ConfigPage, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigGroup(object):
|
|
|
|
|
"""
|
|
|
|
|
A simple object class representing a group of variables (tuple) with
|
|
|
|
|
a special title.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, title, variables):
|
|
|
|
|
self.title = title
|
|
|
|
|
self.variables = variables
|
|
|
|
|
|
|
|
|
|
def get_field_names(self):
|
|
|
|
|
return [variable.name for variable in self.variables if variable.form_field is not None]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigVariable(object):
|
|
|
|
|
"""
|
|
|
|
|
A simple object class to wrap new config variables. The keyword
|
|
|
|
|
arguments 'name' and 'default_value' are required. The keyword
|
|
|
|
|
argument 'form_field' has to be set, if the variable should appear
|
2013-09-08 10:26:51 +02:00
|
|
|
|
on the ConfigView. The argument 'on_change' can get a callback
|
|
|
|
|
which is called every time, the variable is changed.
|
2013-03-01 17:13:12 +01:00
|
|
|
|
"""
|
2013-09-08 10:26:51 +02:00
|
|
|
|
def __init__(self, name, default_value, form_field=None, on_change=None):
|
2013-03-01 17:13:12 +01:00
|
|
|
|
self.name = name
|
|
|
|
|
self.default_value = default_value
|
|
|
|
|
self.form_field = form_field
|
2013-09-08 10:26:51 +02:00
|
|
|
|
self.on_change = on_change
|