mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Quota support improvements.
* A mailbox can now use the domain's default quota. (fixes #402) * Possibility to define unlimited quotas (fixes #343)
This commit is contained in:
+20
-8
@@ -84,6 +84,7 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
q.save()
|
||||
old_mail_homes = dict((mb.id, mb.mail_home) for mb in d.mailbox_set.all())
|
||||
d.save()
|
||||
Mailbox.objects.filter(domain=d, use_domain_quota=True).update(quota=d.quota)
|
||||
if old_mail_homes is not None:
|
||||
for mb in d.mailbox_set.all():
|
||||
mb.rename_dir(old_mail_homes[mb.id])
|
||||
@@ -511,9 +512,10 @@ class AccountFormMail(forms.Form, DynamicForm):
|
||||
quota = forms.IntegerField(
|
||||
label=ugettext_lazy("Quota"),
|
||||
required=False,
|
||||
help_text=_("Quota in MB for this mailbox. Leave empty to use the value defined at domain level."),
|
||||
help_text=_("Quota in MB for this mailbox. Define a custom value or use domain's default one. Leave empty to define an unlimited value (not allowed for domain administrators)."),
|
||||
widget=forms.widgets.TextInput(attrs={"class": "span1"})
|
||||
)
|
||||
quota_act = forms.BooleanField(required=False)
|
||||
aliases = forms.EmailField(
|
||||
label=ugettext_lazy("Alias(es)"),
|
||||
required=False,
|
||||
@@ -534,8 +536,12 @@ class AccountFormMail(forms.Form, DynamicForm):
|
||||
name = "aliases_%d" % cpt
|
||||
self._create_field(forms.EmailField, name, alias.full_address)
|
||||
cpt += 1
|
||||
self.fields["email"].initial = self.mb.full_address
|
||||
self.fields["quota"].initial = self.mb.quota
|
||||
self.fields["email"].initial = self.mb.full_address
|
||||
self.fields["quota_act"].initial = self.mb.use_domain_quota
|
||||
if not self.mb.use_domain_quota and self.mb.quota:
|
||||
self.fields["quota"].initial = self.mb.quota
|
||||
else:
|
||||
self.fields["quota_act"].initial = True
|
||||
|
||||
if len(args) and isinstance(args[0], QueryDict):
|
||||
self._load_from_qdict(args[0], "aliases", forms.EmailField)
|
||||
@@ -557,15 +563,19 @@ class AccountFormMail(forms.Form, DynamicForm):
|
||||
if not user.can_access(domain):
|
||||
raise PermDeniedException
|
||||
|
||||
if self.cleaned_data["quota_act"]:
|
||||
self.cleaned_data["quota"] = None
|
||||
|
||||
if not hasattr(self, "mb") or self.mb is None:
|
||||
try:
|
||||
self.mb = Mailbox.objects.get(address=locpart, domain=domain)
|
||||
except Mailbox.DoesNotExist:
|
||||
events.raiseEvent("CanCreate", user, "mailboxes")
|
||||
self.mb = Mailbox()
|
||||
self.mb.save_from_user(locpart, domain, account,
|
||||
self.cleaned_data["quota"],
|
||||
owner=user)
|
||||
self.mb = Mailbox(address=locpart, domain=domain, user=account,
|
||||
use_domain_quota=self.cleaned_data["quota_act"])
|
||||
self.mb.set_quota(self.cleaned_data["quota"],
|
||||
user.has_perm("admin.add_domain"))
|
||||
self.mb.save()
|
||||
grant_access_to_object(user, self.mb, is_owner=True)
|
||||
events.raiseEvent("CreateMailbox", user, self.mb)
|
||||
if user.is_superuser and not self.mb.user.has_perm("admin.add_domain"):
|
||||
@@ -587,7 +597,9 @@ class AccountFormMail(forms.Form, DynamicForm):
|
||||
self.mb.address = locpart
|
||||
q.username = self.mb.full_address
|
||||
q.save()
|
||||
self.mb.set_quota(self.cleaned_data["quota"], user.has_perm("admin.add_domain"))
|
||||
self.mb.use_domain_quota = self.cleaned_data["quota_act"]
|
||||
override_rules = True if not self.mb.quota or user.has_perm("admin.add_domain") else False
|
||||
self.mb.set_quota(self.cleaned_data["quota"], override_rules)
|
||||
self.mb.save()
|
||||
if old_mail_home is not None:
|
||||
# Problem here: the mailbox has already been saved so,
|
||||
|
||||
+21
-23
@@ -440,8 +440,9 @@ class User(DUser):
|
||||
raise AdminError(_("Account import failed (%s): domain does not exist" % self.username))
|
||||
if not user.can_access(domain):
|
||||
raise PermDeniedException
|
||||
mb = Mailbox()
|
||||
mb.save_from_user(mailbox, domain, self, owner=user)
|
||||
mb = Mailbox(address=mailbox, domain=domain, user=self, use_domain_quota=True)
|
||||
mb.set_quota(override_rules=user.has_perm("admin.change_domain"))
|
||||
mb.save()
|
||||
self.save()
|
||||
if grpname == "DomainAdmins":
|
||||
for domname in row[8:]:
|
||||
@@ -586,6 +587,7 @@ class Domain(DatesAware):
|
||||
def to_csv(self, csvwriter):
|
||||
csvwriter.writerow(["domain", self.name, self.quota, self.enabled])
|
||||
|
||||
|
||||
class DomainAlias(DatesAware):
|
||||
name = models.CharField(ugettext_lazy("name"), max_length=100, unique=True,
|
||||
help_text=ugettext_lazy("The alias name"))
|
||||
@@ -641,7 +643,8 @@ class Mailbox(DatesAware):
|
||||
ugettext_lazy('address'), max_length=100,
|
||||
help_text=ugettext_lazy("Mailbox address (without the @domain.tld part)")
|
||||
)
|
||||
quota = models.IntegerField()
|
||||
quota = models.PositiveIntegerField()
|
||||
use_domain_quota = models.BooleanField(default=False)
|
||||
domain = models.ForeignKey(Domain)
|
||||
user = models.ForeignKey(User)
|
||||
|
||||
@@ -718,20 +721,25 @@ class Mailbox(DatesAware):
|
||||
if code:
|
||||
raise AdminError(_("Failed to remove mailbox: %s" % output))
|
||||
|
||||
def set_quota(self, value, override_domain=False):
|
||||
def set_quota(self, value=None, override_rules=False):
|
||||
"""Set or update quota's value for this mailbox.
|
||||
|
||||
:param integer value: the quota's value
|
||||
:param bool override_domain: allow to override domain's limit or not
|
||||
:param bool override_rules: allow to override defined quota rules
|
||||
"""
|
||||
if value is None:
|
||||
self.quota = self.domain.quota
|
||||
elif int(value) > self.domain.quota and not override_domain:
|
||||
if self.use_domain_quota:
|
||||
self.quota = self.domain.quota
|
||||
else:
|
||||
self.quota = 0
|
||||
elif int(value) > self.domain.quota and not override_rules:
|
||||
raise AdminError(
|
||||
_("Quota is greater than the allowed domain's limit (%dM)" % self.domain.quota)
|
||||
)
|
||||
else:
|
||||
self.quota = value
|
||||
if not self.quota and not override_rules:
|
||||
raise AdminError(_("A quota is required"))
|
||||
|
||||
def get_quota(self):
|
||||
q = Quota.objects.get(username=self.full_address)
|
||||
@@ -743,20 +751,9 @@ class Mailbox(DatesAware):
|
||||
q = Quota.objects.get(username=self.full_address)
|
||||
return int(q.bytes / float(self.quota * 1048576) * 100)
|
||||
|
||||
def save_from_user(self, localpart, domain, user, quota=None, owner=None):
|
||||
"""Simple save method called for automatic creations
|
||||
|
||||
:param localpart: the mailbox
|
||||
:param domain: the associated Domain object
|
||||
:param user: the associated User object
|
||||
"""
|
||||
self.address = localpart
|
||||
self.domain = domain
|
||||
self.user = user
|
||||
self.set_quota(quota, True if (owner and owner.has_perm("admin.add_domain")) else False)
|
||||
super(Mailbox, self).save()
|
||||
|
||||
Quota.objects.create(username=self.full_address)
|
||||
def save(self, *args, **kwargs):
|
||||
super(Mailbox, self).save(*args, **kwargs)
|
||||
quota, created = Quota.objects.get_or_create(username=self.full_address)
|
||||
|
||||
def delete(self, keepdir=False):
|
||||
"""Custom delete method
|
||||
@@ -1030,8 +1027,9 @@ def populate_callback(user):
|
||||
try:
|
||||
mb = Mailbox.objects.get(domain=domain, address=localpart)
|
||||
except Mailbox.DoesNotExist:
|
||||
mb = Mailbox()
|
||||
mb.save_from_user(localpart, domain, user)
|
||||
mb = Mailbox(address=localpart, domain=domain, user=user, use_domain_quota=True)
|
||||
mb.set_quota()
|
||||
mb.save()
|
||||
events.raiseEvent("CreateMailbox", sadmins[0], mb)
|
||||
grant_access_to_object(sadmins[0], mb, True)
|
||||
for su in sadmins[1:]:
|
||||
|
||||
@@ -339,7 +339,7 @@ Identities.prototype = {
|
||||
choices: get_domains_list
|
||||
})
|
||||
.dynamic_input();
|
||||
|
||||
activate_widget.call($("#id_quota_act"));
|
||||
},
|
||||
|
||||
accountform_init: function() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% load libextras %}
|
||||
{% render_field form.email %}
|
||||
{% render_field_appended form.quota _("MB") %}
|
||||
{% include "common/generic_field.html" with field=form.quota help_display_mode="tooltip" appended_text=_("MB") activator=True activator_value=form.quota_act.value deactivate_if_empty=False activator_label=_("Use domain default value") %}
|
||||
{% render_fields_group form "aliases" %}
|
||||
|
||||
@@ -77,6 +77,7 @@ class AccountTestCase(ModoTestCase):
|
||||
def test(self):
|
||||
values = dict(username="tester@test.com", first_name="Tester", last_name="Toto",
|
||||
password1="toto", password2="toto", role="SimpleUsers",
|
||||
quota_act=True,
|
||||
is_active=True, email="tester@test.com", stepid=2)
|
||||
self.check_ajax_post(reverse("modoboa.admin.views.newaccount"), values)
|
||||
|
||||
@@ -236,7 +237,7 @@ class PermissionsTestCase(ModoTestCase):
|
||||
True)
|
||||
admin = User.objects.get(username="admin@test.com")
|
||||
values = dict(username="admin@test.com", first_name="Admin", password1="", password2="",
|
||||
is_active=True, email="admin@test.com")
|
||||
quota=10, is_active=True, email="admin@test.com")
|
||||
self.check_ajax_post(reverse("modoboa.admin.views.editaccount", args=[admin.id]), values)
|
||||
self.assertEqual(admin.group, "DomainAdmins")
|
||||
self.assertEqual(admin.can_access(Domain.objects.get(name="test.com")), True)
|
||||
|
||||
@@ -118,10 +118,7 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
$(document).bind('domform_init', function() {
|
||||
var checked = $('#id_spam_subject_tag2_act').attr('checked');
|
||||
if (checked && checked == 'checked') {
|
||||
$('#id_spam_subject_tag2').attr('disabled', true);
|
||||
}
|
||||
activate_widget.call($('#id_spam_subject_tag2_act'));
|
||||
});
|
||||
});
|
||||
</script>""")
|
||||
|
||||
@@ -107,9 +107,9 @@ def render_field_appended(field, text):
|
||||
@register.simple_tag
|
||||
def render_field_with_activator(field, activator_label=ugettext_lazy("activate")):
|
||||
return render_to_string("common/generic_field.html", {
|
||||
"field" : field, "help_display_mode" : "tooltip", "activator" : True,
|
||||
"activator_label" : activator_label
|
||||
})
|
||||
"field": field, "help_display_mode": "tooltip", "activator": True,
|
||||
"activator_label": activator_label, "deactivate_if_empty": True
|
||||
})
|
||||
|
||||
@register.simple_tag
|
||||
def render_and_hide_field(field):
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% if appended_text %}<div class="input-append">{% endif %}
|
||||
{{ field }}{% if appended_text %}<span class="add-on">{{ appended_text }}</span></div>{% endif %}{% if help_display_mode == "inline" and field.help_text %}<span class="help-inline">{{ field.help_text }}</span>{% endif %}
|
||||
{% if activator %}<label class="checkbox inline" for="id_{{ field.name }}_act">
|
||||
<input type="checkbox" class="activator" id="id_{{ field.name }}_act" name="{{ field.name }}_act" {% if field.value == None %}checked='checked'{% endif %}/>{{ activator_label }}
|
||||
<input type="checkbox" class="activator" id="id_{{ field.name }}_act" name="{{ field.name }}_act" {% if activator_value %}checked='checked'{% else %}{% if deactivate_if_empty and field.value == None %}checked='checked'{% endif %}{% endif %}/>{{ activator_label }}
|
||||
</label>{% endif %}
|
||||
{% if field.errors %}<p class="help-block">{% for error in field.errors %}{{ error|safe }}{% endfor %}</p>{% endif %}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user