django-orchestra/orchestra/contrib/domains/forms.py

165 lines
6.5 KiB
Python
Raw Permalink Normal View History

2014-05-08 16:59:35 +00:00
from django import forms
from django.core.exceptions import ValidationError
from django.utils.text import capfirst
from django.utils.translation import gettext_lazy as _
2014-05-08 16:59:35 +00:00
from orchestra.admin.forms import AdminFormSet, AdminFormMixin
2014-05-08 16:59:35 +00:00
from . import validators
from .helpers import domain_for_validation
from .models import Domain, Record
2014-05-08 16:59:35 +00:00
2015-03-11 20:01:08 +00:00
class BatchDomainCreationAdminForm(forms.ModelForm):
name = forms.CharField(label=_("Names"), widget=forms.Textarea(attrs={'rows': 5, 'cols': 50}),
help_text=_("Fully qualified domain name per line. "
"All domains will have the provided account and records."))
2015-03-11 20:01:08 +00:00
def clean_name(self):
self.extra_names = []
target = None
2016-09-02 14:50:43 +00:00
existing = set()
2015-05-26 12:59:16 +00:00
errors = []
2016-09-02 14:50:43 +00:00
domain_names = self.cleaned_data['name'].strip().splitlines()
for name in domain_names:
2015-03-11 20:01:08 +00:00
name = name.strip()
if not name:
continue
2015-05-26 12:59:16 +00:00
if name in existing:
2016-09-02 14:50:43 +00:00
errors.append(ValidationError(_("%s domain name provided multiple times.") % name))
2015-05-26 12:59:16 +00:00
existing.add(name)
2015-03-11 20:01:08 +00:00
if target is None:
target = name
else:
domain = Domain(name=name)
try:
domain.full_clean(exclude=['top'])
except ValidationError as e:
2016-09-02 14:50:43 +00:00
for error in e.error_dict['name']:
for msg in error.messages:
errors.append(
ValidationError("%s: %s" % (name, msg))
)
2015-03-11 20:01:08 +00:00
self.extra_names.append(name)
2015-05-26 12:59:16 +00:00
if errors:
raise ValidationError(errors)
2015-03-11 20:01:08 +00:00
return target
2014-05-08 16:59:35 +00:00
def clean(self):
2015-03-29 16:10:07 +00:00
""" inherit related parent domain account, when exists """
2016-09-02 14:50:43 +00:00
cleaned_data = super().clean()
2014-05-08 16:59:35 +00:00
if not cleaned_data['account']:
2015-03-11 20:01:08 +00:00
account = None
2016-09-02 14:50:43 +00:00
domain_names = []
if 'name' in cleaned_data:
first = cleaned_data['name']
domain_names.append(first)
domain_names.extend(self.extra_names)
for name in domain_names:
parent = Domain.objects.get_parent(name)
2015-03-29 16:10:07 +00:00
if not parent:
2015-03-11 20:01:08 +00:00
# Fake an account to make django validation happy
account_model = self.fields['account']._queryset.model
cleaned_data['account'] = account_model()
raise ValidationError({
'account': _("An account should be provided for top domain names."),
})
2015-03-29 16:10:07 +00:00
elif account and parent.account != account:
2015-03-11 20:01:08 +00:00
# Fake an account to make django validation happy
account_model = self.fields['account']._queryset.model
cleaned_data['account'] = account_model()
raise ValidationError({
'account': _("Provided domain names belong to different accounts."),
})
2015-03-29 16:10:07 +00:00
account = parent.account
2016-09-02 14:50:43 +00:00
cleaned_data['account'] = account
2014-05-08 16:59:35 +00:00
return cleaned_data
2016-09-02 14:50:43 +00:00
def full_clean(self):
# set extra_names on instance to use it on inline formsets validation
super().full_clean()
self.instance.extra_names = extra_names
2014-05-08 16:59:35 +00:00
class RecordForm(forms.ModelForm):
class Meta:
fields = ('ttl', 'type', 'value')
def __init__(self, *args, **kwargs):
super(RecordForm, self).__init__(*args, **kwargs)
self.fields['ttl'].widget = forms.TextInput(attrs={'size': '10'})
self.fields['value'].widget = forms.TextInput(attrs={'size': '100'})
class ValidateZoneMixin(object):
2014-05-08 16:59:35 +00:00
def clean(self):
""" Checks if everything is consistent """
super(ValidateZoneMixin, self).clean()
if any(self.errors):
2014-05-08 16:59:35 +00:00
return
2016-10-22 07:23:45 +00:00
is_host = True
for form in self.forms:
2016-10-22 07:23:45 +00:00
if form.cleaned_data.get('type') in (Record.TXT, Record.SRV, Record.CNAME):
is_host = False
break
2016-09-02 14:50:43 +00:00
domain_names = []
if self.instance.name:
2016-09-02 14:50:43 +00:00
domain_names.append(self.instance.name)
domain_names.extend(getattr(self.instance, 'extra_names', []))
errors = []
for name in domain_names:
2014-05-08 16:59:35 +00:00
records = []
for form in self.forms:
2014-05-08 16:59:35 +00:00
data = form.cleaned_data
if data and not data['DELETE']:
records.append(data)
2016-10-22 07:23:45 +00:00
if '_' in name and is_host:
2016-09-02 14:50:43 +00:00
errors.append(ValidationError(
2016-10-22 07:23:45 +00:00
_("%s: Hosts can not have underscore character '_', consider providing a SRV, CNAME or TXT record.") % name
2016-09-02 14:50:43 +00:00
))
domain = domain_for_validation(self.instance, records)
2016-09-02 14:50:43 +00:00
try:
validators.validate_zone(domain.render_zone())
except ValidationError as error:
for msg in error:
errors.append(
ValidationError("%s: %s" % (name, msg))
)
if errors:
raise ValidationError(errors)
class RecordEditFormSet(ValidateZoneMixin, AdminFormSet):
pass
class RecordInlineFormSet(ValidateZoneMixin, forms.models.BaseInlineFormSet):
pass
class SOAForm(AdminFormMixin, forms.Form):
refresh = forms.CharField()
clear_refresh = forms.BooleanField(label=_("Clear refresh"), required=False,
help_text=_("Remove custom refresh value for all selected domains."))
retry = forms.CharField()
clear_retry = forms.BooleanField(label=_("Clear retry"), required=False,
help_text=_("Remove custom retry value for all selected domains."))
expire = forms.CharField()
clear_expire = forms.BooleanField(label=_("Clear expire"), required=False,
help_text=_("Remove custom expire value for all selected domains."))
min_ttl = forms.CharField()
clear_min_ttl = forms.BooleanField(label=_("Clear min TTL"), required=False,
help_text=_("Remove custom min TTL value for all selected domains."))
def __init__(self, *args, **kwargs):
super(SOAForm, self).__init__(*args, **kwargs)
for name in self.fields:
if not name.startswith('clear_'):
2016-04-30 11:23:13 +00:00
field = Domain._meta.get_field(name)
self.fields[name] = forms.CharField(
label=capfirst(field.verbose_name),
help_text=field.help_text,
validators=field.validators,
required=False,
)