Merge pull request #1529 from normanjaeckel/RESTConfig
Added config update view.
This commit is contained in:
commit
1ccd2ab91c
@ -36,6 +36,7 @@ Other:
|
||||
- Refactored projector API using metaclasses now.
|
||||
- Renamed SignalConnectMetaClass classmethod get_all_objects to get_all
|
||||
(private API).
|
||||
- Refactored config API.
|
||||
- Used AngularJS with additional libraries for single page frontend.
|
||||
- Removed use of 'django.views.i18n.javascript_catalog'. Used angular-gettext
|
||||
now.
|
||||
|
@ -19,25 +19,21 @@ class ConfigHandler(object):
|
||||
return self[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
# Save the new value to the database
|
||||
# Check if the variable is defined.
|
||||
if key not in self:
|
||||
raise ConfigNotFound('The config variable %s was not found.' % key)
|
||||
|
||||
# Save the new value to the database.
|
||||
updated_rows = ConfigStore.objects.filter(key=key).update(value=value)
|
||||
if not updated_rows:
|
||||
ConfigStore.objects.create(key=key, value=value)
|
||||
|
||||
# Update cache
|
||||
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
|
||||
# Update cache.
|
||||
self._cache[key] = value
|
||||
|
||||
# Call on_change callback
|
||||
for receiver, config_collection in config_signal.send(sender='set_value'):
|
||||
for config_variable in config_collection.variables:
|
||||
if config_variable.name == key and config_variable.on_change:
|
||||
config_variable.on_change()
|
||||
break
|
||||
# Call on_change callback.
|
||||
if self.get_config_variables()[key].on_change:
|
||||
self.get_config_variables()[key].on_change()
|
||||
|
||||
def items(self):
|
||||
"""
|
||||
@ -47,15 +43,27 @@ class ConfigHandler(object):
|
||||
self.setup_cache()
|
||||
return self._cache.items()
|
||||
|
||||
def get_config_variables(self):
|
||||
"""
|
||||
Returns a dictionary with all ConfigVariable instances of all
|
||||
collections. The key is the name of the config variables.
|
||||
"""
|
||||
result = {}
|
||||
for receiver, config_collection in config_signal.send(sender='get_config_variables'):
|
||||
for config_variable in config_collection.variables:
|
||||
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_default(self, key):
|
||||
"""
|
||||
Returns the default value for 'key'.
|
||||
"""
|
||||
for receiver, config_collection in config_signal.send(sender='get_default'):
|
||||
for config_variable in config_collection.variables:
|
||||
if config_variable.name == key:
|
||||
return config_variable.default_value
|
||||
raise ConfigNotFound('The config variable %s was not found.' % key)
|
||||
try:
|
||||
return self.get_config_variables()[key].default_value
|
||||
except KeyError:
|
||||
raise ConfigNotFound('The config variable %s was not found.' % key)
|
||||
|
||||
def setup_cache(self):
|
||||
"""
|
||||
@ -63,11 +71,8 @@ class ConfigHandler(object):
|
||||
save the default to the cache.
|
||||
"""
|
||||
self._cache = {}
|
||||
for receiver, config_collection in config_signal.send(sender='setup_cache'):
|
||||
for config_variable in config_collection.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 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
|
||||
|
||||
@ -84,10 +89,9 @@ class ConfigHandler(object):
|
||||
Generator to get all config variables as strings when their values are
|
||||
intended to be translated.
|
||||
"""
|
||||
for receiver, config_collection in config_signal.send(sender='get_all_translatable'):
|
||||
for config_variable in config_collection.variables:
|
||||
if config_variable.translatable:
|
||||
yield config_variable.name
|
||||
for config_variable in self.get_config_variables().values():
|
||||
if config_variable.translatable:
|
||||
yield config_variable.name
|
||||
|
||||
config = ConfigHandler()
|
||||
"""
|
||||
|
@ -1,10 +1,11 @@
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
from django.http import Http404
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from openslides.utils.rest_api import Response, ViewSet
|
||||
from openslides.utils.rest_api import Response, ValidationError, ViewSet
|
||||
from openslides.utils.views import FormView
|
||||
|
||||
from .api import config
|
||||
@ -119,7 +120,7 @@ class ConfigViewSet(ViewSet):
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
"""
|
||||
Retrieves one config variable.
|
||||
Retrieves one config variable. Everybody can see it.
|
||||
"""
|
||||
# TODO: Check if we need permission check here.
|
||||
key = kwargs['pk']
|
||||
@ -129,12 +130,32 @@ class ConfigViewSet(ViewSet):
|
||||
raise Http404
|
||||
return Response(data)
|
||||
|
||||
def update(self, request, pk=None):
|
||||
def update(self, request, *args, **kwargs):
|
||||
"""
|
||||
TODO
|
||||
Updates one config variable. Only managers can do this.
|
||||
|
||||
Example: {"value": 42}
|
||||
"""
|
||||
# Check permission.
|
||||
if not request.user.has_perm('config.can_manage'):
|
||||
self.permission_denied(request)
|
||||
else:
|
||||
# TODO: Implement update method
|
||||
self.permission_denied(request)
|
||||
|
||||
# Check if pk is a valid config variable key.
|
||||
key = kwargs['pk']
|
||||
if key not in config:
|
||||
raise Http404
|
||||
|
||||
# Validate value.
|
||||
form_field = config.get_config_variables()[key].form_field
|
||||
value = request.data['value']
|
||||
if form_field:
|
||||
try:
|
||||
form_field.clean(value)
|
||||
except DjangoValidationError as e:
|
||||
raise ValidationError({'detail': e.messages[0]})
|
||||
|
||||
# Change value.
|
||||
config[key] = value
|
||||
|
||||
# Return response.
|
||||
return Response({'key': key, 'value': value})
|
||||
|
0
tests/integration/config/__init__.py
Normal file
0
tests/integration/config/__init__.py
Normal file
60
tests/integration/config/test_views.py
Normal file
60
tests/integration/config/test_views.py
Normal file
@ -0,0 +1,60 @@
|
||||
from django import forms
|
||||
from django.dispatch import receiver
|
||||
from django.core.urlresolvers import reverse
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from openslides.config.api import config, ConfigCollection, ConfigVariable
|
||||
from openslides.config.signals import config_signal
|
||||
from openslides.utils.test import TestCase
|
||||
|
||||
|
||||
class ConfigViewSet(TestCase):
|
||||
"""
|
||||
Tests requests to deal with config variables.
|
||||
"""
|
||||
def test_retrieve(self):
|
||||
self.client.login(username='admin', password='admin')
|
||||
config['test_var_aeW3Quahkah1phahCheo'] = 'test_value_Oovoojieme7eephaed2A'
|
||||
response = self.client.get(reverse('config-detail', args=['test_var_aeW3Quahkah1phahCheo']))
|
||||
self.assertEqual(
|
||||
response.data,
|
||||
{'key': 'test_var_aeW3Quahkah1phahCheo',
|
||||
'value': 'test_value_Oovoojieme7eephaed2A'})
|
||||
|
||||
def test_update(self):
|
||||
self.client = APIClient()
|
||||
self.client.login(username='admin', password='admin')
|
||||
response = self.client.put(
|
||||
reverse('config-detail', args=['test_var_Xeiizi7ooH8Thuk5aida']),
|
||||
{'value': 'test_value_Phohx3oopeichaiTheiw'})
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(config['test_var_Xeiizi7ooH8Thuk5aida'], 'test_value_Phohx3oopeichaiTheiw')
|
||||
|
||||
def test_update_wrong_datatype(self):
|
||||
self.client = APIClient()
|
||||
self.client.login(username='admin', password='admin')
|
||||
response = self.client.put(
|
||||
reverse('config-detail', args=['test_var_ohhii4iavoh5Phoh5ahg']),
|
||||
{'value': 'test_value_string'})
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
self.assertEqual(response.data, {'detail': 'Enter a whole number.'})
|
||||
|
||||
|
||||
@receiver(config_signal, dispatch_uid='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
|
||||
grouping.
|
||||
"""
|
||||
return ConfigCollection(
|
||||
title='Config vars for testing',
|
||||
url='test_url_ieXao5Wae5Duoy6Wohtu',
|
||||
variables=(ConfigVariable(name='test_var_aeW3Quahkah1phahCheo',
|
||||
default_value=None),
|
||||
ConfigVariable(name='test_var_Xeiizi7ooH8Thuk5aida',
|
||||
default_value='',
|
||||
form_field=forms.CharField()),
|
||||
ConfigVariable(name='test_var_ohhii4iavoh5Phoh5ahg',
|
||||
default_value=0,
|
||||
form_field=forms.IntegerField())))
|
@ -67,9 +67,9 @@ class HandleConfigTest(TestCase):
|
||||
|
||||
def test_set_value_before_getting_it(self):
|
||||
"""
|
||||
Try to call __setitem__ before __getitem.
|
||||
Try to call __setitem__ before __getitem__.
|
||||
"""
|
||||
config['my_config_var'] = 'value'
|
||||
config['additional_config_var'] = 'value'
|
||||
|
||||
def test_on_change(self):
|
||||
"""
|
||||
|
@ -1,6 +1,8 @@
|
||||
from django.dispatch import receiver
|
||||
from django.template import Context, Template
|
||||
|
||||
from openslides.config.api import config
|
||||
from openslides.config.api import ConfigCollection, ConfigVariable, config
|
||||
from openslides.config.signals import config_signal
|
||||
from openslides.utils.test import TestCase
|
||||
|
||||
|
||||
@ -27,3 +29,18 @@ class ConfigTagAndFilter(TestCase):
|
||||
template = Template(template_code)
|
||||
self.assertTrue('FdgfkR04jtg9f8bq' in template.render(Context({})))
|
||||
self.assertFalse('bad_e0fvkfHFD' in template.render(Context({})))
|
||||
|
||||
|
||||
@receiver(config_signal, dispatch_uid='set_simple_config_view_template_tag_test')
|
||||
def set_simple_config_view_template_tag_test(sender, **kwargs):
|
||||
"""
|
||||
Sets a simple config view with some config variables but without
|
||||
grouping.
|
||||
"""
|
||||
return ConfigCollection(
|
||||
title='Config vars for testing with template tag',
|
||||
url='testsimplepagetemplatetag',
|
||||
variables=(ConfigVariable(name='taiNg3reQuooGha4', default_value=None),
|
||||
ConfigVariable(name='fkjTze56ncuejWqs', default_value=None),
|
||||
ConfigVariable(name='jfhsnezfh452w6Fg', default_value=None),
|
||||
ConfigVariable(name='sdmvldkfgj4534gk', default_value=None)))
|
||||
|
Loading…
Reference in New Issue
Block a user