mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
wip: Per-domain policy support
* The domain edition form was converted to a "TabsForm" * New events added : "ExtraDomainForm" and "FillDomainInstances" * Creation and modification of policies work see #260
This commit is contained in:
+30
-4
@@ -10,7 +10,7 @@ from modoboa.lib.permissions import get_account_roles
|
||||
from modoboa.lib.formutils import *
|
||||
from modoboa.lib.permissions import *
|
||||
|
||||
class DomainForm(forms.ModelForm, DynamicForm):
|
||||
class DomainFormGeneral(forms.ModelForm, DynamicForm):
|
||||
aliases = DomainNameField(
|
||||
label=ugettext_lazy("Alias(es)"),
|
||||
required=False,
|
||||
@@ -25,7 +25,7 @@ class DomainForm(forms.ModelForm, DynamicForm):
|
||||
self.oldname = None
|
||||
if kwargs.has_key("instance"):
|
||||
self.oldname = kwargs["instance"].name
|
||||
super(DomainForm, self).__init__(*args, **kwargs)
|
||||
super(DomainFormGeneral, self).__init__(*args, **kwargs)
|
||||
|
||||
if len(args) and isinstance(args[0], QueryDict):
|
||||
self._load_from_qdict(args[0], "aliases", DomainNameField)
|
||||
@@ -36,7 +36,7 @@ class DomainForm(forms.ModelForm, DynamicForm):
|
||||
self._create_field(forms.CharField, name, dalias.name, 3)
|
||||
|
||||
def clean(self):
|
||||
super(DomainForm, self).clean()
|
||||
super(DomainFormGeneral, self).clean()
|
||||
if len(self._errors):
|
||||
raise forms.ValidationError(self._errors)
|
||||
|
||||
@@ -69,7 +69,7 @@ class DomainForm(forms.ModelForm, DynamicForm):
|
||||
return cleaned_data
|
||||
|
||||
def save(self, user, commit=True):
|
||||
d = super(DomainForm, self).save(commit=False)
|
||||
d = super(DomainFormGeneral, self).save(commit=False)
|
||||
if commit:
|
||||
if self.oldname is not None and d.name != self.oldname:
|
||||
if not d.rename_dir(self.oldname):
|
||||
@@ -98,6 +98,32 @@ class DomainForm(forms.ModelForm, DynamicForm):
|
||||
dalias.delete()
|
||||
return d
|
||||
|
||||
class DomainForm(TabForms):
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
self.user = user
|
||||
self.forms = [
|
||||
dict(id="general", title=_("General"), formtpl="admin/domain_general_form.html",
|
||||
cls=DomainFormGeneral, mandatory=True),
|
||||
]
|
||||
cbargs = [user]
|
||||
if kwargs.has_key("instances"):
|
||||
cbargs += [kwargs["instances"]["general"]]
|
||||
self.forms += events.raiseQueryEvent("ExtraDomainForm", *cbargs)
|
||||
|
||||
super(DomainForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, user):
|
||||
"""Custom save method
|
||||
|
||||
As forms interact with each other, it is simpler to make
|
||||
custom code to save them.
|
||||
"""
|
||||
self.forms[0]["instance"].save(user)
|
||||
if len(self.forms) <= 1:
|
||||
return
|
||||
for f in self.forms[1:]:
|
||||
f["instance"].save()
|
||||
|
||||
class DlistForm(forms.ModelForm, DynamicForm):
|
||||
email = forms.EmailField(
|
||||
label=ugettext_lazy("Email address"),
|
||||
|
||||
+14
-11
@@ -45,7 +45,7 @@ def domains_list(request):
|
||||
return ajax_simple_response(doms)
|
||||
|
||||
def _validate_domain(request, form, successmsg, commonctx, tplname,
|
||||
callback=None):
|
||||
callback=None, tpl_form_name="form"):
|
||||
"""Domain form validation
|
||||
|
||||
Common function shared between creation and modification actions.
|
||||
@@ -56,15 +56,15 @@ def _validate_domain(request, form, successmsg, commonctx, tplname,
|
||||
domain = form.save(request.user)
|
||||
except AdminError, e:
|
||||
error = str(e)
|
||||
except IntegrityError:
|
||||
error = _("An alias with this name already exists")
|
||||
# except IntegrityError:
|
||||
# error = _("An alias with this name already exists")
|
||||
else:
|
||||
if callback is not None:
|
||||
callback(request.user, domain)
|
||||
messages.info(request, successmsg, fail_silently=True)
|
||||
return ajax_response(request, url=reverse(admin.views.domains))
|
||||
|
||||
commonctx["form"] = form
|
||||
commonctx[tpl_form_name] = form
|
||||
commonctx["error"] = error
|
||||
return ajax_response(request, status="ko", template=tplname, **commonctx)
|
||||
|
||||
@@ -83,10 +83,10 @@ def newdomain(request, tplname="admin/newdomainform.html"):
|
||||
"action" : reverse(newdomain),
|
||||
"formid" : "domform"}
|
||||
if request.method == "POST":
|
||||
form = DomainForm(request.POST)
|
||||
form = DomainFormGeneral(request.POST)
|
||||
return _validate_domain(request, form, _("Domain created"), commonctx,
|
||||
tplname, callback=newdomain_cb)
|
||||
form = DomainForm()
|
||||
form = DomainFormGeneral()
|
||||
commonctx["form"] = form
|
||||
return _render(request, tplname, commonctx)
|
||||
|
||||
@@ -103,7 +103,10 @@ def editdomain(request, dom_id, tplname="admin/editdomainform.html"):
|
||||
)
|
||||
if not request.user.is_superuser:
|
||||
domadmins = filter(lambda u: u.group == "DomainAdmins", domadmins)
|
||||
|
||||
|
||||
instances = dict(general=domain)
|
||||
events.raiseEvent("FillDomainInstances", request.user, domain, instances)
|
||||
|
||||
commonctx = {"title" : domain.name,
|
||||
"action_label" : _("Update"),
|
||||
"action_classes" : "submit",
|
||||
@@ -111,11 +114,11 @@ def editdomain(request, dom_id, tplname="admin/editdomainform.html"):
|
||||
"formid" : "domform",
|
||||
"domain" : domain}
|
||||
if request.method == "POST":
|
||||
form = DomainForm(request.POST, instance=domain)
|
||||
return _validate_domain(request, form, _("Domain modified"), commonctx, tplname)
|
||||
form = DomainForm(request.user, request.POST, instances=instances)
|
||||
return _validate_domain(request, form, _("Domain modified"), commonctx, tplname,
|
||||
tpl_form_name="tabs")
|
||||
|
||||
form = DomainForm(instance=domain)
|
||||
commonctx["form"] = form
|
||||
commonctx["tabs"] = DomainForm(request.user, instances=instances)
|
||||
commonctx["domadmins"] = domadmins
|
||||
return _render(request, tplname, commonctx)
|
||||
|
||||
|
||||
@@ -92,6 +92,17 @@ def menu(target, user):
|
||||
]
|
||||
return []
|
||||
|
||||
@events.observe("DeleteDomain")
|
||||
def on_delete_domain(domain):
|
||||
from models import Users
|
||||
|
||||
try:
|
||||
u = Users.objects.get(email="@%s" % domain.name)
|
||||
except Users.DoesNotExist:
|
||||
return
|
||||
u.policy.delete()
|
||||
u.delete()
|
||||
|
||||
@events.observe("CreateMailbox")
|
||||
def create_user_record(user, mailbox):
|
||||
from models import Users
|
||||
@@ -170,3 +181,21 @@ def display_requests(user):
|
||||
return [tpl.render(Context(dict(
|
||||
label=_("%d pending requests" % nbrequests), url=url, css=css
|
||||
)))]
|
||||
|
||||
@events.observe("ExtraDomainForm")
|
||||
def extra_domain_form(user, domain):
|
||||
from forms import DomainPolicyForm
|
||||
|
||||
if not user.is_superuser and not user.belongs_to_group("Resellers"):
|
||||
return []
|
||||
return [
|
||||
dict(
|
||||
id="amavis", title=_("Amavis"), cls=DomainPolicyForm
|
||||
)
|
||||
]
|
||||
|
||||
@events.observe("FillDomainInstances")
|
||||
def fill_domain_instances(user, domain, instances):
|
||||
if not user.is_superuser and not user.belongs_to_group("Resellers"):
|
||||
return
|
||||
instances["amavis"] = domain
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# coding: utf-8
|
||||
|
||||
from django import forms
|
||||
from models import Policy, Users
|
||||
|
||||
class DomainPolicyForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Policy
|
||||
fields = ('bypass_virus_checks', 'bypass_spam_checks', 'spam_modifies_subj',
|
||||
'spam_tag2_level', 'spam_kill_level')
|
||||
widgets = {
|
||||
'bypass_spam_checks' : forms.Select(attrs={'class' : 'span1'}),
|
||||
'bypass_virus_checks' : forms.Select(attrs={'class' : 'span1'}),
|
||||
'spam_modifies_subj' : forms.Select(attrs={'class' : 'span1'}),
|
||||
'spam_tag2_level' : forms.TextInput(attrs={'class' : 'span1'}),
|
||||
'spam_kill_level' : forms.TextInput(attrs={'class' : 'span1'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.has_key("instance"):
|
||||
self.domain = kwargs["instance"]
|
||||
try:
|
||||
policy = Users.objects.get(email="@%s" % self.domain.name).policy
|
||||
kwargs["instance"] = policy
|
||||
except (Users.DoesNotExist, Policy.DoesNotExist), e:
|
||||
del kwargs["instance"]
|
||||
super(DomainPolicyForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
p = super(DomainPolicyForm, self).save(commit=False)
|
||||
if commit:
|
||||
p.save()
|
||||
print p.id
|
||||
try:
|
||||
u = Users.objects.get(policy__id=p.id)
|
||||
except Users.DoesNotExist:
|
||||
u = Users()
|
||||
u.email = "@%s" % self.domain.name
|
||||
u.fullname = self.domain.name
|
||||
u.policy = p
|
||||
u.local = "1"
|
||||
u.priority = 7
|
||||
u.save()
|
||||
p.save()
|
||||
return p
|
||||
@@ -10,6 +10,7 @@
|
||||
# Original Amavis version : 2.6.2
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
class Maddr(models.Model):
|
||||
partition_tag = models.IntegerField(unique=True, null=True, blank=True)
|
||||
@@ -68,17 +69,26 @@ class Msgrcpt(models.Model):
|
||||
unique_together = ("mail", "rid")
|
||||
|
||||
class Policy(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
id = models.AutoField(primary_key=True)
|
||||
policy_name = models.CharField(max_length=96, blank=True)
|
||||
virus_lover = models.CharField(max_length=3, blank=True)
|
||||
spam_lover = models.CharField(max_length=3, blank=True)
|
||||
banned_files_lover = models.CharField(max_length=3, blank=True)
|
||||
bad_header_lover = models.CharField(max_length=3, blank=True)
|
||||
bypass_virus_checks = models.CharField(max_length=3, blank=True)
|
||||
bypass_spam_checks = models.CharField(max_length=3, blank=True)
|
||||
bypass_virus_checks = models.CharField(
|
||||
ugettext_lazy("Bypass virus checks"), max_length=3,
|
||||
choices=(('Y', 'yes'), ('N', 'no')), blank=True
|
||||
)
|
||||
bypass_spam_checks = models.CharField(
|
||||
ugettext_lazy("Bypass spam checks"), max_length=3,
|
||||
choices=(('Y', 'yes'), ('N', 'no')), blank=True
|
||||
)
|
||||
bypass_banned_checks = models.CharField(max_length=3, blank=True)
|
||||
bypass_header_checks = models.CharField(max_length=3, blank=True)
|
||||
spam_modifies_subj = models.CharField(max_length=3, blank=True)
|
||||
spam_modifies_subj = models.CharField(
|
||||
ugettext_lazy("Modify spam subject"),
|
||||
choices=(('Y', 'yes'), ('N', 'no')), max_length=3, blank=True
|
||||
)
|
||||
virus_quarantine_to = models.CharField(max_length=192, blank=True)
|
||||
spam_quarantine_to = models.CharField(max_length=192, blank=True)
|
||||
banned_quarantine_to = models.CharField(max_length=192, blank=True)
|
||||
@@ -86,8 +96,12 @@ class Policy(models.Model):
|
||||
clean_quarantine_to = models.CharField(max_length=192, blank=True)
|
||||
other_quarantine_to = models.CharField(max_length=192, blank=True)
|
||||
spam_tag_level = models.FloatField(null=True, blank=True)
|
||||
spam_tag2_level = models.FloatField(null=True, blank=True)
|
||||
spam_kill_level = models.FloatField(null=True, blank=True)
|
||||
spam_tag2_level = models.FloatField(
|
||||
ugettext_lazy("Spam tag2 level"), null=True, blank=True
|
||||
)
|
||||
spam_kill_level = models.FloatField(
|
||||
ugettext_lazy("Spam kill level"), null=True, blank=True
|
||||
)
|
||||
spam_dsn_cutoff_level = models.FloatField(null=True, blank=True)
|
||||
spam_quarantine_cutoff_level = models.FloatField(null=True, blank=True)
|
||||
addr_extension_virus = models.CharField(max_length=192, blank=True)
|
||||
@@ -122,9 +136,9 @@ class Quarantine(models.Model):
|
||||
unique_together = ("mail", "chunk_ind")
|
||||
|
||||
class Users(models.Model):
|
||||
id = models.IntegerField(primary_key=True)
|
||||
id = models.AutoField(primary_key=True)
|
||||
priority = models.IntegerField()
|
||||
policy_id = models.IntegerField()
|
||||
policy = models.ForeignKey(Policy)
|
||||
email = models.CharField(unique=True, max_length=255)
|
||||
fullname = models.CharField(max_length=765, blank=True)
|
||||
local = models.CharField(max_length=3, blank=True)
|
||||
|
||||
@@ -42,6 +42,9 @@ events = [
|
||||
"ExtraAccountForm",
|
||||
"CheckExtraAccountForm",
|
||||
"FillAccountInstances",
|
||||
|
||||
"ExtraDomainForm",
|
||||
"FillDomainInstances",
|
||||
|
||||
"GetExtraRoles",
|
||||
|
||||
|
||||
+1
-5
@@ -28,14 +28,10 @@ class Column:
|
||||
def __unicode__(self):
|
||||
try:
|
||||
label = getattr(self, "label")
|
||||
except KeyError:
|
||||
except AttributeError:
|
||||
label = getattr(self, "name")
|
||||
return _(label)
|
||||
|
||||
def __str__(self):
|
||||
return self.__unicode__()
|
||||
|
||||
|
||||
class SelectionColumn(Column):
|
||||
"""Specific column: selection
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{% load libextras %}
|
||||
{% render_field form.name %}
|
||||
{% render_field form.quota %}
|
||||
{% render_fields_group form "aliases" %}
|
||||
{% render_field form.enabled %}
|
||||
@@ -1,34 +1,22 @@
|
||||
{% extends "common/generic_modal.html" %}{% load i18n libextras admin_extras %}
|
||||
{% block modalbody %}
|
||||
<ul class="nav nav-pills">
|
||||
<li class="active"><a href="#general" data-toggle="tab">{% trans "General" %}</a></li>
|
||||
{% extends "common/tabforms.html" %}{% load i18n libextras admin_extras %}
|
||||
{% block extratabs %}
|
||||
<li><a href="#admins" data-toggle="tab">{% trans "Administrators" %}</a></li>
|
||||
<li><a href="#misc" data-toggle="tab">{% trans "Miscellaneous" %}</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="general">
|
||||
{% if error %}<div class="alert alert-error">{{ error }}</div>{% endif %}
|
||||
<form class="form-horizontal" action="{{ action }}" method="POST" id="{{ formid }}" name="{{ formid }}">
|
||||
{% render_field form.name %}
|
||||
{% render_field form.quota %}
|
||||
{% render_fields_group form "aliases" %}
|
||||
{% render_field form.enabled %}
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="admins">{% if domadmins %}
|
||||
<table id="domadmins" class="table table-condensed">
|
||||
<tr><th>{% trans "Username" %}</th><th>{% trans "Name" %}</th><th></th></tr>
|
||||
{% for da in domadmins %}<tr>
|
||||
<td>{{ da.username }}</td><td>{{ da.fullname }}</td><td name="actions">{% domadmin_actions da.id domain.id %}</td>
|
||||
</tr>{% endfor %}
|
||||
</table>{% else %}<div class="alert alert-info">{% trans "No domain administrator defined" %}</div>{% endif %}
|
||||
</div>
|
||||
<div class="tab-pane" id="misc">
|
||||
<div class="row"><span class="title">{% trans "Creation date" %}</span><span>{{ domain.creation }}</<span></div>
|
||||
<div class="row"><span class="title">{% trans "Last modification date" %}</span><span>{{ domain.last_modification }}</<span></div>
|
||||
<div class="row"><span class="title">{% trans "Domain aliases" %}</span><span>{{ domain.domainalias_count }}</<span></div>
|
||||
<div class="row"><span class="title">{% trans "Mailboxes" %}</span><span>{{ domain.mailbox_count }}</<span></div>
|
||||
<div class="row"><span class="title">{% trans "Mailbox aliases" %}</span><span>{{ domain.mbalias_count }}</<span></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extratabs_content %}
|
||||
<div class="tab-pane" id="admins">{% if domadmins %}
|
||||
<table id="domadmins" class="table table-condensed">
|
||||
<tr><th>{% trans "Username" %}</th><th>{% trans "Name" %}</th><th></th></tr>
|
||||
{% for da in domadmins %}<tr>
|
||||
<td>{{ da.username }}</td><td>{{ da.fullname }}</td><td name="actions">{% domadmin_actions da.id domain.id %}</td>
|
||||
</tr>{% endfor %}
|
||||
</table>{% else %}<div class="alert alert-info">{% trans "No domain administrator defined" %}</div>{% endif %}
|
||||
</div>
|
||||
<div class="tab-pane" id="misc">
|
||||
<div class="row"><span class="title">{% trans "Creation date" %}</span><span>{{ domain.creation }}</span></div>
|
||||
<div class="row"><span class="title">{% trans "Last modification date" %}</span><span>{{ domain.last_modification }}</span></div>
|
||||
<div class="row"><span class="title">{% trans "Domain aliases" %}</span><span>{{ domain.domainalias_count }}</span></div>
|
||||
<div class="row"><span class="title">{% trans "Mailboxes" %}</span><span>{{ domain.mailbox_count }}</span></div>
|
||||
<div class="row"><span class="title">{% trans "Mailbox aliases" %}</span><span>{{ domain.mbalias_count }}</span></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,23 +2,21 @@
|
||||
{% load i18n libextras %}
|
||||
{% block modalbody %}
|
||||
<form id="{{ formid }}" class="form-horizontal" action="{{ action }}" method="POST">
|
||||
<ul class="nav nav-pills">
|
||||
{% for tab in tabs %}
|
||||
<ul class="nav nav-pills">{% for tab in tabs %}
|
||||
<li class="{% if tabs.active_id == tab.id %}active{% endif %}">
|
||||
<a href="#{{ tab.id }}" data-toggle="tab">{{ tab.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</li>{% endfor %}
|
||||
{% block extratabs %}{% endblock %}
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
{% for tab in tabs %}
|
||||
<div class="tab-pane{% if tabs.active_id == tab.id %} active{% endif %}" id="{{ tab.id }}">
|
||||
{% for tab in tabs %}<div class="tab-pane{% if tabs.active_id == tab.id %} active{% endif %}" id="{{ tab.id }}">
|
||||
{% if tab.formtpl %}
|
||||
{% render_form tab.instance tab.formtpl %}
|
||||
{% else %}
|
||||
{% render_form tab.instance %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>{% endfor %}
|
||||
{% block extratabs_content %}{% endblock %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user