diff --git a/.hgignore b/.hgignore index 814ef94af..e224f9837 100644 --- a/.hgignore +++ b/.hgignore @@ -2,3 +2,4 @@ ^[^\.]+\.pyc static/tmp static/js/ckeditor +settings.py diff --git a/admin/permissions.py b/admin/permissions.py new file mode 100644 index 000000000..8f8086443 --- /dev/null +++ b/admin/permissions.py @@ -0,0 +1,123 @@ +# coding: utf8 + +from django.utils.translation import ugettext as _ +from django.contrib.auth.models import User, Group +from modoboa.lib import _render +from forms import * + +class Permissions(object): + @staticmethod + def is_auhorized(user): + return True + + def get_add_form(self, request): + raise NotImplementedError + + def add(self, request): + raise NotImplementedError + + def delete(self, request, selection): + raise NotImplementedError + + def get(self, request): + raise NotImplementedError + +class SuperAdminsPerms(Permissions): + @staticmethod + def is_auhorized(user): + return user.is_superuser + + def get_add_form(self, request): + form = SuperAdminForm() + return _render(request, 'admin/add_permission.html', { + "form" : form, + "title" : _("Add super administrator"), + "role": "super_admins" + }) + + def add(self, request): + form = SuperAdminForm(request.POST) + if form.is_valid(): + user = User.objects.get(pk=request.POST["user"]) + user.is_superuser = True + user.groups.clear() + user.save() + return True, None + + ctx = _ctx_ko("admin/add_superadmin.html", { + "form" : form + }) + return False, ctx + + def delete(self, selection): + for s in selection: + user = User.objects.get(pk=int(s)) + if user.username == "admin": + #messages.error(request, _("admin is intouchable!!"), fail_silently=True) + continue + user.is_superuser = False + user.save() + + def get(self, request): + admins = User.objects.filter(is_superuser=True) + admins_list = [] + for admin in admins: + admins_list += [{"id" : admin.id, "user_name" : admin.username, + "full_name" : "%s %s" % (admin.first_name, admin.last_name), + "enabled" : admin.is_active}] + return SuperAdminsTable(admins_list).render(request) + + +class DomainAdminsPerms(Permissions): + @staticmethod + def is_auhorized(user): + return True + + def get_add_form(self, request): + form = DomainAdminForm() + return _render(request, 'admin/add_domain_admin.html', { + "form" : form, "title" : _("Add domain administrator"), + "role" : "domain_admins" + }) + + def add(self, request): + form = DomainAdminForm(request.POST) + mboxid = request.POST['user'] + form.fields["user"].choices = \ + [(mboxid, Mailbox.objects.get(pk=mboxid)),] + if form.is_valid(): + mb = Mailbox.objects.get(pk=request.POST["user"]) + mb.user.is_superuser = False + mb.user.groups.add(Group.objects.get(name="DomainAdmins")) + mb.user.save() + return True, None + ctx = _ctx_ko("admin/add_domain_admin.html", { + "form" : form + }) + return False, ctx + + def delete(self, selection): + for s in selection: + mbox = Mailbox.objects.get(pk=int(s)) + grp = Group.objects.get(name="DomainAdmins") + mbox.user.groups.remove(grp) + mbox.user.save() + + def get(self, request): + domadmins = Mailbox.objects.filter(user__groups__name="DomainAdmins") + domadmins_list = [] + for admin in domadmins: + domadmins_list += [admin.tohash()] + return DomainAdminsTable(domadmins_list).render(request) + +def get_perms_class(user, role): + parts = role.split("_") + cname = "" + for p in parts: + cname += p.capitalize() + cname += "Perms" + if globals().has_key(cname): + if globals()[cname].is_auhorized(user): + return globals()[cname] + return None + # else raise event for plugins diff --git a/admin/templatetags/admin_extras.py b/admin/templatetags/admin_extras.py index 434e46872..e6aaf0558 100644 --- a/admin/templatetags/admin_extras.py +++ b/admin/templatetags/admin_extras.py @@ -123,10 +123,12 @@ def permissions_menu(user): entries = [ {"name" : "addperm", "label" : _("Add permission"), - "img" : static_url("pics/add.png")}, + "img" : static_url("pics/add.png"), + "url" : reverse(admin.views.add_permission)}, {"name" : "delperms", "label" : _("Remove permissions"), - "img" : static_url("pics/remove.png")}, + "img" : static_url("pics/remove.png"), + "url" : reverse(admin.views.delete_permissions)}, ] return render_to_string('common/menu.html', {"entries" : entries, "user" : user}) diff --git a/admin/urls.py b/admin/urls.py index bdd176238..7c19e5ee3 100644 --- a/admin/urls.py +++ b/admin/urls.py @@ -16,13 +16,14 @@ urlpatterns = patterns('modoboa.admin.views', url(r'^domains/(?P\d+)/aliases/$', "aliases", name="full-aliases"), url(r'^domains/(?P\d+)/aliases/(?P\d+)/$', "aliases", name="mbox-aliases"), (r'^domains/(?P\d+)/delalias/(?P\d+)/$', 'delalias'), + (r'^settings/$', 'viewparameters'), - (r'^settings/delperm/(?P\d+)/(?P\w+)/$', 'deletepermission'), (r'^settings/parameters/$', 'viewparameters'), (r'^settings/parameters/save/$', 'saveparameters'), (r'^settings/extensions/$', 'viewextensions'), (r'^settings/extensions/save/$', 'saveextensions'), + (r'^permissions/$', 'permissions'), - (r'^permissions/superadmin/add/$', 'add_superadmin'), - (r'^permissions/domainadmin/add/$', 'add_domain_admin'), + (r'^permissions/add/$', 'add_permission'), + (r'^permissions/delete/$', 'delete_permissions'), ) diff --git a/admin/views.py b/admin/views.py index 2b2e33699..873c93c63 100644 --- a/admin/views.py +++ b/admin/views.py @@ -15,7 +15,7 @@ from django.contrib import messages from modoboa import admin, userprefs from models import * -from forms 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.models import Parameter @@ -359,28 +359,18 @@ def delalias(request, dom_id, alias_id): def permissions(request): permtables = [] if request.user.is_superuser: - admins = User.objects.filter(is_superuser=True) - admins_list = [] - for admin in admins: - admins_list += [{"id" : admin.id, "user_name" : admin.username, - "full_name" : "%s %s" % (admin.first_name, admin.last_name), - "enabled" : admin.is_active}] permtables += [ - {"title" : _("Super administrators"), - "content" : SuperAdminsTable(admins_list).render(request), - "addurl" : reverse(add_superadmin)} + {"id" : "super_admins", + "title" : _("Super administrators"), + "content" : SuperAdminsPerms().get(request)} ] permtables += events.raiseQueryEvent("PermsGetTables", user=request.user) - domadmins = Mailbox.objects.filter(user__groups__name="DomainAdmins") - domadmins_list = [] - for admin in domadmins: - domadmins_list += [admin.tohash()] permtables += [ - {"title" : _("Domain administrators"), - "content" : DomainAdminsTable(domadmins_list).render(request), - "addurl" : reverse(add_domain_admin)} + {"id" : "domain_admins", + "title" : _("Domain administrators"), + "content" : DomainAdminsPerms().get(request)} ] return _render(request, 'admin/permissions.html', { @@ -388,72 +378,38 @@ def permissions(request): }) @login_required -@user_passes_test(lambda u: u.is_superuser) -def add_superadmin(request): - if request.method == "POST": - form = SuperAdminForm(request.POST) - if form.is_valid(): - user = User.objects.get(pk=request.POST["user"]) - user.is_superuser = True - user.groups.clear() - user.save() - ctx = _ctx_ok(reverse(admin.views.permissions)) - return HttpResponse(simplejson.dumps(ctx), - mimetype="application/json") - ctx = _ctx_ko("admin/add_superadmin.html", { - "form" : form - }) - return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") - - form = SuperAdminForm() - return _render(request, 'admin/add_permission.html', { - "form" : form, "title" : _("Add super administrator"), - "action" : reverse(add_superadmin) - }) - -@login_required -@permission_required("domains.create") -def add_domain_admin(request): - if request.method == "POST": - form = DomainAdminForm(request.POST) - mboxid = request.POST['user'] - form.fields["user"].choices = \ - [(mboxid, Mailbox.objects.get(pk=mboxid)),] - if form.is_valid(): - mb = Mailbox.objects.get(pk=request.POST["user"]) - mb.user.is_superuser = False - mb.user.groups.add(Group.objects.get(name="DomainAdmins")) - mb.user.save() - ctx = _ctx_ok(reverse(admin.views.permissions)) - return HttpResponse(simplejson.dumps(ctx), - mimetype="application/json") - ctx = _ctx_ko("admin/add_domain_admin.html", { - "form" : form - }) - return HttpResponse(simplejson.dumps(ctx), mimetype="application/json") - - form = DomainAdminForm() - return _render(request, 'admin/add_domain_admin.html', { - "form" : form, "title" : _("Add domain administrator"), - "action" : reverse(add_domain_admin) - }) - -@login_required -@user_passes_test(lambda u: u.is_superuser) -def deletepermission(request, mbox_id, group): - if group == "SuperAdmins": - user = User.objects.get(pk=mbox_id) - if user.username == "admin": - messages.error(request, _("admin is intouchable!!"), fail_silently=True) - else: - user.is_superuser = False - user.save() +@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: - mbox = Mailbox.objects.get(pk=mbox_id) - grp = Group.objects.get(name=group) - mbox.user.groups.remove(grp) - mbox.user.save() - return HttpResponseRedirect(reverse(admin.views.settings)) + 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) + ctx = _ctx_ok(reverse(admin.views.permissions)) + return HttpResponse(simplejson.dumps(ctx), + mimetype="application/json") + +@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) diff --git a/static/js/common.js b/static/js/common.js index 4c730afe4..ca7e8f29c 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -12,11 +12,11 @@ callbacks = {}; register_callback = function(name, callback) { callbacks[name] = callback; -} +}; get_callback = function(name) { return callbacks[name]; -} +}; current_anchor = null; @@ -43,13 +43,13 @@ check_anchor = function() { infobox.info(gettext("Done")); infobox.hide(1); }}).get(); -} +}; ajaxListener = function(deflocation, defcallback) { current_anchor = new HashWrapper(deflocation); register_callback("default", defcallback); check_anchor.periodical(300); -} +}; /* * @@ -154,7 +154,7 @@ function HashWrapper(deflocation) { return ""; } return this.params.get(name); - } + }; this.baseurl = function(value) { this.reset(); @@ -213,7 +213,7 @@ parse_menubar = function(id) { parse: 'rel' }); } -} +}; get_iframe_body = function(id) { var saf = navigator.userAgent.match(/Safari/i); @@ -233,7 +233,7 @@ get_iframe_body = function(id) { data = targetif.contentWindow.document.body; } return (data); -} +}; confirmation = function(question, action, callback) { SqueezeBox.initialize({ @@ -259,7 +259,7 @@ confirmation = function(question, action, callback) { } }); SqueezeBox.open("/modoboa/userprefs/confirm/?question=" + question); -} +}; setDivHeight = function(id, extrah, modulo) { var contentsize = $(document.body).getSize().y @@ -272,7 +272,7 @@ setDivHeight = function(id, extrah, modulo) { contentsize -= contentsize % modulo; } $(id).setStyle("height", contentsize + "px"); -} +}; bindRows = function(rooturl, page) { $$("tr").addEvent("click", function(event) { @@ -282,20 +282,20 @@ bindRows = function(rooturl, page) { location.href = url; } }); -} +}; toggleSelection = function(id, value) { $$("input[name=" + id + "]").each(function(obj) { obj.checked = value; }); -} +}; checkTableSelection = function(text) { if (!$$("tr[class*=table-tr-selected]").length) { return false; } return confirm(text); -} +}; searchbox_init = function() { var myFx = new Fx.Slide($("searchparams")); @@ -343,7 +343,7 @@ searchbox_init = function() { $("crit_" + params.criteria).checked = true; } } -} +}; // The following code prevents a bug under IE7 because fullpath is // returned instead of a relative one. (even if mootools uses @@ -358,7 +358,7 @@ gethref = function(obj) { return url.replace(baseurl, ""); } return url; -} +}; saveparams = function(id, message) { $$("input[name=update]").addEvent("click", function(evt) { @@ -373,4 +373,4 @@ saveparams = function(id, message) { } }).send(); }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/static/js/domains.js b/static/js/domains.js index fda427149..9f5124c58 100644 --- a/static/js/domains.js +++ b/static/js/domains.js @@ -4,15 +4,15 @@ window.addEvent('domready', function() { if ($defined($("domcontent"))) { SqueezeBox.assign($("domcontent").getElements('a[class=boxed]'), { - parse: 'rel', + parse: 'rel' }); } if ($defined($("subcontent"))) { SqueezeBox.assign($("subcontent").getElements('a[class=boxed]'), { - parse: 'rel', + parse: 'rel' }); } - + if ($$("a[name=deleteDom]")) $$("a[name=deleteDom]").addEvent('click', function(event) { if (!confirm(gettext("Delete this domain?"))) diff --git a/static/js/form.js b/static/js/form.js index 36d391f24..73e4d1776 100644 --- a/static/js/form.js +++ b/static/js/form.js @@ -17,36 +17,36 @@ window.addEvent("domready", function() { } }); obj.send(); - } + }; generic_submit = function(obj, event, id, callback, onerror) { event.stop(); sqbsubmit(obj, "content", id, callback, onerror); - } - domain_submit = function(event) { - generic_submit(this, event, "domform", domain_submit); - } - mailbox_submit = function(event) { - generic_submit(this, event, "mboxform", mailbox_submit); - } - alias_submit = function(event) { - generic_submit(this, event, "aliasform", alias_submit); - } + }; + domain_submit = function(event) { + generic_submit(this, event, "domform", domain_submit); + }; + mailbox_submit = function(event) { + generic_submit(this, event, "mboxform", mailbox_submit); + }; + alias_submit = function(event) { + generic_submit(this, event, "aliasform", alias_submit); + }; permission_submit = function(event) { generic_submit(this, event, "permform", permission_submit); - } + }; chpassword_submit = function(event) { generic_submit(this, event, "chpwdform", chpassword_submit); - } + }; arm_onerror = function() { new Calendar({id_untildate: "Y-m-d"}, { tweak: {x: -100, y:-100} }); - } + }; arm_submit = function(event) { generic_submit(this, event, "armform", arm_submit, arm_onerror); - } + }; if ($("domform")) $("domform").addEvent("submit", domain_submit); diff --git a/static/js/infobox.js b/static/js/infobox.js index 6c20e43bb..9697db76a 100644 --- a/static/js/infobox.js +++ b/static/js/infobox.js @@ -101,7 +101,7 @@ var InfoBox = new Class({ } this.box.setStyle("display", "block"); }, - + hide: function(timer) { if ($defined(timer)) { this.timer = this.hide.periodical(timer * 1000, this); diff --git a/static/js/permissions.js b/static/js/permissions.js index 5520513b0..9013454dd 100644 --- a/static/js/permissions.js +++ b/static/js/permissions.js @@ -1,12 +1,12 @@ window.addEvent('domready', function() { var tip = new Tips($$(".Tips")); - var addperm_url = ""; + var current_role = ""; var accordion = new Accordion('h3.atStart', 'div.atStart', { opacity: true, onActive: function(toggler, element){ toggler.setStyle('color', '#ff3300'); - addperm_url = element.get("name"); + current_role = element.get("id"); }, onBackground: function(toggler, element) { @@ -16,13 +16,45 @@ window.addEvent('domready', function() { $$("a[name=addperm]").addEvent("click", function(evt) { evt.stop(); - if (addperm_url == "") { - return; - } SqueezeBox.initialize({ size: {x: 300, y: 280}, handler: 'iframe' }); + var addperm_url = evt.target.get("href") + "?role=" + current_role; SqueezeBox.open(addperm_url); }); + + $$("a[name=delperms]").addEvent("click", function(evt) { + evt.stop(); + var selection = $(current_role).getElements("input[id=selection]:checked"); + if (selection.length == 0) { + return; + } + if (!confirm(gettext("Remove this selection?"))) { + return; + } + var sr_selection = ""; + selection.each(function(item) { + if (sr_selection != "") { + sr_selection += ","; + } + sr_selection += item.get("value"); + }); + new Request.JSON({ + url : evt.target.get("href"), + onSuccess: function(response) { + if (response.status == "ok") { + $(current_role).set("html", response.content); + infobox.info(response.message); + } else { + infobox.error(response.message); + } + infobox.hide(2); + + } + }).send({ + method: "get", + data: "role=" + current_role + "&selection=" + sr_selection + }); + }); }); \ No newline at end of file diff --git a/static/js/settings.js b/static/js/settings.js index 2822106fc..0381b691f 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -1,10 +1,4 @@ window.addEvent('domready', function() { - if ($$("a[name=deletePerm]")) - $$("a[name=deletePerm]").addEvent('click', function(event) { - if (!confirm(gettext("Remove this permission?"))) - event.stop(); - }); - var tip = new Tips($$(".Tips")); var accordion = new Accordion('h3.atStart', 'div.atStart', { @@ -12,7 +6,7 @@ window.addEvent('domready', function() { onActive: function(toggler, element){ toggler.setStyle('color', '#ff3300'); }, - + onBackground: function(toggler, element){ toggler.setStyle('color', '#222'); } diff --git a/templates/admin/add_permission.html b/templates/admin/add_permission.html index 0c0e3f73d..189f5d80b 100644 --- a/templates/admin/add_permission.html +++ b/templates/admin/add_permission.html @@ -5,9 +5,10 @@ {% endblock %} {% block content %}

{{ title }}

- {% if error %}
{{ error }}
{% endif %} -
+{% url admin.views.add_permission as addurl %} + + {% include "common/genericform.html" %}
diff --git a/templates/admin/permissions.html b/templates/admin/permissions.html index 95ddf0f63..390b9a362 100644 --- a/templates/admin/permissions.html +++ b/templates/admin/permissions.html @@ -1,5 +1,5 @@ {% extends "nlayout.html" %} -{% load i18n admin_extras %} +{% load i18n libextras admin_extras %} {% block html_head %} {% endblock %} @@ -8,10 +8,13 @@ {% permissions_menu user %} {% endblock %} {% block content %} +{% if messages %} +{% display_messages messages %} +{% endif %}
{% for table in permtables %}

{{ table.title }}

-
+
{{ table.content }}
{% endfor %}