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:
@ -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
|
||||
#
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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'),
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
21
netbox/templates/ipam/role_list.html
Normal file
21
netbox/templates/ipam/role_list.html
Normal 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 %}
|
@ -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:
|
||||
|
Reference in New Issue
Block a user