Niitt
This commit is contained in:
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" %}
|
||||
{% endfor %}
|
||||
{% 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 %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -6,6 +6,10 @@ from django import forms
|
|||
|
||||
from .models import Maintainer, Contact, InetNum
|
||||
|
||||
import re
|
||||
import ipaddress
|
||||
|
||||
|
||||
class WhoisObjectMixin(object):
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
super(WhoisObjectMixin, self).__init__(*args, **kwargs)
|
||||
|
@ -24,9 +28,12 @@ class WhoisObjectMixin(object):
|
|||
|
||||
def clean(self):
|
||||
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"))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class MntForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Maintainer
|
||||
|
@ -38,11 +45,13 @@ class MntForm(forms.ModelForm):
|
|||
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(WhoisObjectMixin, forms.ModelForm):
|
||||
class Meta:
|
||||
model = Contact
|
||||
|
@ -51,24 +60,76 @@ class ContactForm(WhoisObjectMixin, forms.ModelForm):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super(ContactForm, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class ContactInitialForm(ContactForm):
|
||||
class Meta:
|
||||
model = Contact
|
||||
fields = ['handle', 'name']
|
||||
|
||||
|
||||
class InetNumForm(WhoisObjectMixin, forms.ModelForm):
|
||||
prefix = forms.CharField()
|
||||
protectedFields = ['handle', 'protocol', 'parent_range', 'mnt_by', 'prefix']
|
||||
|
||||
class Meta:
|
||||
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):
|
||||
super(MntForm, self).__init__(*args, **kwargs)
|
||||
super(InetNumForm, self).__init__(*args, **kwargs)
|
||||
print("args", args, kwargs)
|
||||
self._editLower = lower
|
||||
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:
|
||||
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):
|
||||
# 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 .validators import HandleValidator, HandleValidatorWithSuffix
|
||||
|
||||
import ipaddress
|
||||
|
||||
|
||||
class WhoisObject(models.Model):
|
||||
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)
|
||||
for candidate in candidates:
|
||||
reasons.append("Object %s would have no maintainers left." % candidate.handle)
|
||||
|
||||
return reasons
|
||||
|
||||
return reasons
|
||||
|
||||
|
||||
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)
|
||||
for candidate in candidates:
|
||||
reasons.append("Object %s would have no contact left." % candidate.handle)
|
||||
|
||||
|
||||
return reasons
|
||||
|
||||
|
||||
class ASBlock(MntdObject):
|
||||
handleSuffix = "ASB"
|
||||
|
||||
|
@ -123,6 +125,7 @@ class ASBlock(MntdObject):
|
|||
|
||||
mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asblock_set', blank=True)
|
||||
|
||||
|
||||
class ASNumber(MntdObject):
|
||||
handleSuffix = "AS"
|
||||
|
||||
|
@ -145,6 +148,20 @@ class InetNum(MntdObject):
|
|||
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)
|
||||
|
||||
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'^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/edit/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ContactEdit.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/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.InetNumEdit.as_view(), name='inetnum-edit'),
|
||||
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 .generic import DeleteCheckView
|
||||
|
||||
|
||||
@login_required
|
||||
def dbDashboard(request):
|
||||
mnts = request.user.maintainer_set.all()
|
||||
contacts = Contact.objects.filter(mnt_by__in=mnts)
|
||||
netblocks = InetNum.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))
|
||||
asnumbers = ASNumber.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)).distinct()
|
||||
asnumbers = ASNumber.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
|
||||
mntForm = contactForm = None
|
||||
|
||||
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})
|
||||
|
||||
|
||||
class MaintainerCreate(LoginRequiredMixin, CreateView):
|
||||
template_name = "whoisdb/obj_create.html"
|
||||
form_class = MntForm
|
||||
|
@ -71,6 +73,7 @@ class MaintainerCreate(LoginRequiredMixin, CreateView):
|
|||
|
||||
return super(MaintainerCreate, self).form_valid(form)
|
||||
|
||||
|
||||
class MaintainerEdit(LoginRequiredMixin, UpdateView):
|
||||
template_name = "whoisdb/maintainer_edit.html"
|
||||
model = Maintainer
|
||||
|
@ -86,6 +89,7 @@ class MaintainerEdit(LoginRequiredMixin, UpdateView):
|
|||
def get_queryset(self):
|
||||
return self.model.objects.filter(auth=self.request.user)
|
||||
|
||||
|
||||
class MaintainerDelete(LoginRequiredMixin, DeleteCheckView):
|
||||
template_name = "whoisdb/obj_delete.html"
|
||||
model = Maintainer
|
||||
|
@ -95,7 +99,7 @@ class MaintainerDelete(LoginRequiredMixin, DeleteCheckView):
|
|||
|
||||
def get_queryset(self):
|
||||
return self.model.objects.filter(auth=self.request.user)
|
||||
|
||||
|
||||
|
||||
class MaintainerDetail(LoginRequiredMixin, DetailView):
|
||||
model = Maintainer
|
||||
|
@ -103,12 +107,14 @@ class MaintainerDetail(LoginRequiredMixin, DetailView):
|
|||
slug_url_kwarg = "handle"
|
||||
context_object_name = "mnt"
|
||||
|
||||
|
||||
class ContactDetail(DetailView):
|
||||
model = Contact
|
||||
slug_field = "handle"
|
||||
slug_url_kwarg = "handle"
|
||||
context_object_name = "contact"
|
||||
|
||||
|
||||
class ContactEdit(LoginRequiredMixin, UpdateView):
|
||||
template_name = "whoisdb/obj_edit.html"
|
||||
model = Contact
|
||||
|
@ -125,6 +131,7 @@ class ContactEdit(LoginRequiredMixin, UpdateView):
|
|||
# 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())
|
||||
|
||||
|
||||
class ContactCreate(LoginRequiredMixin, CreateView):
|
||||
template_name = "whoisdb/obj_create.html"
|
||||
form_class = ContactForm
|
||||
|
@ -138,6 +145,7 @@ class ContactCreate(LoginRequiredMixin, CreateView):
|
|||
}
|
||||
return kwargs
|
||||
|
||||
|
||||
class ContactDelete(LoginRequiredMixin, DeleteCheckView):
|
||||
template_name = "whoisdb/obj_delete.html"
|
||||
model = Contact
|
||||
|
@ -148,6 +156,7 @@ class ContactDelete(LoginRequiredMixin, DeleteCheckView):
|
|||
def get_queryset(self):
|
||||
return self.model.objects.filter(mnt_by__in=self.request.user.maintainer_set.all())
|
||||
|
||||
|
||||
# InetNum
|
||||
class InetNumCreate(LoginRequiredMixin, CreateView):
|
||||
template_name = "whoisdb/obj_create.html"
|
||||
|
@ -158,7 +167,51 @@ class InetNumCreate(LoginRequiredMixin, CreateView):
|
|||
kwargs["user"] = self.request.user
|
||||
kwargs["initial"] = {
|
||||
"handle": "AUTO",
|
||||
"type": Contact.TYPE_PERSON
|
||||
}
|
||||
|
||||
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…
Reference in New Issue