Files
modoboa/admin/views.py
T
Antoine Nguyen 858fe43cdd "Top redirection" feature.
A new admin parameter is available to specify the default application that will be launched when no one is present in the url. (ie. when the top level "/" is called).

fixed #165
2011-09-20 14:57:04 +02:00

611 lines
23 KiB
Python

# -*- coding: utf-8 -*-
from django.http import HttpResponse, HttpResponseRedirect
from django.utils import simplejson
from django.utils.translation import ugettext as _, ungettext
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators \
import login_required, permission_required, user_passes_test
from django.db.models import Q
from django.contrib.auth.models import User, Group
from django.contrib import messages
from django.db import transaction, IntegrityError
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from lib import *
from modoboa import admin, userprefs
from models import *
from modoboa.admin.permissions import *
from modoboa.admin.tables import *
from modoboa.lib import events, parameters
from modoboa.auth.lib import crypt_password
from modoboa.lib.webutils \
import _render, ajax_response, ajax_simple_response, getctx
from modoboa.lib.emailutils import split_mailbox
from modoboa.lib.models import Parameter
import copy
def render_listing(request, objtype, tplname="admin/listing.html",
**kwargs):
tblclass = "%sTable" % objtype.capitalize()
if not globals().has_key(tblclass):
raise AdminError(_("Unknown object type"))
tblclass = globals()[tblclass]
if request.GET.has_key("domid"):
kwargs["domid"] = request.GET["domid"]
else:
kwargs["domid"] = ""
kwargs["selection"] = objtype
paginator = Paginator(kwargs["objects"],
int(parameters.get_admin("ITEMS_PER_PAGE")))
try:
page = request.GET.get("page", "1")
except ValueError:
page = 1
try:
kwargs["objects"] = paginator.page(page)
except (EmptyPage, PageNotAnInteger):
kwargs["objects"] = paginator.page(paginator.num_pages)
kwargs["last_page"] = paginator.num_pages
kwargs["total"] = paginator.count
kwargs["table"] = tblclass(request, kwargs["objects"].object_list)
return _render(request, tplname, kwargs)
@login_required
def domains(request):
if not request.user.has_perm("admin.view_domains"):
if request.user.has_perm("admin.view_mailboxes"):
return HttpResponseRedirect(reverse(mailboxes))
return HttpResponseRedirect(reverse(userprefs.views.preferences))
domains = Domain.objects.all()
for dom in domains:
dom.mbalias_counter = len(Alias.objects.filter(domain=dom.id))
deloptions = {"keepdir" : _("Do not delete domain directory")}
return render_listing(request, "domains",
"admin/domains.html",
title=_("Available domains"),
objects=domains,
rel="310 190",
deloptions=deloptions)
def _validate_domain(request, form, successmsg, commonctx,
callback=None, tplname="admin/adminform.html"):
"""Domain validation
Common function shared between creation and modification actions.
"""
error = None
if form.is_valid():
try:
domain = form.save()
except AdminError, e:
error = str(e)
except IntegrityError:
error = _("Domain with this name already defined")
else:
if callback is not None:
callback(domain)
messages.info(request, successmsg, fail_silently=True)
return ajax_response(request, url=reverse(admin.views.domains))
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
@login_required
@permission_required("admin.add_domain")
def newdomain(request, tplname="admin/adminform.html"):
def newdomain_cb(domain):
events.raiseEvent("CreateDomain", dom=domain)
commonctx = {"title" : _("New domain"),
"submit_label" : _("Create"),
"action" : reverse(newdomain),
"formid" : "domform"}
if request.method == "POST":
form = DomainForm(request.POST)
return _validate_domain(request, form, _("Domain created"), commonctx,
newdomain_cb)
form = DomainForm()
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@permission_required("admin.change_domain")
def editdomain(request, dom_id, tplname="admin/adminform.html"):
domain = Domain.objects.get(pk=dom_id)
commonctx = {"title" : _("Domain editing"),
"submit_label" : _("Update"),
"action" : reverse(editdomain, args=[dom_id]),
"formid" : "domform"}
if request.method == "POST":
form = DomainForm(request.POST, instance=domain)
return _validate_domain(request, form, _("Domain modified"), commonctx)
form = DomainForm(instance=domain)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@permission_required("admin.delete_domain")
def deldomain(request):
selection = request.GET["selection"].split(",")
error = None
if request.user.id != 1:
mb = Mailbox.objects.get(user__id=request.user.id)
if str(mb.domain.id) in selection:
error = _("You can't delete your own domain")
if error is None:
if request.GET.has_key("keepdir") and request.GET["keepdir"] == "true":
keepdir = True
else:
keepdir = False
for dom in Domain.objects.filter(id__in=selection):
events.raiseEvent("DeleteDomain", dom=dom)
dom.delete(keepdir=keepdir)
msg = ungettext("Domain deleted", "Domains deleted", len(selection))
messages.info(request, msg, fail_silently=True)
return ajax_response(request)
return ajax_response(request, status="ko", respmsg=error)
@login_required
@permission_required("admin.view_domaliases")
def domaliases(request):
if request.GET.has_key("domid"):
domain = Domain.objects.get(pk=request.GET["domid"])
domaliases = DomainAlias.objects.filter(target=request.GET["domid"])
else:
domain = None
domaliases = DomainAlias.objects.all()
return render_listing(request, "domaliases",
title=_("Domain aliases"),
rel="310 190",
objects=domaliases)
@login_required
@good_domain
@permission_required("admin.add_domainalias")
def newdomalias(request, tplname="admin/adminform.html"):
commonctx = {"title" : _("New domain alias"),
"submit_label" : _("Create"),
"action" : reverse(newdomalias),
"formid" : "domaliasform"}
if request.method == "POST":
form = DomainAliasForm(request.user, request.POST)
error = None
if form.is_valid():
domalias = form.save(commit=False)
if Domain.objects.filter(name=domalias.name):
error = _("A domain with this name already exists")
else:
try:
domalias.save()
except IntegrityError:
error = _("Alias with this name already exists")
else:
messages.info(request, _("Domain alias created"), fail_silently=True)
return ajax_response(request, url=reverse(admin.views.domaliases))
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = DomainAliasForm(request.user)
if request.GET.has_key("domid"):
form.fields["target"].initial = request.GET["domid"]
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.change_domainalias")
def editdomalias(request, alias_id, tplname="admin/adminform.html"):
domalias = DomainAlias.objects.get(pk=alias_id)
commonctx = {"title" : _("Domain alias editing"),
"submit_label" : _("Update"),
"action" : reverse(editdomalias, args=[alias_id]),
"formid" : "domaliasform"}
if request.method == "POST":
form = DomainAliasForm(request.user, request.POST, instance=domalias)
error = None
if form.is_valid():
ndomalias = form.save(commit=False)
if Domain.objects.filter(name=ndomalias.name):
error = _("A domain with this name already exists")
else:
try:
ndomalias.save()
except IntegrityError:
error = _("Alias with this name already exists")
else:
messages.info(request, _("Domain alias updated"), fail_silently=True)
return ajax_response(request, url=reverse(admin.views.domaliases))
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = DomainAliasForm(request.user, instance=domalias)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.delete_domainalias")
def deldomalias(request):
selection = request.GET["selection"].split(",")
DomainAlias.objects.filter(id__in=selection).delete()
msg = ungettext("Domain alias deleted", "Domain aliases deleted", len(selection))
messages.info(request, msg, fail_silently=True)
return ajax_response(request)
@login_required
@good_domain
@permission_required("admin.view_mailboxes")
def mailboxes(request):
title = _("Available mailboxes")
if request.GET.has_key("domid"):
domain = Domain.objects.get(pk=request.GET["domid"])
mboxes = Mailbox.objects.filter(domain=domain.id)
title += " (%s)" % domain.name
else:
mboxes = Mailbox.objects.all()
domain = None
deloptions = {"keepdir" : _("Do not delete mailbox directory")}
return render_listing(request, "mailboxes",
title=title,
rel="310 320",
objects=mboxes, domain=domain, deloptions=deloptions)
@login_required
@good_domain
@permission_required("admin.view_mailboxes")
def mailboxes_raw(request, dom_id=None):
target = request.GET.has_key("target") and request.GET["target"] or "permissions"
if target == "permissions":
mailboxes = Mailbox.objects.filter(domain=dom_id).exclude(user__id=request.user.id)
else:
mailboxes = Mailbox.objects.filter(domain=dom_id)
return _render(request, 'admin/mailboxes_raw.html', {
"mailboxes" : mailboxes,
"target" : target
})
@login_required
@good_domain
@permission_required("admin.view_mailboxes")
def mailboxes_search(request):
if request.method != "POST":
return
local_part, domain = split_mailbox(request.POST["search"])
query = Q(address__startswith=local_part)
if domain is not None and domain != "":
query &= Q(domain__name__startswith=domain)
if request.GET.has_key("domid"):
query = Q(domain=request.GET["domid"]) & query
mboxes = Mailbox.objects.filter(query)
result = map(lambda mb: mb.full_address, mboxes)
return ajax_simple_response(result)
@login_required
@good_domain
@permission_required("admin.add_mailbox")
def newmailbox(request, tplname="admin/adminform.html"):
commonctx = {"title" : _("New mailbox"),
"submit_label" : _("Create"),
"action" : reverse(newmailbox),
"formid" : "mboxform"}
if request.method == "POST":
form = MailboxForm(request.user, request.POST)
error = None
if form.is_valid():
try:
mb = form.save()
except AdminError as e:
error = str(e)
else:
events.raiseEvent("CreateMailbox", mbox=mb)
messages.info(request, _("Mailbox created"),
fail_silently=True)
return ajax_response(request, url=reverse(admin.views.mailboxes) + "?domid=%d" % mb.domain.id)
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = MailboxForm(request.user)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.change_mailbox")
def editmailbox(request, mbox_id=None, tplname="admin/adminform.html"):
mb = Mailbox.objects.get(pk=mbox_id)
commonctx = {"title" : _("Mailbox editing"),
"submit_label" : _("Create"),
"action" : reverse(editmailbox, args=[mbox_id]),
"formid" : "mboxform"}
if request.method == "POST":
oldmb = copy.deepcopy(mb)
form = MailboxForm(request.user, request.POST, instance=mb)
error = None
if form.is_valid():
try:
mb = form.save(commit=False)
except AdminError, inst:
error = str(inst)
else:
if oldmb.rename_dir(mb.domain.name, mb.address):
form.commit_save(mb)
events.raiseEvent("ModifyMailbox", mbox=mb, oldmbox=oldmb)
messages.info(request, _("Mailbox modified"),
fail_silently=True)
return ajax_response(request, url=reverse(admin.views.mailboxes) + "?domid=%d" % mb.domain.id)
error = _("Failed to rename mailbox, check permissions")
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
form = MailboxForm(request.user, instance=mb)
commonctx["form"] = form
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.delete_mailbox")
def delmailbox(request):
selection = request.GET["selection"].split(",")
error = None
if not request.user.is_superuser:
mb = Mailbox.objects.get(user__pk=request.user.id)
if str(mb.id) in selection:
error = _("You can't delete your own mailbox")
if error is None:
if request.GET.has_key("keepdir") and request.GET["keepdir"] == "true":
keepdir = True
else:
keepdir = False
for mb in Mailbox.objects.filter(id__in=selection):
events.raiseEvent("DeleteMailbox", mbox=mb)
mb.delete(keepdir=keepdir)
msg = ungettext("Mailbox deleted", "Mailboxes deleted", len(selection))
messages.info(request, msg, fail_silently=True)
return ajax_response(request)
return ajax_response(request, status="ko", error=error)
@login_required
@good_domain
@permission_required("admin.view_aliases")
def mbaliases(request):
if request.GET.has_key("domid"):
aliases = Alias.objects.filter(domain=request.GET["domid"])
elif request.GET.has_key("mbid"):
aliases = Alias.objects.filter(mboxes__id=request.GET["mbid"]).distinct()
else:
aliases = Alias.objects.all()
return render_listing(request, "mbaliases",
title=_("Mailbox aliases"),
rel="320 300",
objects=aliases)
def _validate_mbalias(request, form, successmsg, tplname, commonctx):
"""Mailbox alias validation
Common function shared between creation and modification actions.
"""
error = None
if form.is_valid():
try:
if not request.POST.has_key("targets"):
raise AdminError(_("No target defined"))
form.set_targets(request.user, request.POST.getlist("targets"))
try:
alias = form.save()
except IntegrityError:
raise AdminError(_("Alias with this name already exists"))
messages.info(request, successmsg, fail_silently=True)
return ajax_response(request, url=reverse(admin.views.mbaliases))
except AdminError, e:
error = str(e)
if request.POST.has_key("targets"):
targets = request.POST.getlist("targets")
commonctx["targets"] = targets[:-1]
commonctx["form"] = form
commonctx["error"] = error
return ajax_response(request, status="ko", template=tplname, **commonctx)
@login_required
@good_domain
@permission_required("admin.add_alias")
def newmbalias(request, tplname="admin/mbaliasform.html"):
commonctx = {"title" : _("New mailbox alias"),
"submit_label" : _("Create"),
"action" : reverse(newmbalias),
"formid" : "mbaliasform"}
if request.method == "POST":
form = AliasForm(request.user, request.POST)
return _validate_mbalias(request, form, _("Mailbox alias created"),
tplname, commonctx)
form = AliasForm(request.user)
commonctx["form"] = form
commonctx["noerrors"] = True
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.change_alias")
def editmbalias(request, alias_id, tplname="admin/mbaliasform.html"):
alias = Alias.objects.get(pk=alias_id)
commonctx = {"title" : _("Mailbox alias editing"),
"submit_label" : _("Update"),
"action" : reverse(editmbalias, args=[alias.id]),
"formid" : "mbaliasform"}
if request.method == "POST":
form = AliasForm(request.user, request.POST, instance=alias)
return _validate_mbalias(request, form, _("Mailbox alias modified"),
tplname, commonctx)
form = AliasForm(request.user, instance=alias)
commonctx["form"] = form
commonctx["targets"] = alias.get_targets()
return _render(request, tplname, commonctx)
@login_required
@good_domain
@permission_required("admin.delete_alias")
def delmbalias(request):
selection = request.GET["selection"].split(",")
Alias.objects.filter(id__in=selection).delete()
msg = ungettext("Alias deleted", "Aliases deleted", len(selection))
messages.info(request, msg, fail_silently=True)
return ajax_response(request)
@login_required
@permission_required("auth.view_permissions")
def permissions(request, tplname='admin/permissions.html'):
permtables = []
if request.user.is_superuser:
permtables += [
{"id" : "super_admins",
"title" : _("Super administrators"),
"rel" : "300 140",
"content" : SuperAdminsPerms().get(request)}
]
permtables += events.raiseQueryEvent("PermsGetTables", user=request.user)
permtables += [
{"id" : "domain_admins",
"title" : _("Domain administrators"),
"rel" : "310 180",
"content" : DomainAdminsPerms().get(request)}
]
return _render(request, tplname, {
"permtables" : permtables
})
@login_required
@permission_required("auth.view_permissions")
def add_permission(request):
role = request.method == "GET" and request.GET["role"] or request.POST["role"]
pclass = get_perms_class(request.user, role)
if pclass is None:
messages.error(request, _("Permission denied!"),
fail_silently=True)
else:
pobj = pclass()
if request.method == "GET":
return pobj.get_add_form(request)
status, data = pobj.add(request)
if not status:
return HttpResponse(simplejson.dumps(data), mimetype="application/json")
messages.info(request, _("Permission added."),
fail_silently=True)
return ajax_response(request, url=reverse(admin.views.permissions))
@login_required
def delete_permissions(request):
pclass = get_perms_class(request.user, request.GET["role"])
if pclass is None:
ctx = getctx("ko", message=_("Permission denied!"))
else:
selection = request.GET["selection"].split(",")
pobj = pclass()
pobj.delete(selection)
ctx = getctx("ok", content=pobj.get(request),
message=_("Permissions removed"))
return HttpResponse(simplejson.dumps(ctx), mimetype="application/json")
@login_required
@user_passes_test(lambda u: u.is_superuser)
def viewparameters(request, tplname='admin/parameters.html'):
apps = sorted(parameters._params.keys())
gparams = []
for app in apps:
tmp = {"name" : app, "params" : []}
for p in parameters._params_order[app]['A']:
param_def = parameters._params[app]['A'][p]
newdef = {"name" : p,
"value" : parameters.get_admin(p, app=app),
"help" : param_def["help"],
"default" : param_def["deflt"],
"type" : param_def["type"]}
if "values" in param_def.keys():
newdef["values"] = param_def["values"]
tmp["params"] += [newdef]
gparams += [tmp]
return _render(request, tplname, {
"gparams" : gparams
})
@login_required
@user_passes_test(lambda u: u.is_superuser)
def saveparameters(request):
for pname, v in request.POST.iteritems():
if pname == "update":
continue
app, name = pname.split('.')
parameters.save_admin(name, v, app=app)
return ajax_response(request)
@login_required
@user_passes_test(lambda u: u.is_superuser)
def viewextensions(request, tplname='admin/extensions.html'):
from modoboa.extensions import list_extensions
exts = list_extensions()
for ext in exts:
try:
dbext = Extension.objects.get(name=ext["id"])
ext["selection"] = dbext.enabled
except Extension.DoesNotExist:
dbext = Extension()
dbext.name = ext["id"]
dbext.enabled = False
dbext.save()
ext["selection"] = False
tbl = ExtensionsTable(request, exts)
return _render(request, tplname, {
"extensions" : tbl
})
@login_required
@user_passes_test(lambda u: u.is_superuser)
def saveextensions(request):
from modoboa import extensions
actived_exts = Extension.objects.filter(enabled=True)
found = []
for k, v in request.POST.iteritems():
if k.startswith("select_"):
parts = k.split("_", 1)
dbext = Extension.objects.get(name=parts[1])
if not dbext in actived_exts:
dbext.on()
dbext.enabled = True
dbext.save()
else:
found += [dbext]
for ext in actived_exts:
if not ext in found:
ext.off()
ext.enabled = False
ext.save()
messages.info(request, _("Modifications applied."), fail_silently=True)
return HttpResponseRedirect(reverse(admin.views.viewextensions))