Jan Dittberner
6cebd80c89
This commit is a rough port to Django 2.1, Python 3 and a Docker based local development setup. Tests fail/error but migrations and the web frontend are already runnable. Task queue functionality is untested and translations seem to have trouble.
298 lines
10 KiB
Python
298 lines
10 KiB
Python
"""
|
|
This module defines form classes for mailbox and mail address editing.
|
|
|
|
"""
|
|
from __future__ import absolute_import, unicode_literals
|
|
|
|
from django import forms
|
|
from django.core.validators import validate_email
|
|
from django.urls import reverse
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from crispy_forms.helper import FormHelper
|
|
from crispy_forms.bootstrap import AppendedText
|
|
from crispy_forms.layout import (
|
|
Div,
|
|
Layout,
|
|
Submit,
|
|
)
|
|
|
|
from .models import (
|
|
MailAddress,
|
|
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):
|
|
"""
|
|
This form is used to create new Mailbox instances.
|
|
|
|
"""
|
|
class Meta:
|
|
model = Mailbox
|
|
fields = []
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.hosting_package = kwargs.pop('hostingpackage')
|
|
super(CreateMailboxForm, self).__init__(*args, **kwargs)
|
|
self.helper = FormHelper()
|
|
self.helper.form_action = reverse(
|
|
'create_mailbox', kwargs={'package': self.hosting_package.id})
|
|
self.helper.add_input(Submit('submit', _('Create mailbox')))
|
|
|
|
def save(self, commit=True):
|
|
"""
|
|
Set the new mailbox's password and osuser.
|
|
|
|
:param boolean commit: whether to save the created mailbox
|
|
:return: mailbox instance
|
|
:rtype: :py:class:`managemails.models.Mailbox`
|
|
|
|
"""
|
|
osuser = self.hosting_package.osuser
|
|
self.instance.osuser = osuser
|
|
self.instance.username = Mailbox.objects.get_next_mailbox_name(osuser)
|
|
self.instance.set_password(self.cleaned_data['password1'])
|
|
return super(CreateMailboxForm, self).save(commit=commit)
|
|
|
|
|
|
class ChangeMailboxPasswordForm(PasswordModelFormMixin, forms.ModelForm):
|
|
"""
|
|
This form is used to set a new password for an existing mailbox.
|
|
|
|
"""
|
|
class Meta:
|
|
model = Mailbox
|
|
fields = []
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.hosting_package = kwargs.pop('hostingpackage')
|
|
super(ChangeMailboxPasswordForm, self).__init__(*args, **kwargs)
|
|
self.helper = FormHelper()
|
|
self.helper.form_action = reverse(
|
|
'change_mailbox_password', kwargs={
|
|
'package': self.hosting_package.id,
|
|
'slug': self.instance.username,
|
|
})
|
|
self.helper.add_input(Submit('submit', _('Set password')))
|
|
|
|
def save(self, commit=True):
|
|
"""
|
|
Set the mailbox password.
|
|
|
|
:param boolean commit: whether to save the mailbox instance
|
|
:return: mailbox instance
|
|
:rtype: :py:class:`managemails.models.Mailbox`
|
|
|
|
"""
|
|
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 MailAddressFieldMixin(forms.Form):
|
|
"""
|
|
This mixin defines form fields common to mail address forms.
|
|
|
|
"""
|
|
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,
|
|
)
|
|
# TODO: refactor as separate field class returning a list
|
|
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 AddMailAddressForm(forms.ModelForm, MailAddressFieldMixin):
|
|
"""
|
|
This form is used to add a new mail address.
|
|
|
|
"""
|
|
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.unused(
|
|
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 mail address')),
|
|
)
|
|
|
|
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):
|
|
super(AddMailAddressForm, self).clean()
|
|
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: # pragma: no cover
|
|
# should not happen because of the field's validation
|
|
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
|
|
data = self.cleaned_data
|
|
target_choice = data['mailbox_or_forwards']
|
|
if target_choice == MAILBOX_OR_FORWARDS.mailbox:
|
|
mabox = self.instance.set_mailbox(data['mailbox'], commit=False)
|
|
elif target_choice == MAILBOX_OR_FORWARDS.forwards:
|
|
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:
|
|
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: # pragma: no cover
|
|
# should not happen because of the field's validation
|
|
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_forward_addresses(targets, commit)
|
|
return super(EditMailAddressForm, self).save(commit)
|