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.

198 lines
5.9 KiB

from django.db import models
from django.urls import reverse
from dncore.models import User
from .validators import HandleValidator, HandleValidatorWithSuffix
import ipaddress
class WhoisObject(models.Model):
class Meta:
abstract = True
handleSuffix = ""
handle = models.SlugField(max_length=32, unique=True, verbose_name='handle', validators=[HandleValidator()])
created = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.handle
def genHandle(self, main=None):
if not main:
main = self.name
return self.genGenericHandle(main)
@classmethod
def genGenericHandle(clazz, main):
prefix = ""
if " " in main:
parts = main.split(" ")
prefix = "".join(map(lambda _x: _x[0], parts))
if len(prefix) < 3 and len(parts[-1]) > 1:
prefix += parts[-1][1:4 - len(prefix)]
else:
prefix = main[0:3]
prefix = prefix.upper()
i = 1
handle = "%s%%d-%s" % (prefix, clazz.handleSuffix)
while True:
try:
prefix
clazz.objects.get(handle=handle % i)
i += 1
except clazz.DoesNotExist:
break
return handle % i
def getNoDeleteReasons(self):
raise NotImplementedError()
def canBeDeleted(self):
return not bool(self.getNoDeleteReasons())
def handleAuto(self, name=None):
if self.handle == "AUTO":
self.handle = self.genHandle(name)
class Maintainer(WhoisObject):
handleSuffix = "MNT"
auth = models.ManyToManyField(User)
handle = models.SlugField(max_length=32, unique=True, verbose_name='handle', validators=[HandleValidatorWithSuffix('MNT')], help_text="Must end with -MNT, eg FOO3-MNT")
description = models.CharField(max_length=64, blank=True, help_text="Short description what this maintainer is for")
admin_c = models.ManyToManyField("Contact")
rir = models.BooleanField(default=False)
lir = models.BooleanField(default=False)
# autoInclude = models.BooleanField(default=True)
def get_absolute_url(self):
return reverse("whoisdb:mnt-detail", kwargs={"handle": self.handle})
def getNoDeleteReasons(self):
reasons = []
mntables = [Contact, ASBlock, ASNumber, InetNum]
for mntable in mntables:
candidates = mntable.objects.filter(mnt_by=self).annotate(mntCount=models.Count('mnt_by')).filter(mntCount__lte=1)
for candidate in candidates:
reasons.append("Object %s would have no maintainers left." % candidate.handle)
return reasons
class MntdObject(WhoisObject):
class Meta:
abstract = True
mnt_by = models.ManyToManyField(Maintainer)
class Contact(MntdObject):
handleSuffix = "DN"
TYPE_PERSON = 'PERSON'
TYPE_ROLE = 'ROLE'
TYPE = (('person', TYPE_PERSON), ('role', TYPE_ROLE))
TYPE = (('person', TYPE_PERSON),)
name = models.CharField(max_length=128)
type = models.CharField(max_length=10, choices=TYPE, default=TYPE_PERSON)
def get_absolute_url(self):
return reverse("whoisdb:contact-detail", kwargs={"handle": self.handle})
def getNoDeleteReasons(self):
reasons = []
contactables = [Maintainer]
for contactable in contactables:
candidates = contactable.objects.filter(admin_c=self).annotate(contactCount=models.Count('admin_c')).filter(contactCount__lte=1)
for candidate in candidates:
reasons.append("Object %s would have no contact left." % candidate.handle)
return reasons
class ASBlock(MntdObject):
handleSuffix = "ASB"
parent_block = models.ForeignKey("ASBlock", models.CASCADE, null=True, blank=True, default=None)
name = models.CharField(max_length=32)
asBegin = models.PositiveIntegerField()
asEnd = models.PositiveIntegerField()
description = models.CharField(max_length=64, blank=True)
admin_c = models.ManyToManyField("Contact")
mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asblock_set', blank=True)
def get_absolute_url(self):
return reverse("whoisdb:asblock-detail", kwargs={"handle": self.handle})
def getNoDeleteReasons(self):
reasons = []
if self.asblock_set.count() > 0:
reasons.append("The AS block is referenced by the following other blocks: %s" % (", ".join(map(lambda _x: _x.handle, self.asblock_set.all()))))
if self.asnumber_set.count() > 0:
reasons.append("The AS block is referenced by the following as numbers: %s" % (", ".join(map(lambda _x: _x.handle, self.asnumber_set.all()))))
return reasons
class ASNumber(MntdObject):
handleSuffix = "AS"
number = models.PositiveIntegerField(unique=True, db_index=True)
volatile = models.BooleanField(default=False, help_text="Check if this AS is not going to be online 24/7 (for example on a laptop)")
asblock = models.ForeignKey(ASBlock, models.CASCADE)
name = models.CharField(max_length=32)
description = models.CharField(max_length=64, blank=True)
admin_c = models.ManyToManyField("Contact")
mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asnumber_set', blank=True)
def get_absolute_url(self):
return reverse("whoisdb:asnumber-detail", kwargs={"handle": self.handle})
def getNoDeleteReasons(self):
reasons = []
return reasons
class InetNum(MntdObject):
handleSuffix = "NET"
IPv4 = "ipv4"
IPv6 = "ipv6"
PROTO = ((IPv4, 'IPv4'), (IPv6, 'IPv6'))
protocol = models.CharField(max_length=4, choices=PROTO)
address = models.GenericIPAddressField(db_index=True)
netmask = models.PositiveIntegerField()
parent_range = models.ForeignKey("InetNum", models.CASCADE, null=True, blank=True, default=None)
name = models.CharField(max_length=64)
description = models.CharField(max_length=64, blank=True)
admin_c = models.ManyToManyField("Contact")
mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_inetnum_set', blank=True)
def getNetwork(self):
return ipaddress.ip_network("%s/%s" % (self.address, self.netmask))
def get_absolute_url(self):
return reverse("whoisdb:inetnum-detail", kwargs={"handle": self.handle})
def getNoDeleteReasons(self):
reasons = []
if self.inetnum_set.all().count() > 0:
reasons.append("The following networks depend on this network: %s" % ", ".join(map(lambda _x: _x.handle, self.inetnum_set.all())))
return reasons