diff --git a/docs/changelog.rst b/docs/changelog.rst index b8bfab6..3381054 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* :feature:`-` implement adding mail address to mail domains * :feature:`-` implement adding options to hosting packages * :bug:`-` fix disk space calculation in hostingpackages.models.CustomerHostingPackage diff --git a/gnuviechadmin/managemails/forms.py b/gnuviechadmin/managemails/forms.py index 04829f8..ba723e7 100644 --- a/gnuviechadmin/managemails/forms.py +++ b/gnuviechadmin/managemails/forms.py @@ -6,14 +6,32 @@ from __future__ import absolute_import, unicode_literals from django import forms from django.core.urlresolvers import reverse -from django.utils.translation import ugettext as _ +from django.core.validators import validate_email +from django.utils.translation import ugettext_lazy as _ from crispy_forms.helper import FormHelper -from crispy_forms.layout import Submit +from crispy_forms.bootstrap import AppendedText +from crispy_forms.layout import ( + Div, + Layout, + Submit, +) -from .models import Mailbox +from .models import ( + MailAddress, + MailAddressForward, + MailAddressMailbox, + Mailbox, +) from gvawebcore.forms import PasswordModelFormMixin +from model_utils import Choices + +MAILBOX_OR_FORWARDS = Choices( + (0, 'mailbox', _('Mailbox')), + (1, 'forwards', _('Forwards')), +) + class CreateMailboxForm(PasswordModelFormMixin, forms.ModelForm): """ @@ -79,3 +97,129 @@ class ChangeMailboxPasswordForm(PasswordModelFormMixin, forms.ModelForm): """ self.instance.set_password(self.cleaned_data['password1']) return super(ChangeMailboxPasswordForm, self).save(commit=commit) + + +def multiple_email_validator(value): + if value: + for email in [part.strip() for part in value.split(',')]: + validate_email(email) + return value + + +class AddMailAddressForm(forms.ModelForm): + """ + This form is used to add a new mail address. + + """ + mailbox_or_forwards = forms.TypedChoiceField( + label=_('Mailbox or Forwards'), + choices=MAILBOX_OR_FORWARDS, + widget=forms.RadioSelect, + coerce=int, + ) + mailbox = forms.ModelChoiceField( + Mailbox.objects, + label=_('Mailbox'), + required=False, + ) + forwards = forms.CharField( + label=_('Forwards'), + required=False, + error_messages={ + 'invalid': _( + 'Please enter one or more email addresses separated by ' + 'commas.'), + }, + validators=[multiple_email_validator], + ) + + class Meta: + model = MailAddress + fields = ['localpart'] + + def __init__(self, *args, **kwargs): + 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.helper = FormHelper() + self.helper.form_action = reverse( + 'add_mailaddress', kwargs={ + 'package': self.hosting_package.id, + 'domain': self.maildomain.domain, + }) + self.helper.layout = Layout( + Div( + Div( + AppendedText('localpart', '@' + self.maildomain.domain), + css_class='col-lg-4 col-md-4 col-xs-12', + ), + Div( + 'mailbox_or_forwards', + css_class='col-lg-2 col-md-2 col-xs-12', + ), + Div( + 'mailbox', + 'forwards', + css_class='col-lg-6 col-md-6 col-xs-12', + ), + css_class='row', + ), + Submit('submit', _('Add mailaddress')), + ) + + def clean_localpart(self): + localpart = self.cleaned_data['localpart'] + if MailAddress.objects.filter( + domain=self.maildomain, + localpart=localpart, + ).exists(): + raise forms.ValidationError( + _('This mail address is already in use.')) + validate_email('{0}@{1}'.format(localpart, self.maildomain.domain)) + return localpart + + def clean(self): + data = self.cleaned_data + if data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.mailbox: + if not data['mailbox']: + raise forms.ValidationError(_('No mailbox selected')) + elif data['mailbox_or_forwards'] == MAILBOX_OR_FORWARDS.forwards: + if 'forwards' not in data: + raise forms.ValidationError( + _('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: whether to save the mail address instance + :return: mail address instance + :rtype: :py:class:`managemails.models.MailAddress` + + """ + self.instance.domain = self.maildomain + target_choice = self.cleaned_data['mailbox_or_forwards'] + mailaddress = super(AddMailAddressForm, self).save(commit) + if target_choice == MAILBOX_OR_FORWARDS.mailbox: + mailbox = MailAddressMailbox( + mailaddress=mailaddress, + mailbox=self.cleaned_data['mailbox']) + if commit: + mailbox.save() + 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) + if commit: + forward.save() + return mailaddress diff --git a/gnuviechadmin/managemails/urls.py b/gnuviechadmin/managemails/urls.py index 5e942d2..08bef92 100644 --- a/gnuviechadmin/managemails/urls.py +++ b/gnuviechadmin/managemails/urls.py @@ -8,6 +8,7 @@ from __future__ import absolute_import, unicode_literals from django.conf.urls import patterns, url from .views import ( + AddMailAddress, ChangeMailboxPassword, CreateMailbox, ) @@ -18,4 +19,6 @@ urlpatterns = patterns( CreateMailbox.as_view(), name='create_mailbox'), url(r'^(?P\d+)/mailbox/(?P[\w0-9]+)/setpassword$', ChangeMailboxPassword.as_view(), name='change_mailbox_password'), + url(r'^(?P\d+)/mailaddress/(?P[\w0-9-.]+)/create$', + AddMailAddress.as_view(), name='add_mailaddress'), ) diff --git a/gnuviechadmin/managemails/views.py b/gnuviechadmin/managemails/views.py index 837edd4..97a74b8 100644 --- a/gnuviechadmin/managemails/views.py +++ b/gnuviechadmin/managemails/views.py @@ -17,12 +17,16 @@ from gvacommon.viewmixins import StaffOrSelfLoginRequiredMixin from hostingpackages.models import CustomerHostingPackage +from domains.models import MailDomain from .forms import ( - CreateMailboxForm, + AddMailAddressForm, ChangeMailboxPasswordForm, + CreateMailboxForm, +) +from .models import ( + MailAddress, + Mailbox, ) -from .models import Mailbox - class HostingPackageAndCustomerMixin(object): @@ -119,3 +123,36 @@ class ChangeMailboxPassword( ) ) return redirect(self.get_hosting_package()) + + +class AddMailAddress( + HostingPackageAndCustomerMixin, StaffOrSelfLoginRequiredMixin, CreateView +): + """ + This view is used to add a new mail address to a domain. + + """ + context_object_name = 'mailaddress' + form_class = AddMailAddressForm + model = MailAddress + template_name_suffix = '_create' + + def get_maildomain(self): + return get_object_or_404(MailDomain, domain=self.kwargs['domain']) + + def get_form_kwargs(self): + kwargs = super(AddMailAddress, self).get_form_kwargs() + kwargs.update({ + 'hostingpackage': self.get_hosting_package(), + 'maildomain': self.get_maildomain(), + }) + return kwargs + + def form_valid(self, form): + address = form.save() + messages.success( + self.request, + _('Successfully added mail address {mailaddress}').format( + mailaddress=address) + ) + return redirect(self.get_hosting_package()) diff --git a/gnuviechadmin/templates/managemails/mailaddress_create.html b/gnuviechadmin/templates/managemails/mailaddress_create.html new file mode 100644 index 0000000..5ae5b62 --- /dev/null +++ b/gnuviechadmin/templates/managemails/mailaddress_create.html @@ -0,0 +1,34 @@ +{% extends "managemails/base.html" %} +{% load i18n crispy_forms_tags %} + +{% block title %}{{ block.super }} - {% spaceless %} +{% if user == customer %} +{% blocktrans %}Add new Mail Address{% endblocktrans %} +{% else %} +{% blocktrans with full_name=customer.get_full_name %} +Add new Mail Address for Customer {{ full_name }} +{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock title %} + +{% block page_title %}{% spaceless %} +{% if user == customer %} +{% blocktrans %}Add new Mail Address{% endblocktrans %} +{% else %} +{% blocktrans with full_name=customer.get_full_name %} +Add new Mail Address for Customer {{ full_name }} +{% endblocktrans %} +{% endif %} +{% endspaceless %}{% endblock page_title %} + +{% block content %} +{% crispy form %} +{% endblock content %} + +{% block extra_js %} + +{% endblock extra_js %}