From add222840cb299f03e929d9a5effc3af63bb3146 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Mon, 6 Jun 2011 15:44:30 +0200 Subject: [PATCH] Added per-user forward definition (with a custom interface available inside the "Options" menu). It will not be available for admins. see #143 --- admin/lib.py | 45 +++++++++++++++++++++++++ admin/views.py | 24 +------------ templates/userprefs/setforward.html | 18 ++++++++++ userprefs/forms.py | 23 ++++++++++++- userprefs/templatetags/uprefs_extras.py | 11 ++++++ userprefs/urls.py | 1 + userprefs/views.py | 39 +++++++++++++++++++-- 7 files changed, 134 insertions(+), 27 deletions(-) create mode 100644 admin/lib.py create mode 100644 templates/userprefs/setforward.html diff --git a/admin/lib.py b/admin/lib.py new file mode 100644 index 000000000..40b896dd2 --- /dev/null +++ b/admin/lib.py @@ -0,0 +1,45 @@ +# coding: utf-8 +from django.http import HttpResponse, HttpResponseRedirect +from django.contrib.auth.models import User, Group +from models import * + +def is_domain_admin(user): + """Tell if a user is administrator for a domain of not + + Whatever the domain, we just want to know if the given user is + declared as a domain administrator. + + :param user: a User object + :return: True if the user is a domain administrator, False otherwise. + """ + grp = Group.objects.get(name="DomainAdmins") + return grp in user.groups.all() + +def good_domain(f): + """Custom permission decorator + + Check if a domain administrator is accessing the good domain. + + :param f: the original called function + """ + def dec(request, **kwargs): + if request.user.is_superuser: + return f(request, **kwargs) + mb = Mailbox.objects.get(user=request.user.id) + access = True + if request.GET.has_key("domid"): + dom_id = int(request.GET["domid"]) + if dom_id != mb.domain.id: + access = False + else: + q = request.GET.copy() + q["domid"] = mb.domain.id + request.GET = q + if access: + return f(request, **kwargs) + + from django.conf import settings + path = urlquote(request.get_full_path()) + login_url = settings.LOGIN_URL + return HttpResponseRedirect("%s?next=%s" % (login_url, path)) + return dec diff --git a/admin/views.py b/admin/views.py index ab30b955c..aff0c36dc 100644 --- a/admin/views.py +++ b/admin/views.py @@ -11,6 +11,7 @@ from django.contrib.auth.models import User, Group from django.contrib import messages from django.db import transaction, IntegrityError +from lib import * from modoboa import admin, userprefs from models import * from admin.permissions import * @@ -20,29 +21,6 @@ from modoboa.lib import _render, ajax_response, ajax_simple_response, \ from modoboa.lib.models import Parameter import copy -def good_domain(f): - def dec(request, **kwargs): - if request.user.is_superuser: - return f(request, **kwargs) - mb = Mailbox.objects.get(user=request.user.id) - access = True - if request.GET.has_key("domid"): - dom_id = int(request.GET["domid"]) - if dom_id != mb.domain.id: - access = False - else: - q = request.GET.copy() - q["domid"] = mb.domain.id - request.GET = q - if access: - return f(request, **kwargs) - - from django.conf import settings - path = urlquote(request.get_full_path()) - login_url = settings.LOGIN_URL - return HttpResponseRedirect("%s?next=%s" % (login_url, path)) - return dec - def render_domains_page(request, page, **kwargs): template = "admin/%s.html" % page if request.GET.has_key("domid"): diff --git a/templates/userprefs/setforward.html b/templates/userprefs/setforward.html new file mode 100644 index 000000000..67659ca3c --- /dev/null +++ b/templates/userprefs/setforward.html @@ -0,0 +1,18 @@ +{% extends "layout_simple.html" %} +{% block html_head %} + +{% endblock %} +{% block content %} +{% load i18n %} +

{% trans "Define your forward" %}

+ +{% if error %}
{{ error }}
{% endif %} +{% url userprefs.views.setforward as action_url %} +
+ {% include "common/genericform.html" %} + +
+ +
+
+{% endblock %} diff --git a/userprefs/forms.py b/userprefs/forms.py index 2adf07b0c..cd954f746 100644 --- a/userprefs/forms.py +++ b/userprefs/forms.py @@ -1,8 +1,12 @@ from django import forms -from modoboa.admin.models import Mailbox +from modoboa.admin.models import Domain from modoboa.lib import _check_password from django.contrib.auth.models import check_password from django.utils.translation import ugettext as _ +from modoboa.lib import split_mailbox + +class BadDestination(Exception): + pass class ChangePasswordForm(forms.Form): oldpassword = forms.CharField(label=_("Old password"), @@ -30,3 +34,20 @@ class ChangePasswordForm(forms.Form): if self.cleaned_data["newpassword"] != self.cleaned_data["confirmation"]: raise forms.ValidationError(_("Passwords mismatch")) return self.cleaned_data["confirmation"] + +class ForwardForm(forms.Form): + dest = forms.CharField(label=_("Destination(s)"), widget=forms.Textarea) + + def parse_dest(self): + self.dests = [] + for d in self.cleaned_data["dest"].strip().split(","): + local_part, domname = split_mailbox(d) + if not local_part or not domname or not len(domname): + raise BadDestination("Invalid mailbox syntax for %s" % d) + try: + mb = Domain.objects.get(name=domname) + except Mailbox.DoesNotExist: + self.dests += [d] + else: + raise BadDestination(_("You can't define a forward to a local destination. Please ask your administrator to create an alias instead.")) + diff --git a/userprefs/templatetags/uprefs_extras.py b/userprefs/templatetags/uprefs_extras.py index 8e0268d52..9a844f754 100644 --- a/userprefs/templatetags/uprefs_extras.py +++ b/userprefs/templatetags/uprefs_extras.py @@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _ from django.core.urlresolvers import reverse from modoboa import userprefs from modoboa.lib import events, static_url +from modoboa.admin.lib import is_domain_admin register = template.Library() @@ -29,6 +30,16 @@ def options_menu(user): ] }, ] + if not user.is_superuser and not is_domain_admin(user): + entries[0]["menu"] += [{ + "name" : "setforwards", + "url" : reverse(userprefs.views.setforward), + "img" : static_url("pics/alias.png"), + "label" : _("Forward"), + "class" : "boxed", + "rel" : "{handler:'iframe',size:{x:360,y:320}}" + }] + entries[0]["menu"] += events.raiseQueryEvent("UserMenuDisplay", target="options_menu") diff --git a/userprefs/urls.py b/userprefs/urls.py index 06bde3ff4..a14919f38 100644 --- a/userprefs/urls.py +++ b/userprefs/urls.py @@ -5,4 +5,5 @@ urlpatterns = patterns('modoboa.userprefs.views', (r'^preferences/$', 'preferences'), (r'^preferences/save/$', 'savepreferences'), (r'^changepassword/$', 'changepassword'), + (r'^setforward/$', 'setforward'), ) diff --git a/userprefs/views.py b/userprefs/views.py index 9a77897f0..37f986bb2 100644 --- a/userprefs/views.py +++ b/userprefs/views.py @@ -2,12 +2,13 @@ import copy from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect from django.contrib.auth.decorators \ - import login_required + import login_required, user_passes_test from django.utils.translation import ugettext as _ from modoboa.lib import _render, ajax_response, parameters from modoboa.lib import crypt_password -from forms import ChangePasswordForm -from modoboa.admin.models import Mailbox +from forms import * +from modoboa.admin.models import Mailbox, Alias +from modoboa.admin.lib import is_domain_admin @login_required def index(request): @@ -36,6 +37,38 @@ def changepassword(request, tplname="userprefs/chpassword.html"): "form" : form }) +@login_required +@user_passes_test(lambda u: not u.is_superuser and not is_domain_admin(u)) +def setforward(request, tplname="userprefs/setforward.html"): + mb = Mailbox.objects.get(user=request.user.id) + try: + al = Alias.objects.get(address=mb.address, + domain__name=mb.domain.name) + except Alias.DoesNotExist: + al = None + if request.method == "POST": + form = ForwardForm(request.POST) + error = None + if form.is_valid(): + try: + if al is None: + al = Alias() + al.address = mb.address + al.domain = mb.domain + al.enabled = mb.user.is_active + form.parse_dest() + al.save([], 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) + form = ForwardForm() + if al is not None: + form.fields["dest"].initial = al.extmboxes + return _render(request, tplname, { + "form" : form + }) + @login_required def preferences(request): apps = sorted(parameters._params.keys())