dnmgmt/domains/forms.py

185 lines
5.5 KiB
Python

from django import forms
from django.db.models import Q
from whoisdb.models import InetNum
from whoisdb.forms import MntFormMixin, WhoisObjectFormMixin
from whoisdb.validators import IP46CIDRValidator
from .models import Domain, Nameserver, ReverseZone
import re
import ipaddress
class DomainForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
class Meta:
model = Domain
fields = ['name', 'nameservers', 'mnt_by', 'admin_c']
def __init__(self, *args, **kwargs):
super(DomainForm, self).__init__(*args, **kwargs)
mnts = self._user.maintainer_set.all()
self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts))
instance = getattr(self, "instance", None)
self._create = not (instance and instance.pk)
if not self._create:
self.fields['name'].disabled = True
self.fields['nameservers'].queryset |= self.instance.nameservers.all()
self.fields['nameservers'].queryset.distinct()
def clean_name(self):
name = self.cleaned_data['name'].lower()
if self._create:
if not name.endswith("."):
name += "."
if not name.endswith("dn."):
raise forms.ValidationError("Only .dn domains can be registered at this point")
if name.count(".") > 2:
raise forms.ValidationError("No subdomains can be registered")
if not re.match("^[a-z0-9.-]+$", name):
raise forms.ValidationError("Only a-z, 0-9 and - are allowed inside the domain name")
try:
Domain.objects.get(name=name)
raise forms.ValidationError("Domain already exists")
except Domain.DoesNotExist:
pass
return name
class NameserverForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
class Meta:
model = Nameserver
fields = ['name', 'glueIPv4', 'glueIPv6', 'mnt_by', 'admin_c']
help_texts = {
"glueIPv4": "Note: You can only set a glue record if the base domain of this nameserver belongs to you!"
}
def __init__(self, *args, **kwargs):
super(NameserverForm, self).__init__(*args, **kwargs)
instance = getattr(self, "instance", None)
self._create = not (instance and instance.pk)
def clean_name(self):
name = self.cleaned_data['name'].lower().strip()
if not name.endswith("."):
name += "."
if name.count(".") <= 2:
raise forms.ValidationError("Nameserver must be inside a domain (e.g. ns1.noot.dn.)")
mnts = self._user.maintainer_set.all()
try:
obj = Nameserver.objects.get(name=name, mnt_by__in=mnts)
if self._create or not self._create and obj.pk != self.instance.pk:
raise forms.ValidationError("You already have a nameserver with this name under your control")
except Nameserver.DoesNotExist:
pass
except Nameserver.MultipleObjectsReturned:
pass
return name
def clean(self):
cleaned_data = super(NameserverForm, self).clean()
if not self.errors:
name = cleaned_data.get("name")
mntBy = cleaned_data.get("mnt_by")
zone = ".".join(name.split(".")[-3:])
ipv4 = cleaned_data.get("glueIPv4", None)
ipv6 = cleaned_data.get("glueIPv6", None)
if not ipv4:
ipv4 = None
if not ipv6:
ipv6 = None
if self._create and (ipv4 or ipv6) or not self._create and not (self.instance.glueIPv4 == ipv4 and self.instance.glueIPv6 == ipv6):
mnts = self._user.maintainer_set.all()
domains = Domain.objects.filter(mnt_by__in=mnts)
found = False
for domain in domains:
if domain.name == zone:
found = True
break
if not found:
raise forms.ValidationError("You have glue IPs set, but this domain is not under a domain you control.")
failedMnts = set()
for ns in Nameserver.objects.filter(name=name, mnt_by__in=mntBy):
if self._create or self.instance.pk != ns.pk:
for mnt in ns.mnt_by.all():
if mnt in mntBy:
failedMnts.add(mnt.handle)
if len(failedMnts) > 0:
raise forms.ValidationError("The following maintainer objects already have this nameservers: %s" % ", ".join(failedMnts))
return cleaned_data
class ReverseZoneForm(forms.ModelForm):
prefix = forms.CharField(validators=[IP46CIDRValidator])
class Meta:
model = ReverseZone
fields = ['parentNet', 'nameservers']
def __init__(self, user, *args, **kwargs):
self._user = user
super(ReverseZoneForm, self).__init__(*args, **kwargs)
instance = getattr(self, "instance", None)
self._create = not (instance and instance.pk)
mnts = self._user.maintainer_set.all()
self.fields['parentNet'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts))
if not self._create:
self.fields['prefix'].disabled = True
self.fields['nameservers'].queryset |= self.instance.nameservers.all()
self.fields['nameservers'].queryset.distinct()
def clean(self):
cleaned_data = super(ReverseZoneForm, self).clean()
if not self.errors:
if self._create:
net = ipaddress.ip_network(cleaned_data['prefix'])
parentNet = cleaned_data['parentNet'].getNetwork()
if net.network_address not in parentNet:
raise forms.ValidationError("Given prefix %s is not inside of parent netblock %s" % (net, parentNet))
# For now just check all the zones...
#zones = ReverseZone.objects.filter(parentNet=cleaned_data['parentNet'])
zones = ReverseZone.objects.all()
for zone in zones:
if net.network_address in zone.parentNet.getNetwork():
raise forms.ValidationError("Given prefix already has a reverse zone object associated to it: %s" % zone)
self.instance.address = str(net.network_address)
self.instance.netmask = net.prefixlen
return cleaned_data