mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
352 lines
10 KiB
Python
352 lines
10 KiB
Python
# 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.lib import events
|
|
from modoboa.lib.sysutils import guess_extension_name
|
|
from modoboa.lib.exceptions import ModoboaException
|
|
|
|
_params = {'A': {}, 'U': {}}
|
|
|
|
|
|
class NotDefined(ModoboaException):
|
|
http_code = 404
|
|
|
|
def __init__(self, app, name):
|
|
self.app = app
|
|
self.name = name
|
|
|
|
def __str__(self):
|
|
return "Application '%s' and/or parameter '%s' not defined" \
|
|
% (self.app, self.name)
|
|
|
|
|
|
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):
|
|
if self.app is None:
|
|
raise NotImplementedError
|
|
|
|
kwargs["prefix"] = self.app
|
|
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:
|
|
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()
|
|
|
|
def save(self):
|
|
raise NotImplementedError
|
|
|
|
|
|
class AdminParametersForm(GenericParametersForm):
|
|
def _load_initial_values(self):
|
|
from .models import Parameter
|
|
|
|
names = ["%s.%s" % (self.app, name.upper()) for name in self.fields.keys()]
|
|
for p in Parameter.objects.filter(name__in=names):
|
|
self.fields[p.shortname].initial = self._decode_value(p.value)
|
|
|
|
def save(self):
|
|
from .models import Parameter
|
|
from modoboa.lib.formutils 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 = Parameter.objects.get(name=fullname)
|
|
except Parameter.DoesNotExist:
|
|
p = Parameter()
|
|
p.name = fullname
|
|
self._save_parameter(p, name, value)
|
|
|
|
def to_django_settings(self):
|
|
pass
|
|
|
|
def get_current_values(self):
|
|
values = {}
|
|
for key in self.fields.keys():
|
|
try:
|
|
values[key] = get_admin(key.upper(), app=self.app)
|
|
except 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 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)
|
|
|
|
@staticmethod
|
|
def has_access(user):
|
|
return True
|
|
|
|
def save(self):
|
|
from .models import UserParameter
|
|
from modoboa.lib.formutils 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
|
|
"""
|
|
from modoboa.lib.formutils import SeparatorField
|
|
|
|
if issubclass(formclass, AdminParametersForm):
|
|
level = 'A'
|
|
elif issubclass(formclass, UserParametersForm):
|
|
level = 'U'
|
|
else:
|
|
raise RuntimeError("Unknown parameter class")
|
|
_params[level][formclass.app] = {
|
|
"label": label, "form": formclass, "defaults": {}
|
|
}
|
|
form = formclass()
|
|
for name, field in form.fields.items():
|
|
if type(field) is SeparatorField:
|
|
continue
|
|
_params[level][formclass.app]["defaults"][name.upper()] = field.initial
|
|
|
|
|
|
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):
|
|
if not level in ['A', 'U'] \
|
|
or not app in _params[level] \
|
|
or not name in _params[level][app]["defaults"]:
|
|
raise NotDefined(app, name)
|
|
|
|
|
|
def save_admin(name, value, app=None):
|
|
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
|
|
"""
|
|
from .models import Parameter
|
|
|
|
if app is None:
|
|
app = guess_extension_name()
|
|
try:
|
|
__is_defined(app, "A", name)
|
|
except NotDefined:
|
|
if raise_error:
|
|
raise
|
|
return None
|
|
try:
|
|
p = Parameter.objects.get(name="%s.%s" % (app, name))
|
|
except Parameter.DoesNotExist:
|
|
return _params["A"][app]["defaults"][name]
|
|
return p.value.decode("unicode_escape").replace('\\r\\n', '\n')
|
|
|
|
|
|
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_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.
|
|
|
|
Generates an instance of each declared form.
|
|
"""
|
|
for app in get_sorted_apps('A'):
|
|
formdef = _params['A'][app]
|
|
yield {"label": formdef["label"],
|
|
"form": formdef["form"](*args, **kwargs)}
|
|
|
|
|
|
def get_user_forms(user, *args, **kwargs):
|
|
kwargs["user"] = user
|
|
sorted_apps = get_sorted_apps('U', first="general")
|
|
|
|
def realfunc():
|
|
for app in sorted_apps:
|
|
formdef = _params['U'][app]
|
|
if not formdef["form"].has_access(user):
|
|
continue
|
|
yield {"label": formdef["label"],
|
|
"form": formdef["form"](*args, **kwargs)}
|
|
|
|
return realfunc
|
|
|
|
|
|
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()
|