master
Sebastian Lohff 7 years ago
parent 814a8b62cb
commit f9b98a03f5

@ -0,0 +1,16 @@
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">Header</div>
<div class="panel-body">
{{ inetnum }}
{{ inetnum.address }}/{{ inetnum.netmask }}
</div>
</div>
</div>
</div>
{% endblock %}

@ -48,7 +48,7 @@
{% include "whoisdb/handle_table_row.html" with obj=asnumber objType="AS Number" prefix="contact" %} {% include "whoisdb/handle_table_row.html" with obj=asnumber objType="AS Number" prefix="contact" %}
{% endfor %} {% endfor %}
{% for netblock in netblocks %} {% for netblock in netblocks %}
{% include "whoisdb/handle_table_row.html" with obj=netblock objType="IP Netblock" prefix="contact" %} {% include "whoisdb/handle_table_row.html" with obj=netblock objType="IP Netblock" prefix="inetnum" %}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>

@ -6,6 +6,10 @@ from django import forms
from .models import Maintainer, Contact, InetNum from .models import Maintainer, Contact, InetNum
import re
import ipaddress
class WhoisObjectMixin(object): class WhoisObjectMixin(object):
def __init__(self, user, *args, **kwargs): def __init__(self, user, *args, **kwargs):
super(WhoisObjectMixin, self).__init__(*args, **kwargs) super(WhoisObjectMixin, self).__init__(*args, **kwargs)
@ -24,9 +28,12 @@ class WhoisObjectMixin(object):
def clean(self): def clean(self):
cleaned_data = super(WhoisObjectMixin, self).clean() cleaned_data = super(WhoisObjectMixin, self).clean()
if cleaned_data.get("handle") == "AUTO": if cleaned_data.get("handle") == "AUTO" and not self.errors:
cleaned_data['handle'] = self._meta.model.genGenericHandle(cleaned_data.get("name")) cleaned_data['handle'] = self._meta.model.genGenericHandle(cleaned_data.get("name"))
return cleaned_data
class MntForm(forms.ModelForm): class MntForm(forms.ModelForm):
class Meta: class Meta:
model = Maintainer model = Maintainer
@ -38,11 +45,13 @@ class MntForm(forms.ModelForm):
if 'admin_c' in self.fields: if 'admin_c' in self.fields:
self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by=user.maintainer_set.all()) self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by=user.maintainer_set.all())
class MntInitialForm(MntForm): class MntInitialForm(MntForm):
class Meta: class Meta:
model = Maintainer model = Maintainer
fields = ['handle', 'description'] fields = ['handle', 'description']
class ContactForm(WhoisObjectMixin, forms.ModelForm): class ContactForm(WhoisObjectMixin, forms.ModelForm):
class Meta: class Meta:
model = Contact model = Contact
@ -51,24 +60,76 @@ class ContactForm(WhoisObjectMixin, forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs) super(ContactForm, self).__init__(*args, **kwargs)
class ContactInitialForm(ContactForm): class ContactInitialForm(ContactForm):
class Meta: class Meta:
model = Contact model = Contact
fields = ['handle', 'name'] fields = ['handle', 'name']
class InetNumForm(WhoisObjectMixin, forms.ModelForm): class InetNumForm(WhoisObjectMixin, forms.ModelForm):
prefix = forms.CharField()
protectedFields = ['handle', 'protocol', 'parent_range', 'mnt_by', 'prefix']
class Meta: class Meta:
model = InetNum model = InetNum
fields = ['protocol', 'parent_range', 'address', 'description', 'mnt_lower'] fields = ['handle', 'protocol', 'parent_range', 'prefix', 'name', 'description', 'mnt_by', 'mnt_lower']
def __init__(self, lower=False, *args, **kwargs): def __init__(self, lower=False, *args, **kwargs):
super(MntForm, self).__init__(*args, **kwargs) super(InetNumForm, self).__init__(*args, **kwargs)
print("args", args, kwargs)
self._editLower = lower self._editLower = lower
if 'admin_c' in self.fields: if 'admin_c' in self.fields:
self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by=self.user.maintainer_set.all()) self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by__in=self.user.maintainer_set.all())
if self._editLower: 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
print("HALLO")
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(self): def clean(self):
# FIXME: Reset certain field sto instance: # FIXME: Reset certain field sto instance:
pass 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

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-01 00:03
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('whoisdb', '0007_asblock_mnt_lower'),
]
operations = [
migrations.AddField(
model_name='inetnum',
name='name',
field=models.CharField(default='', max_length=64),
preserve_default=False,
),
migrations.AlterField(
model_name='inetnum',
name='protocol',
field=models.CharField(choices=[('ipv4', 'IPv4'), ('ipv6', 'IPv6')], max_length=4),
),
]

@ -4,6 +4,8 @@ from django.urls import reverse
from dncore.models import User from dncore.models import User
from .validators import HandleValidator, HandleValidatorWithSuffix from .validators import HandleValidator, HandleValidatorWithSuffix
import ipaddress
class WhoisObject(models.Model): class WhoisObject(models.Model):
class Meta: class Meta:
@ -79,9 +81,8 @@ class Maintainer(WhoisObject):
candidates = mntable.objects.filter(mnt_by=self).annotate(mntCount=models.Count('mnt_by')).filter(mntCount__lte=1) candidates = mntable.objects.filter(mnt_by=self).annotate(mntCount=models.Count('mnt_by')).filter(mntCount__lte=1)
for candidate in candidates: for candidate in candidates:
reasons.append("Object %s would have no maintainers left." % candidate.handle) reasons.append("Object %s would have no maintainers left." % candidate.handle)
return reasons
return reasons
class MntdObject(WhoisObject): class MntdObject(WhoisObject):
@ -112,9 +113,10 @@ class Contact(MntdObject):
candidates = contactable.objects.filter(admin_c=self).annotate(contactCount=models.Count('admin_c')).filter(contactCount__lte=1) candidates = contactable.objects.filter(admin_c=self).annotate(contactCount=models.Count('admin_c')).filter(contactCount__lte=1)
for candidate in candidates: for candidate in candidates:
reasons.append("Object %s would have no contact left." % candidate.handle) reasons.append("Object %s would have no contact left." % candidate.handle)
return reasons return reasons
class ASBlock(MntdObject): class ASBlock(MntdObject):
handleSuffix = "ASB" handleSuffix = "ASB"
@ -123,6 +125,7 @@ class ASBlock(MntdObject):
mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asblock_set', blank=True) mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asblock_set', blank=True)
class ASNumber(MntdObject): class ASNumber(MntdObject):
handleSuffix = "AS" handleSuffix = "AS"
@ -145,6 +148,20 @@ class InetNum(MntdObject):
address = models.GenericIPAddressField(db_index=True) address = models.GenericIPAddressField(db_index=True)
netmask = models.PositiveIntegerField() netmask = models.PositiveIntegerField()
parent_range = models.ForeignKey("InetNum", models.CASCADE, null=True, blank=True, default=None) 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) description = models.CharField(max_length=64, blank=True)
mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_inetnum_set', blank=True) 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

@ -16,8 +16,7 @@ urlpatterns = [
url(r'^contact/delete/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ContactDelete.as_view(), name='contact-delete'), url(r'^contact/delete/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ContactDelete.as_view(), name='contact-delete'),
url(r'^inetnum/create/$', whoisdb_views.InetNumCreate.as_view(), name='inetnum-create'), url(r'^inetnum/create/$', whoisdb_views.InetNumCreate.as_view(), name='inetnum-create'),
url(r'^inetnum/show/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ContactDetail.as_view(), name='inetnum-detail'), url(r'^inetnum/show/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.InetNumDetail.as_view(), name='inetnum-detail'),
url(r'^inetnum/edit/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ContactEdit.as_view(), name='inetnum-edit'), url(r'^inetnum/edit/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.InetNumEdit.as_view(), name='inetnum-edit'),
url(r'^inetnum/delete/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ContactDelete.as_view(), name='inetnum-delete'), url(r'^inetnum/delete/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.InetNumDelete.as_view(), name='inetnum-delete'),
] ]

@ -10,13 +10,14 @@ from .models import Maintainer, Contact, InetNum, ASBlock, ASNumber
from .forms import MntForm, MntInitialForm, ContactForm, ContactInitialForm, InetNumForm from .forms import MntForm, MntInitialForm, ContactForm, ContactInitialForm, InetNumForm
from .generic import DeleteCheckView from .generic import DeleteCheckView
@login_required @login_required
def dbDashboard(request): def dbDashboard(request):
mnts = request.user.maintainer_set.all() mnts = request.user.maintainer_set.all()
contacts = Contact.objects.filter(mnt_by__in=mnts) contacts = Contact.objects.filter(mnt_by__in=mnts)
netblocks = InetNum.objects.filter(Q(mnt_by__in=mnts)|Q(mnt_lower__in=mnts)) netblocks = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
asblocks = ASBlock.objects.filter(Q(mnt_by__in=mnts)|Q(mnt_lower__in=mnts)) asblocks = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
asnumbers = ASNumber.objects.filter(Q(mnt_by__in=mnts)|Q(mnt_lower__in=mnts)) asnumbers = ASNumber.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
mntForm = contactForm = None mntForm = contactForm = None
if mnts.count() == 0: if mnts.count() == 0:
@ -49,6 +50,7 @@ def dbDashboard(request):
return render(request, "whoisdb/overview.html", {"mnts": mnts, "contacts": contacts, "mntForm": mntForm, "contactForm": contactForm, "netblocks": netblocks, "asblocks": asblocks, "asnumbers": asnumbers}) return render(request, "whoisdb/overview.html", {"mnts": mnts, "contacts": contacts, "mntForm": mntForm, "contactForm": contactForm, "netblocks": netblocks, "asblocks": asblocks, "asnumbers": asnumbers})
class MaintainerCreate(LoginRequiredMixin, CreateView): class MaintainerCreate(LoginRequiredMixin, CreateView):
template_name = "whoisdb/obj_create.html" template_name = "whoisdb/obj_create.html"
form_class = MntForm form_class = MntForm
@ -71,6 +73,7 @@ class MaintainerCreate(LoginRequiredMixin, CreateView):
return super(MaintainerCreate, self).form_valid(form) return super(MaintainerCreate, self).form_valid(form)
class MaintainerEdit(LoginRequiredMixin, UpdateView): class MaintainerEdit(LoginRequiredMixin, UpdateView):
template_name = "whoisdb/maintainer_edit.html" template_name = "whoisdb/maintainer_edit.html"
model = Maintainer model = Maintainer
@ -86,6 +89,7 @@ class MaintainerEdit(LoginRequiredMixin, UpdateView):
def get_queryset(self): def get_queryset(self):
return self.model.objects.filter(auth=self.request.user) return self.model.objects.filter(auth=self.request.user)
class MaintainerDelete(LoginRequiredMixin, DeleteCheckView): class MaintainerDelete(LoginRequiredMixin, DeleteCheckView):
template_name = "whoisdb/obj_delete.html" template_name = "whoisdb/obj_delete.html"
model = Maintainer model = Maintainer
@ -95,7 +99,7 @@ class MaintainerDelete(LoginRequiredMixin, DeleteCheckView):
def get_queryset(self): def get_queryset(self):
return self.model.objects.filter(auth=self.request.user) return self.model.objects.filter(auth=self.request.user)
class MaintainerDetail(LoginRequiredMixin, DetailView): class MaintainerDetail(LoginRequiredMixin, DetailView):
model = Maintainer model = Maintainer
@ -103,12 +107,14 @@ class MaintainerDetail(LoginRequiredMixin, DetailView):
slug_url_kwarg = "handle" slug_url_kwarg = "handle"
context_object_name = "mnt" context_object_name = "mnt"
class ContactDetail(DetailView): class ContactDetail(DetailView):
model = Contact model = Contact
slug_field = "handle" slug_field = "handle"
slug_url_kwarg = "handle" slug_url_kwarg = "handle"
context_object_name = "contact" context_object_name = "contact"
class ContactEdit(LoginRequiredMixin, UpdateView): class ContactEdit(LoginRequiredMixin, UpdateView):
template_name = "whoisdb/obj_edit.html" template_name = "whoisdb/obj_edit.html"
model = Contact model = Contact
@ -125,6 +131,7 @@ class ContactEdit(LoginRequiredMixin, UpdateView):
# FIXME: we need all maintainers to be available. autofill own maintainers # FIXME: we need all maintainers to be available. autofill own maintainers
return self.model.objects.filter(mnt_by__in=self.request.user.maintainer_set.all()) return self.model.objects.filter(mnt_by__in=self.request.user.maintainer_set.all())
class ContactCreate(LoginRequiredMixin, CreateView): class ContactCreate(LoginRequiredMixin, CreateView):
template_name = "whoisdb/obj_create.html" template_name = "whoisdb/obj_create.html"
form_class = ContactForm form_class = ContactForm
@ -138,6 +145,7 @@ class ContactCreate(LoginRequiredMixin, CreateView):
} }
return kwargs return kwargs
class ContactDelete(LoginRequiredMixin, DeleteCheckView): class ContactDelete(LoginRequiredMixin, DeleteCheckView):
template_name = "whoisdb/obj_delete.html" template_name = "whoisdb/obj_delete.html"
model = Contact model = Contact
@ -148,6 +156,7 @@ class ContactDelete(LoginRequiredMixin, DeleteCheckView):
def get_queryset(self): def get_queryset(self):
return self.model.objects.filter(mnt_by__in=self.request.user.maintainer_set.all()) return self.model.objects.filter(mnt_by__in=self.request.user.maintainer_set.all())
# InetNum # InetNum
class InetNumCreate(LoginRequiredMixin, CreateView): class InetNumCreate(LoginRequiredMixin, CreateView):
template_name = "whoisdb/obj_create.html" template_name = "whoisdb/obj_create.html"
@ -158,7 +167,51 @@ class InetNumCreate(LoginRequiredMixin, CreateView):
kwargs["user"] = self.request.user kwargs["user"] = self.request.user
kwargs["initial"] = { kwargs["initial"] = {
"handle": "AUTO", "handle": "AUTO",
"type": Contact.TYPE_PERSON
} }
return kwargs return kwargs
class InetNumDetail(DetailView):
model = InetNum
slug_field = "handle"
slug_url_kwarg = "handle"
context_object_name = "inetnum"
class InetNumEdit(LoginRequiredMixin, UpdateView):
template_name = "whoisdb/obj_edit.html"
model = InetNum
form_class = InetNumForm
slug_field = "handle"
slug_url_kwarg = "handle"
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(InetNumEdit, self).get_form_kwargs(*args, **kwargs)
kwargs["user"] = self.request.user
mnts = self.request.user.maintainer_set.all()
if not any(mnt in self.object.mnt_by.all() for mnt in mnts):
# we are in mnt_lower
kwargs["lower"] = True
kwargs["initial"] = {'prefix': str(self.object.getNetwork())}
return kwargs
def get_queryset(self):
# FIXME: we need all maintainers to be available. autofill own maintainers
mnts = self.request.user.maintainer_set.all()
return self.model.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
class InetNumDelete(LoginRequiredMixin, DeleteCheckView):
template_name = "whoisdb/obj_delete.html"
model = InetNum
slug_field = "handle"
slug_url_kwarg = "handle"
success_url = reverse_lazy("whoisdb:dashboard")
def get_queryset(self):
mnts = self.request.user.maintainer_set.all()
return self.model.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts))

Loading…
Cancel
Save