see #951
This commit is contained in:
Antoine Nguyen
2016-10-28 15:48:08 +02:00
parent 08943f15ec
commit 3fb1c13f18
42 changed files with 352 additions and 578 deletions
-14
View File
@@ -563,20 +563,6 @@ Must return a list of set. Each set must contain at least three entries::
[('<limit_name>', '<limit label>', '<limit help text>')]
GetExtraParameters
==================
Raised to request extra parameters for a given parameters form.
*Callback prototype*::
def callback(application, level): pass
* ``application`` is the name of the form's application (ie. admin, amavis, etc.)
* ``level`` is the form's level: ``A`` for admin or ``U`` for user
Must return a dictionary. Each entry must be a valid Django form field.
.. _getextrarolepermissions:
GetExtraRolePermissions
+6 -6
View File
@@ -6,11 +6,11 @@ from django import forms
from django.conf import settings
from django.utils.translation import ugettext_lazy
from ..lib import events
from modoboa.lib import parameters
from modoboa.lib.form_utils import YesNoField, SeparatorField
from modoboa.lib.sysutils import exec_cmd
from modoboa.parameters import forms as param_forms
from ..lib import events
ADMIN_EVENTS = [
"DomainCreated",
@@ -48,7 +48,7 @@ ADMIN_EVENTS = [
]
class AdminParametersForm(parameters.AdminParametersForm):
class AdminParametersForm(param_forms.AdminParametersForm):
app = "admin"
dom_sep = SeparatorField(label=ugettext_lazy("Domains"))
@@ -174,9 +174,9 @@ class AdminParametersForm(parameters.AdminParametersForm):
def load_admin_settings():
"""Load admin settings."""
from .app_settings import AdminParametersForm
from modoboa.parameters import tools as param_tools
parameters.register(
AdminParametersForm, ugettext_lazy("Administration"))
param_tools.registry.add(
"global", AdminParametersForm, ugettext_lazy("Administration"))
events.declare(ADMIN_EVENTS)
from . import callbacks
+3 -2
View File
@@ -4,9 +4,10 @@ from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _, ugettext_lazy
from modoboa.core import signals as core_signals
from modoboa.lib import parameters, events
from modoboa.lib import events
from modoboa.lib.email_utils import split_mailbox
from modoboa.lib.exceptions import PermDeniedException, BadRequest, Conflict
from modoboa.parameters import tools as param_tools
from .models import (
Domain, DomainAlias, Mailbox, Alias
@@ -154,7 +155,7 @@ def account_auto_created(user):
from modoboa.lib.permissions import grant_access_to_object
from .lib import check_if_domain_exists
if not parameters.get_admin("AUTO_CREATE_DOMAIN_AND_MAILBOX"):
if not param_tools.get_global_parameter("auto_create_domain_and_mailbox"):
return
localpart, domname = split_mailbox(user.username)
if user.role != 'SimpleUsers' and domname is None:
+5 -4
View File
@@ -9,9 +9,9 @@ from django.utils.translation import ugettext as _, ugettext_lazy
from passwords.fields import PasswordField
from modoboa.core.models import User
from modoboa.core import signals as core_signals
from modoboa.lib import events, parameters
from modoboa.core.models import User
from modoboa.lib import events
from modoboa.lib.email_utils import split_mailbox
from modoboa.lib import exceptions as lib_exceptions
from modoboa.lib import fields as lib_fields
@@ -21,6 +21,7 @@ from modoboa.lib.form_utils import (
from modoboa.lib.permissions import get_account_roles
from modoboa.lib.validators import validate_utf8_email
from modoboa.lib.web_utils import render_to_json_response
from modoboa.parameters import tools as param_tools
from .. import models
@@ -111,8 +112,8 @@ class AccountFormGeneral(forms.ModelForm):
self.fields["role"].initial = self.instance.role
condition = (
not self.instance.is_local and
parameters.get_admin(
"LDAP_AUTH_METHOD", app="core") == "directbind")
param_tools.get_global_parameter(
"ldap_auth_method", app="core") == "directbind")
if condition:
del self.fields["password1"]
del self.fields["password2"]
+8 -6
View File
@@ -5,15 +5,16 @@ from django.core.urlresolvers import reverse
from django.http import QueryDict
from django.utils.translation import ugettext as _, ugettext_lazy
from modoboa.core.models import User
from modoboa.core import signals as core_signals
from modoboa.lib import events, parameters
from modoboa.core.models import User
from modoboa.lib import events
from modoboa.lib.exceptions import Conflict
from modoboa.lib.fields import DomainNameField
from modoboa.lib.form_utils import (
YesNoField, WizardForm, WizardStep, DynamicForm, TabForms
)
from modoboa.lib.web_utils import render_to_json_response
from modoboa.parameters import tools as param_tools
from ..lib import check_if_domain_exists
from ..models import (
@@ -75,11 +76,12 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
self._create_field(forms.CharField, name, dalias.name, 3)
def clean_quota(self):
if self.cleaned_data['quota'] is None:
return int(parameters.get_admin('DEFAULT_DOMAIN_QUOTA'))
if self.cleaned_data['quota'] < 0:
"""Check quota value."""
if self.cleaned_data["quota"] is None:
return param_tools.get_global_parameter("default_domain_quota")
if self.cleaned_data["quota"] < 0:
raise forms.ValidationError(_("Must be a positive integer"))
return self.cleaned_data['quota']
return self.cleaned_data["quota"]
def clean(self):
"""Custom fields validation.
@@ -1,3 +1,4 @@
"""A management command to apply mailbox operations."""
import logging
from optparse import make_option
@@ -5,7 +6,7 @@ import os
from django.core.management.base import BaseCommand
from modoboa.lib import parameters
from param_tools import tools as param_tools
from modoboa.lib.sysutils import exec_cmd
from modoboa.lib.exceptions import InternalError
@@ -14,22 +15,26 @@ from ...models import MailboxOperation
class OperationError(Exception):
"""Custom exception."""
pass
class Command(BaseCommand):
help = 'Handles rename and delete operations on mailboxes'
"""Command definition"""
help = "Handles rename and delete operations on mailboxes"
option_list = BaseCommand.option_list + (
make_option(
'--pidfile', default='/tmp/handle_mailbox_operations.pid',
help='Path to the file that will contain the PID of this process'
"--pidfile", default="/tmp/handle_mailbox_operations.pid",
help="Path to the file that will contain the PID of this process"
),
)
def __init__(self, *args, **kwargs):
super(Command, self).__init__(*args, **kwargs)
self.logger = logging.getLogger('modoboa.admin')
self.logger = logging.getLogger("modoboa.admin")
def rename_mailbox(self, operation):
if not os.path.exists(operation.argument):
@@ -75,22 +80,23 @@ class Command(BaseCommand):
return True
def handle(self, *args, **options):
"""Command entry point."""
load_admin_settings()
if not parameters.get_admin("HANDLE_MAILBOXES"):
if not param_tools.get_global_parameter("handle_mailboxes"):
return
if not self.check_pidfile(options['pidfile']):
if not self.check_pidfile(options["pidfile"]):
return
for ope in MailboxOperation.objects.all():
try:
f = getattr(self, '%s_mailbox' % ope.type)
f = getattr(self, "%s_mailbox" % ope.type)
except AttributeError:
continue
try:
f(ope)
except (OperationError, InternalError) as e:
self.logger.critical('%s failed (reason: %s)',
ope, str(e).encode('utf-8'))
self.logger.critical("%s failed (reason: %s)",
ope, str(e).encode("utf-8"))
else:
self.logger.info('%s succeed', ope)
self.logger.info("%s succeed", ope)
ope.delete()
os.unlink(options['pidfile'])
os.unlink(options["pidfile"])
@@ -17,8 +17,8 @@ from django.utils.translation import ugettext as _
from modoboa.admin import constants
from modoboa.admin import models
from modoboa.lib import parameters
from modoboa.lib import email_utils
from modoboa.parameters import tools as param_tools
class CheckMXRecords(BaseCommand):
@@ -36,12 +36,12 @@ class CheckMXRecords(BaseCommand):
@cached_property
def sender(self):
"""Return sender address for notifications."""
return parameters.get_admin("SENDER_ADDRESS", app="core")
return param_tools.get_global_parameter("sender_address", app="core")
@cached_property
def valid_mxs(self):
"""Return valid MXs set in admin."""
valid_mxs = parameters.get_admin("VALID_MXS", app="admin")
valid_mxs = param_tools.get_global_parameter("valid_mxs")
return [ipaddress.ip_network(u"{}".format(v.strip()))
for v in valid_mxs.split() if v.strip()]
@@ -217,11 +217,11 @@ class CheckMXRecords(BaseCommand):
"""Check specified domain."""
mx_list = list(self.get_mx_records_for_domain(domain, ttl=ttl))
if parameters.get_admin("ENABLE_MX_CHECKS"):
if param_tools.get_global_parameter("enable_mx_checks"):
self.check_valid_mx(domain, mx_list, **options)
condition = (
not parameters.get_admin("ENABLE_DNSBL_CHECKS") or
not param_tools.get_global_parameter("enable_dnsbl_checks") or
options["no_dnsbl"] is True)
if condition or not mx_list:
return
+9 -8
View File
@@ -13,10 +13,11 @@ from django.contrib.contenttypes.fields import GenericRelation
from reversion import revisions as reversion
from modoboa.core.models import User, ObjectAccess
from modoboa.core import signals as core_signals
from modoboa.lib import events, parameters
from modoboa.core.models import User, ObjectAccess
from modoboa.lib import events
from modoboa.lib.exceptions import BadRequest, Conflict
from modoboa.parameters import tools as param_tools
from .base import AdminObject
@@ -185,11 +186,11 @@ class Domain(AdminObject):
if self.alias_set.count():
events.raiseEvent("MailboxAliasDeleted", self.alias_set.all())
ungrant_access_to_objects(self.alias_set.all())
if parameters.get_admin("AUTO_ACCOUNT_REMOVAL"):
if param_tools.get_global_parameter("auto_account_removal"):
for account in User.objects.filter(mailbox__domain=self):
account.delete(fromuser, keepdir)
elif self.mailbox_set.count():
Quota.objects.filter(username__contains='@%s' % self.name).delete()
Quota.objects.filter(username__contains="@%s" % self.name).delete()
events.raiseEvent("MailboxDeleted", self.mailbox_set.all())
ungrant_access_to_objects(self.mailbox_set.all())
super(Domain, self).delete()
@@ -242,7 +243,7 @@ class MXQuerySet(models.QuerySet):
def has_valids(self):
"""Return managed results."""
if parameters.get_admin("VALID_MXS", app="admin").strip():
if param_tools.get_global_parameter("valid_mxs").strip():
return self.filter(managed=True).exists()
return self.exists()
@@ -259,12 +260,12 @@ class MXRecord(models.Model):
objects = models.Manager.from_queryset(MXQuerySet)()
def is_managed(self):
if not parameters.get_admin("ENABLE_MX_CHECKS"):
if not param_tools.get_global_parameter("enable_mx_checks"):
return False
return bool(parameters.get_admin("VALID_MXS", app="admin").strip())
return bool(param_tools.get_global_parameter("valid_mxs").strip())
def __unicode__(self):
return u'{0.name} ({0.address}) for {0.domain} '.format(self)
return u"{0.name} ({0.address}) for {0.domain} ".format(self)
class DNSBLQuerySet(models.QuerySet):
+14 -10
View File
@@ -12,13 +12,15 @@ from django.utils.translation import ugettext as _, ugettext_lazy
from reversion import revisions as reversion
from .base import AdminObject
from .domain import Domain
from modoboa.core.models import User
from modoboa.lib import events, parameters
from modoboa.lib import events
from modoboa.lib import exceptions as lib_exceptions
from modoboa.lib.email_utils import split_mailbox
from modoboa.lib.sysutils import exec_cmd
from modoboa.parameters import tools as param_tools
from .base import AdminObject
from .domain import Domain
class Quota(models.Model):
@@ -131,15 +133,15 @@ class Mailbox(AdminObject):
several patterns to understand and we don't want to implement
them.
"""
hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False)
if not hm:
admin_params = dict(param_tools.get_global_parameters("admin"))
if not admin_params.get("handle_mailboxes"):
return None
if self.__mail_home is None:
curuser = pwd.getpwuid(os.getuid()).pw_name
mbowner = parameters.get_admin("MAILBOXES_OWNER")
mbowner = admin_params["mailboxes_owner"]
options = {}
if curuser != mbowner:
options['sudo_user'] = mbowner
options["sudo_user"] = mbowner
code, output = exec_cmd(
"doveadm user %s -f home" % self.full_address, **options
)
@@ -180,7 +182,8 @@ class Mailbox(AdminObject):
def rename_dir(self, old_mail_home):
"""Rename local directory if needed."""
hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False)
hm = param_tools.get_global_parameter(
"handle_mailboxes", raise_exception=False)
if not hm:
return
MailboxOperation.objects.create(
@@ -210,10 +213,11 @@ class Mailbox(AdminObject):
self.rename_dir(old_mail_home)
def delete_dir(self):
hm = parameters.get_admin("HANDLE_MAILBOXES", raise_error=False)
hm = param_tools.get_global_parameter(
"handle_mailboxes", raise_exception=False)
if not hm:
return
MailboxOperation.objects.create(type='delete', argument=self.mail_home)
MailboxOperation.objects.create(type="delete", argument=self.mail_home)
def set_quota(self, value=None, override_rules=False):
"""Set or update quota's value for this mailbox.
+1 -1
View File
@@ -13,7 +13,7 @@ from django.contrib.auth.decorators import (
from reversion import revisions as reversion
from modoboa.core.models import User
from modoboa.lib import parameters, events
from modoboa.lib import events
from modoboa.lib.exceptions import (
PermDeniedException, BadRequest
)
+5 -5
View File
@@ -3,12 +3,13 @@ from django import forms
from django.conf import settings
from django.utils.translation import ugettext as _, ugettext_lazy
from modoboa.lib import parameters
from modoboa.lib import fields as lib_fields
from modoboa.lib.cryptutils import random_key
from modoboa.lib.form_utils import (
YesNoField, SeparatorField, InlineRadioSelect
)
from modoboa.parameters import forms as param_forms
from modoboa.parameters import tools as param_tools
from . import constants
@@ -30,8 +31,7 @@ def enabled_applications():
return sorted(result, key=lambda e: e[0])
class GeneralParametersForm(parameters.AdminParametersForm):
class GeneralParametersForm(param_forms.AdminParametersForm):
"""General parameters."""
app = "core"
@@ -348,7 +348,7 @@ class GeneralParametersForm(parameters.AdminParametersForm):
return cleaned_data
def to_django_settings(self):
"""Apply LDAP related parameters to Django settings
"""Apply LDAP related parameters to Django settings.
Doing so, we can use the django_auth_ldap module.
"""
@@ -360,7 +360,7 @@ class GeneralParametersForm(parameters.AdminParametersForm):
except ImportError:
ldap_available = False
values = self.get_current_values()
values = dict(param_tools.get_global_parameters("core"))
if not ldap_available or values["authentication_type"] != "ldap":
return
if not hasattr(settings, "AUTH_LDAP_USER_ATTR_MAP"):
+5 -5
View File
@@ -2,7 +2,7 @@
from django.apps import AppConfig
from django.db.models import signals
from django.utils.translation import ugettext_lazy
BASE_EVENTS = [
"AccountCreated",
@@ -36,7 +36,6 @@ BASE_EVENTS = [
"ExtraUprefsRoutes",
"ExtraUprefsJS",
"GetExtraParameters",
"ExtraFormFields",
"SaveExtraFormFields",
]
@@ -48,11 +47,12 @@ def load_core_settings():
This function must be manually called (see :file:`urls.py`) in
order to load base settings.
"""
from django.utils.translation import ugettext_lazy
from modoboa.lib import parameters, events
from modoboa.lib import events
from modoboa.parameters import tools as param_tools
from .app_settings import GeneralParametersForm
parameters.register(GeneralParametersForm, ugettext_lazy("General"))
param_tools.registry.add(
"global", GeneralParametersForm, ugettext_lazy("General"))
events.declare(BASE_EVENTS)
@@ -63,6 +63,7 @@ MODOBOA_APPS = (
'modoboa.admin',
'modoboa.relaydomains',
'modoboa.limits',
'modoboa.parameters',
# Modoboa extensions here.
{% for extension in extensions %} '{{ extension }}',
{% endfor %}
@@ -81,6 +82,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'modoboa.core.middleware.LocalConfigMiddleware',
'modoboa.lib.middleware.AjaxLoginRedirect',
'modoboa.lib.middleware.CommonExceptionCatcher',
'modoboa.lib.middleware.RequestCatcherMiddleware',
+4 -7
View File
@@ -8,11 +8,10 @@ from django.utils.translation import ugettext as _, ugettext_lazy
from passwords.fields import PasswordField
from modoboa.core.models import User
from modoboa.lib import parameters
from modoboa.parameters import tools as param_tools
class LoginForm(forms.Form):
"""User login form."""
username = forms.CharField(
@@ -30,7 +29,6 @@ class LoginForm(forms.Form):
class ProfileForm(forms.ModelForm):
"""Form to update User profile."""
oldpassword = forms.CharField(
@@ -51,8 +49,8 @@ class ProfileForm(forms.ModelForm):
fields = ("first_name", "last_name", "language",
"phone_number", "secondary_email")
widgets = {
'first_name': forms.TextInput(attrs={'class': 'form-control'}),
'last_name': forms.TextInput(attrs={'class': 'form-control'})
"first_name": forms.TextInput(attrs={"class": "form-control"}),
"last_name": forms.TextInput(attrs={"class": "form-control"})
}
def __init__(self, update_password, *args, **kwargs):
@@ -66,7 +64,7 @@ class ProfileForm(forms.ModelForm):
if self.cleaned_data["oldpassword"] == "":
return self.cleaned_data["oldpassword"]
if parameters.get_admin("AUTHENTICATION_TYPE") != "local":
if param_tools.get_global_parameter("authentication_type") != "local":
return self.cleaned_data["oldpassword"]
if not self.instance.check_password(self.cleaned_data["oldpassword"]):
@@ -93,7 +91,6 @@ class ProfileForm(forms.ModelForm):
class APIAccessForm(forms.Form):
"""Form to control API access."""
enable_api_access = forms.BooleanField(
@@ -7,7 +7,8 @@ from django.core.management.base import BaseCommand
from django.utils import timezone
from modoboa.core.models import Log
from modoboa.lib import parameters
from ... import parameters
class Command(BaseCommand):
@@ -38,7 +39,7 @@ class Command(BaseCommand):
l.addHandler(logging.StreamHandler())
self.verbose = options["verbose"]
log_maximum_age = int(parameters.get_admin("LOG_MAXIMUM_AGE"))
log_maximum_age = parameters.get_global_parameter("log_maximum_age")
self.__vprint("Deleting logs older than %d days..." % log_maximum_age)
limit = timezone.now() - datetime.timedelta(log_maximum_age)
Log.objects.filter(date_created__lt=limit).delete()
@@ -12,7 +12,6 @@ from modoboa.core import PERMISSIONS
from modoboa.core.extensions import exts_pool
from modoboa.lib.cryptutils import random_key
from modoboa.lib import events
from modoboa.lib import models as lib_models
from modoboa.lib.permissions import add_permissions_to_group
import modoboa.relaydomains.models as relay_models
+8 -9
View File
@@ -21,13 +21,12 @@ from reversion import revisions as reversion
from modoboa.core.password_hashers import get_password_hasher
from modoboa.lib import events
from modoboa.lib import parameters as lib_parameters
from modoboa.lib.exceptions import (
PermDeniedException, InternalError, BadRequest, Conflict
)
from modoboa.parameters import tools as param_tools
from . import constants
from . import parameters
try:
@@ -102,7 +101,7 @@ class User(PermissionsMixin):
def __init__(self, *args, **kwargs):
"""Load parameter manager."""
super(User, self).__init__(*args, **kwargs)
self.parameters = parameters.Manager("user", self._parameters)
self.parameters = param_tools.Manager("user", self._parameters)
def delete(self, fromuser, *args, **kwargs):
"""Custom delete method
@@ -147,13 +146,13 @@ class User(PermissionsMixin):
one more time.
"""
try:
scheme = lib_parameters.get_admin("PASSWORD_SCHEME")
except parameters.NotDefined:
scheme = param_tools.get_global_parameter(
"password_scheme", raise_exception=False)
if scheme is None:
from modoboa.core.apps import load_core_settings
load_core_settings()
scheme = lib_parameters.get_admin("PASSWORD_SCHEME")
scheme = param_tools.get_global_parameter(
"password_scheme", raise_exception=False)
if isinstance(raw_value, unicode):
raw_value = raw_value.encode("utf-8")
return get_password_hasher(scheme.upper())().encrypt(raw_value)
@@ -520,4 +519,4 @@ class LocalConfig(models.Model):
def __init__(self, *args, **kwargs):
"""Load parameter manager."""
super(LocalConfig, self).__init__(*args, **kwargs)
self.parameters = parameters.Manager("admin", self._parameters)
self.parameters = param_tools.Manager("global", self._parameters)
+8 -5
View File
@@ -3,9 +3,12 @@ Advanced (ie. stronger) password hashers.
This module relies on `passlib` to provide more secure hashers.
"""
from passlib.hash import bcrypt, md5_crypt, sha256_crypt, sha512_crypt
from modoboa.core.password_hashers.base import PasswordHasher
from modoboa.lib import parameters
from modoboa.parameters import tools as param_tools
from .base import PasswordHasher
class BLFCRYPTHasher(PasswordHasher):
@@ -26,7 +29,7 @@ class BLFCRYPTHasher(PasswordHasher):
# Using the parameter for rounds will generate the error
# ValueError: rounds too high (bcrypt requires <= 31 rounds)
# when using the bcrypt hasher.
# rounds = int(parameters.get_admin('ROUNDS_NUMBER'))
# rounds = parameters.get_global_parameter("rounds_number")
# To get around this, I use the default of 12.
rounds = 12
return bcrypt.encrypt(clearvalue, rounds=rounds)
@@ -72,7 +75,7 @@ class SHA256CRYPTHasher(PasswordHasher):
return pwhash
def _encrypt(self, clearvalue, salt=None):
rounds = int(parameters.get_admin('ROUNDS_NUMBER'))
rounds = param_tools.get_global_parameter("rounds_number")
return sha256_crypt.encrypt(clearvalue, rounds=rounds)
def verify(self, clearvalue, hashed_value):
@@ -95,7 +98,7 @@ class SHA512CRYPTHasher(PasswordHasher):
return pwhash
def _encrypt(self, clearvalue, salt=None):
rounds = int(parameters.get_admin('ROUNDS_NUMBER'))
rounds = param_tools.get_global_parameter("rounds_number")
return sha512_crypt.encrypt(clearvalue, rounds=rounds)
def verify(self, clearvalue, hashed_value):
+1 -1
View File
@@ -1,7 +1,7 @@
{% load i18n lib_tags %}
<h2>{% trans "Parameters" %} <small>{% trans "Configure Modoboa" %}</small></h2><hr />
<form id="settings_form" method="POST" action="{% url 'core:parameter_save' %}" class="form-horizontal">{% csrf_token %}
{% include "common/parameters.html" %}
{% include "parameters/base_form.html" %}
<hr>
<button type="submit" class="btn btn-primary col-xs-offset-4 col-xs-4" id="update" name="update">{% trans 'Save' %}</button>
</form>
@@ -5,7 +5,7 @@
<form class="form-horizontal" method="POST" action="{% url 'core:user_preferences' %}"
id="uprefs_form">
{% csrf_token %}
{% include "common/parameters.html" %}
{% include "parameters/base_form.html" %}
<hr>
<button type="submit" class="btn btn-primary col-xs-offset-4 col-xs-4" id="update" name="update">{% trans 'Save' %}</button>
</form>
+5 -5
View File
@@ -9,13 +9,13 @@ from django.template.loader import render_to_string
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
from modoboa.lib.listing import get_sort_order, get_listing_page
from modoboa.lib.web_utils import (
_render_to_string, render_to_json_response
)
from modoboa.parameters import tools as param_tools
@login_required
@@ -32,8 +32,8 @@ def viewparameters(request, tplname='core/parameters.html'):
return render_to_json_response({
"left_selection": "parameters",
"content": _render_to_string(request, tplname, {
"forms": core_parameters.registry.get_forms(
"admin", localconfig=request.localconfig)
"forms": param_tools.registry.get_forms(
"global", localconfig=request.localconfig)
})
})
@@ -42,8 +42,8 @@ def viewparameters(request, tplname='core/parameters.html'):
@user_passes_test(lambda u: u.is_superuser)
def saveparameters(request):
"""Save all parameters."""
forms = core_parameters.registry.get_forms(
"admin", request.POST, localconfig=request.localconfig)
forms = param_tools.registry.get_forms(
"global", request.POST, localconfig=request.localconfig)
for formdef in forms:
form = formdef["form"]
if form.is_valid():
+7 -5
View File
@@ -8,12 +8,13 @@ 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 import events
from modoboa.lib.cryptutils import encrypt
from modoboa.lib.web_utils import (
_render_to_string, render_to_json_response
)
from modoboa.parameters import tools as param_tools
from ..forms import ProfileForm, APIAccessForm
@@ -60,7 +61,7 @@ def profile(request, tplname='core/user_profile.html'):
@login_required
def preferences(request):
if request.method == "POST":
forms = core_parameters.registry.get_forms(
forms = param_tools.registry.get_forms(
"user", request.POST, user=request.user)
for formdef in forms:
form = formdef["form"]
@@ -70,12 +71,13 @@ def preferences(request):
return render_to_json_response({
"prefix": form.app, "form_errors": form.errors
}, status=400)
request.user.save()
return render_to_json_response(_("Preferences saved"))
return render_to_json_response({
"content": _render_to_string(request, "core/user_preferences.html", {
"forms": parameters.get_user_forms(request.user)
"forms": param_tools.registry.get_forms(
"user", user=request.user, first_app="general")
})
})
+7 -6
View File
@@ -3,12 +3,11 @@
from django.contrib.auth.backends import ModelBackend
from modoboa.core.models import User
from modoboa.lib import parameters
from modoboa.lib.email_utils import split_mailbox
from modoboa.parameters import tools as param_tools
class SimpleBackend(ModelBackend):
"""Simple authentication backend."""
def authenticate(self, username=None, password=None):
@@ -36,7 +35,7 @@ try:
def __init__(self, *args, **kwargs):
"""Load LDAP settings."""
parameters.apply_to_django_settings()
param_tools.apply_to_django_settings()
super(LDAPBackend, self).__init__(*args, **kwargs)
def get_or_create_user(self, username, ldap_user):
@@ -47,8 +46,9 @@ try:
ldap_user.attrs contains all of their LDAP attributes.
"""
group = 'SimpleUsers'
admin_groups = parameters \
.get_admin('LDAP_ADMIN_GROUPS', app='core').split(';')
admin_groups = (
param_tools.get_global_parameter(
"ldap_admin_groups", app="core").split(";"))
for grp in admin_groups:
if grp.strip() in ldap_user.group_names:
group = 'DomainAdmins'
@@ -75,7 +75,8 @@ try:
return user
def authenticate(self, username, password):
auth_type = parameters.get_admin("AUTHENTICATION_TYPE", app="core")
auth_type = param_tools.get_global_parameter(
"authentication_type", app="core")
if auth_type == "ldap":
return super(LDAPBackend, self).authenticate(
username, password)
+4 -3
View File
@@ -7,7 +7,7 @@ import string
from Crypto.Cipher import AES
from modoboa.lib import parameters
from modoboa.parameters import tools as param_tools
def random_key(l=16):
@@ -25,7 +25,7 @@ def random_key(l=16):
def encrypt(clear):
key = parameters.get_admin("SECRET_KEY", app="core")
key = param_tools.get_global_parameter("secret_key", app="core")
obj = AES.new(key, AES.MODE_ECB)
if type(clear) is unicode:
clear = clear.encode("utf-8")
@@ -38,7 +38,8 @@ def encrypt(clear):
def decrypt(ciph):
obj = AES.new(
parameters.get_admin("SECRET_KEY", app="core"), AES.MODE_ECB
param_tools.get_global_parameter(
"secret_key", app="core"), AES.MODE_ECB
)
ciph = base64.b64decode(ciph)
clear = obj.decrypt(ciph)
+10 -8
View File
@@ -1,8 +1,7 @@
# coding: utf-8
"""
:mod:`ldaputils` --- a collection of LDAP based classes/functions
-----------------------------------------------------------------
A collection of LDAP based classes/functions.
For a first version, the LDAP support offered by Modoboa only supports
one global server definition : the one the django-auth-ldap uses.
@@ -39,14 +38,15 @@ from django.conf import settings
from django.utils.translation import ugettext as _
from modoboa.core.password_hashers import get_password_hasher
from modoboa.lib import parameters
from modoboa.lib.exceptions import InternalError
from modoboa.parameters import tools as param_tools
class LDAPAuthBackend(object):
"""LDAP authentication backend."""
def __init__(self):
parameters.apply_to_django_settings()
param_tools.apply_to_django_settings()
self.server_uri = self._setting(
"AUTH_LDAP_SERVER_URI", "ldap://localhost"
)
@@ -74,7 +74,7 @@ class LDAPAuthBackend(object):
"""Connect to the server according to configuration."""
if self.conn is not None:
return
mode = parameters.get_admin("LDAP_AUTH_METHOD", app="core")
mode = param_tools.get_global_parameter("ldap_auth_method", app="core")
if mode == "searchbind":
bind_dn = self._setting("AUTH_LDAP_BIND_DN", "")
bind_pwd = self._setting("AUTH_LDAP_BIND_PASSWORD", "")
@@ -86,8 +86,9 @@ class LDAPAuthBackend(object):
def _find_user_dn(self, user):
"""Find the DN of the given user."""
sbase = parameters.get_admin("LDAP_SEARCH_BASE", app="core")
sfilter = parameters.get_admin("LDAP_SEARCH_FILTER", app="core")
core_params = param_tools.get_global_parameter("core")
sbase = core_params["ldap_search_base"]
sfilter = core_params["ldap_search_filter"]
sfilter = sfilter % {"user": user}
res = self.conn.search_s(sbase, ldap.SCOPE_SUBTREE, sfilter)
try:
@@ -102,7 +103,8 @@ class LDAPAuthBackend(object):
:param clearpassword: the clear password
:return: the encrypted password
"""
scheme = parameters.get_admin("PASSWORD_SCHEME", app="core")
scheme = param_tools.get_global_parameter(
"password_scheme", app="core")
hasher = get_password_hasher(scheme.upper())('ldap')
return hasher.encrypt(clearpassword)
+3 -2
View File
@@ -1,6 +1,6 @@
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from modoboa.lib import parameters
from modoboa.parameters import tools as param_tools
def get_sort_order(qdict, default, allowed_values=None):
@@ -34,7 +34,8 @@ def get_listing_page(objects, pagenum):
:return: a ``Page`` object
"""
paginator = Paginator(
objects, int(parameters.get_admin("ITEMS_PER_PAGE", app="core")),
objects,
param_tools.get_global_parameter("items_per_page", app="core"),
allow_empty_first_page=False
)
try:
-325
View File
@@ -1,325 +0,0 @@
# coding: utf-8
"""
This interface provides a simple way to declare and store parameters
in Modoboa's database.
Core components or extensions can register their own parameters, which
will be available and modifiable directly from the web interface.
Only super users will be able to access this part of the web interface.
"""
from django import forms
from modoboa.core import parameters as core_parameters
from modoboa.lib import events
from modoboa.lib import signals
from modoboa.lib.sysutils import guess_extension_name
from . import db_utils
from . import form_utils
_params = {'A': {}, 'U': {}}
class GenericParametersForm(forms.Form):
"""Base class for parameter forms.
Each extension has the possibility to define global parameters.
"""
app = None
visibility_rules = None
def __init__(self, *args, **kwargs):
"""Constructor."""
if self.app is None:
raise NotImplementedError
kwargs["prefix"] = self.app
load_values_from_db = kwargs.pop("load_values_from_db", True)
super(GenericParametersForm, self).__init__(*args, **kwargs)
self.visirules = {}
if self.visibility_rules is not None:
for key, rule in self.visibility_rules.items():
field, value = rule.split("=")
visibility = {
"field": "id_%s-%s" % (self.app, field), "value": value
}
self.visirules["%s-%s" % (self.app, key)] = visibility
if not args and load_values_from_db:
self._load_initial_values()
def _load_initial_values(self):
raise NotImplementedError
def _decode_value(self, value):
return value.decode('unicode_escape').replace('\\r\\n', '\n')
def _load_extra_parameters(self, level):
params = events.raiseDictEvent('GetExtraParameters', self.app, level)
for pname, pdef in params.items():
self.fields[pname] = pdef
def _save_parameter(self, p, name, value):
if p.value == value:
return
name = name.lower()
if hasattr(self, "update_%s" % name):
getattr(self, "update_%s" % name)(value)
if type(value) is unicode:
p.value = value.encode("unicode_escape").strip()
else:
p.value = str(value)
p.save()
@staticmethod
def has_access(**kwargs):
return True
def save(self):
raise NotImplementedError
class AdminParametersForm(GenericParametersForm):
"""Base form to declare admin level parameters."""
def __init__(self, *args, **kwargs):
"""Store LocalConfig instance."""
self.localconfig = kwargs.pop("localconfig", None)
super(AdminParametersForm, self).__init__(*args, **kwargs)
def _load_initial_values(self):
"""Load form initial values from database."""
condition = (
not db_utils.db_table_exists("core_localconfig") or
not self.localconfig)
if condition:
return
values = self.localconfig.parameters.get_values(app=self.app)
for key, value in values:
self.fields[key].initial = value
def save(self):
"""Save parameters to database."""
parameters = {}
for name, value in self.cleaned_data.items():
if type(self.fields[name]) is form_utils.SeparatorField:
continue
parameters[name] = value
self.localconfig.parameters.set_values(parameters, app=self.app)
def to_django_settings(self):
"""Inject parameters into django settings module."""
pass
def get_current_values(self):
"""Return current values from the database."""
values = {}
for key in self.fields.keys():
try:
values[key] = get_admin(key.upper(), app=self.app)
except core_parameters.NotDefined:
pass
return values
class UserParametersForm(GenericParametersForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user") if "user" in kwargs else None
super(UserParametersForm, self).__init__(*args, **kwargs)
def _load_initial_values(self):
if not db_utils.db_table_exists("lib_userparameter"):
return
if self.user is None:
return
from .models import UserParameter
names = [
"%s.%s" % (self.app, name.upper()) for name in self.fields.keys()
]
for p in UserParameter.objects.filter(user=self.user, name__in=names):
self.fields[p.shortname].initial = self._decode_value(p.value)
def save(self):
from .models import UserParameter
from modoboa.lib.form_utils import SeparatorField
for name, value in self.cleaned_data.items():
if type(self.fields[name]) is SeparatorField:
continue
fullname = "%s.%s" % (self.app, name.upper())
try:
p = UserParameter.objects.get(user=self.user, name=fullname)
except UserParameter.DoesNotExist:
p = UserParameter()
p.user = self.user
p.name = fullname
self._save_parameter(p, name, value)
def register(formclass, label):
"""Register a form class containing parameters.
formclass must inherit from ``AdminParametersForm`` or
``UserParametersForm``.
:param formclass: a form class
:param string label: the label to display in parameters or settings pages
"""
if issubclass(formclass, AdminParametersForm):
level = "admin"
elif issubclass(formclass, UserParametersForm):
level = "user"
else:
raise RuntimeError("Unknown parameter class")
core_parameters.registry.add(level, formclass, label)
def unregister(app=None):
"""Unregister an application
All parameters associated to this application will also be
removed.
:param app: the application's name (string)
"""
if app is None:
app = guess_extension_name()
for lvlparams in _params.values():
if app in lvlparams:
del lvlparams[app]
def __is_defined(app, level, name):
not_defined = (
level not in ['A', 'U'] or
app not in _params[level] or
name not in _params[level][app]["defaults"]
)
if not_defined:
raise NotDefined(app, name)
def save_admin(name, value, app=None):
"""Set a new value for a given parameter."""
from .models import Parameter
if app is None:
app = guess_extension_name()
__is_defined(app, 'A', name)
fullname = "%s.%s" % (app, name)
try:
p = Parameter.objects.get(name=fullname)
except Parameter.DoesNotExist:
p = Parameter()
p.name = fullname
p.value = None
f = get_parameter_form('A', name, app)
f()._save_parameter(p, name, value)
def save_user(user, name, value, app=None):
from .models import UserParameter
if app is None:
app = guess_extension_name()
__is_defined(app, 'U', name)
fullname = "%s.%s" % (app, name)
try:
p = UserParameter.objects.get(user=user, name=fullname)
except UserParameter.DoesNotExist:
p = UserParameter()
p.user = user
p.name = fullname
f = get_parameter_form('U', name, app)
f()._save_parameter(p, name, value)
def get_admin(name, app=None, raise_error=True):
"""Return an administrative parameter.
A ``NotDefined`` exception if the parameter doesn't exist.
:param name: the parameter's name
:param app: the application owning the parameter
:return: the corresponding value as a string
"""
# FIXME: deprecate this function
request = signals.get_request()
if request:
localconfig = request.localconfig
else:
from modoboa.core import models as core_models
localconfig = core_models.LocalConfig.objects.first()
if app is None:
app = guess_extension_name()
return localconfig.parameters.get_value(
name, app=app, raise_exception=raise_error)
def get_user(user, name, app=None, raise_error=True):
"""Return a parameter for a specific user
A ``NotDefined`` exception if the parameter doesn't exist.
:param ``User`` user: the desired user
:param name: the parameter's name
:param app: the application owning the parameter
:return: the corresponding value as a string
"""
from .models import UserParameter
if app is None:
app = guess_extension_name()
try:
__is_defined(app, "U", name)
except NotDefined:
if raise_error:
raise
return None
try:
p = UserParameter.objects.get(user=user, name="%s.%s" % (app, name))
except UserParameter.DoesNotExist:
return _params["U"][app]["defaults"][name]
return p.value.decode("unicode_escape")
def get_admin_forms(*args, **kwargs):
"""Get all admin level forms.
Generates an instance of each declared form.
"""
return core_parameters.registry.get_forms(
"admin", *args, **kwargs)
def get_user_forms(user, *args, **kwargs):
"""Return an instance of each user-level forms."""
kwargs.update({"user": user, "first_app": "general"})
return core_parameters.registry.get_forms(
"user", *args, **kwargs)
def get_parameter_form(level, name, app=None):
"""Return the form containing a specific parameter
:param string level: associated level
:param string name: paremeter's name
:param string app: parameter's application
:return: a form class
"""
if app is None:
app = guess_extension_name()
__is_defined(app, level, name)
return _params[level][app]["form"]
def apply_to_django_settings():
for form in get_admin_forms():
form["form"].to_django_settings()
-75
View File
@@ -3,14 +3,12 @@
import json
from django import forms
from django.core import management
from django.test import TestCase
from rest_framework.authtoken.models import Token
from rest_framework.test import APITestCase
from modoboa.lib import parameters
from modoboa.core import models as core_models
from . import sysutils
@@ -96,76 +94,3 @@ class ModoAPITestCase(ParametersMixin, APITestCase):
"""Setup."""
super(ModoAPITestCase, self).setUp()
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
class TestParams(parameters.AdminParametersForm):
app = "test"
param1 = forms.CharField(label="Test", initial="toto")
param2 = forms.IntegerField(label="Int", initial=42)
def update_param2(self, value):
raise RuntimeError("new value %d" % value)
class TestUserParams(parameters.UserParametersForm):
app = "test"
param1 = forms.CharField(label="Test", initial="titi")
param2 = forms.IntegerField(label="Int", initial=42)
def update_param2(self, value):
raise RuntimeError("new value %d" % value)
class ParameterTestCase(TestCase):
"""Simple test cases for ``modoboa.lib.parameters`` module.
"""
@classmethod
def setUpTestData(cls):
super(ParameterTestCase, cls).setUpTestData()
cls.user = core_models.User.objects.create(username="tester")
def setUp(self):
"""Initialize tests."""
super(ParameterTestCase, self).setUp()
parameters.register(TestParams, "Test")
parameters.register(TestUserParams, "TestUser")
def test_register_form(self):
self.assertIn("test", parameters._params['A'])
def test_unregister(self):
parameters.unregister("test")
self.assertNotIn("test", parameters._params['A'])
def test_get_parameter_form(self):
self.assertIs(
parameters.get_parameter_form('A', 'PARAM1', 'test'),
TestParams
)
def test_save_admin(self):
parameters.save_admin("PARAM1", "45", app="test")
self.assertEqual(parameters.get_admin("PARAM1", app="test"), "45")
def test_update_param(self):
with self.assertRaisesRegexp(RuntimeError, "new value 35"):
parameters.save_admin("PARAM2", 35, app="test")
def test_get_admin(self):
self.assertEqual(parameters.get_admin("PARAM1", "test"), "toto")
with self.assertRaises(parameters.NotDefined):
parameters.get_admin("TOTO", "test")
def test_get_user(self):
self.assertEqual(
parameters.get_user(self.user, "PARAM1", "test"), "titi")
with self.assertRaises(parameters.NotDefined):
parameters.get_user(self.user, "TOTO", "test")
def test_save_user(self):
parameters.save_user(self.user, "PARAM1", "pouet", "test")
self.assertEqual(
parameters.get_user(self.user, "PARAM1", "test"), "pouet")
+2 -6
View File
@@ -4,10 +4,10 @@ from django import forms
from django.utils.translation import ugettext_lazy as _
from modoboa.lib.form_utils import SeparatorField, YesNoField
from modoboa.lib.parameters import AdminParametersForm
from modoboa.parameters import forms as param_forms
class ParametersForm(AdminParametersForm):
class ParametersForm(param_forms.AdminParametersForm):
"""Available admin parameters."""
app = "limits"
@@ -135,7 +135,3 @@ class ParametersForm(AdminParametersForm):
"deflt_domain_domain_aliases_limit": "enable_domain_limits=True",
"deflt_domain_domain_admins_limit": "enable_domain_limits=True",
}
def __init__(self, *args, **kwargs):
super(ParametersForm, self).__init__(*args, **kwargs)
self._load_extra_parameters('A')
+5 -5
View File
@@ -1,20 +1,20 @@
"""App config for limits."""
from django.apps import AppConfig
from django.utils.translation import ugettext as _
EVENTS = [
'GetExtraLimitTemplates'
"GetExtraLimitTemplates"
]
def load_limits_settings():
"""Load settings."""
from django.utils.translation import ugettext as _
from modoboa.lib import events, parameters
from modoboa.lib import events
from modoboa.parameters import tools as param_tools
from .app_settings import ParametersForm
parameters.register(ParametersForm, _("Limits"))
param_tools.registry.add("global", ParametersForm, _("Limits"))
events.declare(EVENTS)
from . import controls
from . import general_callbacks
+5 -7
View File
@@ -1,18 +1,16 @@
# coding: utf-8
"""
:mod:`controls` --- provides event handlers that check if limits are reached
----------------------------------------------------------------------------
"""
"""Event handlers that check if limits are reached."""
from modoboa.lib import events, parameters
from modoboa.lib import events
from modoboa.lib.permissions import get_object_owner
from modoboa.parameters import tools as param_tools
from . import utils
def move_pool_resource(owner, user):
"""Move resource from one pool to another
"""Move resource from one pool to another.
When an account doesn't need a pool anymore, we move the
associated resource to the pool of its owner.
@@ -40,7 +38,7 @@ def user_can_set_role(user, role, account=None):
:param str newrole: role to check
"""
condition = (
not parameters.get_admin("ENABLE_ADMIN_LIMITS") or
not param_tools.get_global_parameter("enable_admin_limits") or
role != "DomainAdmins")
if condition:
return [True]
+8 -7
View File
@@ -3,7 +3,8 @@
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from modoboa.lib import events, parameters
from modoboa.lib import events
from modoboa.parameters import tools as param_tools
from . import forms
from . import utils
@@ -12,7 +13,7 @@ from . import utils
@events.observe("ExtraAdminContent")
def display_pool_usage(user, target, currentpage):
condition = (
not parameters.get_admin("ENABLE_ADMIN_LIMITS") or
not param_tools.get_global_parameter("enable_admin_limits") or
target != "leftcol" or user.is_superuser)
if condition:
return []
@@ -40,7 +41,7 @@ def display_pool_usage(user, target, currentpage):
@events.observe("ExtraAccountForm")
def extra_account_form(user, account=None):
if not parameters.get_admin("ENABLE_ADMIN_LIMITS"):
if not param_tools.get_global_parameter("enable_admin_limits"):
return []
if user.role not in ["SuperAdmins", "Resellers"]:
return []
@@ -61,7 +62,7 @@ def extra_account_form(user, account=None):
@events.observe("ExtraDomainForm")
def extra_domain_form(user, domain):
"""Include domain limits form."""
if not parameters.get_admin("ENABLE_DOMAIN_LIMITS"):
if not param_tools.get_global_parameter("enable_domain_limits"):
return []
if not user.has_perm("admin.change_domain"):
return []
@@ -74,7 +75,7 @@ def extra_domain_form(user, domain):
@events.observe("FillDomainInstances")
def fill_domain_instances(user, domain, instances):
"""Set domain instance for resources form."""
if not parameters.get_admin("ENABLE_DOMAIN_LIMITS"):
if not param_tools.get_global_parameter("enable_domain_limits"):
return
if not user.has_perm("admin.change_domain"):
return
@@ -93,7 +94,7 @@ def check_form_access(account, form):
@events.observe("FillAccountInstances")
def fill_account_instances(user, account, instances):
condition = (
not parameters.get_admin("ENABLE_ADMIN_LIMITS") or
not param_tools.get_global_parameter("enable_admin_limits") or
(not user.is_superuser and user.role != "Resellers")
)
if condition:
@@ -106,7 +107,7 @@ def fill_account_instances(user, account, instances):
@events.observe("GetStaticContent")
def get_static_content(caller, st_type, user):
condition = (
not parameters.get_admin("ENABLE_ADMIN_LIMITS") or
not param_tools.get_global_parameter("enable_admin_limits") or
caller not in ["domains", "identities"] or
user.role in ["SuperAdmins", "SimpleUsers"]
)
+11 -10
View File
@@ -10,7 +10,7 @@ from modoboa.admin import signals as admin_signals
from modoboa.core import models as core_models
from modoboa.core import signals as core_signals
from modoboa.lib import signals as lib_signals
from modoboa.lib import parameters
from modoboa.parameters import tools as param_tools
from . import lib
from . import models
@@ -21,13 +21,13 @@ from . import utils
def check_object_limit(sender, context, object_type, **kwargs):
"""Check if user can create a new object."""
if context.__class__.__name__ == "User":
if not parameters.get_admin("ENABLE_ADMIN_LIMITS"):
if not param_tools.get_global_parameter("enable_admin_limits"):
return
if context.is_superuser:
return True
limit = context.userobjectlimit_set.get(name=object_type)
elif context.__class__.__name__ == "Domain":
if not parameters.get_admin("ENABLE_DOMAIN_LIMITS"):
if not param_tools.get_global_parameter("enable_domain_limits"):
return
limit = context.domainobjectlimit_set.get(name=object_type)
else:
@@ -50,9 +50,9 @@ def create_user_limits(sender, instance, **kwargs):
max_value = 0
# creator can be None if user was created by a factory
if not creator or creator.is_superuser:
max_value = int(
parameters.get_admin(
"DEFLT_USER_{}_LIMIT".format(name.upper())))
max_value = (
param_tools.get_global_parameter(
"deflt_user_{0}_limit".format(name)))
models.UserObjectLimit.objects.create(
user=instance, name=name, content_type=ct, max_value=max_value)
@@ -63,8 +63,9 @@ def create_domain_limits(sender, instance, **kwargs):
if not kwargs.get("created"):
return
for name, definition in utils.get_domain_limit_templates():
max_value = int(
parameters.get_admin("DEFLT_DOMAIN_{}_LIMIT".format(name.upper())))
max_value = (
param_tools.get_global_parameter(
"deflt_domain_{0}_limit".format(name)))
models.DomainObjectLimit.objects.create(
domain=instance, name=name, max_value=max_value)
@@ -72,7 +73,7 @@ def create_domain_limits(sender, instance, **kwargs):
@receiver(admin_signals.extra_domain_dashboard_widgets)
def display_domain_limits(sender, user, domain, **kwargs):
"""Display resources usage for domain."""
if not parameters.get_admin("ENABLE_DOMAIN_LIMITS"):
if not param_tools.get_global_parameter("enable_domain_limits"):
return []
return [{
"column": "right",
@@ -87,7 +88,7 @@ def display_domain_limits(sender, user, domain, **kwargs):
def display_admin_limits(sender, user, account, **kwargs):
"""Display resources usage for admin."""
condition = (
parameters.get_admin("ENABLE_ADMIN_LIMITS") and
param_tools.get_global_parameter("enable_admin_limits") and
account.role in ["DomainAdmins", "Resellers"]
)
if not condition:
View File
+7
View File
@@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class ParametersConfig(AppConfig):
name = 'parameters'
+107
View File
@@ -0,0 +1,107 @@
"""Parameters forms."""
from django import forms
from modoboa.lib import events
from modoboa.lib import db_utils
from modoboa.lib import form_utils
class GenericParametersForm(forms.Form):
"""Base class for parameter forms.
Each extension has the possibility to define global parameters.
"""
app = None
visibility_rules = None
def __init__(self, *args, **kwargs):
"""Constructor."""
if self.app is None:
raise NotImplementedError
kwargs["prefix"] = self.app
load_values_from_db = kwargs.pop("load_values_from_db", True)
super(GenericParametersForm, self).__init__(*args, **kwargs)
self.visirules = {}
if self.visibility_rules is not None:
for key, rule in self.visibility_rules.items():
field, value = rule.split("=")
visibility = {
"field": "id_%s-%s" % (self.app, field), "value": value
}
self.visirules["%s-%s" % (self.app, key)] = visibility
if not args and load_values_from_db:
self._load_initial_values()
def _load_initial_values(self):
raise NotImplementedError
@staticmethod
def has_access(**kwargs):
return True
def save(self):
raise NotImplementedError
class AdminParametersForm(GenericParametersForm):
"""Base form to declare admin level parameters."""
def __init__(self, *args, **kwargs):
"""Store LocalConfig instance."""
self.localconfig = kwargs.pop("localconfig", None)
super(AdminParametersForm, self).__init__(*args, **kwargs)
def _load_initial_values(self):
"""Load form initial values from database."""
condition = (
not db_utils.db_table_exists("core_localconfig") or
not self.localconfig)
if condition:
return
values = self.localconfig.parameters.get_values(app=self.app)
for key, value in values:
self.fields[key].initial = value
def save(self):
"""Save parameters to database."""
parameters = {}
for name, value in self.cleaned_data.items():
if type(self.fields[name]) is form_utils.SeparatorField:
continue
parameters[name] = value
self.localconfig.parameters.set_values(parameters, app=self.app)
def to_django_settings(self):
"""Inject parameters into django settings module."""
pass
class UserParametersForm(GenericParametersForm):
"""Base form to declare user level parameters."""
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
super(UserParametersForm, self).__init__(*args, **kwargs)
def _load_initial_values(self):
"""Load initial values from User instance."""
if not db_utils.db_table_exists("core_localconfig"):
return
if self.user is None:
return
parameters = self.user.parameters.get_values(self.app)
for parameter, value in parameters:
self.fields[parameter].initial = value
def save(self):
"""Save new values."""
parameters = {}
for name, value in self.cleaned_data.items():
if type(self.fields[name]) is form_utils.SeparatorField:
continue
parameters[name] = value
self.user.parameters.set_values(parameters, app=self.app)
+3
View File
@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.
@@ -2,6 +2,7 @@
from modoboa.lib import exceptions
from modoboa.lib import form_utils
from modoboa.lib import signals
from modoboa.lib.sysutils import guess_extension_name
@@ -27,7 +28,7 @@ class Registry(object):
def __init__(self):
"""Constructor."""
self._registry = {
"admin": {},
"global": {},
"user": {}
}
@@ -123,7 +124,9 @@ class Manager(object):
app = guess_extension_name()
values = registry.get_defaults(self._level, app)
for parameter, value in values.iteritems():
yield (parameter, self._parameters[app].get(parameter, value))
if app in self._parameters:
value = self._parameters[app].get(parameter, value)
yield (parameter, value)
def set_value(self, parameter, value, app=None):
"""Set parameter for the given app."""
@@ -144,3 +147,52 @@ class Manager(object):
if app not in self._parameters:
self._parameters[app] = registry.get_defaults(self._level, app)
self._parameters[app].update(values)
def get_localconfig():
"""Retrieve current LocalConfig instance."""
from modoboa.core import models as core_models
request = signals.get_request()
if request:
return request.localconfig
return core_models.LocalConfig.objects.first()
def get_global_parameter(name, app=None, **kwargs):
"""Retrieve a global parameter.
This is a shortcut to use when a LocalConfig instance is not
available (ie. when no request object is available).
A ``NotDefined`` exception if the parameter doesn't exist.
:param name: the parameter's name
:param app: the application owning the parameter
:return: the corresponding value
"""
if app is None:
app = guess_extension_name()
return get_localconfig().parameters.get_value(name, app=app, **kwargs)
def get_global_parameters(app, **kwargs):
"""Retrieve global parameters of a given app.
This is a shortcut to use when a LocalConfig instance is not
available (ie. when no request object is available).
A ``NotDefined`` exception if the parameter doesn't exist.
:param name: the parameter's name
:param app: the application owning the parameter
:return: the corresponding value
"""
return get_localconfig().parameters.get_values(app, **kwargs)
def apply_to_django_settings():
"""Apply global parameters to Django settings module."""
for form in registry.get_forms("global"):
form["form"].to_django_settings()
+2 -2
View File
@@ -3,11 +3,11 @@
from django import forms
from django.utils.translation import ugettext_lazy
from modoboa.lib import parameters
from modoboa.lib.form_utils import SeparatorField
from modoboa.parameters import forms as param_forms
class AdminParametersForm(parameters.AdminParametersForm):
class AdminParametersForm(param_forms.AdminParametersForm):
"""Admin parameters definition."""
app = "relaydomains"
+4 -4
View File
@@ -1,7 +1,7 @@
"""AppConfig for relaydomains."""
from django.apps import AppConfig
from django.utils.translation import ugettext as _
EVENTS = [
"RelayDomainCreated",
@@ -16,11 +16,11 @@ EVENTS = [
def load_relaydomains_settings():
"""Load application settings."""
from django.utils.translation import ugettext as _
from modoboa.lib import events, parameters
from modoboa.parameters import tools as param_tools
from modoboa.lib import events
from .app_settings import AdminParametersForm
parameters.register(AdminParametersForm, _("Relay domains"))
param_tools.registry.add("global", AdminParametersForm, _("Relay domains"))
events.declare(EVENTS)
from . import general_callbacks
+2 -2
View File
@@ -7,8 +7,8 @@ from django.utils.translation import ugettext as _, ugettext_lazy
from reversion import revisions as reversion
from modoboa.admin import models as admin_models
from modoboa.lib import parameters
from modoboa.lib.exceptions import BadRequest
from modoboa.parameters import tools as param_tools
class ServiceManager(Manager):
@@ -20,7 +20,7 @@ class ServiceManager(Manager):
entries are saved and outdated ones (ie. present in the
database but not in the file) are removed.
"""
with open(parameters.get_admin('MASTER_CF_PATH')) as fp:
with open(param_tools.get_global_parameter("master_cf_path")) as fp:
content = fp.read()
services = []
for line in content.split('\n'):