mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-19 05:58:34 +02:00
Better parameters management.
This commit is contained in:
+15
-5
@@ -18,14 +18,24 @@ export const updateDomain = data => {
|
||||
}
|
||||
|
||||
var customParametersActions = {
|
||||
applications: {method: 'GET', url: '/api/v1/parameters/applications/'},
|
||||
structure: {method: 'GET', url: '/api/v1/parameters/structure/'}
|
||||
}
|
||||
var parametersResource = Vue.resource('/api/v1/parameters/', {}, customParametersActions)
|
||||
var parametersResource = Vue.resource(
|
||||
'/api/v1/parameters{/app}/', {}, customParametersActions)
|
||||
|
||||
export const getParameters = () => {
|
||||
return parametersResource.get()
|
||||
export const getParametersForApplication = (app) => {
|
||||
return parametersResource.get({app: app})
|
||||
}
|
||||
|
||||
export const getParametersStructure = () => {
|
||||
return parametersResource.structure()
|
||||
export const getParametersApplications = () => {
|
||||
return parametersResource.applications()
|
||||
}
|
||||
|
||||
export const getParametersStructure = (app) => {
|
||||
return parametersResource.structure({app: app})
|
||||
}
|
||||
|
||||
export const saveParametersForApplication = (app, values) => {
|
||||
return parametersResource.update({app: app}, values)
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
v-else-if="item.children"
|
||||
v-model="item.model"
|
||||
:key="item.text"
|
||||
:prepend-icon="item.model ? item.icon : item['icon-alt']"
|
||||
append-icon=""
|
||||
:prepend-icon="item.icon"
|
||||
:append-icon="item['icon-alt']"
|
||||
>
|
||||
<v-list-tile slot="activator">
|
||||
<v-list-tile-content>
|
||||
@@ -66,6 +66,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as api from '@/api'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
@@ -78,8 +80,7 @@ export default {
|
||||
{
|
||||
text: 'Domains',
|
||||
to: { name: 'DomainList' },
|
||||
icon: 'domain',
|
||||
model: true
|
||||
icon: 'domain'
|
||||
},
|
||||
{
|
||||
text: 'Identities',
|
||||
@@ -90,12 +91,22 @@ export default {
|
||||
text: 'Logs'
|
||||
},
|
||||
{
|
||||
to: { name: 'ParametersEdit' },
|
||||
icon: 'settings',
|
||||
text: 'Parameters'
|
||||
text: 'Parameters',
|
||||
children: []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created () {
|
||||
api.getParametersApplications().then(response => {
|
||||
response.data.forEach(item => {
|
||||
this.items[4].children.push({
|
||||
text: item.label,
|
||||
to: { name: 'ParametersEdit', params: {app: item.name} }
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,36 +1,57 @@
|
||||
<template>
|
||||
<v-layout>
|
||||
<v-layout row wrap>
|
||||
<v-flex>
|
||||
<h1 class="title">Parameters</h1>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-content
|
||||
v-for="(element, index) in structure"
|
||||
:key="index"
|
||||
<h1>Parameters</h1>
|
||||
<v-tabs v-model="active">
|
||||
<v-tab v-for="(element, index) in structure"
|
||||
:key="index"
|
||||
|
||||
v-if="display(element)"
|
||||
>
|
||||
<div slot="header">{{ element.label }}</div>
|
||||
<v-card>
|
||||
<v-card-text>
|
||||
<v-text-field v-for="(param, index) in element.parameters"
|
||||
:label="param.label"
|
||||
:key="index"
|
||||
:hint="param.help_text"
|
||||
{{ element.label }}
|
||||
</v-tab>
|
||||
<v-tabs-items>
|
||||
<v-tab-item
|
||||
v-for="(element, index) in structure"
|
||||
:key="index"
|
||||
v-if="display(element)"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-text>
|
||||
<v-text-field v-for="(param, index) in element.parameters"
|
||||
:label="param.label"
|
||||
:key="index"
|
||||
:hint="param.help_text"
|
||||
v-model="parameters[param.name]"
|
||||
:error="formErrors[param.name] !== undefined"
|
||||
:error-messages="formErrors[param.name]"
|
||||
v-if="(param.widget === 'CharField' || param.widget === 'IntegerField') && display(param)">
|
||||
</v-text-field>
|
||||
<v-checkbox :label="param.label"
|
||||
v-model="parameters[param.name]"
|
||||
v-if="param.widget === 'CharField' || param.widget === 'IntegerField'">
|
||||
</v-text-field>
|
||||
<v-checkbox :label="param.label"
|
||||
v-else-if="param.widget === 'BooleanField' && display(param)"
|
||||
>
|
||||
</v-checkbox>
|
||||
<v-select :label="param.label"
|
||||
v-model="parameters[param.name]"
|
||||
v-else-if="param.widget === 'BooleanField'"
|
||||
>
|
||||
</v-checkbox>
|
||||
<v-select :label="param.label"
|
||||
v-model="parameters[param.name]"
|
||||
:items="param.choices"
|
||||
v-else-if="param.widget === 'ChoiceField'">
|
||||
</v-select>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
:items="param.choices"
|
||||
v-else-if="param.widget === 'ChoiceField' && display(param)">
|
||||
</v-select>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</v-tabs>
|
||||
<v-btn fixed
|
||||
dark
|
||||
fab
|
||||
bottom
|
||||
right
|
||||
color="green"
|
||||
@click="save"
|
||||
>
|
||||
<v-icon>save</v-icon>
|
||||
</v-btn>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</template>
|
||||
@@ -41,17 +62,37 @@ import * as api from '@/api'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
active: 0,
|
||||
structure: [],
|
||||
parameters: {}
|
||||
parameters: {},
|
||||
formErrors: {}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
api.getParametersStructure().then(response => {
|
||||
var app = this.$route.params.app
|
||||
api.getParametersStructure(app).then(response => {
|
||||
this.structure = response.data
|
||||
})
|
||||
api.getParameters().then(response => {
|
||||
api.getParametersForApplication(app).then(response => {
|
||||
this.parameters = response.data
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
display (element) {
|
||||
if (element.display === '') {
|
||||
return true
|
||||
}
|
||||
var [field, value] = element.display.split('=')
|
||||
return this.parameters[field] === value
|
||||
},
|
||||
save () {
|
||||
api.saveParametersForApplication(
|
||||
this.$route.params.app, this.parameters
|
||||
).then(response => {
|
||||
}, response => {
|
||||
this.formErrors = response.data
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -24,7 +24,7 @@ export default new Router({
|
||||
component: DomainForm
|
||||
},
|
||||
{
|
||||
path: '/parameters/',
|
||||
path: '/parameters/:app',
|
||||
name: 'ParametersEdit',
|
||||
component: ParametersForm
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import collections
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import password_validation
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from modoboa.lib import fields as lib_fields
|
||||
from modoboa.lib.form_utils import (
|
||||
HorizontalRadioSelect, SeparatorField, YesNoField
|
||||
@@ -445,178 +445,135 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
|
||||
settings.AUTH_LDAP_GLOBAL_OPTIONS[ldap.OPT_REFERRALS] = False
|
||||
|
||||
|
||||
GLOBAL_PARAMETERS = {
|
||||
"authentication": {
|
||||
GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([
|
||||
("authentication", {
|
||||
"label": ugettext_lazy("Authentication"),
|
||||
"params": {
|
||||
"authentication_type": {
|
||||
"field": serializers.ChoiceField(
|
||||
choices=[("local", ugettext_lazy("Local")),
|
||||
("ldap", "LDAP")],
|
||||
default="local"
|
||||
),
|
||||
"params": collections.OrderedDict([
|
||||
("authentication_type", {
|
||||
"label": ugettext_lazy("Authentication type"),
|
||||
"help_text": ugettext_lazy(
|
||||
"The backend used for authentication"),
|
||||
},
|
||||
"password_scheme": {
|
||||
}),
|
||||
("password_scheme", {
|
||||
"label": ugettext_lazy("Default password scheme"),
|
||||
"field": serializers.ChoiceField(
|
||||
choices=[("sha512crypt", "sha512crypt"),
|
||||
("sha256crypt", "sha256crypt"),
|
||||
("blfcrypt", "bcrypt"),
|
||||
("md5crypt", ugettext_lazy("md5crypt (weak)")),
|
||||
("sha256", ugettext_lazy("sha256 (weak)")),
|
||||
("md5", ugettext_lazy("md5 (weak)")),
|
||||
("crypt", ugettext_lazy("crypt (weak)")),
|
||||
("plain", ugettext_lazy("plain (weak)"))],
|
||||
default="sha512crypt"
|
||||
),
|
||||
"help_text": ugettext_lazy(
|
||||
"Scheme used to crypt mailbox passwords"),
|
||||
},
|
||||
"rounds_number": {
|
||||
}),
|
||||
("rounds_number", {
|
||||
"label": ugettext_lazy("Rounds"),
|
||||
"field": serializers.IntegerField(default=70000),
|
||||
"help_text": ugettext_lazy(
|
||||
"Number of rounds to use (only used by sha256crypt and "
|
||||
"sha512crypt). Must be between 1000 and 999999999, "
|
||||
"inclusive."
|
||||
)
|
||||
},
|
||||
"default_password": {
|
||||
}),
|
||||
("default_password", {
|
||||
"label": ugettext_lazy("Default password"),
|
||||
"field": serializers.CharField(default="password"),
|
||||
"help_text": ugettext_lazy(
|
||||
"Default password for automatically created accounts.")
|
||||
},
|
||||
"random_password_length": {
|
||||
}),
|
||||
("random_password_length", {
|
||||
"label": ugettext_lazy("Random password length"),
|
||||
"field": serializers.IntegerField(min_value=8, default=8),
|
||||
"help_text": ugettext_lazy(
|
||||
"Length of randomly generated passwords.")
|
||||
}
|
||||
}
|
||||
},
|
||||
"ldap": {
|
||||
})
|
||||
])
|
||||
}),
|
||||
("ldap", {
|
||||
"label": _("LDAP"),
|
||||
"display": "authentication_type=ldap",
|
||||
"params": {
|
||||
"ldap_server_address": {
|
||||
"params": collections.OrderedDict([
|
||||
("ldap_server_address", {
|
||||
"label": ugettext_lazy("Server address"),
|
||||
"field": serializers.CharField(default="localhost"),
|
||||
"help_text": ugettext_lazy(
|
||||
"The IP address or the DNS name of the LDAP server"),
|
||||
},
|
||||
"ldap_server_port": {
|
||||
}),
|
||||
("ldap_server_port", {
|
||||
"label": ugettext_lazy("Server port"),
|
||||
"field": serializers.IntegerField(default=389),
|
||||
"help_text": ugettext_lazy(
|
||||
"The TCP port number used by the LDAP server")
|
||||
},
|
||||
"ldap_secured": {
|
||||
}),
|
||||
("ldap_secured", {
|
||||
"label": ugettext_lazy("Use a secured connection"),
|
||||
"field": serializers.ChoiceField(
|
||||
choices=constants.LDAP_SECURE_MODES,
|
||||
default="none"
|
||||
),
|
||||
"help_text": ugettext_lazy(
|
||||
"Use an SSL/STARTTLS connection to access the LDAP server")
|
||||
},
|
||||
"ldap_auth_method": {
|
||||
}),
|
||||
("ldap_auth_method", {
|
||||
"label": ugettext_lazy("Authentication method"),
|
||||
"field": serializers.ChoiceField(
|
||||
choices=constants.LDAP_AUTH_METHODS,
|
||||
default="searchbind",
|
||||
),
|
||||
"help_text": ugettext_lazy(
|
||||
"Choose the authentication method to use"),
|
||||
},
|
||||
"ldap_bind_dn": {
|
||||
}),
|
||||
("ldap_bind_dn", {
|
||||
"label": ugettext_lazy("Bind DN"),
|
||||
"field": serializers.CharField(default="", required=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"The distinguished name to use when binding to the LDAP "
|
||||
"server. Leave empty for an anonymous bind"
|
||||
),
|
||||
"display": "ldap_auth_method=searchbind"
|
||||
},
|
||||
"ldap_bind_password": {
|
||||
}),
|
||||
("ldap_bind_password", {
|
||||
"label": ugettext_lazy("Bind password"),
|
||||
"field": serializers.CharField(default="", required=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"The password to use when binding to the LDAP server "
|
||||
"(with 'Bind DN')"
|
||||
),
|
||||
"display": "ldap_auth_method=searchbind"
|
||||
},
|
||||
"ldap_search_base": {
|
||||
}),
|
||||
("ldap_search_base", {
|
||||
"label": ugettext_lazy("Users search base"),
|
||||
"field": serializers.CharField(default="", required=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"The distinguished name of the search base used to find "
|
||||
"users"
|
||||
),
|
||||
"display": "ldap_auth_method=searchbind"
|
||||
},
|
||||
"ldap_search_filter": {
|
||||
}),
|
||||
("ldap_search_filter", {
|
||||
"label": ugettext_lazy("Search filter"),
|
||||
"field": serializers.CharField(
|
||||
default="(mail=%(user)s)", required=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"An optional filter string (e.g. '(objectClass=person)'). "
|
||||
"In order to be valid, it must be enclosed in parentheses."
|
||||
),
|
||||
"display": "ldap_auth_method=searchbind"
|
||||
},
|
||||
"ldap_user_dn_template": {
|
||||
}),
|
||||
("ldap_user_dn_template", {
|
||||
"label": ugettext_lazy("User DN template"),
|
||||
"field": serializers.CharField(default="", required=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"The template used to construct a user's DN. It should "
|
||||
"contain one placeholder (ie. %(user)s)"
|
||||
),
|
||||
"display": "ldap_auth_method=directbind"
|
||||
},
|
||||
"ldap_password_attribute": {
|
||||
}),
|
||||
("ldap_password_attribute", {
|
||||
"label": ugettext_lazy("Password attribute"),
|
||||
"field": serializers.CharField(default="userPassword"),
|
||||
"help_text": ugettext_lazy(
|
||||
"The attribute used to store user passwords"),
|
||||
},
|
||||
"ldap_is_active_directory": {
|
||||
}),
|
||||
("ldap_is_active_directory", {
|
||||
"label": ugettext_lazy("Active Directory"),
|
||||
"field": serializers.BooleanField(default=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"Tell if the LDAP server is an Active Directory one")
|
||||
},
|
||||
"ldap_admin_groups": {
|
||||
}),
|
||||
("ldap_admin_groups", {
|
||||
"label": ugettext_lazy("Administrator groups"),
|
||||
"field": serializers.CharField(default="", required=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"Members of those LDAP Posix groups will be created as "
|
||||
"domain administrators. Use ';' characters to separate "
|
||||
"groups."
|
||||
)
|
||||
},
|
||||
"ldap_group_type": {
|
||||
}),
|
||||
("ldap_group_type", {
|
||||
"label": ugettext_lazy("Group type"),
|
||||
"field": serializers.ChoiceField(
|
||||
default="posixgroup",
|
||||
choices=constants.LDAP_GROUP_TYPES
|
||||
),
|
||||
"help_text": ugettext_lazy(
|
||||
"The LDAP group type to use with your directory."
|
||||
)
|
||||
},
|
||||
"ldap_groups_search_base": {
|
||||
}),
|
||||
("ldap_groups_search_base", {
|
||||
"label": ugettext_lazy("Groups search base"),
|
||||
"field": serializers.CharField(default="", required=False),
|
||||
"help_text": ugettext_lazy(
|
||||
"The distinguished name of the search base used to find "
|
||||
"groups"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
])
|
||||
})
|
||||
])
|
||||
|
||||
@@ -17,12 +17,14 @@ def load_core_settings():
|
||||
"""
|
||||
from modoboa.parameters import tools as param_tools
|
||||
from . import app_settings
|
||||
from . import serializers
|
||||
|
||||
param_tools.registry.add(
|
||||
"global", app_settings.GeneralParametersForm, ugettext_lazy("General"))
|
||||
param_tools.registry.add2(
|
||||
"global", "core", ugettext_lazy("General"),
|
||||
app_settings.GLOBAL_PARAMETERS)
|
||||
app_settings.GLOBAL_PARAMETERS_STRUCT,
|
||||
serializers.CoreGlobalParametersSerializer)
|
||||
|
||||
|
||||
class CoreConfig(AppConfig):
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
"""Core serializers."""
|
||||
|
||||
from django.utils.translation import ugettext_lazy, ugettext as _
|
||||
|
||||
from django.contrib.auth import password_validation
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from . import constants
|
||||
|
||||
|
||||
class CoreGlobalParametersSerializer(serializers.Serializer):
|
||||
"""A serializer for global parameters."""
|
||||
|
||||
# General settings
|
||||
authentication_type = serializers.ChoiceField(
|
||||
choices=[("local", ugettext_lazy("Local")),
|
||||
("ldap", "LDAP")],
|
||||
default="local"
|
||||
)
|
||||
password_scheme = serializers.ChoiceField(
|
||||
choices=[("sha512crypt", "sha512crypt"),
|
||||
("sha256crypt", "sha256crypt"),
|
||||
("blfcrypt", "bcrypt"),
|
||||
("md5crypt", ugettext_lazy("md5crypt (weak)")),
|
||||
("sha256", ugettext_lazy("sha256 (weak)")),
|
||||
("md5", ugettext_lazy("md5 (weak)")),
|
||||
("crypt", ugettext_lazy("crypt (weak)")),
|
||||
("plain", ugettext_lazy("plain (weak)"))],
|
||||
default="sha512crypt"
|
||||
)
|
||||
rounds_number = serializers.IntegerField(default=70000)
|
||||
default_password = serializers.CharField(default="password")
|
||||
random_password_length = serializers.IntegerField(min_value=8, default=8)
|
||||
|
||||
# LDAP settings
|
||||
ldap_server_address = serializers.CharField(default="localhost")
|
||||
ldap_server_port = serializers.IntegerField(default=389)
|
||||
ldap_secured = serializers.ChoiceField(
|
||||
choices=constants.LDAP_SECURE_MODES,
|
||||
default="none"
|
||||
)
|
||||
ldap_auth_method = serializers.ChoiceField(
|
||||
choices=constants.LDAP_AUTH_METHODS,
|
||||
default="searchbind",
|
||||
)
|
||||
ldap_bind_dn = serializers.CharField(
|
||||
default="", required=False, allow_blank=True)
|
||||
ldap_bind_password = serializers.CharField(
|
||||
default="", required=False, allow_blank=True)
|
||||
ldap_search_base = serializers.CharField(
|
||||
default="", required=False, allow_blank=True)
|
||||
ldap_search_filter = serializers.CharField(
|
||||
default="(mail=%(user)s)", required=False,
|
||||
allow_blank=True)
|
||||
ldap_user_dn_template = serializers.CharField(
|
||||
default="", required=False, allow_blank=True)
|
||||
ldap_password_attribute = serializers.CharField(default="userPassword")
|
||||
ldap_is_active_directory = serializers.BooleanField(default=False)
|
||||
ldap_admin_groups = serializers.CharField(
|
||||
default="", required=False, allow_blank=True)
|
||||
ldap_group_type = serializers.ChoiceField(
|
||||
default="posixgroup",
|
||||
choices=constants.LDAP_GROUP_TYPES
|
||||
)
|
||||
ldap_groups_search_base = serializers.CharField(
|
||||
default="", required=False, allow_blank=True)
|
||||
|
||||
def validate_ldap_user_dn_template(self, value):
|
||||
try:
|
||||
value % {"user": "toto"}
|
||||
except (KeyError, ValueError):
|
||||
raise serializers.ValidationError(_("Invalid syntax"))
|
||||
return value
|
||||
|
||||
def validate_rounds_number(self, value):
|
||||
if value < 1000 or value > 999999999:
|
||||
raise serializers.ValidationError(_("Invalid rounds number"))
|
||||
return value
|
||||
|
||||
def validate_default_password(self, value):
|
||||
"""Check password complexity."""
|
||||
password_validation.validate_password(value)
|
||||
return value
|
||||
|
||||
def validate(self, data):
|
||||
"""Custom validation method
|
||||
|
||||
Depending on 'ldap_auth_method' value, we check for different
|
||||
required parameters.
|
||||
"""
|
||||
if data["authentication_type"] != "ldap":
|
||||
return data
|
||||
if data["ldap_auth_method"] == "searchbind":
|
||||
required_fields = ["ldap_search_base", "ldap_search_filter"]
|
||||
else:
|
||||
required_fields = ["ldap_user_dn_template"]
|
||||
errors = {}
|
||||
for f in required_fields:
|
||||
if data.get(f, u"") == u"":
|
||||
errors[f] = _("This field is required")
|
||||
if len(errors):
|
||||
raise serializers.ValidationError(errors)
|
||||
return data
|
||||
@@ -10,7 +10,8 @@ class ParametersSerializer(serializers.Serializer):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Generate serializer."""
|
||||
app = kwargs.pop("app")
|
||||
super(ParametersSerializer, self).__init__(*args, **kwargs)
|
||||
for name, field in tools.registry.get_fields("global"):
|
||||
for name, field in tools.registry.get_fields("global", app):
|
||||
field.source = None
|
||||
self.fields[name] = field
|
||||
|
||||
+32
-12
@@ -46,10 +46,11 @@ class Registry(object):
|
||||
"label": label, "formclass": formclass, "defaults": {}
|
||||
}
|
||||
|
||||
def add2(self, level, app, label, params):
|
||||
def add2(self, level, app, label, structure, serializer_class):
|
||||
"""Add new parameters for given app and level."""
|
||||
self._registry2[level][app] = {
|
||||
"label": label, "params": params
|
||||
"label": label, "structure": structure,
|
||||
"serializer_class": serializer_class
|
||||
}
|
||||
|
||||
def _load_default_values(self, level):
|
||||
@@ -61,6 +62,12 @@ class Registry(object):
|
||||
continue
|
||||
data["defaults"][name] = field.initial
|
||||
|
||||
def get_applications(self, level):
|
||||
"""Return all applications registered for level."""
|
||||
result = [{"name": key, "label": value["label"]}
|
||||
for key, value in self._registry2[level].items()]
|
||||
return result
|
||||
|
||||
def get_forms(self, level, *args, **kwargs):
|
||||
"""Return form instances for all app of the given level."""
|
||||
sorted_apps = []
|
||||
@@ -86,37 +93,49 @@ class Registry(object):
|
||||
})
|
||||
return result
|
||||
|
||||
def get_fields(self, level, *args, **kwargs):
|
||||
def get_fields(self, level, for_app=None):
|
||||
"""Return fields to include in serializer."""
|
||||
result = []
|
||||
for app, fields in list(self._registry2[level].items()):
|
||||
for section, sconfig in list(fields["params"].items()):
|
||||
if app and for_app != app:
|
||||
continue
|
||||
for section, sconfig in list(fields["structure"].items()):
|
||||
for name, config in list(sconfig["params"].items()):
|
||||
result.append(("{}-{}".format(app, name), config["field"]))
|
||||
return result
|
||||
|
||||
def get_structure(self, level):
|
||||
def get_serializer_class(self, level, app):
|
||||
"""Return serializer class for given level and app."""
|
||||
if app not in self._registry2[level]:
|
||||
raise NotDefined(app)
|
||||
return self._registry2[level][app]["serializer_class"]
|
||||
|
||||
def get_structure(self, level, for_app=None):
|
||||
"""Return fields structure."""
|
||||
result = []
|
||||
for app, fields in list(self._registry2[level].items()):
|
||||
for section, sconfig in list(fields["params"].items()):
|
||||
if for_app and for_app != app:
|
||||
continue
|
||||
serializer = fields["serializer_class"]()
|
||||
for section, sconfig in list(fields["structure"].items()):
|
||||
item = {
|
||||
"label": sconfig["label"],
|
||||
"display": sconfig.get("display", ""),
|
||||
"parameters": []
|
||||
}
|
||||
for name, config in list(sconfig["params"].items()):
|
||||
field = serializer.fields[name]
|
||||
data = {
|
||||
"name": "{}-{}".format(app, name),
|
||||
"name": name,
|
||||
"label": config["label"],
|
||||
"help_text": config.get("help_text", ""),
|
||||
"display": config.get("display", ""),
|
||||
"widget": config["field"].__class__.__name__,
|
||||
"widget": field.__class__.__name__,
|
||||
}
|
||||
if data["widget"] == "ChoiceField":
|
||||
data["choices"] = [
|
||||
{"text": value, "value": key}
|
||||
for key, value in config["field"].choices.items()
|
||||
for key, value in field.choices.items()
|
||||
]
|
||||
item["parameters"].append(data)
|
||||
result.append(item)
|
||||
@@ -188,9 +207,10 @@ class Manager(object):
|
||||
if app is None:
|
||||
app = guess_extension_name()
|
||||
values = registry.get_defaults(self._level, app)
|
||||
return {
|
||||
parameter: value for parameter, value in list(values.items())
|
||||
}
|
||||
for parameter, value in list(values.items()):
|
||||
if app in self._parameters:
|
||||
values[parameter] = self._parameters[app].get(parameter, value)
|
||||
return values
|
||||
|
||||
def set_value(self, parameter, value, app=None):
|
||||
"""Set parameter for the given app."""
|
||||
|
||||
@@ -2,22 +2,40 @@
|
||||
|
||||
from rest_framework import decorators, response, viewsets
|
||||
|
||||
from . import serializers
|
||||
from . import tools
|
||||
|
||||
|
||||
class ParametersViewSet(viewsets.ViewSet):
|
||||
"""Parameter viewset."""
|
||||
|
||||
lookup_value_regex = r"\w+"
|
||||
|
||||
@decorators.list_route(methods=["get"])
|
||||
def applications(self, request):
|
||||
"""Return application list."""
|
||||
applications = tools.registry.get_applications("global")
|
||||
return response.Response(applications)
|
||||
|
||||
@decorators.list_route(methods=["get"])
|
||||
def structure(self, request):
|
||||
"""Return parameter schema."""
|
||||
data = tools.registry.get_structure("global")
|
||||
app = request.GET.get("app")
|
||||
data = tools.registry.get_structure("global", app)
|
||||
return response.Response(data)
|
||||
|
||||
def list(self, request):
|
||||
"""Return all parameters."""
|
||||
parameters = request.localconfig.parameters.get_values_dict("core")
|
||||
serializer = serializers.ParametersSerializer(data=parameters)
|
||||
def retrieve(self, request, pk):
|
||||
"""Return all parameters for given app."""
|
||||
parameters = request.localconfig.parameters.get_values_dict(pk)
|
||||
serializer = tools.registry.get_serializer_class("global", pk)(
|
||||
parameters)
|
||||
return response.Response(serializer.data)
|
||||
|
||||
def update(self, request, pk):
|
||||
"""Save parameters for given app."""
|
||||
serializer = tools.registry.get_serializer_class("global", pk)(
|
||||
data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
return response.Response(serializer.validated_data)
|
||||
request.localconfig.parameters.set_values(
|
||||
serializer.validated_data, app=pk)
|
||||
request.localconfig.save(update_fields=["_parameters"])
|
||||
return response.Response()
|
||||
|
||||
Reference in New Issue
Block a user