You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
8.6 KiB

from django import forms
from django.db.models import Case, When, IntegerField
from .models import Maintainer, Contact, InetNum, ASBlock, ASNumber
import re
import ipaddress
class WhoisObjectFormMixin(object):
def __init__(self, user, *args, **kwargs):
super(WhoisObjectFormMixin, self).__init__(*args, **kwargs)
self._user = user
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['handle'].widget.attrs['readonly'] = True
# only show users contacts and already present contacts
if 'admin_c' in self.fields:
self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by__in=self._user.maintainer_set.all())
if instance and instance.pk:
self.fields['admin_c'].queryset |= instance.admin_c.all()
def clean_handle(self):
instance = getattr(self, 'instance', None)
if instance and instance.pk:
return instance.handle
else:
return self.cleaned_data['handle']
def clean(self):
cleaned_data = super(WhoisObjectFormMixin, self).clean()
if cleaned_data.get("handle") == "AUTO" and not self.errors:
cleaned_data['handle'] = self._meta.model.genGenericHandle(cleaned_data.get("name"))
return cleaned_data
class MntFormMixin(object):
protectedFields = []
def __init__(self, lower=False, *args, **kwargs):
super(MntFormMixin, self).__init__(*args, **kwargs)
self._editLower = lower
if self._editLower:
for key in self.protectedFields:
self.fields[key].disabled = True
#self.fields["mnt_by"].widget.attrs["data-role"] = "tagsinput"
instance = getattr(self, "instance", None)
mntWhens = [When(auth=self._user, then=2)]
if instance and instance.pk:
mntWhens.append(When(handle__in=instance.mnt_by.all().values_list("handle"), then=1))
mntQs = Maintainer.objects.annotate(card=Case(*mntWhens, default=0, output_field=IntegerField())).order_by("-card")
self.fields["mnt_by"].queryset = mntQs
class MntForm(forms.ModelForm):
class Meta:
model = Maintainer
fields = ['handle', 'description', 'admin_c']
def __init__(self, user, *args, **kwargs):
super(MntForm, self).__init__(*args, **kwargs)
self._user = user
if 'admin_c' in self.fields:
self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by=user.maintainer_set.all())
class MntInitialForm(MntForm):
class Meta:
model = Maintainer
fields = ['handle', 'description']
class ContactForm(WhoisObjectFormMixin, forms.ModelForm):
class Meta:
model = Contact
fields = ['handle', 'name', 'mnt_by']
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.fields['mnt_by'].queryset = Maintainer.objects.filter(auth=self._user)
class ContactInitialForm(ContactForm):
class Meta:
model = Contact
fields = ['handle', 'name']
class InetNumForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
prefix = forms.CharField()
protectedFields = ['handle', 'protocol', 'parent_range', 'mnt_by', 'prefix']
class Meta:
model = InetNum
fields = ['handle', 'protocol', 'parent_range', 'prefix', 'name', 'description', 'mnt_by', 'mnt_lower']
def __init__(self, *args, **kwargs):
super(InetNumForm, self).__init__(*args, **kwargs)
if 'admin_c' in self.fields:
self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by__in=self.user.maintainer_set.all())
instance = getattr(self, "instance", None)
if instance and instance.pk:
self.fields['admin_c'].queryset |= instance.admin_c.all()
if self._editLower:
for key in self.protectedFields:
self.fields[key].disabled = True
self.fields[key].widget.attrs['readonly'] = False
def clean_prefix(self):
# make sure this is a subnet we're getting
net = self.cleaned_data['prefix']
if not re.match(r"[0-9:.]+/[0-9]+", net):
raise forms.ValidationError("Address needs to be a subnet in the format of ip/cidr")
try:
net = ipaddress.ip_network(net)
except ValueError as e:
raise forms.ValidationError(str(e))
return net
def clean_parent_range(self):
parent_range = self.cleaned_data.get('parent_range', None)
# allow parent range to be unset for already present objects
if not (self.instance and self.instance.pk) and not parent_range:
raise forms.ValidationError("Parent range must be set")
def clean(self):
cleaned_data = super(InetNumForm, self).clean()
if not self._editLower:
if not self.errors:
prefix = cleaned_data['prefix']
parent = cleaned_data['parent_range']
if parent:
parentNet = parent.getNetwork()
if cleaned_data['protocol'] != parent.protocol:
raise forms.ValidationError("Protocol type for prefix must be same as parent network")
# check if in parent block
if prefix.network_address not in parentNet or prefix.prefixlen < parentNet.prefixlen:
raise forms.ValidationError("Prefix must be inside parent network range")
# check if parent block has net that overlaps with us
for otherNet in parent.inetnum_set.all():
if self.instance and self.instance.pk == otherNet.pk:
continue
if otherNet.getNetwork().overlaps(prefix):
raise forms.ValidationError("The given prefix overlaps with network %s" % otherNet.handle)
self.instance.address = str(prefix.network_address)
self.instance.netmask = prefix.prefixlen
return cleaned_data
class ASBlockForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
protectedFields = ['handle', 'parent_block', 'asBegin', 'asEnd', 'mnt_by']
# FIXME: Filter blocks
class Meta:
model = ASBlock
fields = ['handle', 'parent_block', 'asBegin', 'asEnd', 'name', 'description', 'mnt_by', 'mnt_lower']
def __init__(self, *args, **kwargs):
super(ASBlockForm, self).__init__(*args, **kwargs)
if not self.instance or self.instance and self.instance and self.instance.parent_block:
self.fields["parent_block"].required = True
if self.instance and self.instance.pk:
self.fields["parent_block"].disabled = True
def clean(self):
cleaned_data = super(ASBlockForm, self).clean()
if not self.errors:
asBegin = cleaned_data['asBegin']
asEnd = cleaned_data['asEnd']
parent = cleaned_data['parent_block']
# check if somebody is already using this block
# check if in range
if asBegin > asEnd:
raise forms.ValidationError("AS beginning must be smaller or equal to AS end")
if parent:
if parent.asnumber_set.count() > 0:
raise forms.ValidationError("The parent AS block is already references by following AS number objects: %s" % (", ".join(map(lambda _x: _x.handle, parent.asnumber_set.all())),))
# check if same range
if not (asBegin >= parent.asBegin and asEnd <= parent.asEnd):
raise forms.ValidationError("AS beginning and end must be inside the range of the parent AS block")
if parent.asBegin == asBegin and parent.asEnd == asEnd:
raise forms.ValidationError("The range of this block cannot be the same range AS the parent AS block")
# check for overlap with other asblocks
for block in parent.asblock_set.all():
if self.instance and self.instance.pk and block.pk == self.instance.pk:
continue
if block.asBegin <= asBegin <= block.asEnd or block.asBegin <= asEnd <= block.asEnd or \
asBegin <= block.asBegin <= asEnd or asBegin <= block.asEnd <= asEnd:
raise forms.ValidationError("Block overlaps with block %s" % block.handle)
return cleaned_data
class ASNumberForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
protectedFields = ['handle', 'asblock', 'number', 'mnt_by']
class Meta:
model = ASNumber
fields = ['handle', 'asblock', 'number', 'volatile', 'name', 'description', 'mnt_by', 'mnt_lower', 'admin_c']
def __init__(self, *args, **kwargs):
super(ASNumberForm, self).__init__(*args, **kwargs)
if not (self.instance and self.instance.pk):
self.fields["asblock"].required = True
else:
self.fields["asblock"].disabled = True
def clean(self):
cleaned_data = super(ASNumberForm, self).clean()
if not self.errors:
number = cleaned_data['number']
block = cleaned_data['asblock']
# belongs to asblock?
if number < block.asBegin or number > block.asEnd:
raise forms.ValidationError("AS number is not inside AS block")
# does an entry already exist?
try:
otherAS = ASNumber.objects.get(number=number)
if not (self.instance and self.instance.pk and self.instance.pk == otherAS.pk):
raise forms.ValidationError("This AS number is already represented by %s" % otherAS.handle)
except ASNumber.DoesNotExist:
pass
# has already other asblock?
if block.asblock_set.count() > 0:
raise forms.ValidationError("The given AS block is already references by following sub AS blocks: %s" % (", ".join(map(lambda _x: _x.handle, block.asblock_set.all())),))