Good, good, queryset foo

This commit is contained in:
Sebastian Lohff 2017-03-21 02:36:07 +01:00
parent baa2dcc38b
commit 189ae23b4a
12 changed files with 303 additions and 58 deletions

View File

@ -1,10 +1,14 @@
from django import forms from django import forms
from django.db.models import Q
from whoisdb.models import InetNum
from whoisdb.forms import MntFormMixin from whoisdb.forms import MntFormMixin
from whoisdb.validators import IP46CIDRValidator
from .models import Domain, Nameserver from .models import Domain, Nameserver, ReverseZone
import re import re
import ipaddress
class DomainForm(MntFormMixin, forms.ModelForm): class DomainForm(MntFormMixin, forms.ModelForm):
@ -17,11 +21,17 @@ class DomainForm(MntFormMixin, forms.ModelForm):
super(DomainForm, self).__init__(*args, **kwargs) super(DomainForm, self).__init__(*args, **kwargs)
mnts = self._user.maintainer_set.all()
self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts))
instance = getattr(self, "instance", None) instance = getattr(self, "instance", None)
self._create = not (instance and instance.pk) self._create = not (instance and instance.pk)
if not self._create: if not self._create:
self.fields['name'].disabled = True self.fields['name'].disabled = True
self.fields['nameservers'].queryset |= self.instance.nameservers.all()
self.fields['nameservers'].queryset.distinct()
def clean_name(self): def clean_name(self):
name = self.cleaned_data['name'].lower() name = self.cleaned_data['name'].lower()
@ -87,3 +97,56 @@ class NameserverForm(MntFormMixin, forms.ModelForm):
cleaned_data = super(NameserverForm, self).clean() cleaned_data = super(NameserverForm, self).clean()
return cleaned_data return cleaned_data
class ReverseZoneForm(forms.ModelForm):
prefix = forms.CharField(validators=[IP46CIDRValidator])
class Meta:
model = ReverseZone
fields = ['parentNet', 'nameservers']
def __init__(self, user, *args, **kwargs):
self._user = user
super(ReverseZoneForm, self).__init__(*args, **kwargs)
instance = getattr(self, "instance", None)
self._create = not (instance and instance.pk)
mnts = self._user.maintainer_set.all()
self.fields['parentNet'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct()
self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts))
if not self._create:
self.fields['prefix'].disabled = True
self.fields['nameservers'].queryset |= self.instance.nameservers.all()
self.fields['nameservers'].queryset.distinct()
def clean(self):
cleaned_data = super(ReverseZoneForm, self).clean()
if not self.errors:
if self._create:
net = ipaddress.ip_network(cleaned_data['prefix'])
parentNet = cleaned_data['parentNet'].getNetwork()
if net.network_address not in parentNet:
raise forms.ValidationError("Given prefix %s is not inside of parent netblock %s" % (net, parentNet))
# For now just check all the zones...
#zones = ReverseZone.objects.filter(parentNet=cleaned_data['parentNet'])
zones = ReverseZone.objects.all()
for zone in zones:
if net.network_address in zone.parentNet.getNetwork():
raise forms.ValidationError("Given prefix already has a reverse zone object associated to it: %s" % zone)
self.instance.address = str(net.network_address)
self.instance.netmask = net.prefixlen
return cleaned_data

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-14 21:04 # Generated by Django 1.10.5 on 2017-03-20 11:31
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

View File

@ -3,6 +3,8 @@ from django.urls import reverse
from whoisdb.models import MntdObject, Contact, InetNum from whoisdb.models import MntdObject, Contact, InetNum
import ipaddress
# generally allow domains for .dn to be created # generally allow domains for .dn to be created
# allow owners of a subnet to create reverse dns record? # allow owners of a subnet to create reverse dns record?
@ -49,12 +51,6 @@ class Domain(MntdObject):
return reasons return reasons
#class NameserverDomainAssignment(models.Model):
# domain = models.ForeignKey(Domain)
# nameserver = models.ForeignKey(Nameserver)
#
# order = models.PositiveSmallIntegerField(default=0)
class ReverseZone(models.Model): class ReverseZone(models.Model):
parentNet = models.ForeignKey(InetNum) parentNet = models.ForeignKey(InetNum)
@ -63,9 +59,18 @@ class ReverseZone(models.Model):
nameservers = models.ManyToManyField(Nameserver) nameservers = models.ManyToManyField(Nameserver)
def prefix(self):
""" Helper function, mainly used in templates """
return "%s/%s" % (self.address, self.netmask)
#class NameserverReverseZoneAssignment(models.Model): def getNetwork(self):
# reversezone = models.ForeignKey(ReverseZone) return ipaddress.ip_network(self.prefix())
# nameserver = models.ForeignKey(Nameserver)
# def get_absolute_url(self):
# order = models.PositiveSmallIntegerField() return reverse("domains:reversezone-show", args=(self.pk,))
def __str__(self):
return "%s @ %s" % (self.prefix(), self.parentNet)
def getNoDeleteReasons(self):
return []

View File

@ -14,4 +14,10 @@ urlpatterns = [
url(r'nameserver/show/(?P<domain>[a-z0-9.-]+)/$', domains_views.NameserverDetail.as_view(), name='nameserver-show'), url(r'nameserver/show/(?P<domain>[a-z0-9.-]+)/$', domains_views.NameserverDetail.as_view(), name='nameserver-show'),
url(r'nameserver/edit/(?P<domain>[a-z0-9.-]+)/$', domains_views.NameserverEdit.as_view(), name='nameserver-edit'), url(r'nameserver/edit/(?P<domain>[a-z0-9.-]+)/$', domains_views.NameserverEdit.as_view(), name='nameserver-edit'),
url(r'nameserver/delete/(?P<domain>[a-z0-9.-]+)/$', domains_views.NameserverDelete.as_view(), name='nameserver-delete'), url(r'nameserver/delete/(?P<domain>[a-z0-9.-]+)/$', domains_views.NameserverDelete.as_view(), name='nameserver-delete'),
url(r'reversezone/create/$', domains_views.ReverseZoneCreate.as_view(), name='reversezone-create'),
url(r'reversezone/show/(?P<pk>[0-9]+)/$', domains_views.ReverseZoneDetail.as_view(), name='reversezone-show'),
url(r'reversezone/edit/(?P<pk>[0-9]+)/$', domains_views.ReverseZoneEdit.as_view(), name='reversezone-edit'),
url(r'reversezone/delete/(?P<pk>[0-9]+)/$', domains_views.ReverseZoneDelete.as_view(), name='reversezone-delete'),
] ]

View File

@ -3,11 +3,12 @@ from django.urls import reverse_lazy
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
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.db.models import Q
from whoisdb.generic import MntGenericMixin, DeleteCheckView from whoisdb.generic import MntGenericMixin, DeleteCheckView
from .models import Domain, Nameserver from .models import Domain, Nameserver, ReverseZone
from .forms import DomainForm, NameserverForm from .forms import DomainForm, NameserverForm, ReverseZoneForm
@login_required @login_required
@ -15,10 +16,11 @@ def overview(request):
mnts = request.user.maintainer_set.all() mnts = request.user.maintainer_set.all()
# get all domains and nameservers # get all domains and nameservers
domains = Domain.objects.filter(mnt_by__in=mnts) domains = Domain.objects.filter(mnt_by__in=mnts).distinct()
nameservers = Nameserver.objects.filter(mnt_by__in=mnts) nameservers = Nameserver.objects.filter(mnt_by__in=mnts).distinct()
reversezones = ReverseZone.objects.filter(parentNet__mnt_by__in=mnts).distinct()
return render(request, "domains/overview.html", {"domains": domains, "nameservers": nameservers}) return render(request, "domains/overview.html", {"domains": domains, "nameservers": nameservers, 'reversezones': reversezones})
class DomainCreate(LoginRequiredMixin, CreateView): class DomainCreate(LoginRequiredMixin, CreateView):
@ -38,6 +40,8 @@ class DomainDetail(LoginRequiredMixin, DetailView):
slug_url_kwarg = "domain" slug_url_kwarg = "domain"
context_object_name = "domain" context_object_name = "domain"
template_name = "domains/handle_show.html"
class DomainEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): class DomainEdit(MntGenericMixin, LoginRequiredMixin, UpdateView):
model = Domain model = Domain
@ -97,3 +101,55 @@ class NameserverDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView):
slug_field = "name" slug_field = "name"
slug_url_kwarg = "domain" slug_url_kwarg = "domain"
success_url = reverse_lazy("domains:overview") success_url = reverse_lazy("domains:overview")
class ReverseZoneCreate(LoginRequiredMixin, CreateView):
template_name = "domains/obj_create.html"
form_class = ReverseZoneForm
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(ReverseZoneCreate, self).get_form_kwargs(*args, **kwargs)
kwargs["user"] = self.request.user
return kwargs
class ReverseZoneDetail(LoginRequiredMixin, DetailView):
model = ReverseZone
slug_field = "name"
slug_url_kwarg = "domain"
context_object_name = "nameserver"
class ReverseZoneEdit(MntGenericMixin, LoginRequiredMixin, UpdateView):
model = ReverseZone
form_class = ReverseZoneForm
#slug_field = "name"
#slug_url_kwarg = "domain"
template_name = "domains/obj_edit.html"
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(ReverseZoneEdit, self).get_form_kwargs(*args, **kwargs)
kwargs["user"] = self.request.user
if not "initial" in kwargs:
kwargs["initial"] = {}
kwargs["initial"]["prefix"] = self.object.prefix()
return kwargs
def get_queryset(self):
mnts = self.request.user.maintainer_set.all()
return ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct()
class ReverseZoneDelete(LoginRequiredMixin, DeleteCheckView):
template_name = "domains/obj_delete.html"
model = ReverseZone
success_url = reverse_lazy("domains:overview")
#slug_field = "name"
#slug_url_kwarg = "domain"
def get_queryset(self):
mnts = self.request.user.maintainer_set.all()
return ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct()

View File

@ -0,0 +1,34 @@
{% extends "base.html" %}
{% load handletags %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">{{ object }} <small>({{ object.getClassName }})</small></div>
<div class="panel-body">
<table class="table">
{% for field in object|getFields:user %}
<tr>
<td>{{ field.0 }}</td>
<td>{% if field.1.through %}{{ field.1.all|linkObjects|default:"-" }}{% else %}{{ field.1|default:"-" }}{% endif %}</td>
</tr>
{% endfor %}
{% if object|userCanEdit:user %}
<tr>
<td>Actions</td>
{% with "domains:"|add:object.getClassName|lower|add:"-edit" as editView %}
{% with "domains:"|add:object.getClassName|lower|add:"-delete" as deleteView %}
<td><a href="{% url editView object.name %}">Edit object<a/>, <a href="{% url deleteView object.name %}">Delete object</a></td>
{% endwith %}
{% endwith %}
</tr>
{% endif %}
</table>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -6,7 +6,7 @@
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<div class="panel panel-{% if reasons %}danger{%else%}default{%endif%}"> <div class="panel panel-{% if reasons %}danger{%else%}default{%endif%}">
<div class="panel-heading">Header</div> <div class="panel-heading">Delete {{ object }}?</div>
<div class="panel-body"> <div class="panel-body">
{% if reasons %} {% if reasons %}
<p> <p>
@ -19,10 +19,12 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
{{ obj }} <p>
Are you sure you want to delete {{ object }}?
</p>
<form method="post" action="#"> <form method="post" action="#">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-primary">Delete</button> <button type="submit" class="btn btn-primary">Delete {{ object }}</button>
</form> </form>
{% endif %} {% endif %}
</div> </div>

View File

@ -1,13 +1,14 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load handletags %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Resource Requests</div> <div class="panel-heading">DNS Overview</div>
<div class="panel-body"> <div class="panel-body">
<p> <h4>Your Nameservers (<a href="{% url "domains:nameserver-create" %}">New nameserver</a>)</h4>
Your nameservers (<a href="{% url "domains:nameserver-create" %}">New nameserver</a>)
<table class="table"> <table class="table">
<tr> <tr>
<th>Nameserver</th> <th>Nameserver</th>
@ -19,35 +20,62 @@
{% for nameserver in nameservers %} {% for nameserver in nameservers %}
<tr> <tr>
<td><a href="{% url "domains:nameserver-show" nameserver.name %}">{{ nameserver.name }}</a></td> <td><a href="{% url "domains:nameserver-show" nameserver.name %}">{{ nameserver.name }}</a></td>
<td></td> <td>{{ nameserver.glueIPv4|default:"-" }}</td>
<td></td> <td>{{ nameserver.glueIPv6|default:"-" }}</td>
<td></td> <td>{{ nameserver.mnt_by.all|linkObjects }}</td>
<td><a href="{% url "domains:nameserver-edit" nameserver.name %}">Edit</a> <a href="{% url "domains:nameserver-delete" nameserver.name %}">Delete</a></td> <td><a href="{% url "domains:nameserver-edit" nameserver.name %}">Edit</a> <a href="{% url "domains:nameserver-delete" nameserver.name %}">Delete</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</p>
<p> <h4>Your Domains (<a href="{% url "domains:domain-create" %}">New domain</a>)</h4>
Your domains (<a href="{% url "domains:domain-create" %}">New domain</a>)
<table class="table"> <table class="table">
<tr> <tr>
<th>Domain</th> <th>Domain</th>
<th>Nameserver</th> <th>Nameserver</th>
<th>Glue IPv6</th>
<th>MNTs</th> <th>MNTs</th>
<th></th> <th></th>
</tr> </tr>
{% for domain in domains %} {% for domain in domains %}
<tr> <tr>
<td><a href="{% url "domains:domain-show" domain.name %}">{{ domain.name }}</a></td> <td><a href="{% url "domains:domain-show" domain.name %}">{{ domain.name }}</a></td>
<td></td> <td>
<td></td> <ul>
<td></td> {% for nameserver in domain.nameservers.all %}
<li>{{ nameserver|linkObject }}</li>
{% endfor %}
</ul>
</td>
<td>{{ domain.mnt_by.all|linkObjects }}</td>
<td><a href="{% url "domains:domain-edit" domain.name %}">Edit</a> <a href="{% url "domains:domain-delete" domain.name %}">Delete</a></td> <td><a href="{% url "domains:domain-edit" domain.name %}">Edit</a> <a href="{% url "domains:domain-delete" domain.name %}">Delete</a></td>
</tr> </tr>
{{ domain }}<br />
{% endfor %} {% endfor %}
</table> </table>
<h4>Your Reverse Zones (<a href="{% url "domains:reversezone-create" %}">New reverse zone</a>)</h4>
<table class="table">
<tr>
<th>Zone</th>
<th>Network</th>
<th>Nameserver</th>
<th></th>
</tr>
{% for reversezone in reversezones %}
<tr>
<td><a href="{% url "domains:reversezone-show" reversezone.pk %}">{{ reversezone.prefix }}</a></td>
<td></td>
<td>
<ul>
{% for nameserver in domain.nameservers.all %}
<li>{{ nameserver|linkObject }}</li>
{% endfor %}
</ul>
</td>
<td><a href="{% url "domains:reversezone-edit" reversezone.pk %}">Edit</a> <a href="{% url "domains:reversezone-delete" reversezone.pk %}">Delete</a></td>
</tr>
{% endfor %}
</table>
</div> </div>
</div> </div>
</div> </div>

View File

@ -14,18 +14,19 @@ class WhoisObjectFormMixin(object):
instance = getattr(self, 'instance', None) instance = getattr(self, 'instance', None)
if instance and instance.pk: if instance and instance.pk:
self._create = False
self.fields['handle'].widget.attrs['readonly'] = True self.fields['handle'].widget.attrs['readonly'] = True
else:
self._create = True
# only show users contacts and already present contacts # only show users contacts and already present contacts
mnts = self._user.maintainer_set.all()
if 'admin_c' in self.fields: if 'admin_c' in self.fields:
self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by__in=self._user.maintainer_set.all()) self.fields['admin_c'].queryset = Contact.getMntQueryset(mnts, self.instance, "admin_c")
if instance and instance.pk:
self.fields['admin_c'].queryset |= instance.admin_c.all()
def clean_handle(self): def clean_handle(self):
instance = getattr(self, 'instance', None) if not self._create:
if instance and instance.pk: return self.instance.handle
return instance.handle
else: else:
return self.cleaned_data['handle'] return self.cleaned_data['handle']
@ -56,17 +57,14 @@ class MntFormMixin(object):
mntQs = Maintainer.objects.annotate(card=Case(*mntWhens, default=0, output_field=IntegerField())).order_by("-card") mntQs = Maintainer.objects.annotate(card=Case(*mntWhens, default=0, output_field=IntegerField())).order_by("-card")
self.fields["mnt_by"].queryset = mntQs self.fields["mnt_by"].queryset = mntQs
class MntForm(forms.ModelForm): if "mnt_lower" in self.fields:
self.fields["mnt_lower"].queryset = mntQs
class MntForm(WhoisObjectFormMixin, forms.ModelForm):
class Meta: class Meta:
model = Maintainer model = Maintainer
fields = ['handle', 'description', 'admin_c'] 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())
class MntInitialForm(MntForm): class MntInitialForm(MntForm):
class Meta: class Meta:
@ -82,7 +80,7 @@ class ContactForm(WhoisObjectFormMixin, forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs) super(ContactForm, self).__init__(*args, **kwargs)
self.fields['mnt_by'].queryset = Maintainer.objects.filter(auth=self._user) self.fields['mnt_by'].queryset = Maintainer.objects.filter(auth=self._user).distinct()
class ContactInitialForm(ContactForm): class ContactInitialForm(ContactForm):
@ -101,16 +99,18 @@ class InetNumForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(InetNumForm, self).__init__(*args, **kwargs) super(InetNumForm, self).__init__(*args, **kwargs)
if 'admin_c' in self.fields:
self.fields['admin_c'].queryset = Contact.objects.filter(mnt_by__in=self.user.maintainer_set.all())
instance = getattr(self, "instance", None)
if instance and instance.pk:
self.fields['admin_c'].queryset |= instance.admin_c.all()
if self._editLower: if self._editLower:
for key in self.protectedFields: for key in self.protectedFields:
self.fields[key].disabled = True self.fields[key].disabled = True
self.fields[key].widget.attrs['readonly'] = False
mnts = self._user.maintainer_set.all()
#self.fields['parent_range'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts))
#if not self._create:
# self.fields['parent_range'].queryset |= InetNum.objects.filter(pk=self.instance.pk)
#self.fields['parent_range'].queryset = self.fields['parent_range'].queryset.distinct()
self.fields['parent_range'].queryset = InetNum.getMntQueryset(mnts, self.instance, "parent_range")
def clean_prefix(self): def clean_prefix(self):
# make sure this is a subnet we're getting # make sure this is a subnet we're getting
@ -128,9 +128,19 @@ class InetNumForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
parent_range = self.cleaned_data.get('parent_range', None) parent_range = self.cleaned_data.get('parent_range', None)
# allow parent range to be unset for already present objects # allow parent range to be unset for already present objects
if not (self.instance and self.instance.pk) and not parent_range: if not parent_range and (self._create or not self._create and self.instance.parent_range):
raise forms.ValidationError("Parent range must be set") raise forms.ValidationError("Parent range must be set")
if not self._create and parent_range:
# make sure we don't have circular dependencies
obj = parent_range
while obj.parent_range:
if obj.pk == self.instance.pk:
raise forms.ValidationError("No circular dependencies allowed")
obj = obj.parent_range
return parent_range
def clean(self): def clean(self):
cleaned_data = super(InetNumForm, self).clean() cleaned_data = super(InetNumForm, self).clean()
@ -177,6 +187,9 @@ class ASBlockForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
if self.instance and self.instance.pk: if self.instance and self.instance.pk:
self.fields["parent_block"].disabled = True self.fields["parent_block"].disabled = True
mnts = self._user.maintainer_set.all()
self.fields['parent_block'].queryset = ASBlock.getMntQueryset(mnts, self.instance, "parent_block")
def clean(self): def clean(self):
cleaned_data = super(ASBlockForm, self).clean() cleaned_data = super(ASBlockForm, self).clean()
@ -229,6 +242,9 @@ class ASNumberForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm):
else: else:
self.fields["asblock"].disabled = True self.fields["asblock"].disabled = True
mnts = self._user.maintainer_set.all()
self.fields['asblock'].queryset = ASBlock.getMntQueryset(mnts, self.instance, "asblock")
def clean(self): def clean(self):
cleaned_data = super(ASNumberForm, self).clean() cleaned_data = super(ASNumberForm, self).clean()

View File

@ -1,8 +1,9 @@
import whoisdb.models import whoisdb.models
import domains.models
def _addFields(fields, obj, fieldNames): def _addFields(fields, obj, fieldNames):
for fieldName in fieldNames: for fieldName in fieldNames:
fields.append((fieldName.capitalize(), getattr(obj, fieldName))) fields.append((fieldName.capitalize().replace("_", " "), getattr(obj, fieldName)))
def getWhoisObjectFields(obj, owner): def getWhoisObjectFields(obj, owner):
@ -27,7 +28,15 @@ def getWhoisObjectFields(obj, owner):
elif c == whoisdb.models.InetNum: elif c == whoisdb.models.InetNum:
_addFields(fields, obj, ["name"]) _addFields(fields, obj, ["name"])
fields.append(("Address CIDR", obj.prefix())) fields.append(("Address CIDR", obj.prefix()))
_addFields(fields, obj, ["description", "mnt_by", "mnt_lower", "admin_c"]) _addFields(fields, obj, ["description", "parent_range", "mnt_by", "mnt_lower", "admin_c"])
elif c == domains.models.Domain:
_addFields(fields, obj, ["name", "nameservers", "mnt_by", "admin_c"])
elif c == domains.models.Nameserver:
_addFields(fields, obj, ["name", "glueIPv4", "glueIPv6", "mnt_by", "admin_c"])
elif c == domains.models.ReverseZone:
_addFields(fields, obj, ["name"])
fields.append(("Address CIDR", obj.prefix()))
_addFields(fields, obj, ["parentNet", "nameservers"])
return fields return fields

View File

@ -1,4 +1,5 @@
from django.db import models from django.db import models
from django.db.models import Q
from django.urls import reverse from django.urls import reverse
from dncore.models import User from dncore.models import User
@ -111,6 +112,20 @@ class MntdObject(WhoisObject):
return True return True
return False return False
@classmethod
def getMntQueryset(clazz, mnts, instance, attr=None):
mntQ = Q(mnt_by__in=mnts)
if hasattr(clazz, "mnt_lower"):
mntQ |= Q(mnt_lower__in=mnts)
qs = clazz.objects.filter(mntQ)
if attr and instance and instance.pk:
if type(getattr(instance, attr)) == models.ManyToManyField:
qs |= getattr(instance, attr).all()
else:
qs |= clazz.objects.filter(pk=instance.pk)
return qs.distinct()
class Contact(MntdObject): class Contact(MntdObject):
handleSuffix = "DN" handleSuffix = "DN"

View File

@ -1,9 +1,11 @@
from django.core import validators from django.core import validators
from django.core.exceptions import ValidationError
from django.utils import six from django.utils import six
from django.utils.deconstruct import deconstructible from django.utils.deconstruct import deconstructible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import re import re
import ipaddress
@deconstructible @deconstructible
@ -26,3 +28,12 @@ class HandleValidatorWithSuffix(validators.RegexValidator):
) )
super(HandleValidatorWithSuffix, self).__init__() super(HandleValidatorWithSuffix, self).__init__()
def IP46CIDRValidator(value):
if not re.match(r"[0-9:.]+/[0-9]+", value):
raise ValidationError("Address needs to be a subnet in the format of ip/cidr")
try:
ipaddress.ip_network(value)
except ValueError as e:
raise ValidationError(str(e))