From d3b354781111bb479e24dd0122affce90cf2fce0 Mon Sep 17 00:00:00 2001 From: Santiago Lamora Date: Wed, 29 Nov 2023 15:03:12 +0100 Subject: [PATCH] Validate domain records (on update & creation) --- orchestra/contrib/musician/forms.py | 9 ++++- .../templates/musician/record_form.html | 7 +++- orchestra/contrib/musician/validators.py | 39 +++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 orchestra/contrib/musician/validators.py diff --git a/orchestra/contrib/musician/forms.py b/orchestra/contrib/musician/forms.py index 9440c88e..28e70086 100644 --- a/orchestra/contrib/musician/forms.py +++ b/orchestra/contrib/musician/forms.py @@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _ from orchestra.contrib.domains.models import Domain, Record from orchestra.contrib.mailboxes.models import Address, Mailbox +from orchestra.contrib.musician.validators import ValidateZoneMixin from . import api @@ -137,7 +138,7 @@ class MailboxUpdateForm(forms.ModelForm): model = Mailbox -class RecordCreateForm(forms.ModelForm): +class RecordCreateForm(ValidateZoneMixin, forms.ModelForm): class Meta: model = Record @@ -155,8 +156,12 @@ class RecordCreateForm(forms.ModelForm): return instance -class RecordUpdateForm(forms.ModelForm): +class RecordUpdateForm(ValidateZoneMixin, forms.ModelForm): class Meta: model = Record fields = ("ttl", "type", "value") + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.domain = self.instance.domain diff --git a/orchestra/contrib/musician/templates/musician/record_form.html b/orchestra/contrib/musician/templates/musician/record_form.html index 4088dcca..ef920893 100644 --- a/orchestra/contrib/musician/templates/musician/record_form.html +++ b/orchestra/contrib/musician/templates/musician/record_form.html @@ -4,13 +4,16 @@ {% block content %} {% trans "Go back" %} -

{% trans "Add record for" %} {{ form.domain.name }}

+

+ {% if form.instance.pk %}{% trans "Update record of" %}{% else %}{% trans "Add record to" %}{% endif %} + {{ form.domain.name }} +

{% csrf_token %} {% bootstrap_form form %} {% buttons %} - {% trans "Cancel" %} + {% trans "Cancel" %} {% if form.instance.pk %}
diff --git a/orchestra/contrib/musician/validators.py b/orchestra/contrib/musician/validators.py new file mode 100644 index 00000000..5289ccff --- /dev/null +++ b/orchestra/contrib/musician/validators.py @@ -0,0 +1,39 @@ +from orchestra.contrib.domains.helpers import domain_for_validation +from orchestra.contrib.domains.models import Record +from orchestra.contrib.domains.validators import validate_zone + + +class ValidateZoneMixin: + # NOTE: adapted code of orchestra.contrib.domains.forms.ValidateZoneMixin + # but only for one form (instead a admin inline formset) + def clean(self): + """ Checks if everything is consistent """ + super(ValidateZoneMixin, self).clean() + if any(self.errors): + return + + is_host = self.cleaned_data.get('type') in (Record.TXT, Record.SRV, Record.CNAME) + + domain_names = [] + if self.domain.name: + domain_names.append(self.domain.name) + domain_names.extend(getattr(self.domain, 'extra_names', [])) + errors = [] + for name in domain_names: + if '_' in name and is_host: + errors.append(ValidationError( + _("%s: Hosts can not have underscore character '_', consider providing a SRV, CNAME or TXT record.") % name + )) + + records = [self.cleaned_data] + domain = domain_for_validation(self.domain, records) + + try: + 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)