diff --git a/admin/forms.py b/admin/forms.py index 9222f8207..770d90b38 100644 --- a/admin/forms.py +++ b/admin/forms.py @@ -34,6 +34,11 @@ class MailboxForm(forms.ModelForm): for f in ['name', 'address', 'quota', 'password1', 'password2']: self.fields[f].widget.attrs['size'] = 14 + def clean_address(self): + if self.cleaned_data["address"].find('@') != -1: + return self.cleaned_data["address"].rsplit("@", 1)[0] + return self.cleaned_data["address"] + def clean_password2(self): if self.cleaned_data["password1"] != self.cleaned_data["password2"]: raise forms.ValidationError(_("Passwords mismatch")) @@ -55,6 +60,11 @@ class AliasForm(forms.ModelForm): model = Alias fields = ('address', 'mboxes', 'enabled') + def clean_address(self): + if self.cleaned_data["address"].find('@') != -1: + return self.cleaned_data["address"].rsplit("@", 1)[0] + return self.cleaned_data["address"] + class SuperAdminForm(forms.Form): user = forms.ModelChoiceField([], label=_("User"), required=True, empty_label=_("Select a user"), diff --git a/admin/templatetags/admin_extras.py b/admin/templatetags/admin_extras.py index e6aaf0558..33b8c912b 100644 --- a/admin/templatetags/admin_extras.py +++ b/admin/templatetags/admin_extras.py @@ -28,6 +28,16 @@ def admin_menu(user): "label" : _("Domains"), "img" : static_url("pics/domains.png")} ] + elif user.has_perm("admin.view_mailboxes"): + entries[0]["menu"] += [ + {"name" : "mailboxes", + "url" : reverse(admin.views.domains), + "label" : _("Mailboxes"), + "img" : static_url("pics/mailbox.png")} + ] + entries[0]["menu"] += \ + events.raiseQueryEvent("AdminMenuDisplay", target="top_menu", + user=user) if user.has_perm("auth.view_permissions"): entries[0]["menu"] += [ {"name" : "permissions", diff --git a/admin/views.py b/admin/views.py index f158a4a4b..6741b16f0 100644 --- a/admin/views.py +++ b/admin/views.py @@ -1,41 +1,32 @@ # -*- coding: utf-8 -*- -from django.shortcuts import get_object_or_404, render_to_response -from django.template.loader import render_to_string -from django.template import RequestContext from django.http import HttpResponse, HttpResponseRedirect from django.utils import simplejson from django.utils.translation import ugettext as _ from django.utils.http import urlquote -from django.core import serializers from django.core.urlresolvers import reverse from django.contrib.auth.decorators \ import login_required, permission_required, user_passes_test from django.contrib.auth.models import User, Group from django.contrib import messages +from django.db import transaction, IntegrityError from modoboa import admin, userprefs from models import * from admin.permissions import * from modoboa.lib.authbackends import crypt_password -from modoboa.lib import _render, _ctx_ok, _ctx_ko, getctx, events, parameters +from modoboa.lib import _render, _render_to_string, _ctx_ok, \ + getctx, events, parameters from modoboa.lib.models import Parameter -import string import copy import pwd -def is_superuser(user): - if not user.is_superuser: - user.message_set.create(message=_("Permission denied.")) - return False - return True - def good_domain(f): def dec(request, dom_id, **kwargs): if request.user.is_superuser: return f(request, dom_id, **kwargs) mb = Mailbox.objects.get(user=request.user.id) if isinstance(dom_id, str) or isinstance(dom_id, unicode): - dom_id = string.atoi(dom_id) + dom_id = int(dom_id) if dom_id == mb.domain.id: return f(request, dom_id, **kwargs) @@ -48,7 +39,6 @@ def good_domain(f): @login_required def domains(request): if not request.user.has_perm("admin.view_domains"): - print "redirect" if request.user.has_perm("admin.view_mailboxes"): mb = Mailbox.objects.get(user=request.user.id) return mailboxes(request, dom_id=mb.domain.id) @@ -78,12 +68,14 @@ def newdomain(request): form.save() events.raiseEvent("CreateDomain", dom=domain) ctx = _ctx_ok(reverse(admin.views.domains)) + messages.info(request, _("Domain created"), fail_silently=True) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") error = _("Failed to initialise domain, check permissions") - ctx = _ctx_ko("admin/newdomain.html", { + content = _render_to_string(request, "admin/newdomain.html", { "form" : form, "error" : error }) + ctx = getctx("ko", content=content) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") form = DomainForm() @@ -95,23 +87,26 @@ def newdomain(request): @permission_required("admin.change_domain") def editdomain(request, dom_id): domain = Domain.objects.get(pk=dom_id) + olddomain = copy.deepcopy(domain) if request.method == "POST": form = DomainForm(request.POST, instance=domain) error = None if form.is_valid(): - if domain.name != request.POST["name"]: - if Domain.objects.filter(name=request.POST["name"]): + if domain.name != olddomain.name: + if Domain.objects.filter(name=domain.name): error = _("Domain with this name already defined") else: - if not domain.rename_dir(request.POST["name"]): + if not olddomain.rename_dir(domain.name): error = _("Failed to rename domain, check permissions") if not error: form.save() ctx = _ctx_ok(reverse(admin.views.domains)) + messages.info(request, _("Domain modified"), fail_silently=True) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") - ctx = _ctx_ko("admin/editdomain.html", { + content = _render_to_string(request, "admin/editdomain.html", { "domain" : domain, "form" : form, "error" : error }) + ctx = getctx("ko", content=content) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") form = DomainForm(instance=domain) @@ -126,7 +121,8 @@ def deldomain(request, dom_id): events.raiseEvent("DeleteDomain", dom=domain) domain.delete_dir() domain.delete() - return HttpResponseRedirect('/modoboa/admin/') + messages.info(request, _("Domain deleted"), fail_silently=True) + return HttpResponseRedirect(reverse(admin.views.domains)) @login_required @good_domain @@ -156,51 +152,51 @@ def newmailbox(request, dom_id=None): form = MailboxForm(request.POST) error = None if form.is_valid(): - if Mailbox.objects.filter(address=request.POST["address"], - domain=dom_id): - error = _("Mailbox with this address already exists") - else: - mb = form.save(commit=False) - if mb.create_dir(domain): - from django.conf import settings + mb = form.save(commit=False) + if mb.create_dir(domain): + from django.conf import settings - user = User() - user.username = user.email = "%s@%s" % (mb.address, domain.name) - user.set_unusable_password() - user.is_active = request.POST.has_key("enabled") \ - and True or False - try: - fname, lname = mb.name.split() - except ValueError: - fname = mb.name - lname = "" - user.first_name = fname - user.last_name = lname + user = User() + user.username = user.email = "%s@%s" % (mb.address, domain.name) + user.set_unusable_password() + user.is_active = request.POST.has_key("enabled") \ + and True or False + try: + fname, lname = mb.name.split() + except ValueError: + fname = mb.name + lname = "" + user.first_name = fname + user.last_name = lname + try: user.save() + except IntegrityError: + error = _("Mailbox with this address already exists") + else: mb.user = user - mb.password = crypt_password(request.POST["password1"]) - mb.uid = pwd.getpwnam(parameters.get_admin("VIRTUAL_UID")).pw_uid mb.gid = pwd.getpwnam(parameters.get_admin("VIRTUAL_GID")).pw_gid mb.domain = domain mb.quota = request.POST["quota"] if not mb.quota: mb.quota = domain.quota - mb.full_address = "%s@%s" % (mb.address, domain.name) + mb.full_address = user.email mb.save() events.raiseEvent("CreateMailbox", mbox=mb) - + messages.info(request, _("Mailbox created."), fail_silently=True) ctx = _ctx_ok(reverse(admin.views.mailboxes, args=[domain.id])) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") - error = _("Failed to initialise mailbox, check permissions") - ctx = _ctx_ko("admin/newmailbox.html", { + else: + error = _("Failed to initialise mailbox, check permissions") + content = _render_to_string("ko", "admin/newmailbox.html", { "form" : form, "domain" : domain, "error" : error }) + ctx = getctx("ko", content=content) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") form = MailboxForm() @@ -211,6 +207,7 @@ def newmailbox(request, dom_id=None): @login_required @good_domain @permission_required("admin.change_mailbox") +@transaction.commit_manually def editmailbox(request, dom_id, mbox_id=None): mb = Mailbox.objects.get(pk=mbox_id) if request.method == "POST": @@ -218,33 +215,38 @@ def editmailbox(request, dom_id, mbox_id=None): form = MailboxForm(request.POST, instance=mb) error = None if form.is_valid(): - if mb.address != request.POST["address"]: - if Mailbox.objects.filter(address=request.POST["address"], - domain=dom_id): - error = _("Mailbox with this address already exists") - else: - if not mb.rename_dir(mb.domain.name, request.POST["address"]): - error = _("Failed to rename mailbox, check permissions") - if not error: - mb = form.save(commit=False) - mb.user.is_active = request.POST.has_key("enabled") \ - and request.POST["enabled"] or False + mb = form.save(commit=False) + mb.user.is_active = request.POST.has_key("enabled") \ + and request.POST["enabled"] or False + mb.user.username = mb.user.email = \ + "%s@%s" % (mb.address, mb.domain.name) + try: mb.user.save() - - if request.POST["password1"] != u"é": - mb.password = crypt_password(request.POST["password1"]) - mb.quota = request.POST["quota"] - if not mb.quota: - mb.quota = mb.domain.quota - mb.full_address = "%s@%s" % (mb.address, mb.domain.name) - mb.save() - events.raiseEvent("ModifyMailbox", mbox=mb, oldmbox=oldmb) - ctx = _ctx_ok(reverse(admin.views.mailboxes, args=[dom_id])) - return HttpResponse(simplejson.dumps(ctx), - mimetype="application/json") - ctx = _ctx_ko("admin/editmailbox.html", { - "mbox" : mb, "form" : form, "error" : error - }) + except IntegrityError: + error = _("Mailbox with this address already exists") + else: + if not oldmb.rename_dir(mb.domain.name, mb.address): + error = _("Failed to rename mailbox, check permissions") + else: + if request.POST["password1"] != u"é": + mb.password = crypt_password(request.POST["password1"]) + mb.quota = request.POST["quota"] + if not mb.quota: + mb.quota = mb.domain.quota + mb.full_address = mb.user.email + mb.save() + transaction.commit() + events.raiseEvent("ModifyMailbox", mbox=mb, oldmbox=oldmb) + messages.info(request, _("Mailbox modified"), + fail_silently=True) + ctx = _ctx_ok(reverse(admin.views.mailboxes, args=[dom_id])) + return HttpResponse(simplejson.dumps(ctx), + mimetype="application/json") + if error is not None: + transaction.rollback() + ctx = getctx("ko", content=_render_to_string(request, "admin/editmailbox.html", { + "mbox" : mb, "form" : form, "error" : error + })) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") form = MailboxForm(instance=mb) @@ -261,16 +263,18 @@ def editmailbox(request, dom_id, mbox_id=None): @permission_required("admin.delete_mailbox") def delmailbox(request, dom_id, mbox_id=None): mb = Mailbox.objects.get(pk=mbox_id) - events.raiseEvent("DeleteMailbox", mbox=mb) - if not request.GET.has_key("keepdir") or request.GET["keepdir"] != "true": - mb.delete_dir() - mb.user.delete() - mb.delete() - ctx = _ctx_ok(""); + if mb.user.id != request.user.id: + events.raiseEvent("DeleteMailbox", mbox=mb) + if not request.GET.has_key("keepdir") or request.GET["keepdir"] != "true": + mb.delete_dir() + mb.user.delete() + mb.delete() + messages.info(request, _("Mailbox deleted"), fail_silently=True) + ctx = _ctx_ok("") + else: + ctx = getctx("ko", error=_("You can't delete your own mailbox")) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") -# return HttpResponseRedirect(reverse(admin.views.mailboxes, -# args=[dom_id])) @login_required @good_domain @@ -302,11 +306,13 @@ def newalias(request, dom_id): alias.save() form.save_m2m() ctx = _ctx_ok(reverse(admin.views.aliases, args=[dom_id])) + messages.info(request, _("Alias created"), fail_silently=True) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") - ctx = _ctx_ko("admin/newalias.html", { + content = _render_to_string(request, "admin/newalias.html", { "domain" : dom_id, "form" : form, "error" : error }) + ctx = getctx("ko", content=content) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") form = AliasForm(domain=domain) @@ -334,11 +340,14 @@ def editalias(request, dom_id, alias_id): alias.save() form.save_m2m() ctx = _ctx_ok(reverse(admin.views.aliases, args=[dom_id])) + messages.info(request, _("Alias modified"), + fail_silently=True) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") - ctx = _ctx_ko("admin/editalias.html", { - "alias" : alias, "form" : form, "error" : error + content = _render_to_string(request, "admin/editalias.html", { + "domain" : dom_id, "alias" : alias, "form" : form, "error" : error }) + ctx = getctx("ko", content=content) return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") form = AliasForm(instance=alias) return _render(request, 'admin/editalias.html', { @@ -351,6 +360,7 @@ def editalias(request, dom_id, alias_id): def delalias(request, dom_id, alias_id): alias = Alias.objects.get(pk=alias_id) alias.delete() + messages.info(request, _("Alias deleted"), fail_silently=True) return HttpResponseRedirect(reverse(admin.views.aliases, args=[dom_id])) diff --git a/extensions/webmail/templates/webmail/index.html b/extensions/webmail/templates/webmail/index.html index aa616bd3c..d054c0df0 100644 --- a/extensions/webmail/templates/webmail/index.html +++ b/extensions/webmail/templates/webmail/index.html @@ -211,6 +211,7 @@ var fromrow = -1; var torow = -1; + /* The IE way for disabling default selection */ $$("tbody>tr").set("unselectable", "on"); @@ -237,14 +238,14 @@ var tr = $$("tr[name=" + i + "]")[0]; toggleSelectRow(tr) } - } + }; rangeDown2Up = function(start, end) { for (var i = start - 1; i >= end; i--) { var tr = $$("tr[name=" + i + "]")[0]; toggleSelectRow(tr) } - } + }; toggleSelectRow = function(tr) { if (!tr.hasClass("selected")) { @@ -252,7 +253,7 @@ } else { unselectRow(tr, true); } - } + }; selectRow = function(tr) { tr.addClass("selected"); diff --git a/static/js/common.js b/static/js/common.js index ca7e8f29c..75cf58992 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -244,20 +244,31 @@ confirmation = function(question, action, callback) { var elt = ibody.getElement("input[name=result]"); if (elt.get("value") == "ok") { - params = ""; + var params = ""; if (typeof callback != "undefined") { params = callback(ibody); } - new Request({ + new Request.JSON({ method: "get", url: action.get("href"), onSuccess: function(res) { - window.location.reload(); + if (res.status == "ok") { + window.location.reload(); + } else { + infobox.error(res.error); + infobox.hide(2); + } } }).send(params); } } }); + + /* FIXME: avoid using a hard coded address like this, maybe it + could be fixed by creating a new class for "confirmation" and + create one instance for each section/page using it (I mean + directly inside the html template) */ + SqueezeBox.open("/modoboa/userprefs/confirm/?question=" + question); }; diff --git a/static/js/domains.js b/static/js/domains.js index 9f5124c58..5f0a92d13 100644 --- a/static/js/domains.js +++ b/static/js/domains.js @@ -23,7 +23,7 @@ window.addEvent('domready', function() { $$("a[name=deleteMb]").addEvent('click', function(event) { event.stop(); confirmation(gettext("Delete this mailbox?"), this, function(body) { - result = ""; + var result = ""; body.getElements("input[type=checkbox]:checked").each(function(obj) { if (result != "") { result += "&"; @@ -42,9 +42,9 @@ window.addEvent('domready', function() { $(document.body).addEvent('click', function(event) { - target = event.target; + var target = event.target; if (target.get('tag') == 'a') { - name = target.get('name'); + var name = target.get('name'); if (name == 'undefined') return; if (typeof(handlers[name]) != 'undefined') { @@ -81,7 +81,7 @@ newdom = function() { }; loadPage = function(url, destination, callback) { - var destination = (destination == null) ? "page" : destination; + destination = (destination == null) ? "page" : destination; if (callback) new Request({url: url, method: "get", onSuccess: callback}).send(); diff --git a/templates/admin/domains.html b/templates/admin/domains.html index 8e1d149ae..2d8c3ccbd 100644 --- a/templates/admin/domains.html +++ b/templates/admin/domains.html @@ -1,6 +1,5 @@ {% extends "nlayout.html" %} -{% load i18n %} -{% load admin_extras %} +{% load i18n admin_extras libextras %} {% block html_head %}