2017-02-23 22:28:06 +01:00
from django import forms
2017-03-02 18:28:15 +01:00
from django . db . models import Case , When , IntegerField
2017-02-23 22:28:06 +01:00
2017-03-02 18:28:15 +01:00
from . models import Maintainer , Contact , InetNum , ASBlock , ASNumber
2017-02-28 19:44:15 +01:00
2017-03-01 03:21:03 +01:00
import re
import ipaddress
2017-03-14 20:18:57 +01:00
class WhoisObjectFormMixin ( object ) :
2017-02-28 19:44:15 +01:00
def __init__ ( self , user , * args , * * kwargs ) :
2017-03-14 20:18:57 +01:00
super ( WhoisObjectFormMixin , self ) . __init__ ( * args , * * kwargs )
2017-02-28 19:44:15 +01:00
self . _user = user
instance = getattr ( self , ' instance ' , None )
if instance and instance . pk :
2017-03-21 02:36:07 +01:00
self . _create = False
2017-02-28 19:44:15 +01:00
self . fields [ ' handle ' ] . widget . attrs [ ' readonly ' ] = True
2017-03-21 02:36:07 +01:00
else :
self . _create = True
2017-02-28 19:44:15 +01:00
2017-03-02 18:28:15 +01:00
# only show users contacts and already present contacts
2017-03-21 02:36:07 +01:00
mnts = self . _user . maintainer_set . all ( )
2017-03-02 18:28:15 +01:00
if ' admin_c ' in self . fields :
2017-03-21 02:36:07 +01:00
self . fields [ ' admin_c ' ] . queryset = Contact . getMntQueryset ( mnts , self . instance , " admin_c " )
2017-03-02 18:28:15 +01:00
2017-02-28 19:44:15 +01:00
def clean_handle ( self ) :
2017-03-21 02:36:07 +01:00
if not self . _create :
return self . instance . handle
2017-02-28 19:44:15 +01:00
else :
return self . cleaned_data [ ' handle ' ]
def clean ( self ) :
2017-03-14 20:18:57 +01:00
cleaned_data = super ( WhoisObjectFormMixin , self ) . clean ( )
2017-03-01 03:21:03 +01:00
if cleaned_data . get ( " handle " ) == " AUTO " and not self . errors :
2017-02-28 19:44:15 +01:00
cleaned_data [ ' handle ' ] = self . _meta . model . genGenericHandle ( cleaned_data . get ( " name " ) )
2017-02-23 22:28:06 +01:00
2017-03-01 03:21:03 +01:00
return cleaned_data
2017-03-02 18:28:15 +01:00
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
2017-03-21 02:36:07 +01:00
if " mnt_lower " in self . fields :
self . fields [ " mnt_lower " ] . queryset = mntQs
class MntForm ( WhoisObjectFormMixin , forms . ModelForm ) :
2017-02-28 19:44:15 +01:00
class Meta :
model = Maintainer
fields = [ ' handle ' , ' description ' , ' admin_c ' ]
2017-03-01 03:21:03 +01:00
2017-02-28 19:44:15 +01:00
class MntInitialForm ( MntForm ) :
2017-02-23 22:28:06 +01:00
class Meta :
model = Maintainer
fields = [ ' handle ' , ' description ' ]
2017-03-01 03:21:03 +01:00
2017-03-14 20:18:57 +01:00
class ContactForm ( WhoisObjectFormMixin , forms . ModelForm ) :
2017-02-23 22:28:06 +01:00
class Meta :
model = Contact
2017-03-14 20:18:57 +01:00
fields = [ ' handle ' , ' name ' , ' mnt_by ' ]
2017-02-23 22:28:06 +01:00
2017-02-28 19:44:15 +01:00
def __init__ ( self , * args , * * kwargs ) :
2017-02-23 22:28:06 +01:00
super ( ContactForm , self ) . __init__ ( * args , * * kwargs )
2017-02-28 19:44:15 +01:00
2017-03-21 02:36:07 +01:00
self . fields [ ' mnt_by ' ] . queryset = Maintainer . objects . filter ( auth = self . _user ) . distinct ( )
2017-03-14 20:18:57 +01:00
2017-03-01 03:21:03 +01:00
2017-02-28 19:44:15 +01:00
class ContactInitialForm ( ContactForm ) :
class Meta :
model = Contact
fields = [ ' handle ' , ' name ' ]
2017-03-01 03:21:03 +01:00
2017-03-14 20:18:57 +01:00
class InetNumForm ( MntFormMixin , WhoisObjectFormMixin , forms . ModelForm ) :
2017-03-01 03:21:03 +01:00
prefix = forms . CharField ( )
protectedFields = [ ' handle ' , ' protocol ' , ' parent_range ' , ' mnt_by ' , ' prefix ' ]
2017-02-28 19:44:15 +01:00
class Meta :
model = InetNum
2017-03-20 00:16:33 +01:00
fields = [ ' handle ' , ' protocol ' , ' parent_range ' , ' prefix ' , ' name ' , ' description ' , ' mnt_by ' , ' mnt_lower ' , ' admin_c ' ]
2017-02-28 19:44:15 +01:00
2017-03-02 18:28:15 +01:00
def __init__ ( self , * args , * * kwargs ) :
2017-03-01 03:21:03 +01:00
super ( InetNumForm , self ) . __init__ ( * args , * * kwargs )
2017-02-28 19:44:15 +01:00
if self . _editLower :
2017-03-01 03:21:03 +01:00
for key in self . protectedFields :
self . fields [ key ] . disabled = True
2017-03-21 02:36:07 +01:00
mnts = self . _user . maintainer_set . all ( )
#self.fields['parent_range'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts))
#if not self._create:
# self.fields['parent_range'].queryset |= InetNum.objects.filter(pk=self.instance.pk)
#self.fields['parent_range'].queryset = self.fields['parent_range'].queryset.distinct()
self . fields [ ' parent_range ' ] . queryset = InetNum . getMntQueryset ( mnts , self . instance , " parent_range " )
2017-03-01 03:21:03 +01:00
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
2017-02-28 19:44:15 +01:00
2017-03-14 20:18:57 +01:00
def clean_parent_range ( self ) :
parent_range = self . cleaned_data . get ( ' parent_range ' , None )
# allow parent range to be unset for already present objects
2017-03-21 02:36:07 +01:00
if not parent_range and ( self . _create or not self . _create and self . instance . parent_range ) :
2017-03-14 20:18:57 +01:00
raise forms . ValidationError ( " Parent range must be set " )
2017-03-21 02:36:07 +01:00
if not self . _create and parent_range :
# make sure we don't have circular dependencies
obj = parent_range
while obj . parent_range :
if obj . pk == self . instance . pk :
raise forms . ValidationError ( " No circular dependencies allowed " )
obj = obj . parent_range
return parent_range
2017-02-28 19:44:15 +01:00
def clean ( self ) :
2017-03-01 03:21:03 +01:00
cleaned_data = super ( InetNumForm , self ) . clean ( )
2017-03-14 20:18:57 +01:00
if not self . _editLower :
if not self . errors :
2017-03-01 03:21:03 +01:00
prefix = cleaned_data [ ' prefix ' ]
parent = cleaned_data [ ' parent_range ' ]
2017-03-14 20:18:57 +01:00
if parent :
parentNet = parent . getNetwork ( )
2017-03-01 03:21:03 +01:00
2017-03-14 20:18:57 +01:00
if cleaned_data [ ' protocol ' ] != parent . protocol :
raise forms . ValidationError ( " Protocol type for prefix must be same as parent network " )
2017-03-01 03:21:03 +01:00
2017-03-14 20:18:57 +01:00
# 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 " )
2017-03-01 03:21:03 +01:00
2017-03-14 20:18:57 +01:00
# 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
2017-03-01 03:21:03 +01:00
2017-03-14 20:18:57 +01:00
if otherNet . getNetwork ( ) . overlaps ( prefix ) :
raise forms . ValidationError ( " The given prefix overlaps with network %s " % otherNet . handle )
2017-03-01 03:21:03 +01:00
self . instance . address = str ( prefix . network_address )
self . instance . netmask = prefix . prefixlen
return cleaned_data
2017-03-02 18:28:15 +01:00
2017-03-14 20:18:57 +01:00
class ASBlockForm ( MntFormMixin , WhoisObjectFormMixin , forms . ModelForm ) :
2017-03-02 18:28:15 +01:00
protectedFields = [ ' handle ' , ' parent_block ' , ' asBegin ' , ' asEnd ' , ' mnt_by ' ]
# FIXME: Filter blocks
class Meta :
model = ASBlock
2017-03-20 00:16:33 +01:00
fields = [ ' handle ' , ' parent_block ' , ' asBegin ' , ' asEnd ' , ' name ' , ' description ' , ' mnt_by ' , ' mnt_lower ' , ' admin_c ' ]
2017-03-02 18:28:15 +01:00
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
2017-03-21 02:36:07 +01:00
mnts = self . _user . maintainer_set . all ( )
self . fields [ ' parent_block ' ] . queryset = ASBlock . getMntQueryset ( mnts , self . instance , " parent_block " )
2017-03-02 18:28:15 +01:00
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
2017-03-14 20:18:57 +01:00
class ASNumberForm ( MntFormMixin , WhoisObjectFormMixin , forms . ModelForm ) :
2017-03-02 18:28:15 +01:00
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
2017-03-21 02:36:07 +01:00
mnts = self . _user . maintainer_set . all ( )
self . fields [ ' asblock ' ] . queryset = ASBlock . getMntQueryset ( mnts , self . instance , " asblock " )
2017-03-02 18:28:15 +01:00
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 ( ) ) ) , ) )