Evvverything!
This commit is contained in:
parent
8dbd77dc79
commit
81bbcda8eb
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ApiConfig(AppConfig):
|
||||||
|
name = 'api'
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
|
@ -0,0 +1,9 @@
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views as api_views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'asblock/free-as/$', api_views.asblockFreeAS, name='asblock-free-as'),
|
||||||
|
url(r'asblock/free-subnet/$', api_views.freeSubnet, name='inetnum-free-subnet'),
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,107 @@
|
||||||
|
#from django.shortcuts import render
|
||||||
|
from django.http import JsonResponse
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.contrib.auth.views import login_required
|
||||||
|
|
||||||
|
from whoisdb.models import ASBlock, ASNumber, InetNum
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def asblockFreeAS(request):
|
||||||
|
|
||||||
|
ret = {
|
||||||
|
"success": False,
|
||||||
|
"errorMsg": None,
|
||||||
|
"number": -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
blockName = request.GET.get('block', None)
|
||||||
|
if not blockName:
|
||||||
|
raise ValidationError("No block given")
|
||||||
|
|
||||||
|
try:
|
||||||
|
mnts = request.user.maintainer_set.all()
|
||||||
|
block = ASBlock.objects.filter(mnt_by__in=mnts).distinct().get(handle=blockName)
|
||||||
|
if block.asblock_set.count() > 0:
|
||||||
|
raise ValidationError("AS Block already has sub AS Blocks")
|
||||||
|
if block.asnumber_set.count() > 0:
|
||||||
|
num = block.asnumber_set.order_by("-number")[0].number + 1
|
||||||
|
if num > block.asEnd:
|
||||||
|
num = None
|
||||||
|
for n in range(block.asBegin, block.asEnd+1):
|
||||||
|
try:
|
||||||
|
ASNumber.objects.get(number=n)
|
||||||
|
except ASNumber.DoesNotExist:
|
||||||
|
num = n
|
||||||
|
break
|
||||||
|
if not num:
|
||||||
|
raise ValidationError("No free AS Number in block")
|
||||||
|
ret["number"] = num
|
||||||
|
else:
|
||||||
|
ret["number"] = block.asBegin
|
||||||
|
except ASBlock.DoesNotExist:
|
||||||
|
raise ValidationError("Could not get AS Block")
|
||||||
|
|
||||||
|
ret["success"] = True
|
||||||
|
except ValidationError as e:
|
||||||
|
ret["errorMsg"] = e.message
|
||||||
|
return JsonResponse(ret)
|
||||||
|
@login_required
|
||||||
|
def freeSubnet(request):
|
||||||
|
|
||||||
|
ret = {
|
||||||
|
"success": False,
|
||||||
|
"errorMsg": None,
|
||||||
|
"network": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
parentRangeName = request.GET.get('parentRange', None)
|
||||||
|
if not parentRangeName:
|
||||||
|
raise ValidationError("No subnet given")
|
||||||
|
|
||||||
|
parentRange = None
|
||||||
|
try:
|
||||||
|
mnts = request.user.maintainer_set.all()
|
||||||
|
parentRange = InetNum.objects.filter(mnt_by__in=mnts).distinct().get(handle=parentRangeName)
|
||||||
|
except InetNum.DoesNotExist:
|
||||||
|
raise ValidationError("Parent range does not exist / is not maintained by you")
|
||||||
|
|
||||||
|
prefixLen = 0
|
||||||
|
try:
|
||||||
|
prefixLen = int(request.GET.get("prefixLen", 27))
|
||||||
|
if prefixLen < 8 or \
|
||||||
|
(parentRange.protocol == InetNum.IPv4 and prefixLen > 32) or \
|
||||||
|
(parentRange.protocol == InetNum.IPv6 and prefixLen > 128):
|
||||||
|
raise ValidationError("Given prefix length is out of range")
|
||||||
|
except ValueError:
|
||||||
|
raise ValidationError("PrefixLen is not a number")
|
||||||
|
nets = list(parentRange.getNetwork().subnets())
|
||||||
|
for subRange in parentRange.inetnum_set.all():
|
||||||
|
newNet = None
|
||||||
|
for net in nets:
|
||||||
|
if subRange.getNetwork().network_address in net:
|
||||||
|
newNet = net
|
||||||
|
if not newNet:
|
||||||
|
# critical error, we want a 500 here
|
||||||
|
raise ValueError("Subnet not in range")
|
||||||
|
|
||||||
|
nets.remove(newNet)
|
||||||
|
nets.extend(newNet.address_exclude(subRange.getNetwork()))
|
||||||
|
|
||||||
|
nets = sorted(nets)
|
||||||
|
usableNet = None
|
||||||
|
for net in nets:
|
||||||
|
if net.prefixlen <= prefixLen:
|
||||||
|
usableNet = net
|
||||||
|
break
|
||||||
|
|
||||||
|
if not usableNet:
|
||||||
|
raise ValidationError("No space left in given range")
|
||||||
|
|
||||||
|
ret["network"] = "%s/%s" % (usableNet.network_address, prefixLen)
|
||||||
|
ret["success"] = True
|
||||||
|
except ValidationError as e:
|
||||||
|
ret["errorMsg"] = e.message
|
||||||
|
return JsonResponse(ret)
|
|
@ -39,10 +39,12 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'crispy_forms',
|
'crispy_forms',
|
||||||
|
'formtools',
|
||||||
'dncore',
|
'dncore',
|
||||||
'whoisdb',
|
'whoisdb',
|
||||||
'rrequests',
|
'rrequests',
|
||||||
'domains',
|
'domains',
|
||||||
|
'api',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|
|
@ -21,6 +21,7 @@ import dncore.views
|
||||||
import whoisdb.urls
|
import whoisdb.urls
|
||||||
import rrequests.urls
|
import rrequests.urls
|
||||||
import domains.urls
|
import domains.urls
|
||||||
|
import api.urls
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -32,4 +33,5 @@ urlpatterns = [
|
||||||
url(r'^whoisdb/', include(whoisdb.urls, namespace='whoisdb')),
|
url(r'^whoisdb/', include(whoisdb.urls, namespace='whoisdb')),
|
||||||
url(r'^rrequests/', include(rrequests.urls, namespace='rrequests')),
|
url(r'^rrequests/', include(rrequests.urls, namespace='rrequests')),
|
||||||
url(r'^domains/', include(domains.urls, namespace='domains')),
|
url(r'^domains/', include(domains.urls, namespace='domains')),
|
||||||
|
url(r'^api/', include(api.urls, namespace='api')),
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.5 on 2017-03-22 18:01
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('domains', '0002_auto_20170321_1854'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='nameserver',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=256),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,76 @@
|
||||||
|
<script>
|
||||||
|
function findASNumber(step) {
|
||||||
|
// extra field foo
|
||||||
|
var ef = ""
|
||||||
|
if(step >= 0)
|
||||||
|
ef = "" + step + "-";
|
||||||
|
|
||||||
|
var asNumInp = $('#div_id_'+ef+'number input');
|
||||||
|
asNumInp.val("");
|
||||||
|
asNumInp.attr("placeholder", "Getting AS number...");
|
||||||
|
|
||||||
|
var blockOpt = $('#id_'+ef+'asblock option:selected');
|
||||||
|
if(blockOpt.val()) {
|
||||||
|
$.get("{% url "api:asblock-free-as" %}", {block: blockOpt.text()}, function(data) {
|
||||||
|
if(data.success) {
|
||||||
|
asNumInp.attr("placeholder", "")
|
||||||
|
asNumInp.val(data.number);
|
||||||
|
} else {
|
||||||
|
errorMsg = "Nothing returned via API";
|
||||||
|
if(data.errorMsg)
|
||||||
|
errorMsg = data.errorMsg;
|
||||||
|
asNumInp.attr("placeholder", data.errorMsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
asNumInp.attr("placeholder", "No AS Block selected!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findPrefix(size, step) {
|
||||||
|
// extra field foo
|
||||||
|
var ef = ""
|
||||||
|
if(step >= 0)
|
||||||
|
ef = "" + step + "-";
|
||||||
|
|
||||||
|
var netInp = $('#div_id_'+ef+'prefix input');
|
||||||
|
var netInpText = netInp.val();
|
||||||
|
netInp.val("");
|
||||||
|
netInp.attr("placeholder", "Searching free prefix...");
|
||||||
|
|
||||||
|
var parentRangeOpt = $('#id_'+ef+'parent_range option:selected');
|
||||||
|
if(parentRangeOpt.val()) {
|
||||||
|
var prefixLen = 27;
|
||||||
|
var m = netInpText.match("([0-9.:]+/)?(\\d+)");
|
||||||
|
console.log(prefixLen)
|
||||||
|
console.log(netInpText);
|
||||||
|
if(m) {
|
||||||
|
prefixLen = m[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$.get("{% url "api:inetnum-free-subnet" %}", {parentRange: parentRangeOpt.text(), prefixLen: prefixLen}, function(data) {
|
||||||
|
if(data.success) {
|
||||||
|
netInp.attr("placeholder", "")
|
||||||
|
netInp.val(data.network);
|
||||||
|
} else {
|
||||||
|
errorMsg = "Nothing returned via API";
|
||||||
|
if(data.errorMsg)
|
||||||
|
errorMsg = data.errorMsg;
|
||||||
|
netInp.attr("placeholder", data.errorMsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
netInp.attr("placeholder", "No Parent Range selected!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
console.log("NOOT NOOT");
|
||||||
|
$('#div_id_number label').append(' <small>(<a onClick="findASNumber();">next free number</a>)</small>');
|
||||||
|
$('#div_id_0-number label').append(' <small>(<a onClick="findASNumber(0);">next free number</a>)</small>');
|
||||||
|
$('#div_id_prefix label').append(' <small>(<a onClick="findPrefix(27);">next free /27</a>)</small>');
|
||||||
|
$('#div_id_1-prefix label').append(' <small>(<a onClick="findPrefix(27, 1);">next free /27</a>)</small>');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
@ -17,5 +17,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% include "whoisdb/create_js.html" %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
Create <a href="{% url "whoisdb:mnt-create" %}">new Maintainer</a>, create <a href="{% url "whoisdb:contact-create" %}">new Contact</a>, <a href="{% url "rrequests:dashboard" %}">request resources</a>{% if netblocks %}, create <a href="{% url "whoisdb:inetnum-create" %}">Subnet</a>{% endif %}{% if asblocks %}, create <a href="{% url "whoisdb:asnumber-create" %}">AS</a>, create <a href="{% url "whoisdb:asblock-create" %}">ASblock</a>{% endif %}
|
Create <a href="{% url "whoisdb:mnt-create" %}">new Maintainer</a>, create <a href="{% url "whoisdb:contact-create" %}">new Contact</a>, <a href="{% url "rrequests:dashboard" %}">request resources</a>{% if netblocks %}, create <a href="{% url "whoisdb:inetnum-create" %}">Subnet</a>{% endif %}{% if asblocks %}, create <a href="{% url "whoisdb:asnumber-create" %}">AS</a>, create <a href="{% url "whoisdb:asblock-create" %}">ASblock</a>{% endif %}{% if netblocks and asblocks %}, create <a href="{% url "whoisdb:asandsubnet-wizard" %}">AS / Subnet pair</a>{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<!--
|
<!--
|
||||||
<h3>Create Database Objects</h3>
|
<h3>Create Database Objects</h3>
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Create AS & Net - Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
|
||||||
|
<p>{{ message }}</p>
|
||||||
|
<form action="" method="post">{% csrf_token %}
|
||||||
|
<table>
|
||||||
|
{{ wizard.management_form }}
|
||||||
|
{% if wizard.form.forms %}
|
||||||
|
{{ wizard.form.management_form }}
|
||||||
|
{% for form in wizard.form.forms %}
|
||||||
|
{{ form }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
{{ wizard.form|crispy }}
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
{% if wizard.steps.prev %}
|
||||||
|
<button class="btn" name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">Back</button>
|
||||||
|
{% endif %}
|
||||||
|
{% if wizard.steps.next %}
|
||||||
|
{# <button class="btn" name="wizard_goto_step" type="submit" value="{{ wizard.steps.next }}">Next</button> #}
|
||||||
|
{# <button class="btn" name="wizard_goto_step" type="submit" value="{{ wizard.steps.next }}">{% if wizard.steps.next %}Next{% else %}Create{% endif %}</button> #}
|
||||||
|
{% else %}
|
||||||
|
{# <button class="btn btn-primary" type="submit" value="submit">Create</button> #}
|
||||||
|
{% endif %}
|
||||||
|
<button class="btn" type="submit" value="{{ wizard.steps.next }}">{% if wizard.steps.next %}Next{% else %}Create{% endif %}</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% include "whoisdb/create_js.html" %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -37,4 +37,7 @@ urlpatterns = [
|
||||||
url(r'^asnumber/show/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ASNumberDetail.as_view(), name='asnumber-detail'),
|
url(r'^asnumber/show/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ASNumberDetail.as_view(), name='asnumber-detail'),
|
||||||
url(r'^asnumber/edit/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ASNumberEdit.as_view(), name='asnumber-edit'),
|
url(r'^asnumber/edit/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ASNumberEdit.as_view(), name='asnumber-edit'),
|
||||||
url(r'^asnumber/delete/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ASNumberDelete.as_view(), name='asnumber-delete'),
|
url(r'^asnumber/delete/(?P<handle>[A-Z0-9-]+)/$', whoisdb_views.ASNumberDelete.as_view(), name='asnumber-delete'),
|
||||||
|
|
||||||
|
|
||||||
|
url(r'^assubnetset/create/$', whoisdb_views.ASAndSubnetWizard.as_view(), name='asandsubnet-wizard'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,6 +5,8 @@ from django.http import HttpResponseRedirect, Http404
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.views.generic import DetailView, CreateView, UpdateView
|
from django.views.generic import DetailView, CreateView, UpdateView
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.contrib import messages
|
||||||
|
from formtools.wizard.views import SessionWizardView
|
||||||
|
|
||||||
from .models import Maintainer, Contact, InetNum, ASBlock, ASNumber
|
from .models import Maintainer, Contact, InetNum, ASBlock, ASNumber
|
||||||
from .forms import MntForm, MntInitialForm, ContactForm, ContactInitialForm, InetNumForm, ASBlockForm, ASNumberForm
|
from .forms import MntForm, MntInitialForm, ContactForm, ContactInitialForm, InetNumForm, ASBlockForm, ASNumberForm
|
||||||
|
@ -307,3 +309,37 @@ class ASNumberDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView):
|
||||||
slug_field = "handle"
|
slug_field = "handle"
|
||||||
slug_url_kwarg = "handle"
|
slug_url_kwarg = "handle"
|
||||||
success_url = reverse_lazy("whoisdb:dashboard")
|
success_url = reverse_lazy("whoisdb:dashboard")
|
||||||
|
|
||||||
|
|
||||||
|
class ASAndSubnetWizard(LoginRequiredMixin, SessionWizardView):
|
||||||
|
form_list = [ASNumberForm, InetNumForm]
|
||||||
|
template_name = "whoisdb/wizard.html"
|
||||||
|
|
||||||
|
def get_form_initial(self, step):
|
||||||
|
return {"handle": "AUTO"}
|
||||||
|
|
||||||
|
def done(self, form_list, **kwargs):
|
||||||
|
fl = list(form_list)
|
||||||
|
asNum = fl[0].save()
|
||||||
|
net = fl[1].save()
|
||||||
|
|
||||||
|
messages.info(self.request, "The following objects have been created: AS %s %s, Subnet %s %s" % (asNum.handle, asNum.number, net.handle, net.getNetwork()))
|
||||||
|
|
||||||
|
return HttpResponseRedirect(reverse("whoisdb:dashboard"))
|
||||||
|
|
||||||
|
def get_form_kwargs(self, *args, **kwargs):
|
||||||
|
kwargs = super(ASAndSubnetWizard, self).get_form_kwargs(*args, **kwargs)
|
||||||
|
kwargs["user"] = self.request.user
|
||||||
|
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
d = super(ASAndSubnetWizard, self).get_context_data(*args, **kwargs)
|
||||||
|
|
||||||
|
step = d["wizard"]["steps"].step1
|
||||||
|
if step == 1:
|
||||||
|
d["message"] = "Create an AS object"
|
||||||
|
elif step == 2:
|
||||||
|
d["message"] = "Create a Subnet"
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
Loading…
Reference in New Issue