diff --git a/INSTALL b/INSTALL index f61245c1d..71fc3d0ef 100644 --- a/INSTALL +++ b/INSTALL @@ -544,6 +544,12 @@ they already exist) the following parameters:: virtual_transport = dovecot dovecot_destination_recipient_limit = 1 +Then, edit the */etc/postfix/master.cf* file and add the following +definition at the end:: + + dovecot unix - n n - - pipe + flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient} + If you have followed the :ref:`postfix-label` section to install your environnement, you need to modify the SQL query corresponding to the ``virtual_mailbox_maps`` parameter. Edit the diff --git a/admin/__init__.py b/admin/__init__.py index 1003d4e9d..c886038f4 100644 --- a/admin/__init__.py +++ b/admin/__init__.py @@ -24,22 +24,27 @@ parameters.register_admin("PASSWORD_SCHEME", type="list", deflt="crypt", parameters.register_admin("ITEMS_PER_PAGE", type="int", deflt=30, help=_("Number of displayed items per page")) -# -# Quick fix for #184 -# -# Just catch the DatabaseError exception raised when runnning the -# first ``syncdb`` command. -# -try: - enabled_extensions = list(Extension.objects.filter(enabled=True)) -except DatabaseError: - enabled_extensions = [] +def enabled_applications(): + """Return the list of currently enabled extensions + + Quick fix for #184: + + Just catch the DatabaseError exception raised when runnning the + first ``syncdb`` command. + + :return: a list + """ + result = [("admin", "admin"), ("userprefs", "userprefs")] + try: + exts = list(Extension.objects.filter(enabled=True)) + except DatabaseError: + exts = [] + result += map(lambda ext: (ext.name, ext.name), exts) + return sorted(result) parameters.register_admin("DEFAULT_TOP_REDIRECTION", type="list", deflt="admin", app="general", - values=sorted([("admin", "admin"), ("userprefs", "userprefs")] \ - + map(lambda ext: (ext.name, ext.name), - enabled_extensions)), + values=enabled_applications(), help=_("The default redirection used when no application is specified")) def unset_default_topredirection(**kwargs): @@ -51,4 +56,14 @@ def unset_default_topredirection(**kwargs): if topredirection == kwargs["ext"].name: parameters.save_admin("DEFAULT_TOP_REDIRECTION", "userprefs", app="general") +def update_available_applications(**kwargs): + """Simple callback to update the list of available applications + + Must be called each time an extension is disabled/enabled. + """ + parameters.update_admin("DEFAULT_TOP_REDIRECTION", app="general", + values=enabled_applications()) + events.register("ExtDisabled", unset_default_topredirection) +events.register("ExtDisabled", update_available_applications) +events.register("ExtEnabled", update_available_applications) diff --git a/admin/views.py b/admin/views.py index a6f39b6d5..7c7b56472 100644 --- a/admin/views.py +++ b/admin/views.py @@ -596,16 +596,16 @@ def saveextensions(request): parts = k.split("_", 1) dbext = Extension.objects.get(name=parts[1]) if not dbext in actived_exts: - dbext.on() dbext.enabled = True dbext.save() + dbext.on() else: found += [dbext] for ext in actived_exts: if not ext in found: - ext.off() ext.enabled = False ext.save() + ext.off() messages.info(request, _("Modifications applied."), fail_silently=True) return HttpResponseRedirect(reverse(admin.views.viewextensions)) diff --git a/extensions/webmail/static/js/webmail.js b/extensions/webmail/static/js/webmail.js index 09fd0c762..16e520fc9 100644 --- a/extensions/webmail/static/js/webmail.js +++ b/extensions/webmail/static/js/webmail.js @@ -782,11 +782,10 @@ function sendmail_callback(evt) { function compose_callback(resp) { wm_updatelisting(resp); - window.addEvent("resize", resize_window_callback); - var editormode = resp.editor; if (editormode == "html") { + window.addEvent("resize", resize_window_callback); var instance = CKEDITOR.instances[editorid]; if (instance) { CKEDITOR.remove(instance); diff --git a/lib/events.py b/lib/events.py index 434dd358a..732ea08bc 100644 --- a/lib/events.py +++ b/lib/events.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- """ +:mod:`events` --- simple events handling +---------------------------------------- + This module provides a simple way of managing events between Modoboa core application and additional components. diff --git a/lib/parameters.py b/lib/parameters.py index 2e01e6d23..59ddc6e25 100644 --- a/lib/parameters.py +++ b/lib/parameters.py @@ -36,7 +36,12 @@ def __is_defined(app, level, name): def __register(app, level, name, **kwargs): """Register a new parameter. - app corresponds to a core component (admin, main) or an extension. + ``app`` corresponds to a core component (admin, main) or to an + extension. + + :param name: the application's name + :param level: the level this parameter is available from + :param name: the parameter's name """ if not app in _params.keys(): _params[app] = {} @@ -53,7 +58,24 @@ def __register(app, level, name, **kwargs): for k, v in kwargs.iteritems(): _params[app][level][name][k] = v +def __update(app, level, name, **kwargs): + """Update a parameter's definition + + :param app: the application's name + :param level: the level this parameter is available from + :param name: the parameter's name + """ + if not app in _params.keys() or not level in _levels.keys() \ + or not _params[app][level].has_key(name): + return + for k, v in kwargs.iteritems(): + _params[app][level][name][k] = v + def __guess_extension(): + """Tries to guess the application's name by inspecting the stack + + :return: a string or None + """ modname = inspect.getmodule(inspect.stack()[2][0]).__name__ m = re.match("(?:modoboa\.)?(?:extensions\.)?([^\.$]+)", modname) if m: @@ -61,6 +83,13 @@ def __guess_extension(): return None def register_admin(name, **kwargs): + """Register a new parameter (admin level) + + Each parameter is associated to one application. If no application + is provided, the function tries to guess the appropriate one. + + :param name: the parameter's name + """ if kwargs.has_key("app"): app = kwargs["app"] del kwargs["app"] @@ -68,6 +97,21 @@ def register_admin(name, **kwargs): app = __guess_extension() return __register(app, 'A', name, **kwargs) +def update_admin(name, **kwargs): + """Update a parameter's definition (admin level) + + Each parameter is associated to one application. If no application + is provided, the function tries to guess the appropriate one. + + :param name: the parameter's name + """ + if kwargs.has_key("app"): + app = kwargs["app"] + del kwargs["app"] + else: + app = __guess_extension() + return __update(app, 'A', name, **kwargs) + def register_user(name, **kwargs): if kwargs.has_key("app"): app = kwargs["app"] diff --git a/static/js/dynamic_textinput.js b/static/js/dynamic_textinput.js index 0afd61b72..6e902388b 100644 --- a/static/js/dynamic_textinput.js +++ b/static/js/dynamic_textinput.js @@ -3,7 +3,8 @@ var DynamicTextInput = new Class({ Implements: [Options], options: { - parentContainer: null + parentContainer: null, + containerLevel: 1 }, initialize: function(targets, options) { @@ -68,7 +69,11 @@ var DynamicTextInput = new Class({ "margin-top": "2px" }); if (!this.options.parentContainer) { - field[0].inject(this.target.getParent(), "after"); + var container = this.target; + for (var i = 0; i < this.options.containerLevel; i++) { + container = container.getParent() + } + field[0].inject(container, "after"); } else { field[0].inject(this.options.parentContainer); } diff --git a/templates/admin/mbaliasform.html b/templates/admin/mbaliasform.html index f31802848..3f7e5e8ec 100644 --- a/templates/admin/mbaliasform.html +++ b/templates/admin/mbaliasform.html @@ -9,7 +9,9 @@