mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
Merge
This commit is contained in:
@@ -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
|
||||
|
||||
+28
-13
@@ -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)
|
||||
|
||||
+2
-2
@@ -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))
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
+45
-1
@@ -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"]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
<script type="text/javascript" src="{{ MEDIA_URL }}js/Autocompleter.Request.js"></script>
|
||||
<script type="text/javascript">
|
||||
function init_form() {
|
||||
var dti = new DynamicTextInput($$("input[name=targets]"));
|
||||
var dti = new DynamicTextInput($$("input[name=targets]"), {
|
||||
containerLevel: 2
|
||||
});
|
||||
|
||||
new Autocompleter.Request.JSON("id_targets",
|
||||
"{% url admin.views.mailboxes_search %}", {
|
||||
|
||||
@@ -37,6 +37,7 @@ class ChangePasswordForm(forms.Form):
|
||||
|
||||
class ForwardForm(forms.Form):
|
||||
dest = forms.CharField(label=_("Destination(s)"), widget=forms.Textarea)
|
||||
keepcopies = forms.BooleanField(label=_("Keep local copies"), required=False)
|
||||
|
||||
def parse_dest(self):
|
||||
self.dests = []
|
||||
|
||||
@@ -38,7 +38,7 @@ def options_menu(user):
|
||||
"img" : static_url("pics/alias.png"),
|
||||
"label" : _("Forward"),
|
||||
"class" : "boxed",
|
||||
"rel" : "{handler:'iframe',size:{x:360,y:320},closeBtn:true}"
|
||||
"rel" : "{handler:'iframe',size:{x:360,y:350},closeBtn:true}"
|
||||
}]
|
||||
|
||||
entries[0]["menu"] += events.raiseQueryEvent("UserMenuDisplay",
|
||||
|
||||
+12
-2
@@ -65,15 +65,25 @@ def setforward(request, tplname="userprefs/setforward.html"):
|
||||
al.address = mb.address
|
||||
al.domain = mb.domain
|
||||
al.enabled = mb.user.is_active
|
||||
intdests = []
|
||||
if form.cleaned_data["keepcopies"]:
|
||||
intdests += [mb]
|
||||
form.parse_dest()
|
||||
al.save([], form.dests)
|
||||
al.save(intdests, form.dests)
|
||||
return ajax_response(request, respmsg=_("Forward updated"))
|
||||
except BadDestination, e:
|
||||
error = str(e)
|
||||
return ajax_response(request, status="ko", template=tplname, form=form, error=error)
|
||||
return ajax_response(request, status="ko", template=tplname,
|
||||
form=form, error=error)
|
||||
form = ForwardForm()
|
||||
if al is not None:
|
||||
form.fields["dest"].initial = al.extmboxes
|
||||
try:
|
||||
selfmb = al.mboxes.get(pk=mb.id)
|
||||
except Mailbox.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
form.fields["keepcopies"].initial = True
|
||||
return _render(request, tplname, {
|
||||
"form" : form
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user