1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Introduced CBVs for IPAM Roles

This commit is contained in:
Jeremy Stretch
2016-05-17 15:04:16 -04:00
parent a527e0e527
commit ff46970ba9
9 changed files with 167 additions and 58 deletions

View File

@ -5,7 +5,7 @@ from django.db.models import Count
from dcim.models import Site, Device, Interface
from utilities.forms import BootstrapMixin, ConfirmationForm, APISelect, Livesearch, CSVDataField, BulkImportForm
from .models import VRF, RIR, Aggregate, Prefix, IPAddress, VLAN, Status, Role
from .models import VRF, RIR, Aggregate, Role, Status, Prefix, IPAddress, VLAN
#
@ -110,6 +110,21 @@ class AggregateFilterForm(forms.Form, BootstrapMixin):
widget=forms.SelectMultiple(attrs={'size': 8}))
#
# Roles
#
class RoleForm(forms.ModelForm, BootstrapMixin):
class Meta:
model = Role
fields = ['name', 'slug']
class RoleBulkDeleteForm(ConfirmationForm):
pk = forms.ModelMultipleChoiceField(queryset=Role.objects.all(), widget=forms.MultipleHiddenInput)
#
# Prefixes
#

View File

@ -44,38 +44,6 @@ class VRF(models.Model):
return reverse('ipam:vrf', args=[self.pk])
class Status(models.Model):
"""
The status of a prefix or VLAN (e.g. allocated, reserved, etc.)
"""
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
weight = models.PositiveSmallIntegerField(default=1000)
bootstrap_class = models.PositiveSmallIntegerField(choices=BOOTSTRAP_CLASS_CHOICES, default=0)
class Meta:
ordering = ['weight', 'name']
verbose_name_plural = 'statuses'
def __unicode__(self):
return self.name
class Role(models.Model):
"""
The role of an address resource (e.g. customer, infrastructure, mgmt, etc.)
"""
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
weight = models.PositiveSmallIntegerField(default=1000)
class Meta:
ordering = ['weight', 'name']
def __unicode__(self):
return self.name
class RIR(models.Model):
"""
A regional Internet registry (e.g. ARIN) or governing standard (e.g. RFC 1918)
@ -149,6 +117,46 @@ class Aggregate(models.Model):
return int(children_size / self.prefix.size * 100)
class Status(models.Model):
"""
The status of a prefix or VLAN (e.g. allocated, reserved, etc.)
"""
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
weight = models.PositiveSmallIntegerField(default=1000)
bootstrap_class = models.PositiveSmallIntegerField(choices=BOOTSTRAP_CLASS_CHOICES, default=0)
class Meta:
ordering = ['weight', 'name']
verbose_name_plural = 'statuses'
def __unicode__(self):
return self.name
class Role(models.Model):
"""
The role of an address resource (e.g. customer, infrastructure, mgmt, etc.)
"""
name = models.CharField(max_length=50, unique=True)
slug = models.SlugField(unique=True)
weight = models.PositiveSmallIntegerField(default=1000)
class Meta:
ordering = ['weight', 'name']
def __unicode__(self):
return self.name
@property
def count_prefixes(self):
return self.prefixes.count()
@property
def count_vlans(self):
return self.vlans.count()
class PrefixQuerySet(models.QuerySet):
def annotate_depth(self, limit=None):

View File

@ -1,7 +1,7 @@
import django_tables2 as tables
from django_tables2.utils import Accessor
from .models import VRF, RIR, Aggregate, Prefix, IPAddress, VLAN
from .models import VRF, RIR, Aggregate, Role, Prefix, IPAddress, VLAN
RIR_EDIT_LINK = """
@ -19,6 +19,10 @@ UTILIZATION_GRAPH = """
{% endwith %}
"""
ROLE_EDIT_LINK = """
{% if perms.ipam.change_role %}<a href="{% url 'ipam:role_edit' slug=record.slug %}">Edit</a>{% endif %}
"""
PREFIX_LINK = """
{% if record.has_children %}
<span style="padding-left: {{ record.depth }}0px "><i class="fa fa-caret-right"></i></a>
@ -105,6 +109,27 @@ class AggregateTable(tables.Table):
}
#
# Roles
#
class RoleTable(tables.Table):
pk = tables.CheckBoxColumn(visible=False, default='')
name = tables.Column(verbose_name='Name')
prefix_count = tables.Column(accessor=Accessor('count_prefixes'), orderable=False, verbose_name='Prefixes')
vlan_count = tables.Column(accessor=Accessor('count_vlans'), orderable=False, verbose_name='VLANs')
slug = tables.Column(verbose_name='Slug')
edit = tables.TemplateColumn(template_code=ROLE_EDIT_LINK, verbose_name='')
class Meta:
model = Role
fields = ('pk', 'name', 'prefix_count', 'vlan_count', 'slug', 'edit')
empty_text = "No roles were found."
attrs = {
'class': 'table table-hover',
}
#
# Prefixes
#

View File

@ -30,6 +30,12 @@ urlpatterns = [
url(r'^aggregates/(?P<pk>\d+)/edit/$', views.AggregateEditView.as_view(), name='aggregate_edit'),
url(r'^aggregates/(?P<pk>\d+)/delete/$', views.AggregateDeleteView.as_view(), name='aggregate_delete'),
# Roles
url(r'^roles/$', views.RoleListView.as_view(), name='role_list'),
url(r'^roles/add/$', views.RoleEditView.as_view(), name='role_add'),
url(r'^roles/delete/$', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'),
url(r'^roles/(?P<slug>[\w-]+)/edit/$', views.RoleEditView.as_view(), name='role_edit'),
# Prefixes
url(r'^prefixes/$', views.PrefixListView.as_view(), name='prefix_list'),
url(r'^prefixes/add/$', views.PrefixEditView.as_view(), name='prefix_add'),

View File

@ -14,12 +14,12 @@ from utilities.views import BulkImportView, BulkEditView, BulkDeleteView, Object
from .filters import AggregateFilter, PrefixFilter, IPAddressFilter, VLANFilter, VRFFilter
from .forms import AggregateForm, AggregateImportForm, AggregateBulkEditForm, AggregateBulkDeleteForm,\
AggregateFilterForm, PrefixForm, PrefixImportForm, PrefixBulkEditForm, PrefixBulkDeleteForm, PrefixFilterForm,\
IPAddressForm, IPAddressImportForm, IPAddressBulkEditForm, IPAddressBulkDeleteForm, IPAddressFilterForm, VLANForm,\
VLANImportForm, VLANBulkEditForm, VLANBulkDeleteForm, VRFForm, VRFImportForm, VRFBulkEditForm, VRFBulkDeleteForm,\
VLANFilterForm, RIRForm, RIRBulkDeleteForm
from .models import VRF, RIR, Aggregate, Prefix, IPAddress, VLAN
from .tables import VRFTable, RIRTable, AggregateTable, PrefixTable, PrefixBriefTable, IPAddressBriefTable,\
AggregateFilterForm, RoleForm, RoleBulkDeleteForm, PrefixForm, PrefixImportForm, PrefixBulkEditForm,\
PrefixBulkDeleteForm, PrefixFilterForm, IPAddressForm, IPAddressImportForm, IPAddressBulkEditForm,\
IPAddressBulkDeleteForm, IPAddressFilterForm, VLANForm, VLANImportForm, VLANBulkEditForm, VLANBulkDeleteForm,\
VRFForm, VRFImportForm, VRFBulkEditForm, VRFBulkDeleteForm, VLANFilterForm, RIRForm, RIRBulkDeleteForm
from .models import VRF, RIR, Aggregate, Role, Prefix, IPAddress, VLAN
from .tables import VRFTable, RIRTable, AggregateTable, RoleTable, PrefixTable, PrefixBriefTable, IPAddressBriefTable,\
IPAddressTable, VLANTable
@ -217,6 +217,32 @@ class AggregateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
default_redirect_url = 'ipam:aggregate_list'
#
# Prefix/VLAN roles
#
class RoleListView(ObjectListView):
queryset = Role.objects.all()
table = RoleTable
edit_permissions = ['ipam.change_role', 'ipam.delete_role']
template_name = 'ipam/role_list.html'
class RoleEditView(PermissionRequiredMixin, ObjectEditView):
permission_required = 'ipam.change_role'
model = Role
form_class = RoleForm
success_url = 'ipam:role_list'
cancel_url = 'ipam:role_list'
class RoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'ipam.delete_role'
cls = Role
form = RoleBulkDeleteForm
default_redirect_url = 'ipam:role_list'
#
# Prefixes
#

View File

@ -35,9 +35,7 @@
<li><a href="{% url 'dcim:rack_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Rack</a></li>
<li><a href="{% url 'dcim:rack_import' %}"><i class="glyphicon glyphicon-import" aria-hidden="true"></i> Import Racks</a></li>
{% endif %}
{% if perms.dcim.add_rack or perms.dcim.add_rackgroup %}
<li class="divider"></li>
{% endif %}
<li class="divider"></li>
<li><a href="{% url 'dcim:rackgroup_list' %}"><i class="glyphicon glyphicon-search" aria-hidden="true"></i> Rack Groups</a></li>
{% if perms.dcim.add_rackgroup %}
<li><a href="{% url 'dcim:rackgroup_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Rack Group</a></li>
@ -59,19 +57,21 @@
{% if perms.dcim.add_devicetype %}
<li><a href="{% url 'dcim:devicetype_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Device Type</a></li>
{% endif %}
{% if perms.ipam.add_devicetype or perms.ipam.add_devicerole %}
<li class="divider"></li>
{% endif %}
<li class="divider"></li>
<li><a href="{% url 'dcim:devicerole_list' %}"><i class="glyphicon glyphicon-search" aria-hidden="true"></i> Device Roles</a></li>
{% if perms.dcim.add_devicerole %}
<li><a href="{% url 'dcim:devicerole_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Device Role</a></li>
{% endif %}
<li class="divider"></li>
{% if perms.dcim.add_devicerole or perms.dcim.add_manufacturer %}
<li class="divider"></li>
{% endif %}
<li><a href="{% url 'dcim:manufacturer_list' %}"><i class="glyphicon glyphicon-search" aria-hidden="true"></i> Manufacturers</a></li>
{% if perms.dcim.add_manufacturer %}
<li><a href="{% url 'dcim:manufacturer_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Manufacturer</a></li>
{% endif %}
<li class="divider"></li>
{% if perms.dcim.add_manufacturer or perms.dcim.add_platform %}
<li class="divider"></li>
{% endif %}
<li><a href="{% url 'dcim:platform_list' %}"><i class="glyphicon glyphicon-search" aria-hidden="true"></i> Platforms</a></li>
{% if perms.dcim.add_platform %}
<li><a href="{% url 'dcim:platform_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Platform</a></li>
@ -101,7 +101,7 @@
{% endif %}
</ul>
</li>
<li class="dropdown{% if '/ipam/ip-addresses/' in request.path or '/prefixes/' in request.path or '/aggregates/' in request.path or '/vrfs/' in request.path or '/rirs/' in request.path %} active{% endif %}">
<li class="dropdown{% if '/ipam/' in request.path and not '/ipam/vlans/' in request.path %} active{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">IP Space <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'ipam:ipaddress_list' %}"><i class="glyphicon glyphicon-search" aria-hidden="true"></i> IP Addresses</a></li>
@ -138,9 +138,16 @@
{% if perms.ipam.add_rir %}
<li><a href="{% url 'ipam:rir_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a RIR</a></li>
{% endif %}
{% if perms.ipam.add_rir or perms.ipam.add_role %}
<li class="divider"></li>
{% endif %}
<li><a href="{% url 'ipam:role_list' %}"><i class="glyphicon glyphicon-search" aria-hidden="true"></i> Prefix/VLAN Roles</a></li>
{% if perms.ipam.add_role %}
<li><a href="{% url 'ipam:role_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Role</a></li>
{% endif %}
</ul>
</li>
<li class="dropdown{% if '/vlans/' in request.path %} active{% endif %}">
<li class="dropdown{% if '/ipam/vlans/' in request.path %} active{% endif %}">
{% if perms.ipam.add_vlan %}
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">VLANs <span class="caret"></span></a>
<ul class="dropdown-menu">
@ -168,9 +175,7 @@
<li><a href="{% url 'circuits:circuit_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Circuit</a></li>
<li><a href="{% url 'circuits:circuit_import' %}"><i class="glyphicon glyphicon-import" aria-hidden="true"></i> Import Circuits</a></li>
{% endif %}
{% if perms.circuits.add_circuit or perms.circuits.add_circuittype %}
<li class="divider"></li>
{% endif %}
<li class="divider"></li>
<li><a href="{% url 'circuits:circuittype_list' %}"><i class="glyphicon glyphicon-search" aria-hidden="true"></i> Circuit Types</a></li>
{% if perms.circuits.add_circuittype %}
<li><a href="{% url 'circuits:circuittype_add' %}"><i class="glyphicon glyphicon-plus" aria-hidden="true"></i> Add a Circuit Type</a></li>

View File

@ -5,7 +5,7 @@
{% block content %}
<div class="pull-right">
{% if perms.dcim.add_devicerole %}
{% if perms.ipam.add_rir %}
<a href="{% url 'ipam:rir_add' %}" class="btn btn-primary">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
Add a RIR

View File

@ -0,0 +1,21 @@
{% extends '_base.html' %}
{% load helpers %}
{% block title %}Prefix/VLAN Roles{% endblock %}
{% block content %}
<div class="pull-right">
{% if perms.dcim.add_devicerole %}
<a href="{% url 'ipam:role_add' %}" class="btn btn-primary">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
Add a role
</a>
{% endif %}
</div>
<h1>Prefix/VLAN Roles</h1>
<div class="row">
<div class="col-md-12">
{% include 'utilities/obj_table.html' with bulk_delete_url='ipam:role_bulk_delete' %}
</div>
</div>
{% endblock %}

View File

@ -116,10 +116,13 @@ class ObjectEditView(View):
obj = form.save(commit=False)
obj_created = not obj.pk
obj.save()
messages.success(request, '{} {} <a href="{}">{}</a>'.format('Created' if obj_created else 'Modified',
self.model._meta.verbose_name,
obj.get_absolute_url(),
obj))
msg = 'Created ' if obj_created else 'Modified '
msg += self.model._meta.verbose_name
if hasattr(obj, 'get_absolute_url'):
msg += ' <a href="{}">{}</a>'.format(obj.get_absolute_url(), obj)
else:
msg += ' {}'.format(obj)
messages.success(request, msg)
if '_addanother' in request.POST:
return redirect(request.path)
elif self.success_url: