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-02-28 19:44:15 +01:00
class WhoisObjectMixin ( object ) :
def __init__ ( self , user , * args , * * kwargs ) :
super ( WhoisObjectMixin , self ) . __init__ ( * args , * * kwargs )
self . _user = user
instance = getattr ( self , ' instance ' , None )
if instance and instance . pk :
self . fields [ ' handle ' ] . widget . attrs [ ' readonly ' ] = True
2017-03-02 18:28:15 +01:00
# 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 ( )
2017-02-28 19:44:15 +01:00
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 ( WhoisObjectMixin , 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
print ( mntQs . query )
2017-02-23 22:28:06 +01:00
class MntForm ( forms . ModelForm ) :
2017-02-28 19:44:15 +01:00
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 ( ) )
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-02-28 19:44:15 +01:00
class ContactForm ( WhoisObjectMixin , forms . ModelForm ) :
2017-02-23 22:28:06 +01:00
class Meta :
model = Contact
2017-02-28 19:44:15 +01:00
fields = [ ' type ' , ' 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-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-02 18:28:15 +01:00
class InetNumForm ( MntFormMixin , WhoisObjectMixin , 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-01 03:21:03 +01:00
fields = [ ' handle ' , ' protocol ' , ' parent_range ' , ' prefix ' , ' name ' , ' description ' , ' mnt_by ' , ' mnt_lower ' ]
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 ' admin_c ' in self . fields :
2017-03-01 03:21:03 +01:00
self . fields [ ' admin_c ' ] . queryset = Contact . objects . filter ( mnt_by__in = self . user . maintainer_set . all ( ) )
2017-03-02 18:28:15 +01:00
instance = getattr ( self , " instance " , None )
if instance and instance . pk :
self . fields [ ' admin_c ' ] . queryset | = instance . admin_c . all ( )
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
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
2017-02-28 19:44:15 +01:00
def clean ( self ) :
# FIXME: Reset certain field sto instance:
2017-03-01 03:21:03 +01:00
cleaned_data = super ( InetNumForm , self ) . clean ( )
if self . _editLower :
# reset some fields, just in case
#for key in self.protectedFields:
# cleaned_data[key] = getattr(self.instance, key)
pass
else :
if all ( x in cleaned_data for x in ( ' prefix ' , ' parent_range ' , ' protocol ' ) ) :
prefix = cleaned_data [ ' prefix ' ]
parent = cleaned_data [ ' parent_range ' ]
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
2017-03-02 18:28:15 +01:00
class ASBlockForm ( MntFormMixin , WhoisObjectMixin , 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 :
print ( " AS OVERLAP TEST " , parent . asBegin , parent . asEnd , asBegin , asEnd )
raise forms . ValidationError ( " Block overlaps with block %s " % block . handle )
return cleaned_data
class ASNumberForm ( MntFormMixin , WhoisObjectMixin , 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 ( ) ) ) , ) )