Rename classes in the config api.
Also change attributes for config collection without view.
This commit is contained in:
parent
399ab5a96c
commit
bdf1679eb0
@ -15,6 +15,7 @@ Files:
|
|||||||
Other:
|
Other:
|
||||||
- Changed widget api. Used new metaclass.
|
- Changed widget api. Used new metaclass.
|
||||||
- Changed api for plugins.
|
- Changed api for plugins.
|
||||||
|
- Renamed config api classes.
|
||||||
|
|
||||||
|
|
||||||
Version 1.5.1 (unreleased)
|
Version 1.5.1 (unreleased)
|
||||||
|
@ -11,7 +11,7 @@ from django.template.loader import render_to_string
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||||
|
|
||||||
from openslides.config.api import config, ConfigPage, ConfigVariable
|
from openslides.config.api import config, ConfigCollection, ConfigVariable
|
||||||
from openslides.config.signals import config_signal
|
from openslides.config.signals import config_signal
|
||||||
from openslides.projector.api import get_active_slide, get_active_object
|
from openslides.projector.api import get_active_slide, get_active_object
|
||||||
from openslides.projector.projector import Overlay
|
from openslides.projector.projector import Overlay
|
||||||
@ -29,8 +29,8 @@ def validate_start_time(value):
|
|||||||
|
|
||||||
# TODO: Reinsert the datepicker scripts in the template
|
# TODO: Reinsert the datepicker scripts in the template
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='setup_agenda_config_page')
|
@receiver(config_signal, dispatch_uid='setup_agenda_config')
|
||||||
def setup_agenda_config_page(sender, **kwargs):
|
def setup_agenda_config(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Agenda config variables.
|
Agenda config variables.
|
||||||
"""
|
"""
|
||||||
@ -66,15 +66,15 @@ def setup_agenda_config_page(sender, **kwargs):
|
|||||||
'javascript/jquery-ui-sliderAccess.min.js',
|
'javascript/jquery-ui-sliderAccess.min.js',
|
||||||
'javascript/agenda-config-datepicker.js']
|
'javascript/agenda-config-datepicker.js']
|
||||||
|
|
||||||
return ConfigPage(title=ugettext_noop('Agenda'),
|
return ConfigCollection(title=ugettext_noop('Agenda'),
|
||||||
url='agenda',
|
url='agenda',
|
||||||
required_permission='config.can_manage',
|
required_permission='config.can_manage',
|
||||||
weight=20,
|
weight=20,
|
||||||
variables=(agenda_start_event_date_time,
|
variables=(agenda_start_event_date_time,
|
||||||
agenda_show_last_speakers,
|
agenda_show_last_speakers,
|
||||||
agenda_couple_countdown_and_speakers),
|
agenda_couple_countdown_and_speakers),
|
||||||
extra_context={'extra_stylefiles': extra_stylefiles,
|
extra_context={'extra_stylefiles': extra_stylefiles,
|
||||||
'extra_javascript': extra_javascript})
|
'extra_javascript': extra_javascript})
|
||||||
|
|
||||||
|
|
||||||
@receiver(projector_overlays, dispatch_uid="agenda_list_of_speakers")
|
@receiver(projector_overlays, dispatch_uid="agenda_list_of_speakers")
|
||||||
|
@ -5,12 +5,12 @@ from django.dispatch import receiver
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||||
|
|
||||||
from openslides.config.api import ConfigPage, ConfigVariable
|
from openslides.config.api import ConfigCollection, ConfigVariable
|
||||||
from openslides.config.signals import config_signal
|
from openslides.config.signals import config_signal
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='setup_assignment_config_page')
|
@receiver(config_signal, dispatch_uid='setup_assignment_config')
|
||||||
def setup_assignment_config_page(sender, **kwargs):
|
def setup_assignment_config(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Assignment config variables.
|
Assignment config variables.
|
||||||
"""
|
"""
|
||||||
@ -66,13 +66,13 @@ def setup_assignment_config_page(sender, **kwargs):
|
|||||||
('votes', ugettext_lazy('Always one option per candidate')),
|
('votes', ugettext_lazy('Always one option per candidate')),
|
||||||
('yesnoabstain', ugettext_lazy('Always Yes-No-Abstain per candidate')))))
|
('yesnoabstain', ugettext_lazy('Always Yes-No-Abstain per candidate')))))
|
||||||
|
|
||||||
return ConfigPage(title=ugettext_noop('Elections'),
|
return ConfigCollection(title=ugettext_noop('Elections'),
|
||||||
url='assignment',
|
url='assignment',
|
||||||
required_permission='config.can_manage',
|
required_permission='config.can_manage',
|
||||||
weight=40,
|
weight=40,
|
||||||
variables=(assignment_publish_winner_results_only,
|
variables=(assignment_publish_winner_results_only,
|
||||||
assignment_pdf_ballot_papers_selection,
|
assignment_pdf_ballot_papers_selection,
|
||||||
assignment_pdf_ballot_papers_number,
|
assignment_pdf_ballot_papers_number,
|
||||||
assignment_pdf_title,
|
assignment_pdf_title,
|
||||||
assignment_pdf_preamble,
|
assignment_pdf_preamble,
|
||||||
assignment_poll_vote_values))
|
assignment_poll_vote_values))
|
||||||
|
@ -35,8 +35,8 @@ class ConfigHandler(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# Call on_change callback
|
# Call on_change callback
|
||||||
for receiver, config_page in config_signal.send(sender='set_value'):
|
for receiver, config_collection in config_signal.send(sender='set_value'):
|
||||||
for config_variable in config_page.variables:
|
for config_variable in config_collection.variables:
|
||||||
if config_variable.name == key and config_variable.on_change:
|
if config_variable.name == key and config_variable.on_change:
|
||||||
config_variable.on_change()
|
config_variable.on_change()
|
||||||
break
|
break
|
||||||
@ -45,8 +45,8 @@ class ConfigHandler(object):
|
|||||||
"""
|
"""
|
||||||
Returns the default value for 'key'.
|
Returns the default value for 'key'.
|
||||||
"""
|
"""
|
||||||
for receiver, config_page in config_signal.send(sender='get_default'):
|
for receiver, config_collection in config_signal.send(sender='get_default'):
|
||||||
for config_variable in config_page.variables:
|
for config_variable in config_collection.variables:
|
||||||
if config_variable.name == key:
|
if config_variable.name == key:
|
||||||
return config_variable.default_value
|
return config_variable.default_value
|
||||||
raise ConfigNotFound('The config variable %s was not found.' % key)
|
raise ConfigNotFound('The config variable %s was not found.' % key)
|
||||||
@ -57,8 +57,8 @@ class ConfigHandler(object):
|
|||||||
signal to get the default into the cache.
|
signal to get the default into the cache.
|
||||||
"""
|
"""
|
||||||
self._cache = {}
|
self._cache = {}
|
||||||
for receiver, config_page in config_signal.send(sender='setup_cache'):
|
for receiver, config_collection in config_signal.send(sender='setup_cache'):
|
||||||
for config_variable in config_page.variables:
|
for config_variable in config_collection.variables:
|
||||||
if config_variable.name in self._cache:
|
if config_variable.name in self._cache:
|
||||||
raise ConfigError('Too many values for config variable %s found.' % config_variable.name)
|
raise ConfigError('Too many values for config variable %s found.' % config_variable.name)
|
||||||
self._cache[config_variable.name] = config_variable.default_value
|
self._cache[config_variable.name] = config_variable.default_value
|
||||||
@ -81,15 +81,17 @@ use x = config[...], to set it use config[...] = x.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class ConfigBasePage(object):
|
class ConfigBaseCollection(object):
|
||||||
"""
|
"""
|
||||||
An abstract base class for simple and grouped config pages. The
|
An abstract base class for simple and grouped config collections. The
|
||||||
attributes title and url are required. The attribute weight is used
|
attributes title and url are required for collections that should be
|
||||||
for the order of the links in the submenu of the views. The attribute
|
shown as a view. The attribute required_permission is used to set which
|
||||||
extra_context can be used to insert extra css and js files into the
|
users can control the view showing the colletion. The attribute weight
|
||||||
template.
|
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={}):
|
def __init__(self, title=None, url=None, required_permission=None, weight=0, extra_context={}):
|
||||||
self.title = title
|
self.title = title
|
||||||
self.url = url
|
self.url = url
|
||||||
self.required_permission = required_permission
|
self.required_permission = required_permission
|
||||||
@ -98,25 +100,29 @@ class ConfigBasePage(object):
|
|||||||
|
|
||||||
def is_shown(self):
|
def is_shown(self):
|
||||||
"""
|
"""
|
||||||
Returns True if at least one variable of the page has a form field.
|
Returns True if at least one variable of the collection has a form field.
|
||||||
"""
|
"""
|
||||||
for variable in self.variables:
|
for variable in self.variables:
|
||||||
if variable.form_field is not None:
|
if variable.form_field is not None:
|
||||||
return True
|
is_shown = True
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
return False
|
is_shown = False
|
||||||
|
if is_shown and (self.title is None or self.url is None):
|
||||||
|
raise ConfigError('The config collection %s must have a title and an url attribute.' % self)
|
||||||
|
return is_shown
|
||||||
|
|
||||||
|
|
||||||
class ConfigGroupedPage(ConfigBasePage):
|
class ConfigGroupedCollection(ConfigBaseCollection):
|
||||||
"""
|
"""
|
||||||
A simple object class for a grouped config page. Developers have to
|
A simple object class for a grouped config collection. Developers have to
|
||||||
set the groups attribute (tuple). The config variables are available
|
set the groups attribute (tuple). The config variables are available
|
||||||
via the variables attribute. The page is shown as view in the config
|
via the variables attribute. The collection is shown as a view via the config
|
||||||
tab, if there is at least one variable with a form field.
|
main menu entry if there is at least one variable with a form field.
|
||||||
"""
|
"""
|
||||||
def __init__(self, groups, **kwargs):
|
def __init__(self, groups, **kwargs):
|
||||||
self.groups = groups
|
self.groups = groups
|
||||||
super(ConfigGroupedPage, self).__init__(**kwargs)
|
super(ConfigGroupedCollection, self).__init__(**kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def variables(self):
|
def variables(self):
|
||||||
@ -125,15 +131,16 @@ class ConfigGroupedPage(ConfigBasePage):
|
|||||||
yield variable
|
yield variable
|
||||||
|
|
||||||
|
|
||||||
class ConfigPage(ConfigBasePage):
|
class ConfigCollection(ConfigBaseCollection):
|
||||||
"""
|
"""
|
||||||
A simple object class for a ungrouped config page. Developers have
|
A simple object class for a ungrouped config collection. Developers have
|
||||||
to set the variables (tuple) directly. The page is shown as view in
|
to set the variables (tuple) directly. The collection is shown as a view via
|
||||||
the config tab, if there is at least one variable with a form field.
|
the config main menu entry if there is at least one variable with a
|
||||||
|
form field.
|
||||||
"""
|
"""
|
||||||
def __init__(self, variables, **kwargs):
|
def __init__(self, variables, **kwargs):
|
||||||
self.variables = variables
|
self.variables = variables
|
||||||
super(ConfigPage, self).__init__(**kwargs)
|
super(ConfigCollection, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ConfigGroup(object):
|
class ConfigGroup(object):
|
||||||
@ -153,7 +160,7 @@ class ConfigVariable(object):
|
|||||||
"""
|
"""
|
||||||
A simple object class to wrap new config variables. The keyword
|
A simple object class to wrap new config variables. The keyword
|
||||||
arguments 'name' and 'default_value' are required. The keyword
|
arguments 'name' and 'default_value' are required. The keyword
|
||||||
argument 'form_field' has to be set, if the variable should appear
|
argument 'form_field' has to be set if the variable should appear
|
||||||
on the ConfigView. The argument 'on_change' can get a callback
|
on the ConfigView. The argument 'on_change' can get a callback
|
||||||
which is called every time, the variable is changed.
|
which is called every time, the variable is changed.
|
||||||
"""
|
"""
|
||||||
|
@ -8,12 +8,14 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>
|
<h1>
|
||||||
{% trans 'Configuration' %}
|
{% trans 'Configuration' %}
|
||||||
<small>{% trans active_config_page.title %}</small>
|
<small>{% trans active_config_collection_view.title %}</small>
|
||||||
<small class="pull-right">
|
<small class="pull-right">
|
||||||
<div class="btn-toolbar">
|
<div class="btn-toolbar">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
{% for config_page_dict in config_pages_list %}
|
{% for config_collection_dict in config_collection_list %}
|
||||||
<a href="/config/{{ config_page_dict.config_page.url }}/" class="btn btn-mini {% if config_page_dict.active %}active{% endif %}">{% trans config_page_dict.config_page.title %}</a>
|
<a href="/config/{{ config_collection_dict.config_collection.url }}/" class="btn btn-mini {% if config_collection_dict.active %}active{% endif %}">
|
||||||
|
{% trans config_collection_dict.config_collection.title %}
|
||||||
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,7 +45,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
<p>
|
<p>
|
||||||
{% include 'formbuttons_save.html' %}
|
{% include 'formbuttons_save.html' %}
|
||||||
<a href="/config/{{ active_config_page.url }}/" class="btn">{% trans 'Cancel' %}</a>
|
<a href="/config/{{ active_config_collection_view.url }}/" class="btn">{% trans 'Cancel' %}</a>
|
||||||
</p>
|
</p>
|
||||||
<small>* {% trans 'required' %}</small>
|
<small>* {% trans 'required' %}</small>
|
||||||
</form>
|
</form>
|
||||||
|
@ -11,11 +11,11 @@ urlpatterns = patterns(
|
|||||||
'',
|
'',
|
||||||
url(r'^$',
|
url(r'^$',
|
||||||
RedirectView.as_view(url_name='config_general'),
|
RedirectView.as_view(url_name='config_general'),
|
||||||
name='config_first_config_page')
|
name='config_first_config_collection_view')
|
||||||
)
|
)
|
||||||
|
|
||||||
for receiver, config_page in config_signal.send(sender='config_urls'):
|
for receiver, config_collection in config_signal.send(sender='config_urls'):
|
||||||
if config_page.is_shown():
|
if config_collection.is_shown():
|
||||||
urlpatterns += patterns('', url(r'^%s/$' % config_page.url,
|
urlpatterns += patterns('', url(r'^%s/$' % config_collection.url,
|
||||||
ConfigView.as_view(config_page=config_page),
|
ConfigView.as_view(config_collection=config_collection),
|
||||||
name='config_%s' % config_page.url))
|
name='config_%s' % config_collection.url))
|
||||||
|
@ -14,34 +14,34 @@ from .signals import config_signal
|
|||||||
|
|
||||||
class ConfigView(FormView):
|
class ConfigView(FormView):
|
||||||
"""
|
"""
|
||||||
The view for a config page.
|
The view for a config collection.
|
||||||
"""
|
"""
|
||||||
template_name = 'config/config_form.html'
|
template_name = 'config/config_form.html'
|
||||||
config_page = None
|
config_collection = None
|
||||||
form_class = forms.Form
|
form_class = forms.Form
|
||||||
|
|
||||||
def has_permission(self, *args, **kwargs):
|
def has_permission(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Ensures that only users with tab's permission can see this view.
|
Ensures that only users with permission can see this view.
|
||||||
"""
|
"""
|
||||||
self.permission_required = self.config_page.required_permission
|
self.permission_required = self.config_collection.required_permission
|
||||||
return super(ConfigView, self).has_permission(*args, **kwargs)
|
return super(ConfigView, self).has_permission(*args, **kwargs)
|
||||||
|
|
||||||
def get_form(self, *args):
|
def get_form(self, *args):
|
||||||
"""
|
"""
|
||||||
Gets the form for the view. Includes all form fields given by the
|
Gets the form for the view. Includes all form fields given by the
|
||||||
tab's config objects.
|
config collection.
|
||||||
"""
|
"""
|
||||||
form = super(ConfigView, self).get_form(*args)
|
form = super(ConfigView, self).get_form(*args)
|
||||||
for name, field in self.generate_form_fields_from_config_page():
|
for name, field in self.generate_form_fields_from_config_collection():
|
||||||
form.fields[name] = field
|
form.fields[name] = field
|
||||||
return form
|
return form
|
||||||
|
|
||||||
def generate_form_fields_from_config_page(self):
|
def generate_form_fields_from_config_collection(self):
|
||||||
"""
|
"""
|
||||||
Generates the fields for the get_form function.
|
Generates the fields for the get_form function.
|
||||||
"""
|
"""
|
||||||
for variable in self.config_page.variables:
|
for variable in self.config_collection.variables:
|
||||||
if variable.form_field is not None:
|
if variable.form_field is not None:
|
||||||
yield (variable.name, variable.form_field)
|
yield (variable.name, variable.form_field)
|
||||||
|
|
||||||
@ -51,54 +51,55 @@ class ConfigView(FormView):
|
|||||||
as intial value for the form.
|
as intial value for the form.
|
||||||
"""
|
"""
|
||||||
initial = super(ConfigView, self).get_initial()
|
initial = super(ConfigView, self).get_initial()
|
||||||
for variable in self.config_page.variables:
|
for variable in self.config_collection.variables:
|
||||||
initial.update({variable.name: config[variable.name]})
|
initial.update({variable.name: config[variable.name]})
|
||||||
return initial
|
return initial
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Adds to the context the active config tab, a list of dictionaries
|
Adds to the context the active config view, a list of dictionaries
|
||||||
containing all config tabs each with a flag which is true if the
|
containing all config collections each with a flag which is true if its
|
||||||
tab is the active one and adds a flag whether the config page has
|
view is the active one and adds a flag whether the config collection
|
||||||
groups. Adds also extra_stylefiles and extra_javascript.
|
has groups. Adds also extra_stylefiles and extra_javascript.
|
||||||
"""
|
"""
|
||||||
context = super(ConfigView, self).get_context_data(**kwargs)
|
context = super(ConfigView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
context['active_config_page'] = self.config_page
|
context['active_config_collection_view'] = self.config_collection
|
||||||
|
|
||||||
config_pages_list = []
|
config_collection_list = []
|
||||||
for receiver, config_page in config_signal.send(sender=self):
|
for receiver, config_collection in config_signal.send(sender=self):
|
||||||
if config_page.is_shown():
|
if config_collection.is_shown():
|
||||||
config_pages_list.append({
|
config_collection_list.append({
|
||||||
'config_page': config_page,
|
'config_collection': config_collection,
|
||||||
'active': self.request.path == reverse('config_%s' % config_page.url)})
|
'active': self.request.path == reverse('config_%s' % config_collection.url)})
|
||||||
context['config_pages_list'] = sorted(config_pages_list, key=lambda config_page_dict: config_page_dict['config_page'].weight)
|
context['config_collection_list'] = sorted(
|
||||||
|
config_collection_list, key=lambda config_collection_dict: config_collection_dict['config_collection'].weight)
|
||||||
|
|
||||||
if hasattr(self.config_page, 'groups'):
|
if hasattr(self.config_collection, 'groups'):
|
||||||
context['groups'] = self.config_page.groups
|
context['groups'] = self.config_collection.groups
|
||||||
else:
|
else:
|
||||||
context['groups'] = None
|
context['groups'] = None
|
||||||
|
|
||||||
if 'extra_stylefiles' in self.config_page.extra_context:
|
if 'extra_stylefiles' in self.config_collection.extra_context:
|
||||||
if 'extra_stylefiles' in context:
|
if 'extra_stylefiles' in context:
|
||||||
context['extra_stylefiles'].extend(self.config_page.extra_context['extra_stylefiles'])
|
context['extra_stylefiles'].extend(self.config_collection.extra_context['extra_stylefiles'])
|
||||||
else:
|
else:
|
||||||
context['extra_stylefiles'] = self.config_page.extra_context['extra_stylefiles']
|
context['extra_stylefiles'] = self.config_collection.extra_context['extra_stylefiles']
|
||||||
|
|
||||||
if 'extra_javascript' in self.config_page.extra_context:
|
if 'extra_javascript' in self.config_collection.extra_context:
|
||||||
if 'extra_javascript' in context:
|
if 'extra_javascript' in context:
|
||||||
context['extra_javascript'].extend(self.config_page.extra_context['extra_javascript'])
|
context['extra_javascript'].extend(self.config_collection.extra_context['extra_javascript'])
|
||||||
else:
|
else:
|
||||||
context['extra_javascript'] = self.config_page.extra_context['extra_javascript']
|
context['extra_javascript'] = self.config_collection.extra_context['extra_javascript']
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
"""
|
"""
|
||||||
Returns the success url when changes are saved. Here it is the same
|
Returns the success url when changes are saved. Here it is the same
|
||||||
url as the tab.
|
url as the main menu entry.
|
||||||
"""
|
"""
|
||||||
return reverse('config_%s' % self.config_page.url)
|
return reverse('config_%s' % self.config_collection.url)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""
|
"""
|
||||||
@ -106,17 +107,17 @@ class ConfigView(FormView):
|
|||||||
"""
|
"""
|
||||||
for key in form.cleaned_data:
|
for key in form.cleaned_data:
|
||||||
config[key] = form.cleaned_data[key]
|
config[key] = form.cleaned_data[key]
|
||||||
messages.success(self.request, _('%s settings successfully saved.') % _(self.config_page.title))
|
messages.success(self.request, _('%s settings successfully saved.') % _(self.config_collection.title))
|
||||||
return super(ConfigView, self).form_valid(form)
|
return super(ConfigView, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
def register_tab(request):
|
def register_tab(request):
|
||||||
"""
|
"""
|
||||||
Registers the tab for this app in the main menu.
|
Registers the entry for this app in the main menu.
|
||||||
"""
|
"""
|
||||||
return Tab(
|
return Tab(
|
||||||
title=_('Configuration'),
|
title=_('Configuration'),
|
||||||
app='config',
|
app='config',
|
||||||
url=reverse('config_first_config_page'),
|
url=reverse('config_first_config_collection_view'),
|
||||||
permission=request.user.has_perm('config.can_manage'),
|
permission=request.user.has_perm('config.can_manage'),
|
||||||
selected=request.path.startswith('/config/'))
|
selected=request.path.startswith('/config/'))
|
||||||
|
@ -5,15 +5,15 @@ from django.dispatch import receiver, Signal
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||||
|
|
||||||
from openslides.config.api import ConfigGroup, ConfigGroupedPage, ConfigVariable
|
from openslides.config.api import ConfigGroup, ConfigGroupedCollection, ConfigVariable
|
||||||
from openslides.config.signals import config_signal
|
from openslides.config.signals import config_signal
|
||||||
from openslides.projector.api import update_projector
|
from openslides.projector.api import update_projector
|
||||||
|
|
||||||
post_database_setup = Signal()
|
post_database_setup = Signal()
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='setup_general_config_page')
|
@receiver(config_signal, dispatch_uid='setup_general_config')
|
||||||
def setup_general_config_page(sender, **kwargs):
|
def setup_general_config(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
General config variables for OpenSlides. They are grouped in 'Event',
|
General config variables for OpenSlides. They are grouped in 'Event',
|
||||||
'Welcome Widget' and 'System'.
|
'Welcome Widget' and 'System'.
|
||||||
@ -182,7 +182,7 @@ def setup_general_config_page(sender, **kwargs):
|
|||||||
title=ugettext_lazy('System'),
|
title=ugettext_lazy('System'),
|
||||||
variables=(system_enable_anonymous, system_url, system_wlan_ssid, system_wlan_password, system_wlan_encryption))
|
variables=(system_enable_anonymous, system_url, system_wlan_ssid, system_wlan_password, system_wlan_encryption))
|
||||||
|
|
||||||
return ConfigGroupedPage(
|
return ConfigGroupedCollection(
|
||||||
title=ugettext_noop('General'),
|
title=ugettext_noop('General'),
|
||||||
url='general',
|
url='general',
|
||||||
required_permission='config.can_manage',
|
required_permission='config.can_manage',
|
||||||
|
@ -5,15 +5,15 @@ from django.dispatch import receiver
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||||
|
|
||||||
from openslides.config.api import ConfigPage, ConfigVariable
|
from openslides.config.api import ConfigCollection, ConfigVariable
|
||||||
from openslides.config.signals import config_signal
|
from openslides.config.signals import config_signal
|
||||||
from openslides.core.signals import post_database_setup
|
from openslides.core.signals import post_database_setup
|
||||||
|
|
||||||
from .models import State, Workflow
|
from .models import State, Workflow
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='setup_motion_config_page')
|
@receiver(config_signal, dispatch_uid='setup_motion_config')
|
||||||
def setup_motion_config_page(sender, **kwargs):
|
def setup_motion_config(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Motion config variables.
|
Motion config variables.
|
||||||
"""
|
"""
|
||||||
@ -109,22 +109,22 @@ def setup_motion_config_page(sender, **kwargs):
|
|||||||
('serially_numbered', ugettext_lazy('Serially numbered')),
|
('serially_numbered', ugettext_lazy('Serially numbered')),
|
||||||
('manually', ugettext_lazy('Set it manually'))]))
|
('manually', ugettext_lazy('Set it manually'))]))
|
||||||
|
|
||||||
return ConfigPage(title=ugettext_noop('Motion'),
|
return ConfigCollection(title=ugettext_noop('Motion'),
|
||||||
url='motion',
|
url='motion',
|
||||||
required_permission='config.can_manage',
|
required_permission='config.can_manage',
|
||||||
weight=30,
|
weight=30,
|
||||||
variables=(motion_stop_submitting,
|
variables=(motion_stop_submitting,
|
||||||
motion_min_supporters,
|
motion_min_supporters,
|
||||||
motion_remove_supporters,
|
motion_remove_supporters,
|
||||||
motion_preamble,
|
motion_preamble,
|
||||||
motion_pdf_ballot_papers_selection,
|
motion_pdf_ballot_papers_selection,
|
||||||
motion_pdf_ballot_papers_number,
|
motion_pdf_ballot_papers_number,
|
||||||
motion_pdf_title,
|
motion_pdf_title,
|
||||||
motion_pdf_preamble,
|
motion_pdf_preamble,
|
||||||
motion_pdf_paragraph_numbering,
|
motion_pdf_paragraph_numbering,
|
||||||
motion_allow_disable_versioning,
|
motion_allow_disable_versioning,
|
||||||
motion_workflow,
|
motion_workflow,
|
||||||
motion_identifier))
|
motion_identifier))
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_database_setup, dispatch_uid='motion_create_builtin_workflows')
|
@receiver(post_database_setup, dispatch_uid='motion_create_builtin_workflows')
|
||||||
|
@ -7,7 +7,7 @@ from django.dispatch import receiver
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||||
|
|
||||||
from openslides.config.api import ConfigPage, ConfigVariable
|
from openslides.config.api import ConfigCollection, ConfigVariable
|
||||||
from openslides.config.signals import config_signal
|
from openslides.config.signals import config_signal
|
||||||
from openslides.core.signals import post_database_setup
|
from openslides.core.signals import post_database_setup
|
||||||
|
|
||||||
@ -15,8 +15,8 @@ from .api import create_or_reset_admin_user
|
|||||||
from .models import Group
|
from .models import Group
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='setup_participant_config_page')
|
@receiver(config_signal, dispatch_uid='setup_participant_config')
|
||||||
def setup_participant_config_page(sender, **kwargs):
|
def setup_participant_config(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Participant config variables.
|
Participant config variables.
|
||||||
"""
|
"""
|
||||||
@ -44,13 +44,13 @@ def setup_participant_config_page(sender, **kwargs):
|
|||||||
label=ugettext_lazy('Sort participants by first name'),
|
label=ugettext_lazy('Sort participants by first name'),
|
||||||
help_text=ugettext_lazy('Disable for sorting by last name')))
|
help_text=ugettext_lazy('Disable for sorting by last name')))
|
||||||
|
|
||||||
return ConfigPage(title=ugettext_noop('Participant'),
|
return ConfigCollection(title=ugettext_noop('Participant'),
|
||||||
url='participant',
|
url='participant',
|
||||||
required_permission='config.can_manage',
|
required_permission='config.can_manage',
|
||||||
weight=50,
|
weight=50,
|
||||||
variables=(participant_pdf_welcometitle,
|
variables=(participant_pdf_welcometitle,
|
||||||
participant_pdf_welcometext,
|
participant_pdf_welcometext,
|
||||||
participant_sort_users_by_first_name))
|
participant_sort_users_by_first_name))
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_database_setup, dispatch_uid='participant_create_builtin_groups_and_admin')
|
@receiver(post_database_setup, dispatch_uid='participant_create_builtin_groups_and_admin')
|
||||||
|
@ -7,7 +7,7 @@ from django.dispatch import receiver, Signal
|
|||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
|
|
||||||
from openslides.config.api import config, ConfigPage, ConfigVariable
|
from openslides.config.api import config, ConfigCollection, ConfigVariable
|
||||||
from openslides.config.signals import config_signal
|
from openslides.config.signals import config_signal
|
||||||
|
|
||||||
from .projector import Overlay
|
from .projector import Overlay
|
||||||
@ -15,13 +15,12 @@ from .projector import Overlay
|
|||||||
projector_overlays = Signal(providing_args=['request'])
|
projector_overlays = Signal(providing_args=['request'])
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='setup_projector_config_variables')
|
@receiver(config_signal, dispatch_uid='setup_projector_config')
|
||||||
def config_variables(sender, **kwargs):
|
def setup_projector_config(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Projector config variables for OpenSlides. They are not shown on a
|
Projector config variables for OpenSlides. They are not shown on a
|
||||||
config page.
|
config view.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The active slide. The config-value is a dictonary with at least the entry
|
# The active slide. The config-value is a dictonary with at least the entry
|
||||||
# 'callback'.
|
# 'callback'.
|
||||||
projector = ConfigVariable(
|
projector = ConfigVariable(
|
||||||
@ -68,8 +67,8 @@ def config_variables(sender, **kwargs):
|
|||||||
name='pdf_fullscreen',
|
name='pdf_fullscreen',
|
||||||
default_value=False)
|
default_value=False)
|
||||||
|
|
||||||
return ConfigPage(
|
return ConfigCollection(
|
||||||
title='No title here', url='bar', required_permission=None, variables=(
|
required_permission=None, variables=(
|
||||||
projector, projector_message,
|
projector, projector_message,
|
||||||
countdown_time, countdown_start_stamp, countdown_pause_stamp,
|
countdown_time, countdown_start_stamp, countdown_pause_stamp,
|
||||||
countdown_state, projector_scale, projector_scroll,
|
countdown_state, projector_scale, projector_scroll,
|
||||||
|
@ -277,7 +277,7 @@ class ConfigTest(TestCase):
|
|||||||
self.client = Client()
|
self.client = Client()
|
||||||
self.client.login(username='config_test_admin', password='default')
|
self.client.login(username='config_test_admin', password='default')
|
||||||
|
|
||||||
def test_config_page_css_javascript(self):
|
def test_config_collection_css_javascript(self):
|
||||||
response = self.client.get('/config/agenda/')
|
response = self.client.get('/config/agenda/')
|
||||||
self.assertContains(response, 'timepicker.css', status_code=200)
|
self.assertContains(response, 'timepicker.css', status_code=200)
|
||||||
self.assertContains(response, 'jquery-ui-timepicker-addon.min.js', status_code=200)
|
self.assertContains(response, 'jquery-ui-timepicker-addon.min.js', status_code=200)
|
||||||
|
@ -7,8 +7,8 @@ from django.dispatch import receiver
|
|||||||
from django.test.client import Client
|
from django.test.client import Client
|
||||||
from mock import patch
|
from mock import patch
|
||||||
|
|
||||||
from openslides.config.api import (config, ConfigGroup, ConfigGroupedPage,
|
from openslides.config.api import (config, ConfigCollection, ConfigGroup,
|
||||||
ConfigPage, ConfigVariable)
|
ConfigGroupedCollection, ConfigVariable)
|
||||||
from openslides.config.exceptions import ConfigError, ConfigNotFound
|
from openslides.config.exceptions import ConfigError, ConfigNotFound
|
||||||
from openslides.config.signals import config_signal
|
from openslides.config.signals import config_signal
|
||||||
from openslides.participant.models import User
|
from openslides.participant.models import User
|
||||||
@ -34,11 +34,11 @@ class HandleConfigTest(TestCase):
|
|||||||
callable_obj=self.get_config_var, key='unknown_config_var')
|
callable_obj=self.get_config_var, key='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_page_multiple_vars, dispatch_uid='set_simple_config_page_multiple_vars_for_testing')
|
config_signal.connect(set_simple_config_view_multiple_vars, dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
|
||||||
self.assertRaisesMessage(expected_exception=ConfigError,
|
self.assertRaisesMessage(expected_exception=ConfigError,
|
||||||
expected_message='Too many values for config variable multiple_config_var found.',
|
expected_message='Too many values for config variable multiple_config_var found.',
|
||||||
callable_obj=config.setup_cache)
|
callable_obj=config.setup_cache)
|
||||||
config_signal.disconnect(set_simple_config_page_multiple_vars, dispatch_uid='set_simple_config_page_multiple_vars_for_testing')
|
config_signal.disconnect(set_simple_config_view_multiple_vars, dispatch_uid='set_simple_config_view_multiple_vars_for_testing')
|
||||||
|
|
||||||
def test_database_queries(self):
|
def test_database_queries(self):
|
||||||
"""
|
"""
|
||||||
@ -187,12 +187,50 @@ class ConfigFormTest(TestCase):
|
|||||||
{'integer_var': 'bad_string_value'})
|
{'integer_var': 'bad_string_value'})
|
||||||
self.assertContains(response=response, text='errorlist', status_code=200)
|
self.assertContains(response=response, text='errorlist', status_code=200)
|
||||||
|
|
||||||
def test_disabled_config_page(self):
|
def test_disabled_config_view(self):
|
||||||
response = self.client_manager.get('/config/testsimplepage3/')
|
response = self.client_manager.get('/config/testsimplepage3/')
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
response = self.client_manager.get('/config/testgroupedpage1/')
|
response = self.client_manager.get('/config/testgroupedpage1/')
|
||||||
self.assertNotContains(response=response, text='Ho5iengaoon5Hoht', status_code=200)
|
self.assertNotContains(response=response, text='Ho5iengaoon5Hoht', status_code=200)
|
||||||
|
|
||||||
|
def test_improperly_configured_config_view(self):
|
||||||
|
from openslides.config import urls
|
||||||
|
collection = ConfigCollection(
|
||||||
|
title='Only a small title but no url ci6xahb8Chula0Thesho',
|
||||||
|
variables=(ConfigVariable(name='some_var_paiji9theiW8ooXivae6',
|
||||||
|
default_value='',
|
||||||
|
form_field=forms.CharField()),))
|
||||||
|
|
||||||
|
def setup_bad_config_view_one(sender, **kwargs):
|
||||||
|
return collection
|
||||||
|
|
||||||
|
config_signal.connect(setup_bad_config_view_one, dispatch_uid='setup_bad_config_view_one_for_testing')
|
||||||
|
self.assertRaisesMessage(
|
||||||
|
ConfigError,
|
||||||
|
'The config collection %s must have a title and an url attribute.' % repr(collection),
|
||||||
|
reload,
|
||||||
|
urls)
|
||||||
|
config_signal.disconnect(setup_bad_config_view_one, dispatch_uid='setup_bad_config_view_one_for_testing')
|
||||||
|
|
||||||
|
def test_improperly_configured_config_view_two(self):
|
||||||
|
from openslides.config import urls
|
||||||
|
collection = ConfigCollection(
|
||||||
|
url='only_url_ureiraeY1Oochuad7xei',
|
||||||
|
variables=(ConfigVariable(name='some_var_vuuC6eiXeiyae3ik4gie',
|
||||||
|
default_value='',
|
||||||
|
form_field=forms.CharField()),))
|
||||||
|
|
||||||
|
def setup_bad_config_view_two(sender, **kwargs):
|
||||||
|
return collection
|
||||||
|
|
||||||
|
config_signal.connect(setup_bad_config_view_two, dispatch_uid='setup_bad_config_view_twoe_for_testing')
|
||||||
|
self.assertRaisesMessage(
|
||||||
|
ConfigError,
|
||||||
|
'The config collection %s must have a title and an url attribute.' % repr(collection),
|
||||||
|
reload,
|
||||||
|
urls)
|
||||||
|
config_signal.disconnect(setup_bad_config_view_two, dispatch_uid='setup_bad_config_view_twoe_for_testing')
|
||||||
|
|
||||||
def test_extra_stylefiles(self):
|
def test_extra_stylefiles(self):
|
||||||
response = self.client_manager.get('/config/testgroupedpage1/')
|
response = self.client_manager.get('/config/testgroupedpage1/')
|
||||||
text = '<link href="/static/styles/test-config-sjNN56dFGDrg2.css" type="text/css" rel="stylesheet" />'
|
text = '<link href="/static/styles/test-config-sjNN56dFGDrg2.css" type="text/css" rel="stylesheet" />'
|
||||||
@ -232,24 +270,24 @@ class ConfigWeightTest(TestCase):
|
|||||||
self.client_manager = Client()
|
self.client_manager = Client()
|
||||||
self.client_manager.login(username='config_test_manager', password='default')
|
self.client_manager.login(username='config_test_manager', password='default')
|
||||||
|
|
||||||
def test_order_of_config_pages_abstract(self):
|
def test_order_of_config_views_abstract(self):
|
||||||
config_page_dict = {}
|
config_collection_dict = {}
|
||||||
for receiver, config_page in config_signal.send(sender=self):
|
for receiver, config_collection in config_signal.send(sender=self):
|
||||||
config_page_dict[receiver.__name__] = config_page
|
config_collection_dict[receiver.__name__] = config_collection
|
||||||
self.assertGreater(config_page_dict['set_grouped_config_page'].weight, config_page_dict['set_simple_config_page'].weight)
|
self.assertGreater(config_collection_dict['set_grouped_config_view'].weight, config_collection_dict['set_simple_config_view'].weight)
|
||||||
|
|
||||||
def test_order_of_config_pages_on_view(self):
|
def test_order_of_config_collections_on_view(self):
|
||||||
response = self.client_manager.get('/config/testgroupedpage1/')
|
response = self.client_manager.get('/config/testgroupedpage1/')
|
||||||
import re
|
import re
|
||||||
m1 = re.search('<a href="/config/testgroupedpage1/" class="btn btn-mini active">Config vars for testing 1</a>', response.content)
|
m1 = re.search('<a href="/config/testgroupedpage1/" class="btn btn-mini active">\s*Config vars for testing 1\s*</a>', response.content)
|
||||||
m2 = re.search('<a href="/config/testsimplepage1/" class="btn btn-mini ">Config vars for testing 2</a>', response.content)
|
m2 = re.search('<a href="/config/testsimplepage1/" class="btn btn-mini ">\s*Config vars for testing 2\s*</a>', response.content)
|
||||||
self.assertGreater(m1.start(), m2.start())
|
self.assertGreater(m1.start(), m2.start())
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='set_grouped_config_page_for_testing')
|
@receiver(config_signal, dispatch_uid='set_grouped_config_view_for_testing')
|
||||||
def set_grouped_config_page(sender, **kwargs):
|
def set_grouped_config_view(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Sets a grouped config page which can be reached under the url
|
Sets a grouped config collection view which can be reached under the url
|
||||||
'/config/testgroupedpage1/'. There are some variables, one variable
|
'/config/testgroupedpage1/'. 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,
|
||||||
one with an integer as default value, one with choices and one
|
one with an integer as default value, one with choices and one
|
||||||
@ -278,57 +316,62 @@ def set_grouped_config_page(sender, **kwargs):
|
|||||||
form_field=forms.ChoiceField(choices=((1, 'Choice One Ughoch4ocoche6Ee'), (2, 'Choice Two Vahnoh5yalohv5Eb'))))
|
form_field=forms.ChoiceField(choices=((1, 'Choice One Ughoch4ocoche6Ee'), (2, 'Choice Two Vahnoh5yalohv5Eb'))))
|
||||||
group_2 = ConfigGroup(title='Group 2 Toongai7ahyahy7B', variables=(hidden_var, choices_var))
|
group_2 = ConfigGroup(title='Group 2 Toongai7ahyahy7B', variables=(hidden_var, choices_var))
|
||||||
|
|
||||||
return ConfigGroupedPage(title='Config vars for testing 1',
|
return ConfigGroupedCollection(
|
||||||
url='testgroupedpage1',
|
title='Config vars for testing 1',
|
||||||
required_permission='config.can_manage',
|
url='testgroupedpage1',
|
||||||
weight=10000,
|
required_permission='config.can_manage',
|
||||||
groups=(group_1, group_2),
|
weight=10000,
|
||||||
extra_context={'extra_stylefiles': ['styles/test-config-sjNN56dFGDrg2.css'],
|
groups=(group_1, group_2),
|
||||||
'extra_javascript': ['javascript/test-config-djg4dFGVslk4209f.js']})
|
extra_context={'extra_stylefiles': ['styles/test-config-sjNN56dFGDrg2.css'],
|
||||||
|
'extra_javascript': ['javascript/test-config-djg4dFGVslk4209f.js']})
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='set_simple_config_page_for_testing')
|
@receiver(config_signal, dispatch_uid='set_simple_config_view_for_testing')
|
||||||
def set_simple_config_page(sender, **kwargs):
|
def set_simple_config_view(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Sets a simple config page with some config variables but without
|
Sets a simple config view with some config variables but without
|
||||||
grouping.
|
grouping.
|
||||||
"""
|
"""
|
||||||
return ConfigPage(title='Config vars for testing 2',
|
return ConfigCollection(
|
||||||
url='testsimplepage1',
|
title='Config vars for testing 2',
|
||||||
required_permission='No permission required',
|
url='testsimplepage1',
|
||||||
variables=(ConfigVariable(name='additional_config_var', default_value='BaeB0ahcMae3feem'),
|
required_permission='No permission required',
|
||||||
ConfigVariable(name='additional_config_var_2', default_value='', form_field=forms.CharField()),
|
variables=(ConfigVariable(name='additional_config_var', default_value='BaeB0ahcMae3feem'),
|
||||||
ConfigVariable(name='none_config_var', default_value=None)))
|
ConfigVariable(name='additional_config_var_2', default_value='', form_field=forms.CharField()),
|
||||||
|
ConfigVariable(name='none_config_var', default_value=None)))
|
||||||
|
|
||||||
|
|
||||||
# Do not connect to the signal now but later inside the test.
|
# Do not connect to the signal now but later inside the test.
|
||||||
def set_simple_config_page_multiple_vars(sender, **kwargs):
|
def set_simple_config_view_multiple_vars(sender, **kwargs):
|
||||||
"""
|
"""
|
||||||
Sets a bad config page with some multiple config vars.
|
Sets a bad config view with some multiple config vars.
|
||||||
"""
|
"""
|
||||||
return ConfigPage(title='Config vars for testing 3',
|
return ConfigCollection(
|
||||||
url='testsimplepage2',
|
title='Config vars for testing 3',
|
||||||
required_permission='No permission required',
|
url='testsimplepage2',
|
||||||
variables=(ConfigVariable(name='multiple_config_var', default_value='foobar1'),
|
required_permission='No permission required',
|
||||||
ConfigVariable(name='multiple_config_var', default_value='foobar2')))
|
variables=(ConfigVariable(name='multiple_config_var', default_value='foobar1'),
|
||||||
|
ConfigVariable(name='multiple_config_var', default_value='foobar2')))
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='set_simple_config_page_disabled_page_for_testing')
|
@receiver(config_signal, dispatch_uid='set_simple_config_collection_disabled_view_for_testing')
|
||||||
def set_simple_config_page_disabled_page(sender, **kwargs):
|
def set_simple_config_collection_disabled_view(sender, **kwargs):
|
||||||
return ConfigPage(title='Ho5iengaoon5Hoht',
|
return ConfigCollection(
|
||||||
url='testsimplepage3',
|
title='Ho5iengaoon5Hoht',
|
||||||
required_permission='No permission required',
|
url='testsimplepage3',
|
||||||
variables=(ConfigVariable(name='hidden_config_var_2', default_value=''),))
|
required_permission='No permission required',
|
||||||
|
variables=(ConfigVariable(name='hidden_config_var_2', default_value=''),))
|
||||||
|
|
||||||
|
|
||||||
@receiver(config_signal, dispatch_uid='set_simple_config_page_with_callback_for_testing')
|
@receiver(config_signal, dispatch_uid='set_simple_config_collection_with_callback_for_testing')
|
||||||
def set_simple_config_page_with_callback(sender, **kwargs):
|
def set_simple_config_collection_with_callback(sender, **kwargs):
|
||||||
def callback():
|
def callback():
|
||||||
raise Exception('Change callback dhcnfg34dlg06kdg successfully called.')
|
raise Exception('Change callback dhcnfg34dlg06kdg successfully called.')
|
||||||
return ConfigPage(title='Hvndfhsbgkridfgdfg',
|
return ConfigCollection(
|
||||||
url='testsimplepage4',
|
title='Hvndfhsbgkridfgdfg',
|
||||||
required_permission='No permission required',
|
url='testsimplepage4',
|
||||||
variables=(ConfigVariable(
|
required_permission='No permission required',
|
||||||
name='var_with_callback_ghvnfjd5768gdfkwg0hm2',
|
variables=(ConfigVariable(
|
||||||
default_value='',
|
name='var_with_callback_ghvnfjd5768gdfkwg0hm2',
|
||||||
on_change=callback),))
|
default_value='',
|
||||||
|
on_change=callback),))
|
||||||
|
Loading…
Reference in New Issue
Block a user