mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
@@ -20,6 +20,7 @@ from ..models import Domain, Alias
|
||||
class AliasForm(forms.ModelForm, DynamicForm):
|
||||
"""A form to create/modify an alias."""
|
||||
|
||||
random_address = forms.BooleanField(required=False)
|
||||
address = lib_fields.UTF8AndEmptyUserEmailField(
|
||||
label=ugettext_lazy("Email address"),
|
||||
help_text=ugettext_lazy(
|
||||
@@ -39,16 +40,27 @@ class AliasForm(forms.ModelForm, DynamicForm):
|
||||
|
||||
class Meta:
|
||||
model = Alias
|
||||
fields = ("address", "enabled", )
|
||||
fields = ("address", "domain", "enabled", "expire_at", "description")
|
||||
widgets = {
|
||||
"domain": forms.widgets.Select(
|
||||
attrs={"class": "selectpicker", "data-live-search": "true"})
|
||||
}
|
||||
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
self.user = user
|
||||
super(AliasForm, self).__init__(*args, **kwargs)
|
||||
self.fields = OrderedDict(
|
||||
(key, self.fields[key]) for key in
|
||||
['address', 'recipients', 'enabled']
|
||||
["random_address", "address", "domain", "recipients", "enabled",
|
||||
"expire_at", "description"]
|
||||
)
|
||||
|
||||
if self.instance.pk:
|
||||
del self.fields["random_address"]
|
||||
del self.fields["domain"]
|
||||
else:
|
||||
self.fields["address"].required = False
|
||||
self.fields["domain"].required = False
|
||||
self.fields["domain"].queryset = Domain.objects.get_for_admin(user)
|
||||
if len(args) and isinstance(args[0], QueryDict):
|
||||
if "instance" in kwargs:
|
||||
if not kwargs["instance"].domain.enabled:
|
||||
@@ -66,6 +78,8 @@ class AliasForm(forms.ModelForm, DynamicForm):
|
||||
|
||||
def clean_address(self):
|
||||
"""Check if address points to a local domain."""
|
||||
if not self.cleaned_data["address"]:
|
||||
return self.cleaned_data["address"]
|
||||
localpart, domname = split_mailbox(self.cleaned_data["address"])
|
||||
try:
|
||||
domain = Domain.objects.get(name=domname)
|
||||
@@ -87,6 +101,12 @@ class AliasForm(forms.ModelForm, DynamicForm):
|
||||
def clean(self):
|
||||
"""Check it there is at least one recipient."""
|
||||
super(AliasForm, self).clean()
|
||||
random_address = self.cleaned_data.get("random_address")
|
||||
if not random_address:
|
||||
if not self.cleaned_data.get("address"):
|
||||
self.add_error("address", _("This field is required"))
|
||||
elif not self.cleaned_data.get("domain"):
|
||||
self.add_error("domain", _("This field is required"))
|
||||
for field, value in self.cleaned_data.items():
|
||||
if field.startswith("recipients") and value:
|
||||
return self.cleaned_data
|
||||
@@ -96,8 +116,12 @@ class AliasForm(forms.ModelForm, DynamicForm):
|
||||
def save(self, commit=True):
|
||||
"""Custom save method."""
|
||||
alias = super(AliasForm, self).save(commit=False)
|
||||
local_part, domname = split_mailbox(self.cleaned_data["address"])
|
||||
alias.domain = Domain.objects.get(name=domname)
|
||||
if self.cleaned_data.get("random_address"):
|
||||
alias.address = "{}@{}".format(
|
||||
Alias.generate_random_address(), alias.domain)
|
||||
else:
|
||||
local_part, domname = split_mailbox(self.cleaned_data["address"])
|
||||
alias.domain = Domain.objects.get(name=domname)
|
||||
if commit:
|
||||
alias.save()
|
||||
address_list = [
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.5 on 2016-07-19 07:03
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('admin', '0004_auto_20160608_1423'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='alias',
|
||||
name='description',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='alias',
|
||||
name='expire_at',
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,5 +1,8 @@
|
||||
"""Models related to aliases management."""
|
||||
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||
@@ -37,6 +40,8 @@ class Alias(AdminObject):
|
||||
default=True
|
||||
)
|
||||
internal = models.BooleanField(default=False)
|
||||
description = models.TextField(blank=True)
|
||||
expire_at = models.DateTimeField(blank=True, null=True)
|
||||
_objectname = 'MailboxAlias'
|
||||
|
||||
class Meta:
|
||||
@@ -50,6 +55,14 @@ class Alias(AdminObject):
|
||||
def __str__(self):
|
||||
return smart_text(self.address)
|
||||
|
||||
@classmethod
|
||||
def generate_random_address(self):
|
||||
"""Generate a random address (local part)."""
|
||||
m = hashlib.md5()
|
||||
for x in random.sample(xrange(10000000), 60):
|
||||
m.update(str(x))
|
||||
return m.hexdigest()[:20]
|
||||
|
||||
@property
|
||||
def identity(self):
|
||||
return self.address
|
||||
|
||||
@@ -52,17 +52,17 @@ class AliasesMap(object):
|
||||
mysql = (
|
||||
"SELECT alr.address FROM modoboa_admin_aliasrecipient AS alr "
|
||||
"INNER JOIN admin_alias AS al ON alr.alias_id=al.id "
|
||||
"WHERE al.enabled=1 AND al.address='%s'"
|
||||
"WHERE al.enabled=1 AND al.address='%s' AND al.expire_at>now()"
|
||||
)
|
||||
postgres = (
|
||||
"SELECT alr.address FROM modoboa_admin_aliasrecipient AS alr "
|
||||
"INNER JOIN admin_alias AS al ON alr.alias_id=al.id "
|
||||
"WHERE al.enabled AND al.address='%s'"
|
||||
"WHERE al.enabled AND al.address='%s' AND al.expire_at>now()"
|
||||
)
|
||||
sqlite = (
|
||||
"SELECT alr.address FROM modoboa_admin_aliasrecipient AS alr "
|
||||
"INNER JOIN admin_alias AS al ON alr.alias_id=al.id "
|
||||
"WHERE al.enabled=1 AND al.address='%s'"
|
||||
"WHERE al.enabled=1 AND al.address='%s' AND al.expire_at>now()"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -552,6 +552,15 @@ Identities.prototype = {
|
||||
},
|
||||
|
||||
aliasform_cb: function() {
|
||||
$("#id_random_address").click(function(evt) {
|
||||
if ($(this).prop("checked")) {
|
||||
$("#id_address").parents(".form-group").hide();
|
||||
$("#id_domain").parents(".form-group").show();
|
||||
} else {
|
||||
$("#id_address").parents(".form-group").show();
|
||||
$("#id_domain").parents(".form-group").hide();
|
||||
}
|
||||
});
|
||||
$("#id_address").autocompleter({
|
||||
from_character: "@",
|
||||
choices: $.proxy(this.get_domain_list, this)
|
||||
@@ -565,6 +574,9 @@ Identities.prototype = {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
$("#id_expire_at").datetimepicker({
|
||||
format: 'YYYY-MM-DD HH:mm:ss'
|
||||
});
|
||||
$(".submit").on('click', $.proxy(function(e) {
|
||||
simple_ajax_form_post(e, {
|
||||
formid: "aliasform",
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Created" %}</dt><dd>{{ alias.creation|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
<dt>{% trans "Modified" %}</dt><dd>{{ alias.last_modification|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
{% if alias.expire_at %}
|
||||
<dt>{% trans "Expire at" %}</dt><dd>{{ alias.expire_at|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
{% endif %}
|
||||
{% if alias.description %}
|
||||
<dt>{% trans "Description" %}</dt><dd>{{ alias.description }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
<table class="table">
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
{% extends "common/generic_modal_form.html" %}{% load form_tags %}
|
||||
{% extends "common/generic_modal_form.html" %}
|
||||
|
||||
{% load form_tags %}
|
||||
|
||||
{% block formbody %}
|
||||
{% render_field form.address %}
|
||||
{% render_fields_group form "recipients" %}
|
||||
{% if not form.instance.pk or form.instance.domain.enabled %}
|
||||
{% render_field form.enabled %}
|
||||
{% else %}
|
||||
{% include "common/generic_field.html" with field=form.enabled label_width="col-sm-4" inline_message=_("Domain is disabled") extra_classes="info" %}
|
||||
{% endif %}
|
||||
{% if form.random_address %}{% render_field form.random_address %}{% endif %}
|
||||
{% render_field form.address %}
|
||||
{% if form.domain %}{% render_field form.domain hidden=True %}{% endif %}
|
||||
{% render_fields_group form "recipients" %}
|
||||
{% if not form.instance.pk or form.instance.domain.enabled %}
|
||||
{% render_field form.enabled %}
|
||||
{% else %}
|
||||
{% include "common/generic_field.html" with field=form.enabled label_width="col-sm-4" inline_message=_("Domain is disabled") extra_classes="info" %}
|
||||
{% endif %}
|
||||
{% render_field form.expire_at %}
|
||||
{% render_field form.description %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -8,7 +8,7 @@ from modoboa.core.models import User
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
|
||||
from .. import factories
|
||||
from ..models import Alias, AliasRecipient
|
||||
from ..models import Alias, AliasRecipient, Domain
|
||||
|
||||
|
||||
class AliasTestCase(ModoTestCase):
|
||||
@@ -126,11 +126,13 @@ class AliasTestCase(ModoTestCase):
|
||||
)
|
||||
|
||||
def test_dlist(self):
|
||||
values = dict(address="all@test.com",
|
||||
recipients="user@test.com",
|
||||
recipients_1="admin@test.com",
|
||||
recipients_2="ext@titi.com",
|
||||
enabled=True)
|
||||
values = {
|
||||
"address": "all@test.com",
|
||||
"recipients": "user@test.com",
|
||||
"recipients_1": "admin@test.com",
|
||||
"recipients_2": "ext@titi.com",
|
||||
"enabled": True
|
||||
}
|
||||
self.ajax_post(
|
||||
reverse("admin:alias_add"), values
|
||||
)
|
||||
@@ -214,6 +216,18 @@ class AliasTestCase(ModoTestCase):
|
||||
reverse("admin:alias_add"), values
|
||||
)
|
||||
|
||||
def test_random_alias(self):
|
||||
"""Test creation of a random alias."""
|
||||
alias_count = Alias.objects.count()
|
||||
values = {
|
||||
"random_address": True,
|
||||
"domain": Domain.objects.get(name="test.com").pk,
|
||||
"recipients": "user@test.com",
|
||||
"enabled": True
|
||||
}
|
||||
self.ajax_post(reverse("admin:alias_add"), values)
|
||||
self.assertEqual(Alias.objects.count(), alias_count + 1)
|
||||
|
||||
def test_distribution_list_deletion_on_user_update_bug(self):
|
||||
"""This test demonstrates an issue with distribution list being
|
||||
deleted when one of the users which belong to that list is
|
||||
|
||||
Reference in New Issue
Block a user