mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-21 06:18:45 +02:00
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:
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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}}"},
|
||||
]
|
||||
|
||||
@@ -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"),)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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" %}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user