From 08943f15ecac221109e9df00f8d035d350979944 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 26 Oct 2016 11:19:28 +0200 Subject: [PATCH] WIP see #951 --- .../migrations/0010_auto_20161026_1011.py | 67 +++++++++++++++++++ modoboa/core/models.py | 8 ++- modoboa/core/parameters.py | 4 +- modoboa/core/tests/test_core.py | 16 ++--- modoboa/core/views/admin.py | 2 +- modoboa/core/views/user.py | 5 +- modoboa/lib/parameters.py | 39 ++--------- 7 files changed, 97 insertions(+), 44 deletions(-) create mode 100644 modoboa/core/migrations/0010_auto_20161026_1011.py diff --git a/modoboa/core/migrations/0010_auto_20161026_1011.py b/modoboa/core/migrations/0010_auto_20161026_1011.py new file mode 100644 index 000000000..64961f261 --- /dev/null +++ b/modoboa/core/migrations/0010_auto_20161026_1011.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.5 on 2016-10-26 08:11 +from __future__ import unicode_literals + +from django.db import migrations +import jsonfield.fields + + +def set_parameter(store, parameter): + """Add parameter to the specified store.""" + app, name = parameter.name.split(".") + if app not in store: + store[app] = {} + # decode value + value = parameter.value.decode("unicode_escape") + if value == "yes": + value = True + elif value == "no": + value = False + elif value.isdigit(): + value = int(value) + store[app][name.lower()] = value + + +def move_parameters(apps, schema_editor): + """Move global and user parameters.""" + Parameter = apps.get_model("lib", "Parameter") + LocalConfig = apps.get_model("core", "LocalConfig") + parameters = {} + for parameter in Parameter.objects.all(): + set_parameter(parameters, parameter) + LocalConfig.objects.all().update(_parameters=parameters) + + User = apps.get_model("core", "User") + for user in User.objects.prefetch_related("userparameter_set"): + for parameter in user.userparameter_set.all(): + set_parameter(user._parameters, parameter) + user.save() + + +def clear_parameters(apps, schema_editor): + """Reverse operation.""" + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0009_auto_20161026_1003'), + ('lib', '0005_auto_20160416_1449'), + ] + + operations = [ + migrations.AddField( + model_name='localconfig', + name='_parameters', + field=jsonfield.fields.JSONField(default={}), + preserve_default=False, + ), + migrations.AddField( + model_name='user', + name='_parameters', + field=jsonfield.fields.JSONField(default={}), + preserve_default=False, + ), + migrations.RunPython(move_parameters, clear_parameters) + ] diff --git a/modoboa/core/models.py b/modoboa/core/models.py index 2f0ba8503..7eba10e4c 100644 --- a/modoboa/core/models.py +++ b/modoboa/core/models.py @@ -84,6 +84,7 @@ class User(PermissionsMixin): help_text=ugettext_lazy( "An alternative e-mail address, can be used for recovery needs.") ) + _parameters = jsonfield.JSONField(default={}) objects = UserManager() @@ -98,6 +99,11 @@ class User(PermissionsMixin): password_expr = re.compile(r'\{([\w\-]+)\}(.+)') + def __init__(self, *args, **kwargs): + """Load parameter manager.""" + super(User, self).__init__(*args, **kwargs) + self.parameters = parameters.Manager("user", self._parameters) + def delete(self, fromuser, *args, **kwargs): """Custom delete method @@ -509,7 +515,7 @@ class LocalConfig(models.Model): # API results cache api_versions = jsonfield.JSONField() - _parameters = jsonfield.JSONField() + _parameters = jsonfield.JSONField(default={}) def __init__(self, *args, **kwargs): """Load parameter manager.""" diff --git a/modoboa/core/parameters.py b/modoboa/core/parameters.py index 7a13a6baa..bf65c3b14 100644 --- a/modoboa/core/parameters.py +++ b/modoboa/core/parameters.py @@ -49,7 +49,7 @@ class Registry(object): def get_forms(self, level, *args, **kwargs): """Return form instances for all app of the given level.""" sorted_apps = [] - first_app = "core" + first_app = kwargs.pop("first_app", "core") if first_app in self._registry[level]: sorted_apps.append(first_app) sorted_apps += sorted( @@ -59,6 +59,8 @@ class Registry(object): result = [] for app in sorted_apps: data = self._registry[level][app] + if not data["formclass"].has_access(**kwargs): + continue result.append({ "label": data["label"], "form": data["formclass"](*args, **kwargs) diff --git a/modoboa/core/tests/test_core.py b/modoboa/core/tests/test_core.py index 35db7af34..4fc047042 100644 --- a/modoboa/core/tests/test_core.py +++ b/modoboa/core/tests/test_core.py @@ -9,7 +9,6 @@ from django.core.urlresolvers import reverse from django.test import override_settings, TestCase from modoboa.lib import exceptions -from modoboa.lib import parameters from modoboa.lib.tests import ModoTestCase from modoboa.lib.tests import NO_LDAP @@ -152,7 +151,6 @@ class LDAPTestCaseMixin(object): 'modoboa.lib.authbackends.SimpleBackend', )) class LDAPAuthenticationTestCase(LDAPTestCaseMixin, ModoTestCase): - """Validate LDAP authentication scenarios.""" def setUp(self): @@ -178,9 +176,10 @@ class LDAPAuthenticationTestCase(LDAPTestCaseMixin, ModoTestCase): self.check_created_user(username) self.client.logout() - parameters.save_admin("LDAP_ADMIN_GROUPS", "admins") - parameters.save_admin( - "LDAP_GROUPS_SEARCH_BASE", "ou=groups,dc=example,dc=com") + self.set_global_parameters({ + "ldap_admin_groups": "admins", + "ldap_groups_search_base": "ou=groups,dc=example,dc=com" + }) username = "mailadmin@example.com" self.authenticate(username, "test", False) self.check_created_user(username, "DomainAdmins") @@ -198,9 +197,10 @@ class LDAPAuthenticationTestCase(LDAPTestCaseMixin, ModoTestCase): # 1: must work because usernames of domain admins are not # always email addresses - parameters.save_admin("LDAP_ADMIN_GROUPS", "admins") - parameters.save_admin( - "LDAP_GROUPS_SEARCH_BASE", "ou=groups,dc=example,dc=com") + self.set_global_parameters({ + "ldap_admin_groups": "admins", + "ldap_groups_search_base": "ou=groups,dc=example,dc=com" + }) username = "mailadmin" self.authenticate(username, "test", False) self.check_created_user(username, "DomainAdmins", False) diff --git a/modoboa/core/views/admin.py b/modoboa/core/views/admin.py index 54c10b250..8f4161020 100644 --- a/modoboa/core/views/admin.py +++ b/modoboa/core/views/admin.py @@ -11,7 +11,7 @@ from django.utils.translation import ugettext as _ from modoboa.core.models import Log from modoboa.core import parameters as core_parameters from modoboa.core.utils import check_for_updates -from modoboa.lib import events, parameters +from modoboa.lib import events from modoboa.lib.listing import get_sort_order, get_listing_page from modoboa.lib.web_utils import ( _render_to_string, render_to_json_response diff --git a/modoboa/core/views/user.py b/modoboa/core/views/user.py index 149dc91a3..ea4e1e11a 100644 --- a/modoboa/core/views/user.py +++ b/modoboa/core/views/user.py @@ -8,6 +8,7 @@ from django.contrib.auth.decorators import login_required, user_passes_test from rest_framework.authtoken.models import Token +from modoboa.core import parameters as core_parameters from modoboa.lib import events, parameters from modoboa.lib.cryptutils import encrypt from modoboa.lib.web_utils import ( @@ -59,7 +60,9 @@ def profile(request, tplname='core/user_profile.html'): @login_required def preferences(request): if request.method == "POST": - for formdef in parameters.get_user_forms(request.user, request.POST): + forms = core_parameters.registry.get_forms( + "user", request.POST, user=request.user) + for formdef in forms: form = formdef["form"] if form.is_valid(): form.save() diff --git a/modoboa/lib/parameters.py b/modoboa/lib/parameters.py index 1da89f896..4efbdead1 100644 --- a/modoboa/lib/parameters.py +++ b/modoboa/lib/parameters.py @@ -76,6 +76,10 @@ class GenericParametersForm(forms.Form): p.value = str(value) p.save() + @staticmethod + def has_access(**kwargs): + return True + def save(self): raise NotImplementedError @@ -142,10 +146,6 @@ class UserParametersForm(GenericParametersForm): for p in UserParameter.objects.filter(user=self.user, name__in=names): self.fields[p.shortname].initial = self._decode_value(p.value) - @staticmethod - def has_access(user): - return True - def save(self): from .models import UserParameter from modoboa.lib.form_utils import SeparatorField @@ -290,23 +290,6 @@ def get_user(user, name, app=None, raise_error=True): return p.value.decode("unicode_escape") -def get_sorted_apps(level, first="core"): - """Retrieve the sorted list of all registerd applications. - - :param str level: application level - :param str first: force the first item of the result - :rtype: list - """ - sorted_apps = [] - if first in _params[level]: - sorted_apps.append(first) - sorted_apps += sorted( - [app for app in _params[level].keys() if app != first], - key=lambda app: _params[level][app]["label"] - ) - return sorted_apps - - def get_admin_forms(*args, **kwargs): """Get all admin level forms. @@ -318,17 +301,9 @@ def get_admin_forms(*args, **kwargs): def get_user_forms(user, *args, **kwargs): """Return an instance of each user-level forms.""" - kwargs["user"] = user - sorted_apps = get_sorted_apps('U', first="general") - result = [] - for app in sorted_apps: - formdef = _params["U"][app] - if not formdef["form"].has_access(user): - continue - result.append({ - "label": formdef["label"], - "form": formdef["form"](*args, **kwargs)}) - return result + kwargs.update({"user": user, "first_app": "general"}) + return core_parameters.registry.get_forms( + "user", *args, **kwargs) def get_parameter_form(level, name, app=None):