diff --git a/admin/forms.py b/admin/forms.py
index 3248d5563..f6d9a4216 100644
--- a/admin/forms.py
+++ b/admin/forms.py
@@ -246,7 +246,7 @@ class AccountFormGeneral(forms.ModelForm):
role = None
if self.cleaned_data.has_key("role"):
role = self.cleaned_data["role"]
- elif self.user.group == "DomainAdmins":
+ elif self.user.group == "DomainAdmins" and self.user != account:
role = "SimpleUsers"
if role is not None:
account.groups.clear()
diff --git a/admin/templatetags/admin_extras.py b/admin/templatetags/admin_extras.py
index 8b707452c..f473ca811 100644
--- a/admin/templatetags/admin_extras.py
+++ b/admin/templatetags/admin_extras.py
@@ -203,6 +203,6 @@ def gender(value, target):
return value
@register.simple_tag
-def get_footer_content(user, objtype):
- res = events.raiseQueryEvent("AdminFooterDisplay", user, objtype)
+def get_extra_admin_content(user, target, currentpage):
+ res = events.raiseQueryEvent("ExtraAdminContent", user, target, currentpage)
return "".join(res)
diff --git a/admin/views.py b/admin/views.py
index 5c54b1868..f6ae79024 100644
--- a/admin/views.py
+++ b/admin/views.py
@@ -355,6 +355,7 @@ def editaccount(request, accountid, tplname="common/tabforms.html"):
ctx = dict(
title=account.username,
+ formid="accountform",
action=reverse(editaccount, args=[accountid]),
action_label=_("Update"),
action_classes="submit"
diff --git a/extensions/limits/__init__.py b/extensions/limits/__init__.py
index 96e016929..03911d940 100644
--- a/extensions/limits/__init__.py
+++ b/extensions/limits/__init__.py
@@ -57,36 +57,26 @@ def infos():
"url" : baseurl
}
-#@events.observe('AdminFooterDisplay')
-def display_pool_usage(user, objtype):
+@events.observe("GetExtraRoles")
+def get_extra_roles(user):
if user.is_superuser:
- return []
- if objtype == "domaliases":
- objtype = "domain_aliases"
- elif objtype == "mbaliases":
- objtype = "mailbox_aliases"
- try:
- l = user.limitspool.get_limit('%s_limit' % objtype)
- except LimitsPool.DoesNotExist:
- return []
- if l.maxvalue == -2:
- label = _("undefined")
- elif l.maxvalue == -1:
- label = _("unlimited")
- else:
- label = str(l.maxvalue)
- return [_("Pool usage: %s / %s") % (l.curvalue, label)]
+ return [("Resellers", _("Reseller")),]
+ return []
-@events.observe("DomainAdminActions")
-def get_da_actions(user):
- return [
- {"name" : "editpool",
- "url" : reverse(views.edit_limits_pool, args=[user.id]),
- "img" : static_url("pics/settings.png"),
- "title" : _("Edit limits allocated to this domain admin"),
- "class" : "boxed",
- "rel" : "{handler:'iframe',size:{x:330,y:280}}"},
- ]
+@events.observe("ExtraAdminContent")
+def display_pool_usage(user, target, currentpage):
+ from django.template.loader import render_to_string
+
+ if target != "leftcol" or user.is_superuser:
+ return []
+ if currentpage == "identities":
+ names = ["mailboxes_limit", "mailbox_aliases_limit"]
+ if user.has_perm("admin.add_domain"):
+ names += ["domain_admins_limit"]
+ else:
+ names = ["domains_limit", "domain_aliases_limit"]
+ limits = user.limitspool.limit_set.filter(name__in=names)
+ return [render_to_string("limits/poolusage.html", dict(limits=limits))]
@events.observe("ExtraAccountForm")
def extra_account_form(user, account=None):
@@ -120,3 +110,27 @@ def fill_account_instances(user, account, instances):
not account.belongs_to_group("DomainAdmins"):
return
instances["resources"] = account
+
+@events.observe("GetStaticContent")
+def get_static_content(user):
+ if user.group == "SimpleUsers":
+ return []
+ return """
+
+"""
diff --git a/extensions/limits/controls.py b/extensions/limits/controls.py
index 17d0346c4..fc956bfd6 100644
--- a/extensions/limits/controls.py
+++ b/extensions/limits/controls.py
@@ -43,11 +43,11 @@ def move_pool_resource(owner, user):
except LimitsPool.DoesNotExist:
return
if not owner.is_superuser:
- for lname in reseller_limits_tpl:
- l = user.limitspool.get_limit(lname)
+ for ltpl in limits_tpl:
+ l = user.limitspool.get_limit(ltpl[0])
if l.maxvalue < 0:
continue
- ol = owner.limitspool.get_limit(lname)
+ ol = owner.limitspool.get_limit(ltpl[0])
ol.curvalue += l.curvalue
ol.maxvalue += l.maxvalue
ol.save()
diff --git a/extensions/limits/forms.py b/extensions/limits/forms.py
index 9c3d85ab6..ceec8e590 100644
--- a/extensions/limits/forms.py
+++ b/extensions/limits/forms.py
@@ -49,10 +49,10 @@ class ResourcePoolForm(forms.Form):
return self.check_limit_value("mailbox_aliases_limit")
def load_from_user(self, user):
- for l in reseller_limits_tpl:
- if not self.fields.has_key(l):
+ for l in limits_tpl:
+ if not self.fields.has_key(l[0]):
continue
- self.fields[l].initial = user.limitspool.getmaxvalue(l)
+ self.fields[l[0]].initial = user.limitspool.getmaxvalue(l[0])
def allocate_from_pool(self, limit, pool):
ol = pool.get_limit(limit.name)
@@ -76,13 +76,13 @@ class ResourcePoolForm(forms.Form):
from modoboa.lib.permissions import get_object_owner
owner = get_object_owner(self.account)
- for lname in reseller_limits_tpl:
- if not self.cleaned_data.has_key(lname):
+ for ltpl in limits_tpl:
+ if not self.cleaned_data.has_key(ltpl[0]):
continue
- l = self.account.limitspool.limit_set.get(name=lname)
+ l = self.account.limitspool.limit_set.get(name=ltpl[0])
if not owner.is_superuser:
self.allocate_from_pool(l, owner.limitspool)
- l.maxvalue = self.cleaned_data[lname]
+ l.maxvalue = self.cleaned_data[ltpl[0]]
l.save()
diff --git a/extensions/limits/lib.py b/extensions/limits/lib.py
index 2bfbe0db5..b05902168 100644
--- a/extensions/limits/lib.py
+++ b/extensions/limits/lib.py
@@ -13,7 +13,7 @@ class LimitReached(ModoboaException):
self.limit = limit
def __str__(self):
- return "%s reached" % self.limit.name
+ return _("%s: limit reached") % self.limit.label
class UnsifficientResource(ModoboaException):
def __init__(self, limit):
diff --git a/extensions/limits/models.py b/extensions/limits/models.py
index 90694e592..47c814ac9 100644
--- a/extensions/limits/models.py
+++ b/extensions/limits/models.py
@@ -5,21 +5,21 @@ from django.contrib.contenttypes import generic
from django.utils.translation import ugettext as _, ugettext_noop
from modoboa.admin.models import User
-reseller_limits_tpl = [
- "domain_admins_limit",
- "domains_limit",
- "domain_aliases_limit",
- "mailboxes_limit",
- "mailbox_aliases_limit",
+limits_tpl = [
+ ("domain_admins_limit", ugettext_noop("Domain admins")),
+ ("domains_limit", ugettext_noop("Domains")),
+ ("domain_aliases_limit", ugettext_noop("Domain aliases")),
+ ("mailboxes_limit", ugettext_noop("Mailboxes")),
+ ("mailbox_aliases_limit", ugettext_noop("Mailbox aliases"))
]
class LimitsPool(models.Model):
user = models.OneToOneField(User)
def create_limits(self):
- for lname in reseller_limits_tpl:
+ for ltpl in limits_tpl:
l = Limit()
- l.name = lname
+ l.name = ltpl[0]
l.pool = self
l.save()
@@ -79,3 +79,18 @@ class Limit(models.Model):
class Meta:
unique_together = (("name", "pool"),)
+
+ @property
+ def usage(self):
+ if self.maxvalue < 0:
+ return -1
+ if self.maxvalue == 0:
+ return 0
+ return int(float(self.curvalue) / self.maxvalue * 100)
+
+ @property
+ def label(self):
+ for l in limits_tpl:
+ if l[0] == self.name:
+ return l[1]
+ return ""
diff --git a/extensions/limits/permissions.py b/extensions/limits/permissions.py
deleted file mode 100644
index 2f5b316b8..000000000
--- a/extensions/limits/permissions.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# coding: utf-8
-
-from django.utils.translation import ugettext as _, ugettext_noop
-from modoboa.lib import events
-
-@events.observe("GetExtraRoles")
-def get_extra_roles(user):
- if user.is_superuser:
- return [("Resellers", _("Reseller")),]
- return []
diff --git a/extensions/limits/static/js/resellers.js b/extensions/limits/static/js/resellers.js
deleted file mode 100644
index 6f68e7f2a..000000000
--- a/extensions/limits/static/js/resellers.js
+++ /dev/null
@@ -1,42 +0,0 @@
-var Resellers = new Class({
- initialize: function() {
- this.resellers_table = new HtmlTable($("resellers_table"), {
- selectable: true
- });
- SqueezeBox.assign($("content").getElements('a[class=boxed]'), {
- parse: 'rel'
- });
-
- $$("a[name=remove]").addEvent("click", this.remove_clickcb.bind(this));
- },
-
- remove_clickcb: function(evt) {
- evt.stop();
- if (this.resellers_table._selectedRows.length == 0) {
- return;
- }
-
- if (!confirm(gettext("Remove this selection?"))) {
- return;
- }
-
- var selection = "";
-
- this.resellers_table._selectedRows.each(function(item) {
- if (selection != "") {
- selection += ",";
- }
- selection += item.get("id");
- });
-
- new Request.JSON.mdb({
- url: evt.target.get("href"),
- method: "GET",
- onSuccess: function(res) {
- if (res.status == "ok") {
- window.location.reload();
- }
- }
- }).send("selection=" + selection);
- }
-});
\ No newline at end of file
diff --git a/extensions/limits/tables.py b/extensions/limits/tables.py
deleted file mode 100644
index b4c7a2fce..000000000
--- a/extensions/limits/tables.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# coding: utf-8
-
-from django.utils.translation import ugettext as _, ugettext_noop
-from modoboa.lib import tables
-from templatetags.limits_tags import reseller_actions
-
-class ResellersTable(tables.Table):
- tableid = "resellers_table"
- idkey = "id"
-
- selection = tables.SelectionColumn("selection", width="4%")
- fname = tables.Column("first_name", label=ugettext_noop("First name"))
- lname = tables.Column("last_name", label=ugettext_noop("Last name"))
- username = tables.Column("username", label=ugettext_noop("Username"))
- created = tables.Column("date_joined", label=ugettext_noop("Created on"))
- actions = tables.ActionColumn("actions", label=ugettext_noop("Actions"),
- width="50px",
- align="center", defvalue=reseller_actions)
-
- cols_order = ["selection", "username", "fname", "lname", "created", "actions"]
-
- def __init__(self, request, users):
- super(ResellersTable, self).__init__(request)
- self.populate(self._rows_from_model(users))
diff --git a/extensions/limits/templates/limits/pool.html b/extensions/limits/templates/limits/pool.html
deleted file mode 100644
index 5f4da7005..000000000
--- a/extensions/limits/templates/limits/pool.html
+++ /dev/null
@@ -1,22 +0,0 @@
-{% extends "layout_simple.html" %}
-{% load i18n %}
-{% block html_head %}
-
-
-{% endblock %}
-{% block content %}
-
{% trans "Limits pool for" %} {{ reseller.username }}
-{% if error %}{{ error }}{% endif %}
-
-{% endblock %}
diff --git a/extensions/limits/templates/limits/reseller.html b/extensions/limits/templates/limits/reseller.html
deleted file mode 100644
index 2655cfb32..000000000
--- a/extensions/limits/templates/limits/reseller.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends "layout_simple.html" %}
-{% load i18n %}
-{% block html_head %}
-
-{% endblock %}
-{% block content %}
-{% trans "New reseller" %}
-{% if error %}{{ error }}
{% endif %}
-
-{% endblock %}
diff --git a/extensions/limits/templates/limits/resellers.html b/extensions/limits/templates/limits/resellers.html
deleted file mode 100644
index 0bd6594b0..000000000
--- a/extensions/limits/templates/limits/resellers.html
+++ /dev/null
@@ -1,43 +0,0 @@
-{% extends "nlayout.html" %}
-{% load i18n limits_tags libextras %}
-{% block html_head %}
-
-
-{% endblock %}
-{% block middletitle %}{% trans "Available resellers" %}{% endblock %}
-{% block menu %}{% resellers_menu user %} {% endblock %}
-{% block content %}
-{% if messages %}
-{% display_messages messages %}
-{% endif %}
-
- {{ table|safe }}
-
-{% endblock %}
-{% block footer %}
-
- {% if paginator.count %}
-
- {% endif %}
- {% if page.has_previous %}
-
-
-
-
-
-
- {% endif %}
- {% if page.has_next %}
-
-
-
-
-
-
- {% endif %}
-
-{% endblock %}
diff --git a/extensions/limits/templatetags/__init__.py b/extensions/limits/templatetags/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/extensions/limits/templatetags/limits_tags.py b/extensions/limits/templatetags/limits_tags.py
deleted file mode 100644
index 37310b0d2..000000000
--- a/extensions/limits/templatetags/limits_tags.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# coding: utf-8
-
-from django import template
-from django.utils.translation import ugettext as _
-from django.template.loader import render_to_string
-from django.core.urlresolvers import reverse
-from modoboa.lib.webutils import static_url, render_actions
-from modoboa.extensions.limits import views
-
-register = template.Library()
-
-@register.simple_tag
-def resellers_menu(user):
- entries = [{"name" : "new",
- "label" : _("New"),
- "img" : static_url("pics/add.png"),
- "class" : "boxed",
- "rel" : "{handler:'iframe',size:{x:350,y:300}}",
- "url" : reverse(views.new_reseller)},
- {"name" : "remove",
- "label" : _("Remove"),
- "img" : static_url("pics/remove.png"),
- "url" : reverse(views.delete_resellers)
- }]
- return render_to_string("common/menulist.html",
- {"entries" : entries, "user" : user})
-
-@register.simple_tag
-def reseller_actions(user, resid):
- actions = [
- {"name" : "editreseller",
- "url" : reverse(views.edit_reseller, args=[resid]),
- "img" : static_url("pics/edit.png"),
- "title" : _("Edit reseller"),
- "class" : "boxed",
- "rel" : "{handler:'iframe',size:{x:350,y:300}}"},
- {"name" : "editlimits",
- "url" : reverse(views.edit_limits_pool, args=[resid]),
- "img" : static_url("pics/settings.png"),
- "title" : _("Edit limits allocated to this reseller"),
- "class" : "boxed",
- "rel" : "{handler:'iframe',size:{x:330,y:310}}"},
- ]
- return render_actions(actions)
diff --git a/extensions/limits/urls.py b/extensions/limits/urls.py
index 8f611080c..a0af85f49 100644
--- a/extensions/limits/urls.py
+++ b/extensions/limits/urls.py
@@ -2,6 +2,5 @@ from django.conf.urls.defaults import *
urlpatterns = patterns(
'modoboa.extensions.limits.views',
- (r'reseller/edit/(?P\d+)/$', 'edit_reseller'),
- (r'pool/edit/(?P\d+)/$', 'edit_limits_pool'),
+
)
diff --git a/extensions/limits/views.py b/extensions/limits/views.py
index 638100781..57d631c3f 100644
--- a/extensions/limits/views.py
+++ b/extensions/limits/views.py
@@ -1,63 +1 @@
# coding: utf-8
-from django.utils.translation import ugettext as _
-from django.db import IntegrityError, transaction
-from django.contrib.auth.models import *
-from django.contrib import messages
-from django.contrib.auth.decorators \
- import login_required, user_passes_test, permission_required
-from django.core.urlresolvers import reverse
-from forms import *
-from modoboa.lib.webutils import _render, ajax_response
-
-@login_required
-@user_passes_test(lambda u: u.is_superuser)
-def edit_reseller(request, resid, tplname="admin/add_permission.html"):
- reseller = User.objects.get(pk=resid)
- ctx = dict(title=_("Edit reseller"), submit_label=_("Update"),
- addurl=reverse(edit_reseller, args=[resid]))
- if request.method == "POST":
- if request.POST.get("password1", "") != "" and \
- request.POST.get("password2", "") != "":
- form = ResellerWithPasswordForm(request.POST, instance=reseller)
- else:
- form = ResellerForm(request.POST, instance=reseller)
- if form.is_valid():
- try:
- form.save()
- except IntegrityError:
- error = _("User with this Username already exists")
- else:
- messages.info(request, _("Reseller updated"), fail_silently=True)
- return ajax_response(request,
- url=reverse("modoboa.admin.views.permissions"))
-
- ctx.update(form=form, error=error)
- return ajax_response(request, status="ko", template=tplname, **ctx)
-
- form = ResellerWithPasswordForm(instance=reseller)
- ctx.update(form=form)
- return _render(request, tplname, ctx)
-
-@login_required
-@permission_required("auth.view_permissions")
-@transaction.commit_on_success
-def edit_limits_pool(request, uid, tplname="limits/pool.html"):
- user = User.objects.get(pk=uid)
- ctx = dict(reseller=user)
- if request.method == "POST":
- form = ResellerPoolForm(request.POST)
- if not user.belongs_to_group('Resellers'):
- del form.fields["domain_admins_limit"]
- if form.is_valid():
- form.save_new_limits(user.limitspool)
- messages.info(request, _("Pool updated"), fail_silently=True)
- return ajax_response(request, url=reverse("modoboa.admin.views.permissions"))
- ctx.update(form=form)
- return ajax_response(request, status="ko", template=tplname, **ctx)
-
- form = ResellerPoolForm()
- if not user.belongs_to_group('Resellers'):
- del form.fields["domain_admins_limit"]
- form.load_from_user(user)
- ctx.update(form=form)
- return _render(request, tplname, ctx)
diff --git a/lib/events.py b/lib/events.py
index 37c7eca83..627dd9003 100644
--- a/lib/events.py
+++ b/lib/events.py
@@ -54,7 +54,7 @@ events = [
"GetAnnouncement",
"TopNotifications",
- "AdminFooterDisplay",
+ "ExtraAdminContent",
]
callbacks = {}
diff --git a/lib/templatetags/libextras.py b/lib/templatetags/libextras.py
index ab00740e5..f71ecbc12 100644
--- a/lib/templatetags/libextras.py
+++ b/lib/templatetags/libextras.py
@@ -142,3 +142,12 @@ class="{{ mdclass }}{% if link.class %} {{ link.class }}{% endif %}"
{% if link.img %}{% endif %}
{{ link.label }}""")
return t.render(Context(dict(link=linkdef, mdclass=mdclass)))
+
+@register.simple_tag
+def progress_color(value):
+ value = int(value)
+ if value < 50:
+ return "progress-success"
+ if value < 80:
+ return "progress-warning"
+ return "progress-danger"
diff --git a/static/css/admin.css b/static/css/admin.css
index 97b6fff58..9f3729324 100644
--- a/static/css/admin.css
+++ b/static/css/admin.css
@@ -1,4 +1,4 @@
#searchform {
text-align: center;
margin-bottom: 10px;
-}
\ No newline at end of file
+}
diff --git a/static/js/admin.js b/static/js/admin.js
index 1fa65fb48..464ae1be9 100644
--- a/static/js/admin.js
+++ b/static/js/admin.js
@@ -3,6 +3,7 @@ function domainform_cb() {
$("#id_aliases").dynamic_input();
$(".submit").one('click', function(e) {
simple_ajax_form_post(e, {
+ formid: "domform",
error_cb: domainform_cb
});
});
@@ -24,13 +25,14 @@ function accountform_init() {
function newaccount_cb() {
$('input:text:visible:first').focus();
accountform_init();
- $("#wizard").cwizard();
+ $("#wizard").cwizard({formid: "newaccount_form"});
}
function editaccount_cb() {
accountform_init();
$('.submit').one('click', function(e) {
simple_ajax_form_post(e, {
+ formid: "accountform",
error_cb: editaccount_cb
});
});
@@ -44,6 +46,7 @@ function dlistform_cb() {
$("#id_recipients").dynamic_input();
$(".submit").one('click', function(e) {
simple_ajax_form_post(e, {
+ formid: "dlistform",
error_cb: dlistform_cb
});
});
diff --git a/static/js/creation_wizard.js b/static/js/creation_wizard.js
index 68e5db07f..9777c29be 100644
--- a/static/js/creation_wizard.js
+++ b/static/js/creation_wizard.js
@@ -1,6 +1,7 @@
(function($) {
var Cwizard = function(element, options) {
this.$element = $(element);
+ this.options = $.extend({}, $.fn.cwizard.defaults, options);
this.$element.carousel({pause: true});
this.$element.carousel("pause");
this.setcallbacks();
@@ -16,7 +17,7 @@
},
post: function(last) {
- var $form = $('form');
+ var $form = (this.options.formid) ? $('#' + this.options.formid) : $('form');
var data = $form.serialize() + "&stepid=" + $(".item.active").attr("id");
$.post($form.attr("action"), data, $.proxy(function(resp) {
@@ -79,4 +80,8 @@
});
};
+ $.fn.cwizard.defaults = {
+
+ };
+
})(jQuery);
\ No newline at end of file
diff --git a/templates/admin/domains.html b/templates/admin/domains.html
index 9e49e9f21..f9cd9616c 100644
--- a/templates/admin/domains.html
+++ b/templates/admin/domains.html
@@ -20,4 +20,4 @@
{% endblock %}
{% block leftcol %}{% endblock %}
+{% domains_menu "domains" user %}{{ block.super }}{% endblock %}
diff --git a/templates/admin/identities.html b/templates/admin/identities.html
index f42b67528..3f52867fe 100644
--- a/templates/admin/identities.html
+++ b/templates/admin/identities.html
@@ -32,4 +32,4 @@ $(document).ready(function() {
{% endblock %}
{% block leftcol %}{% endblock %}
+{% identities_menu user %}{{ block.super }}{% endblock %}
diff --git a/templates/admin/listing.html b/templates/admin/listing.html
index 52ff52c0c..abeb560fb 100644
--- a/templates/admin/listing.html
+++ b/templates/admin/listing.html
@@ -16,8 +16,8 @@ $(document).ready(function() {
});
{% endblock %}
+{% block leftcol %}{% get_extra_admin_content user "leftcol" selection %}{% endblock %}
{% block apparea %}
{{ table|safe }}
{% endblock %}
-{% block footerleft %}{% get_footer_content user selection %}
{% endblock %}
{% block footerright %}{% pagination_bar page %}{% endblock %}
diff --git a/templates/common/tabforms.html b/templates/common/tabforms.html
index 5eb25f104..5d7838b45 100644
--- a/templates/common/tabforms.html
+++ b/templates/common/tabforms.html
@@ -1,7 +1,7 @@
{% extends "common/generic_modal.html" %}
{% load i18n libextras %}
{% block modalbody %}
-