Merge pull request #1582 from ostcar/config_accept_str_as_int

Let the config app accept values that can be converted to the right type
This commit is contained in:
Oskar Hahn 2015-06-29 15:54:58 +02:00
commit d3e5f2695c
5 changed files with 34 additions and 14 deletions

View File

@ -60,7 +60,11 @@ class ConfigHandler:
# 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]
if not isinstance(value, expected_type):
# Try to convert value into the expected datatype
try:
value = expected_type(value)
except ValueError:
raise ConfigError(_('Wrong datatype. Expected %s, got %s.') % (expected_type, type(value))) raise ConfigError(_('Wrong datatype. Expected %s, got %s.') % (expected_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' and value not in map(lambda choice: choice['value'], config_variable.choices):
raise ConfigError(_('Invalid input. Choice does not match.')) raise ConfigError(_('Invalid input. Choice does not match.'))

View File

@ -250,7 +250,7 @@ angular.module('OpenSlidesApp.core.site', ['OpenSlidesApp.core'])
controller: 'ConfigCtrl', controller: 'ConfigCtrl',
resolve: { resolve: {
configOption: function($http) { configOption: function($http) {
return $http({ 'method': 'OPTIONS', 'url': '/rest/config/config/' }); return $http({ 'method': 'OPTIONS', 'url': '/rest/core/config/' });
} }
} }
}) })
@ -351,7 +351,7 @@ angular.module('OpenSlidesApp.core.site', ['OpenSlidesApp.core'])
string: 'text', string: 'text',
integer: 'number', integer: 'number',
boolean: 'checkbox', boolean: 'checkbox',
choice: 'radio', choice: 'choice',
}[type]; }[type];
} }
@ -363,8 +363,11 @@ angular.module('OpenSlidesApp.core.site', ['OpenSlidesApp.core'])
var field = $parse(iAttrs.field)($scope); var field = $parse(iAttrs.field)($scope);
var config = Config.get(field.key); var config = Config.get(field.key);
$scope.type = getHtmlType(field.input_type); $scope.type = getHtmlType(field.input_type);
if ($scope.type == 'choice') {
$scope.choices = field.choices;
}
$scope.label = field.label; $scope.label = field.label;
$scope.id = 'field-' + field.id; $scope.key = 'field-' + field.key;
$scope.value = config.value; $scope.value = config.value;
$scope.help_text = field.help_text; $scope.help_text = field.help_text;
} }
@ -433,12 +436,7 @@ angular.module('OpenSlidesApp.core.site', ['OpenSlidesApp.core'])
$scope.configGroups = configOption.data.config_groups; $scope.configGroups = configOption.data.config_groups;
// save changed config value // save changed config value
$scope.save = function(key, value, type) { $scope.save = function(key, value) {
// TODO: find a better way to check the type without using of
// the extra parameter 'type' from template
if (type == 'number') {
value = parseInt(value);
}
Config.get(key).value = value; Config.get(key).value = value;
Config.save(key); Config.save(key);
} }

View File

@ -2,10 +2,15 @@
<label>{{ label }}</label> <label>{{ label }}</label>
<div class="input-group"> <div class="input-group">
<input ng-model="value" ng-change="save(configOption.key, value, type)" id="{{ id }}" type="{{ type }}" <input ng-if="type != 'choice'" ng-model="value" ng-change="save(configOption.key, value)" id="{{ key }}" type="{{ type }}"
class="form-control"> class="form-control">
<select ng-if="type == 'choice'" ng-model="value" ng-change="save(configOption.key, value)" id="{{ key }}"
class="form-control" ng-options="option.value as option.display_name for option in choices">
</select>
<span class="input-group-btn"> <span class="input-group-btn">
<button ng-click="value=configOption.default_value; save(configOption.key, configOption.default_value, type)" class="btn btn-default" translate> <button ng-click="value=configOption.default_value; save(configOption.key, configOption.default_value)" class="btn btn-default" translate>
<i class="fa fa-undo"></i> <i class="fa fa-undo"></i>
<translate>Reset</translate> <translate>Reset</translate>
</button> </button>

View File

@ -11,7 +11,7 @@
{{ group.name }} {{ group.name }}
</a> </a>
</h4> </h4>
</div> </div> <!-- heading -->
<div id="{{ group.name }}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-{{ group.name }}"> <div id="{{ group.name }}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-{{ group.name }}">
<div class="panel-body"> <div class="panel-body">
<div ng-repeat="subgroup in group.subgroups"> <div ng-repeat="subgroup in group.subgroups">
@ -21,7 +21,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div> <!-- group.name -->
</div> </div>
</div> </div>
</div>

View File

@ -97,6 +97,18 @@ class ConfigViewSet(TestCase):
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.data, {'detail': "Wrong datatype. Expected <class 'int'>, got <class 'str'>."}) self.assertEqual(response.data, {'detail': "Wrong datatype. Expected <class 'int'>, got <class 'str'>."})
def test_update_wrong_datatype_that_can_be_converted(self):
"""
Try to send a string that can be converted to an integer to an integer
field.
"""
self.client = APIClient()
self.client.login(username='admin', password='admin')
response = self.client.put(
reverse('config-detail', args=['test_var_ohhii4iavoh5Phoh5ahg']),
{'value': '12345'})
self.assertEqual(response.status_code, 200)
def test_update_good_choice(self): def test_update_good_choice(self):
self.client = APIClient() self.client = APIClient()
self.client.login(username='admin', password='admin') self.client.login(username='admin', password='admin')