implement mail address target editing
- extract common code into managemails.forms.MailAddressFieldMixin - move code from forms into managemails.models.MailAddress - implement managemails.models.MailboxManager.unused and unused_or_own - implement managemails.forms.EditMailAddressForm - add managemails.views.EditMailAddress - add URL pattern 'edit_mailaddress' to managemails.urls - add template managemails/mailaddress_edit.html - add changelog entry
This commit is contained in:
parent
bebcad8c86
commit
5429055f0d
6 changed files with 269 additions and 26 deletions
|
@ -1,6 +1,7 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
* :feature:`-` implement mail address target editing
|
||||
* :feature:`-` implement mail address deletion
|
||||
* :feature:`-` implement adding mail address to mail domains
|
||||
* :feature:`-` implement adding options to hosting packages
|
||||
|
|
|
@ -19,8 +19,6 @@ from crispy_forms.layout import (
|
|||
|
||||
from .models import (
|
||||
MailAddress,
|
||||
MailAddressForward,
|
||||
MailAddressMailbox,
|
||||
Mailbox,
|
||||
)
|
||||
from gvawebcore.forms import PasswordModelFormMixin
|
||||
|
@ -106,9 +104,9 @@ def multiple_email_validator(value):
|
|||
return value
|
||||
|
||||
|
||||
class AddMailAddressForm(forms.ModelForm):
|
||||
class MailAddressFieldMixin(forms.Form):
|
||||
"""
|
||||
This form is used to add a new mail address.
|
||||
This mixin defines form fields common to mail address forms.
|
||||
|
||||
"""
|
||||
mailbox_or_forwards = forms.TypedChoiceField(
|
||||
|
@ -133,6 +131,12 @@ class AddMailAddressForm(forms.ModelForm):
|
|||
validators=[multiple_email_validator],
|
||||
)
|
||||
|
||||
|
||||
class AddMailAddressForm(forms.ModelForm, MailAddressFieldMixin):
|
||||
"""
|
||||
This form is used to add a new mail address.
|
||||
|
||||
"""
|
||||
class Meta:
|
||||
model = MailAddress
|
||||
fields = ['localpart']
|
||||
|
@ -141,8 +145,8 @@ class AddMailAddressForm(forms.ModelForm):
|
|||
self.maildomain = kwargs.pop('maildomain')
|
||||
self.hosting_package = kwargs.pop('hostingpackage')
|
||||
super(AddMailAddressForm, self).__init__(*args, **kwargs)
|
||||
self.fields['mailbox'].queryset = Mailbox.objects.filter(
|
||||
active=True, osuser=self.hosting_package.osuser,
|
||||
self.fields['mailbox'].queryset = Mailbox.objects.unused(
|
||||
osuser=self.hosting_package.osuser,
|
||||
)
|
||||
|
||||
self.helper = FormHelper()
|
||||
|
@ -186,11 +190,10 @@ class AddMailAddressForm(forms.ModelForm):
|
|||
data = self.cleaned_data
|
||||
if data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.mailbox:
|
||||
if not data['mailbox']:
|
||||
raise forms.ValidationError(_('No mailbox selected'))
|
||||
self.add_error('mailbox', _('No mailbox selected'))
|
||||
elif data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.forwards:
|
||||
if 'forwards' not in data:
|
||||
raise forms.ValidationError(
|
||||
_('No forward addresses selected'))
|
||||
if 'forwards' not in data or not data['forwards']:
|
||||
self.add_error('forwards', _('No forward addresses selected'))
|
||||
else:
|
||||
raise forms.ValidationError(
|
||||
_('Illegal choice for target of the mail address'))
|
||||
|
@ -205,21 +208,87 @@ class AddMailAddressForm(forms.ModelForm):
|
|||
|
||||
"""
|
||||
self.instance.domain = self.maildomain
|
||||
target_choice = self.cleaned_data['mailbox_or_forwards']
|
||||
mailaddress = super(AddMailAddressForm, self).save(commit)
|
||||
data = self.cleaned_data
|
||||
target_choice = data['mailbox_or_forwards']
|
||||
if target_choice == MAILBOX_OR_FORWARDS.mailbox:
|
||||
mailbox = MailAddressMailbox(
|
||||
mailaddress=mailaddress,
|
||||
mailbox=self.cleaned_data['mailbox'])
|
||||
if commit:
|
||||
mailbox.save()
|
||||
mabox = self.instance.set_mailbox(data['mailbox'], commit=False)
|
||||
elif target_choice == MAILBOX_OR_FORWARDS.forwards:
|
||||
for address in [
|
||||
part.strip() for part in
|
||||
self.cleaned_data['forwards'].split(',')
|
||||
]:
|
||||
forward = MailAddressForward(
|
||||
mailaddress=mailaddress, target=part)
|
||||
targets = [part.strip() for part in data['forwards'].split()]
|
||||
fwds = self.instance.set_forward_addresses(targets, commit=False)
|
||||
mailaddress = super(AddMailAddressForm, self).save(commit)
|
||||
if commit:
|
||||
forward.save()
|
||||
if target_choice == MAILBOX_OR_FORWARDS.mailbox:
|
||||
mabox.mailaddress = mailaddress
|
||||
mabox.save()
|
||||
elif target_choice == MAILBOX_OR_FORWARDS.forwards:
|
||||
for fwd in fwds:
|
||||
fwd.mailaddress = mailaddress
|
||||
fwd.save()
|
||||
return mailaddress
|
||||
|
||||
|
||||
class EditMailAddressForm(forms.ModelForm, MailAddressFieldMixin):
|
||||
"""
|
||||
This form is used to edit the targets for a mail address.
|
||||
|
||||
"""
|
||||
class Meta:
|
||||
model = MailAddress
|
||||
fields = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.hosting_package = kwargs.pop('hostingpackage')
|
||||
self.maildomain = kwargs.pop('maildomain')
|
||||
super(EditMailAddressForm, self).__init__(*args, **kwargs)
|
||||
self.fields['mailbox'].queryset = Mailbox.objects.unused_or_own(
|
||||
self.instance, self.hosting_package.osuser
|
||||
)
|
||||
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_action = reverse(
|
||||
'edit_mailaddress', kwargs={
|
||||
'package': self.hosting_package.id,
|
||||
'domain': self.maildomain.domain,
|
||||
'pk': self.instance.id,
|
||||
})
|
||||
self.helper.layout = Layout(
|
||||
Div(
|
||||
Div(
|
||||
'mailbox_or_forwards',
|
||||
css_class='col-log-2 col-md-2 col-xs-12',
|
||||
),
|
||||
Div(
|
||||
'mailbox',
|
||||
'forwards',
|
||||
css_class='col-lg-10 col-md-10 col-xs-12',
|
||||
),
|
||||
css_class='row',
|
||||
),
|
||||
Submit('submit', _('Change mail address targets')),
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
data = self.cleaned_data
|
||||
if data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.mailbox:
|
||||
if not data['mailbox']:
|
||||
self.add_error('mailbox', _('No mailbox selected'))
|
||||
elif data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.forwards:
|
||||
if 'forwards' not in data or not data['forwards']:
|
||||
self.add_error('forwards', _('No forward addresses selected'))
|
||||
else:
|
||||
raise forms.ValidationError(
|
||||
_('Illegal choice for target of the mail address'))
|
||||
|
||||
def save(self, commit=True):
|
||||
"""
|
||||
Save the mail address.
|
||||
|
||||
:param boolean commit:
|
||||
"""
|
||||
data = self.cleaned_data
|
||||
if data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.mailbox:
|
||||
self.instance.set_mailbox(data['mailbox'], commit)
|
||||
elif data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.forwards:
|
||||
targets = [part.strip() for part in data['forwards'].split(',')]
|
||||
self.instance.set_foward_addresses(targets, commit)
|
||||
return self.instance
|
||||
|
|
|
@ -61,6 +61,30 @@ class MailboxManager(models.Manager):
|
|||
break
|
||||
return mailboxname
|
||||
|
||||
def unused_or_own(self, mailaddress, osuser):
|
||||
"""
|
||||
Returns a queryset that fetches those mailboxes that belong to the
|
||||
given operating system user and are either not used by any mail address
|
||||
or used by the given mailaddress itself.
|
||||
|
||||
"""
|
||||
return self.filter(
|
||||
models.Q(mailaddressmailbox__isnull=True) |
|
||||
models.Q(mailaddressmailbox__mailaddress=mailaddress),
|
||||
active=True, osuser=osuser,
|
||||
)
|
||||
|
||||
def unused(self, osuser):
|
||||
"""
|
||||
Returns a queryset that fetches unused mailboxes belonging to the
|
||||
given operating system user.
|
||||
|
||||
"""
|
||||
return self.filter(
|
||||
mailaddressmailbox__isnull=True,
|
||||
active=True, osuser=osuser,
|
||||
)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Mailbox(ActivateAbleMixin, TimeStampedModel):
|
||||
|
@ -130,6 +154,70 @@ class MailAddress(ActivateAbleMixin, TimeStampedModel, models.Model):
|
|||
def __str__(self):
|
||||
return "{0}@{1}".format(self.localpart, self.domain)
|
||||
|
||||
def set_mailbox(self, mailbox, commit=True):
|
||||
"""
|
||||
Set the target for this mail address to the given mailbox. This method
|
||||
takes care of removing forwarding addresses or changing existing
|
||||
mailbox relations.
|
||||
|
||||
:param mailbox: :py:class:`Mailbox`
|
||||
:param boolean commit: whether to persist changes or not
|
||||
:return: :py:class:`MailAddressMailbox` instance
|
||||
|
||||
"""
|
||||
if self.pk is not None:
|
||||
if MailAddressMailbox.objects.filter(mailaddress=self).exists():
|
||||
mabox = MailAddressMailbox.objects.get(mailaddress=self)
|
||||
mabox.mailbox = mailbox
|
||||
else:
|
||||
mabox = MailAddressMailbox(mailaddress=self, mailbox=mailbox)
|
||||
if commit:
|
||||
mabox.save()
|
||||
for mafwd in MailAddressForward.objects.filter(mailaddress=self):
|
||||
mafwd.delete()
|
||||
else:
|
||||
mabox = MailAddressMailbox(mailaddress=self, mailbox=mailbox)
|
||||
if commit:
|
||||
mabox.save()
|
||||
return mabox
|
||||
|
||||
def set_forward_addresses(self, addresses, commit=True):
|
||||
"""
|
||||
Set the forwarding addresses for this mail address to the given
|
||||
addresses. This method takes care of removing other mail forwards and
|
||||
mailboxes.
|
||||
|
||||
:param addresses: list of email address strings
|
||||
:param boolean commit: whether to persist changes or not
|
||||
:return: list of :py:class:`MailAddressForward` instances
|
||||
|
||||
"""
|
||||
retval = []
|
||||
if self.pk is not None:
|
||||
if MailAddressMailbox.objects.filter(mailaddress=self).exists():
|
||||
mabox = MailAddressMailbox.objects.get(mailaddress=self)
|
||||
mabox.delete()
|
||||
forwards = MailAddressForward.objects.filter(
|
||||
mailaddress=self).all()
|
||||
for item in forwards:
|
||||
if not item.target in addresses:
|
||||
item.delete()
|
||||
else:
|
||||
retval.append(item)
|
||||
for target in addresses:
|
||||
if not target in [item.target for item in forwards]:
|
||||
mafwd = MailAddressForward(mailaddress=self, target=target)
|
||||
if commit:
|
||||
mafwd.save()
|
||||
retval.append(item)
|
||||
else:
|
||||
for target in addresses:
|
||||
mafwd = MailAddressForward(mailaddress=self, target=target)
|
||||
if commit:
|
||||
mafwd.save()
|
||||
retval.append(item)
|
||||
return retval
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class MailAddressMailbox(TimeStampedModel, models.Model):
|
||||
|
|
|
@ -12,6 +12,7 @@ from .views import (
|
|||
ChangeMailboxPassword,
|
||||
CreateMailbox,
|
||||
DeleteMailAddress,
|
||||
EditMailAddress,
|
||||
)
|
||||
|
||||
urlpatterns = patterns(
|
||||
|
@ -22,6 +23,9 @@ urlpatterns = patterns(
|
|||
ChangeMailboxPassword.as_view(), name='change_mailbox_password'),
|
||||
url(r'^(?P<package>\d+)/mailaddress/(?P<domain>[\w0-9-.]+)/create$',
|
||||
AddMailAddress.as_view(), name='add_mailaddress'),
|
||||
url(r'^(?P<package>\d+)/mailaddress/(?P<domain>[\w0-9-.]+)/(?P<pk>\d+)'
|
||||
r'/edit$',
|
||||
EditMailAddress.as_view(), name='edit_mailaddress'),
|
||||
url(r'^(?P<package>\d+)/mailaddress/(?P<domain>[\w0-9-.]+)/(?P<pk>\d+)'
|
||||
r'/delete$',
|
||||
DeleteMailAddress.as_view(), name='delete_mailaddress'),
|
||||
|
|
|
@ -23,9 +23,12 @@ from .forms import (
|
|||
AddMailAddressForm,
|
||||
ChangeMailboxPasswordForm,
|
||||
CreateMailboxForm,
|
||||
EditMailAddressForm,
|
||||
MAILBOX_OR_FORWARDS,
|
||||
)
|
||||
from .models import (
|
||||
MailAddress,
|
||||
MailAddressMailbox,
|
||||
Mailbox,
|
||||
)
|
||||
|
||||
|
@ -188,3 +191,55 @@ class DeleteMailAddress(
|
|||
|
||||
def get_success_url(self):
|
||||
return self.get_hosting_package().get_absolute_url()
|
||||
|
||||
|
||||
class EditMailAddress(
|
||||
HostingPackageAndCustomerMixin, StaffOrSelfLoginRequiredMixin, UpdateView
|
||||
):
|
||||
"""
|
||||
This view is used to edit a mail address' target mailbox or forwarding
|
||||
addresses.
|
||||
|
||||
"""
|
||||
context_object_name = 'mailaddress'
|
||||
form_class = EditMailAddressForm
|
||||
model = MailAddress
|
||||
template_name_suffix = '_edit'
|
||||
|
||||
def get_maildomain(self):
|
||||
return get_object_or_404(MailDomain, domain=self.kwargs['domain'])
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EditMailAddress, self).get_context_data(**kwargs)
|
||||
context['customer'] = self.get_customer_object()
|
||||
return context
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(EditMailAddress, self).get_form_kwargs()
|
||||
kwargs.update({
|
||||
'hostingpackage': self.get_hosting_package(),
|
||||
'maildomain': self.get_maildomain(),
|
||||
})
|
||||
return kwargs
|
||||
|
||||
def get_initial(self):
|
||||
initial = super(EditMailAddress, self).get_initial()
|
||||
mailaddress = self.get_object()
|
||||
if MailAddressMailbox.objects.filter(mailaddress=mailaddress).exists():
|
||||
initial['mailbox'] = mailaddress.mailaddressmailbox.mailbox
|
||||
initial['mailbox_or_forwards'] = MAILBOX_OR_FORWARDS.mailbox
|
||||
elif mailaddress.mailaddressforward_set.exists():
|
||||
initial['forwards'] = ", ".join(
|
||||
fwd.target for fwd in mailaddress.mailaddressforward_set.all()
|
||||
)
|
||||
initial['mailbox_or_forwards'] = MAILBOX_OR_FORWARDS.forwards
|
||||
return initial
|
||||
|
||||
def form_valid(self, form):
|
||||
mailaddress = form.save()
|
||||
messages.success(
|
||||
self.request,
|
||||
_('Successfully updated mail address {mailaddress} '
|
||||
'targets.').format(mailaddress=mailaddress)
|
||||
)
|
||||
return redirect(self.get_hosting_package())
|
||||
|
|
26
gnuviechadmin/templates/managemails/mailaddress_edit.html
Normal file
26
gnuviechadmin/templates/managemails/mailaddress_edit.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% extends "managemails/base.html" %}
|
||||
{% load i18n crispy_forms_tags %}
|
||||
|
||||
{% block title %}{{ block.super }} - {% spaceless %}
|
||||
{% if user == customer %}
|
||||
{% blocktrans %}Change target of Mail Address{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans with full_name=customer.get_full_name %}
|
||||
Change target of Mail Address for Customer {{ full_name }}
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% endspaceless %}{% endblock title %}
|
||||
|
||||
{% block page_title %}{% spaceless %}
|
||||
{% if user == customer %}
|
||||
{% blocktrans %}Change target of Mail Address{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans with full_name=customer.get_full_name %}
|
||||
Change target of Mail Address for Customer {{ full_name }}
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% endspaceless %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
{% crispy form %}
|
||||
{% endblock content %}
|
Loading…
Reference in a new issue