wip: Limits and resellers

* refactoring, limits are working pretty well
* domain admins can now create domains (under control) when the limits extension is enabled

see #105
This commit is contained in:
Antoine Nguyen
2012-01-24 11:23:31 +01:00
parent 3681bb4198
commit 1c51e97179
18 changed files with 300 additions and 88 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ from django.contrib.auth.models import User
from modoboa.admin.templatetags.admin_extras import gender
from modoboa.lib import tables
from modoboa.lib.emailutils import split_mailbox
from lib import get_user_domains
from lib import get_user_domains, get_user_domains_qs
class DomainForm(forms.ModelForm):
class Meta:
@@ -34,7 +34,7 @@ class ProxyForm(forms.ModelForm):
super(ProxyForm, self).__init__(*args, **kwargs)
if not user.is_superuser:
self._domains = Domain.objects.filter(owners__user=user)
self._domains = get_user_domains_qs(user)
else:
self._domains = None
+115 -36
View File
@@ -2,6 +2,7 @@
from functools import wraps
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.models import User, Group
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext as _
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from models import *
@@ -77,18 +78,6 @@ def good_domain(f):
return HttpResponseRedirect("%s?next=%s" % (login_url, path))
return dec
# def has_access_to_domain(user, domain):
# """
# """
# access = events.raiseQueryEvent("CanViewDomain", user, domain)
# if True in access:
# return True
# if is_domain_admin(user):
# mb = Mailbox.objects.get(user=request.user.id)
# if mb.domain == domain:
# return True
# return False
def render_listing(request, objtype, tplname="admin/listing.html",
**kwargs):
"""Common function to render a listing
@@ -132,14 +121,29 @@ def set_object_ownership(user, obj):
:param user: a ``User`` object
:param obj: an admin. object (Domain, Mailbox, ...)
"""
obj_owner = ObjectOwner(user=user, content_object=obj)
obj_owner.save()
try:
ct = ContentType.objects.get_for_model(obj)
obj_owner = user.objectowner_set.get(content_type=ct, object_id=obj.id)
except ObjectOwner.DoesNotExist:
obj_owner = ObjectOwner(user=user, content_object=obj)
obj_owner.save()
def unset_object_ownership(obj):
"""Remove the ownership of the given object
:param obj: an object inheriting from ``models.Model``
"""
ct = ContentType.objects.get_for_model(obj)
ObjectOwner.objects.get(content_type=ct, object_id=obj.id).delete()
def is_object_owner(user, obj):
"""Check if a user is the object's owner
An object can have multiple owners but this function only
concerns one given user.
An object can only belongs to one user.
This function is recursive : if the given user is not the owner
and if he owns other ``User`` objects, we also check if one of
those users owns the object.
:param user: a ``User`` object
:param obj: a admin object
@@ -148,14 +152,44 @@ def is_object_owner(user, obj):
if user.is_superuser:
return True
qs = user.objectowner_set.filter(content_type__app_label="admin",
content_type__model=obj._meta.module_name)
for entry in qs.all():
if entry.content_object == obj:
ct = ContentType.objects.get_for_model(obj)
try:
ooentry = user.objectowner_set.get(content_type=ct, object_id=obj.id)
except ObjectOwner.DoesNotExist:
pass
else:
return True
if ct.model == "user":
return False
ct = ContentType.objects.get_for_model(User)
qs = user.objectowner_set.filter(content_type=ct)
for ooentry in qs.all():
if is_object_owner(ooentry.content_object, obj):
return True
return False
def get_object_owner(obj):
"""Return this object's owner
:param obj: an object inheriting from ``model.Model``
:return: a ``User`` object
"""
ct = ContentType.objects.get_for_model(obj)
res = ObjectOwner.objects.filter(content_type=ct, object_id=obj.id)
if not len(res):
return None
return res[0].user
def check_domain_ownership(f):
"""Decorator to check if the current user can access to a domain
This decorator only applies to url that contain a 'domid' or
'mbid' parameter. (for a direct access)
Raise a ``PermDeniedError`` if the current user can't view the
requested object.
"""
@wraps(f)
def dec(request, **kwargs):
if not request.user.is_superuser:
@@ -177,41 +211,86 @@ def get_user_domains(user):
if user.is_superuser:
return Domain.objects.all()
qs = user.objectowner_set.filter(content_type__app_label="admin",
content_type__model="domain")
domct = ContentType.objects.get_for_model(Domain)
qs = user.objectowner_set.filter(content_type=domct)
domains = []
for entry in qs.all():
domains += [entry.content_object]
userct = ContentType.objects.get_for_model(User)
qs = user.objectowner_set.filter(content_type=userct)
for entry in qs:
if not is_domain_admin(entry.content_object):
continue
domains += get_user_domains(entry.content_object)
return domains
def get_user_domains_qs(user):
"""Return the domains belonging to this user
The result is a ``QuerySet`` object, so this function can be used
to fill ``ModelChoiceField`` objects.
:param user: a ``User`` object
"""
if user.is_superuser:
return Domain.objects.all()
result = Domain.objects.filter(owners__user=user)
userct = ContentType.objects.get_for_model(User)
for entry in user.objectowner_set.filter(content_type=userct):
if not is_domain_admin(entry.content_object):
continue
result |= get_user_domains_qs(entry.content_object)
return result
def get_user_domaliases(user):
"""Return the domain aliases that belong to this user
The result will contain the domain aliases defined for each domain
that user can see.
:param user: a ``User`` object
:return: a list of ``DomainAlias`` objects
"""
if user.is_superuser:
return DomainAlias.objects.all()
qs = user.objectowner_set.filter(content_type__app_label="admin",
content_type__model="domain")
domains = get_user_domains_qs(user)
domaliases = []
for entry in qs.all():
domaliases += entry.content_object.domainalias_set.all()
for dom in domains:
domaliases += dom.domainalias_set.all()
return domaliases
def get_user_mailboxes(user):
"""Return the mailboxes that belong to this user
The result will contain the mailboxes defined for each domain that
user can see.
:param user: a ``User`` object
:return: a list of ``Mailbox`` objects
"""
if user.is_superuser:
return Mailbox.objects.all()
qs = user.objectowner_set.filter(content_type__app_label="admin",
content_type__model="domain")
mboxes = []
for ro in qs.all():
mboxes += Mailbox.objects.filter(domain=ro.content_object)
domains = get_user_domains_qs(user)
for dom in domains:
mboxes += dom.mailbox_set.all()
return mboxes
def get_user_mbaliases(user):
"""Return the mailbox aliases that belong to this user
The result will contain the mailbox aliases defined for each
domain that user can see.
:param user: a ``User`` object
:return: a list of ``Alias`` objects
"""
if user.is_superuser:
return Alias.objects.all()
qs = user.objectowner_set.filter(content_type__app_label="admin",
content_type__model="domain")
domains = get_user_domains_qs(user)
mbaliases = []
for ro in qs.all():
mbaliases += Alias.objects.filter(domain=ro.content_object)
for dom in domains:
mbaliases += dom.alias_set.all()
return mbaliases
+21 -3
View File
@@ -24,6 +24,9 @@ class ObjectOwner(models.Model):
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Meta:
unique_together = (("content_type", "object_id"),)
class ObjectDates(models.Model):
"""Dates recording for admin objects
@@ -471,21 +474,33 @@ class Alias(DatesAware):
class Extension(models.Model):
name = models.CharField(max_length=150)
enabled = models.BooleanField(ugettext_noop('enabled'),
help_text=ugettext_noop("Check to enable this extension"))
enabled = models.BooleanField(
ugettext_noop('enabled'),
help_text=ugettext_noop("Check to enable this extension")
)
def __getmodule(self):
extname = "modoboa.extensions.%s" % self.name
return __import__(extname, globals(), locals(), ['main'])
def init(self):
module = self.__getmodule()
if hasattr(module.main, "init"):
module.main.init()
def load(self):
self.__getmodule().main.init()
module = self.__getmodule()
if hasattr(module.main, "load"):
module.main.load()
def unload(self):
self.__getmodule().main.destroy()
def on(self):
self.load()
self.init()
self.enabled = True
self.save()
extdir = "%s/extensions/%s" % (settings.MODOBOA_DIR, self.name)
scriptdir = "%s/%s" % (extdir, "scripts")
@@ -503,6 +518,9 @@ class Extension(models.Model):
def off(self):
self.unload()
self.enabled = False
self.save()
extdir = "%s/extensions/%s" % (settings.MODOBOA_DIR, self.name)
scriptdir = "%s/%s" % (extdir, "scripts")
if os.path.exists(scriptdir):
+8 -8
View File
@@ -107,14 +107,14 @@ class DomainAdminsPerms(Permissions):
return False, getctx("ko", content=content)
def delete(self, selection):
User.objects.filter(id__in=selection).delete()
# for s in selection:
# user.delete()
# try:
# mbox = Mailbox.objects.get(pk=int(s))
# grp = Group.objects.get(name="DomainAdmins")
# mbox.user.groups.remove(grp)
# mbox.user.save()
grp = Group.objects.get(name="DomainAdmins")
for uid in selection:
u = User.objects.get(pk=uid)
u.groups.remove(grp)
u.save()
events.raiseEvent("DomainAdminDeleted", u)
if not len(u.mailbox_set.all()):
u.delete()
def get(self, request):
#domadmins = Mailbox.objects.filter(user__groups__name="DomainAdmins")
+4 -2
View File
@@ -2,6 +2,7 @@ from django import template
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _, ugettext_noop
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from modoboa import admin
from modoboa.lib import events
from modoboa.lib.webutils import static_url, render_actions
@@ -179,7 +180,7 @@ def domalias_actions(user, aid):
"img" : static_url("pics/edit.png"),
"title" : _("Edit alias"),
"class" : "boxed",
"rel" : "{handler:'iframe',size:{x:300,y:190}}"}
"rel" : "{handler:'iframe',size:{x:310,y:190}}"}
]
return render_actions(actions)
@@ -191,7 +192,7 @@ def mailbox_actions(user, mboxid):
"img" : static_url("pics/edit.png"),
"title" : _("Edit mailbox"),
"class" : "boxed",
"rel" : "{handler:'iframe',size:{x:300,y:320}}"},
"rel" : "{handler:'iframe',size:{x:310,y:320}}"},
{"name" : "aliases",
"url" : reverse(admin.views.mbaliases) + "?mbid=%d" % mboxid,
"img" : static_url("pics/alias.png"),
@@ -209,6 +210,7 @@ def domain_admin_actions(user, daid):
"class" : "boxed",
"rel" : "{handler:'iframe',size:{x:350,y:320}}"},
]
actions += events.raiseQueryEvent("DomainAdminActions", User.objects.get(pk=daid))
return render_actions(actions)
@register.simple_tag
+18 -12
View File
@@ -126,7 +126,8 @@ def deldomain(request):
if mb and mb.domain == dom:
raise AdminError(_("You can't delete your own domain"))
events.raiseEvent("DeleteDomain", request.user, dom)
events.raiseEvent("DeleteDomain", dom)
unset_object_ownership(dom)
dom.delete(keepdir=keepdir)
msg = ungettext("Domain deleted", "Domains deleted", len(selection))
@@ -152,6 +153,7 @@ def domaliases(request):
@permission_required("admin.add_domainalias")
@transaction.commit_on_success
def newdomalias(request, tplname="admin/adminform.html"):
events.raiseEvent("CanCreateDomainAlias", request.user)
commonctx = {"title" : _("New domain alias"),
"submit_label" : _("Create"),
"action" : reverse(newdomalias),
@@ -160,7 +162,6 @@ def newdomalias(request, tplname="admin/adminform.html"):
form = DomainAliasForm(request.user, request.POST)
error = None
if form.is_valid():
events.raiseEvent("CanCreateDomainAlias", request.user)
domalias = form.save(commit=False)
if Domain.objects.filter(name=domalias.name):
error = _("A domain with this name already exists")
@@ -170,6 +171,7 @@ def newdomalias(request, tplname="admin/adminform.html"):
except IntegrityError:
error = _("Alias with this name already exists")
else:
set_object_ownership(request.user, domalias)
events.raiseEvent("DomainAliasCreated", request.user, domalias)
messages.info(request, _("Domain alias created"), fail_silently=True)
return ajax_response(request, url=reverse(admin.views.domaliases))
@@ -227,7 +229,8 @@ def deldomalias(request):
domalias = DomainAlias.objects.get(pk=daid)
if not is_object_owner(request.user, domalias.target):
raise PermDeniedException(_("You don't have acces to this domain"))
events.raiseEvent("DomainAliasDeleted", request.user, domalias)
events.raiseEvent("DomainAliasDeleted", domalias)
unset_object_ownership(domalias)
domalias.delete()
msg = ungettext("Domain alias deleted", "Domain aliases deleted", len(selection))
messages.info(request, msg, fail_silently=True)
@@ -287,6 +290,7 @@ def mailboxes_search(request):
@permission_required("admin.add_mailbox")
@transaction.commit_on_success
def newmailbox(request, tplname="admin/adminform.html"):
events.raiseEvent("CanCreateMailbox", request.user)
commonctx = {"title" : _("New mailbox"),
"submit_label" : _("Create"),
"action" : reverse(newmailbox),
@@ -299,12 +303,12 @@ def newmailbox(request, tplname="admin/adminform.html"):
if not is_object_owner(request.user, form.cleaned_data["domain"]):
raise PermDeniedException(_("You do not have access to this domain"))
events.raiseEvent("CanCreateMailbox", request.user)
try:
mb = form.save()
except AdminError as e:
error = str(e)
else:
set_object_ownership(request.user, mb)
events.raiseEvent("CreateMailbox", request.user, mb)
messages.info(request, _("Mailbox created"),
fail_silently=True)
@@ -370,7 +374,8 @@ def delmailbox(request):
raise PermDeniedException(_("You don't have access to this domain"))
if usermb and usermb == mb:
raise AdminError(_("You can't delete your own mailbox"))
events.raiseEvent("DeleteMailbox", request.user, mb)
events.raiseEvent("DeleteMailbox", mb)
unset_object_ownership(mb)
mb.delete(keepdir=keepdir)
msg = ungettext("Mailbox deleted", "Mailboxes deleted", len(selection))
@@ -433,6 +438,7 @@ def newmbalias(request, tplname="admin/mbaliasform.html"):
"formid" : "mbaliasform"}
if request.method == "POST":
def callback(user, mbalias):
set_object_ownership(user, mbalias)
events.raiseEvent("MailboxAliasCreated", user, mbalias)
form = AliasForm(request.user, request.POST)
@@ -473,7 +479,8 @@ def delmbalias(request):
mbalias = Alias.objects.get(pk=mbaid)
if not is_object_owner(request.user, mbalias.domain):
raise PermDeniedException(_("You do not have access to this domain"))
events.raiseEvent("MailboxAliasDeleted", request.user, mbalias)
events.raiseEvent("MailboxAliasDeleted", mbalias)
unset_object_ownership(mbalias)
mbalias.delete()
msg = ungettext("Alias deleted", "Aliases deleted", len(selection))
@@ -534,6 +541,7 @@ def create_domain_admin(request, tplname="admin/create_domain_admin.html"):
form = UserWithPasswordForm(request.POST)
if form.is_valid():
user = form.save(group="DomainAdmins")
set_object_ownership(request.user, user)
events.raiseEvent("DomainAdminCreated", user)
messages.info(request, _("Domain admin created"), fail_silently=True)
return ajax_response(request, url=reverse(admin.views.permissions))
@@ -541,7 +549,7 @@ def create_domain_admin(request, tplname="admin/create_domain_admin.html"):
return ajax_response(request, status="ko", template=tplname, form=form)
form = UserWithPasswordForm()
return ajax_response(request, tplname, form=form)
return ajax_response(request, template=tplname, form=form)
@login_required
@permission_required("auth.view_permissions")
@@ -580,6 +588,8 @@ def domain_admin_promotion(request):
u = User.objects.get(username=form.cleaned_data["name"])
u.groups.add(Group.objects.get(name="DomainAdmins"))
u.save()
set_object_ownership(request.user, u)
events.raiseEvent("DomainAdminCreated", u)
messages.info(request, _("Domain admin added"), fail_silently=True)
return ajax_response(request, url=reverse(admin.views.permissions))
@@ -588,7 +598,7 @@ def domain_admin_promotion(request):
form=form)
@login_required
@permission_required("admin.view_permissions")
@permission_required("auth.view_permissions")
@check_domain_ownership
def search_account(request):
search = request.POST.get("search", None)
@@ -687,15 +697,11 @@ def saveextensions(request):
parts = k.split("_", 1)
dbext = Extension.objects.get(name=parts[1])
if not dbext in actived_exts:
dbext.enabled = True
dbext.save()
dbext.on()
else:
found += [dbext]
for ext in actived_exts:
if not ext in found:
ext.enabled = False
ext.save()
ext.off()
messages.info(request, _("Modifications applied."), fail_silently=True)
return HttpResponseRedirect(reverse(admin.views.viewextensions))
+1 -1
View File
@@ -25,7 +25,7 @@ def loadextensions(prefix):
try:
ext = Extension.objects.get(name=f)
if ext.enabled:
module.main.init()
ext.load()
except Extension.DoesNotExist:
pass
u = module.main.urls(prefix)
+44 -6
View File
@@ -5,6 +5,7 @@
"""
from modoboa.admin.models import Mailbox
from modoboa.admin.lib import get_object_owner, set_object_ownership
from modoboa.lib import events
from lib import *
from models import *
@@ -48,8 +49,15 @@ def inc_nb_domains(user, domain):
inc_limit(user, 'domains_limit')
@events.observe('DeleteDomain')
def dec_nb_domains(user, domain):
dec_limit(user, 'domains_limit')
def dec_nb_domains(domain):
owner = get_object_owner(domain)
dec_limit(owner, 'domains_limit')
for domalias in domain.domainalias_set.all():
dec_nb_domaliases(domalias)
for mailbox in domain.mailbox_set.all():
dec_nb_mailboxes(mailbox)
for mbalias in domain.alias_set.all():
dec_nb_mbaliases(mbalias)
@events.observe('CanCreateDomainAlias')
def check_domaliases_limit(user):
@@ -60,8 +68,9 @@ def inc_nb_domaliases(user, domalias):
inc_limit(user, 'domain_aliases_limit')
@events.observe('DomainAliasDeleted')
def dec_nb_domaliases(user, domainalias):
dec_limit(user, 'domain_aliases_limit')
def dec_nb_domaliases(domainalias):
owner = get_object_owner(domainalias)
dec_limit(owner, 'domain_aliases_limit')
@events.observe('CanCreateMailbox')
def check_mboxes_limit(user):
@@ -72,8 +81,9 @@ def inc_nb_mailboxes(user, mailbox):
inc_limit(user, 'mailboxes_limit')
@events.observe('DeleteMailbox')
def dec_nb_mailboxes(user, mailbox):
dec_limit(user, 'mailboxes_limit')
def dec_nb_mailboxes(mailbox):
owner = get_object_owner(mailbox)
dec_limit(owner, 'mailboxes_limit')
@events.observe('CanCreateMailboxAlias')
def check_mbaliases_limit(user):
@@ -82,3 +92,31 @@ def check_mbaliases_limit(user):
@events.observe('MailboxAliasCreated')
def inc_nb_mbaliases(user, mailboxalias):
inc_limit(user, 'mailbox_aliases_limit')
@events.observe('MailboxAliasDeleted')
def dec_nb_mbaliases(mailboxalias):
owner = get_object_owner(mailboxalias)
dec_limit(owner, 'mailbox_aliases_limit')
@events.observe("DomainAdminCreated")
def create_pool(user):
p = LimitsPool(user=user)
p.save()
p.create_limits()
@events.observe("DomainAdminDeleted")
def move_pool_resource(domadmin):
owner = get_object_owner(domadmin)
for ooentry in domadmin.objectowner_set.all():
obj = ooentry.content_object
ooentry.delete()
set_object_ownership(owner, obj)
for lname in reseller_limits_tpl:
l = domadmin.limitspool.get_limit(lname)
ol = owner.limitspool.get_limit(lname)
ol.curvalue += l.curvalue
ol.maxvalue += l.maxvalue
ol.save()
domadmin.limitspool.delete()
+24 -7
View File
@@ -4,7 +4,9 @@ from django import forms
from django.utils.translation import ugettext_noop as _
from django.contrib.auth.models import User, Group
from modoboa.admin.forms import UserForm, UserWithPasswordForm
from modoboa.admin.lib import get_object_owner
from models import *
from lib import *
class ResellerForm(UserForm):
def __init__(self, *args, **kwargs):
@@ -19,14 +21,8 @@ class ResellerForm(UserForm):
except LimitsPool.DoesNotExist:
pool = LimitsPool()
pool.user = user
print pool.user
pool.save()
for lname in reseller_limits_tpl:
l = Limit()
l.name = lname
l.pool = pool
l.save()
pool.create_limits()
return user
@@ -64,9 +60,30 @@ class ResellerPoolForm(forms.Form):
for l in reseller_limits_tpl:
self.fields[l].initial = user.limitspool.getmaxvalue(l)
def allocate_from_pool(self, limit, pool):
ol = pool.get_limit(limit.name)
if ol.maxvalue == -2:
raise BadLimitValue(_("Your pool is not initialized yet"))
newvalue = self.cleaned_data[limit.name]
if newvalue == -1 and ol.maxvalue != -1:
raise BadLimitValue(_("You're not allowed to define unlimited values"))
if limit.maxvalue > -1:
newvalue -= limit.maxvalue
if newvalue == 0:
return
remain = ol.maxvalue - ol.curvalue
if newvalue > remain:
raise UnsifficientResource(ol)
ol.maxvalue -= newvalue
ol.save()
def save_new_limits(self, pool):
owner = get_object_owner(pool.user)
for lname in reseller_limits_tpl:
l = pool.limit_set.get(name=lname)
if not owner.is_superuser:
self.allocate_from_pool(l, owner.limitspool)
l.maxvalue = self.cleaned_data[lname]
l.save()
+8
View File
@@ -5,6 +5,7 @@
"""
from django.contrib.auth.models import Group
from django.utils.translation import ugettext as _
from modoboa.lib.exceptions import ModoboaException
class LimitReached(ModoboaException):
@@ -14,6 +15,13 @@ class LimitReached(ModoboaException):
def __str__(self):
return "%s reached" % self.limit.name
class UnsifficientResource(ModoboaException):
def __init__(self, limit):
self.limit = limit
def __str__(self):
return _("Not enough resource into your pool")
class BadLimitValue(ModoboaException):
pass
+25 -2
View File
@@ -6,6 +6,8 @@ The *limits* extension
"""
from django.contrib.auth.models import Permission, Group
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import ugettext_noop as _, ugettext
from django.core.urlresolvers import reverse
from django.conf.urls.defaults import include
@@ -14,14 +16,25 @@ from modoboa.lib.webutils import static_url
from models import *
import permissions
import controls
import views
baseurl = "limits"
def init():
pass
ct = ContentType.objects.get(app_label="admin", model="domain")
grp = Group.objects.get(name="DomainAdmins")
for pname in ["view_domains", "add_domain", "change_domain", "delete_domain"]:
perm = Permission.objects.get(content_type=ct, codename=pname)
grp.permissions.add(perm)
grp.save()
def destroy():
pass
ct = ContentType.objects.get(app_label="admin", model="domain")
grp = Group.objects.get(name="DomainAdmins")
for pname in ["view_domains", "add_domain", "change_domain", "delete_domain"]:
perm = Permission.objects.get(content_type=ct, codename=pname)
grp.permissions.remove(perm)
grp.save()
def infos():
return {
@@ -53,3 +66,13 @@ def display_pool_usage(user, objtype):
label = str(l.maxvalue)
return [_("Pool usage: %s / %s") % (l.curvalue, label)]
@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}}"},
]
+9
View File
@@ -16,6 +16,13 @@ reseller_limits_tpl = [
class LimitsPool(models.Model):
user = models.OneToOneField(User)
def create_limits(self):
for lname in reseller_limits_tpl:
l = Limit()
l.name = lname
l.pool = self
l.save()
def getcurvalue(self, lname):
l = self.limit_set.get(name=lname)
return l.curvalue
@@ -56,3 +63,5 @@ class Limit(models.Model):
maxvalue = models.IntegerField(default=-2)
pool = models.ForeignKey(LimitsPool)
class Meta:
unique_together = (("name", "pool"),)
+12 -2
View File
@@ -3,6 +3,8 @@
from django.utils.translation import ugettext as _, ugettext_noop
from django.contrib.auth.models import User
from modoboa.admin.permissions import Permissions
from modoboa.admin.lib import set_object_ownership
from modoboa.admin.models import ObjectOwner
from modoboa.lib import events
from modoboa.lib.webutils import _render, _render_to_string
from tables import *
@@ -21,13 +23,21 @@ class ResellersPerms(Permissions):
form = ResellerWithPasswordForm(request.POST)
error = None
if form.is_valid():
form.save(group="Resellers")
r = form.save(group="Resellers")
set_object_ownership(request.user, r)
return True, None
content = self._render_form(request, form, True)
return False, dict(status="ko", content=content)
def delete(self, selection):
User.objects.filter(id__in=selection).delete()
ct = ContentType.objects.get_for_model(User)
for u in User.objects.filter(id__in=selection):
try:
ObjectOwner.objects.get(content_type=ct, object_id=u.id).delete()
except ObjectOwner.DoesNotExist:
pass
u.delete()
def get(self, request):
resellers = User.objects.filter(groups__name="Resellers")
+1 -1
View File
@@ -10,7 +10,7 @@ window.addEvent("domready", function() {
{% endblock %}
{% block content %}
<div class="title"><h1>{% trans "Limits pool for" %} {{ reseller.username }}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
<div class="error">{% if error %}{{ error }}{% endif %}</div>
<form action="{% url extensions.limits.views.edit_limits_pool reseller.id %}"
method="POST" id="limits_pool_form" name="limits_pool_form">
{% include "common/genericform.html" %}
+4 -3
View File
@@ -1,10 +1,10 @@
# coding: utf-8
from django.utils.translation import ugettext as _
from django.db import IntegrityError
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
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
@@ -39,7 +39,8 @@ def edit_reseller(request, resid, tplname="admin/add_permission.html"):
return _render(request, tplname, ctx)
@login_required
@user_passes_test(lambda u: u.is_superuser)
@permission_required("auth.view_permissions")
@transaction.commit_on_success
def edit_limits_pool(request, resid, tplname="limits/pool.html"):
reseller = User.objects.get(pk=resid)
ctx = dict(reseller=reseller)
+2
View File
@@ -31,6 +31,8 @@ events = [
"MailboxAliasDeleted",
"DomainAdminCreated",
"DomainAdminActions",
"DomainAdminDeleted",
"PasswordChange",
+2 -1
View File
@@ -34,4 +34,5 @@ class CommonExceptionCatcher(object):
return _render_error(request, errortpl="error_simple",
user_context=dict(error=str(exception)))
return ajax_response(request, status="ko", respmsg=str(exception))
return ajax_response(request, status="ko", respmsg=str(exception),
norefresh=True)
-2
View File
@@ -65,8 +65,6 @@ var Form = new Class({
var myid = form.get("id");
var data = form.toQueryString();
console.log("submit");
event.stop();
if (this.callbacks["extra_data"][myid] != undefined) {
if (data != "") {