Skip to content

Commit

Permalink
Merge pull request #1032 from digitalocean/develop
Browse files Browse the repository at this point in the history
Release v1.9.4
  • Loading branch information
jeremystretch authored Apr 4, 2017
2 parents be393a9 + 3b2c740 commit 3ffe36e
Show file tree
Hide file tree
Showing 12 changed files with 59 additions and 29 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
**The [2017 NetBox User Survey](https://goo.gl/forms/75HnNS2iE0Y1hVFH3) is open!** Please consider taking a moment to respond. Your feedback helps shape the pace and focus of NetBox development. The survey will remain open until 2017-03-31. Results will be published on the mailing list.

---

![NetBox](docs/netbox_logo.png "NetBox logo")

NetBox is an IP address management (IPAM) and data center infrastructure management (DCIM) tool. Initially conceived by the network engineering team at [DigitalOcean](https://www.digitalocean.com/), NetBox was developed specifically to address the needs of network and infrastructure engineers.
Expand Down
2 changes: 1 addition & 1 deletion netbox/dcim/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1481,7 +1481,7 @@ def __init__(self, device_a, *args, **kwargs):
super(InterfaceConnectionForm, self).__init__(*args, **kwargs)

# Initialize interface A choices
device_a_interfaces = Interface.objects.filter(device=device_a).exclude(
device_a_interfaces = Interface.objects.order_naturally().filter(device=device_a).exclude(
form_factor__in=VIRTUAL_IFACE_TYPES
).select_related(
'circuit_termination', 'connected_as_a', 'connected_as_b'
Expand Down
5 changes: 3 additions & 2 deletions netbox/dcim/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1450,9 +1450,10 @@ def interfaceconnection_add(request, pk):
))
if '_addanother' in request.POST:
base_url = reverse('dcim:interfaceconnection_add', kwargs={'pk': device.pk})
device_b = interfaceconnection.interface_b.device
params = urlencode({
'rack_b': interfaceconnection.interface_b.device.rack.pk,
'device_b': interfaceconnection.interface_b.device.pk,
'rack_b': device_b.rack.pk if device_b.rack else '',
'device_b': device_b.pk,
})
return HttpResponseRedirect('{}?{}'.format(base_url, params))
else:
Expand Down
9 changes: 7 additions & 2 deletions netbox/extras/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@
ACTION_BULK_EDIT = 4
ACTION_DELETE = 5
ACTION_BULK_DELETE = 6
ACTION_BULK_CREATE = 7
ACTION_CHOICES = (
(ACTION_CREATE, 'created'),
(ACTION_BULK_CREATE, 'bulk created'),
(ACTION_IMPORT, 'imported'),
(ACTION_EDIT, 'modified'),
(ACTION_BULK_EDIT, 'bulk edited'),
(ACTION_DELETE, 'deleted'),
(ACTION_BULK_DELETE, 'bulk deleted')
(ACTION_BULK_DELETE, 'bulk deleted'),
)


Expand Down Expand Up @@ -328,6 +330,9 @@ def log_bulk_action(self, user, content_type, action, message):
def log_import(self, user, content_type, message=''):
self.log_bulk_action(user, content_type, ACTION_IMPORT, message)

def log_bulk_create(self, user, content_type, message=''):
self.log_bulk_action(user, content_type, ACTION_BULK_CREATE, message)

def log_bulk_edit(self, user, content_type, message=''):
self.log_bulk_action(user, content_type, ACTION_BULK_EDIT, message)

Expand Down Expand Up @@ -358,7 +363,7 @@ def __str__(self):
return u'{} {} {}'.format(self.user, self.get_action_display(), self.content_type)

def icon(self):
if self.action in [ACTION_CREATE, ACTION_IMPORT]:
if self.action in [ACTION_CREATE, ACTION_BULK_CREATE, ACTION_IMPORT]:
return mark_safe('<i class="glyphicon glyphicon-plus text-success"></i>')
elif self.action in [ACTION_EDIT, ACTION_BULK_EDIT]:
return mark_safe('<i class="glyphicon glyphicon-pencil text-warning"></i>')
Expand Down
22 changes: 19 additions & 3 deletions netbox/ipam/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django_tables2 import RequestConfig
import netaddr

from django.conf import settings
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib import messages
Expand Down Expand Up @@ -295,7 +296,12 @@ def aggregate(request, pk):
prefix_table = tables.PrefixTable(child_prefixes)
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'):
prefix_table.base_columns['pk'].visible = True
RequestConfig(request, paginate={'klass': EnhancedPaginator}).configure(prefix_table)

paginate = {
'klass': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(prefix_table)

# Compile permissions list for rendering the object table
permissions = {
Expand Down Expand Up @@ -427,7 +433,12 @@ def prefix(request, pk):
child_prefix_table = tables.PrefixTable(child_prefixes)
if request.user.has_perm('ipam.change_prefix') or request.user.has_perm('ipam.delete_prefix'):
child_prefix_table.base_columns['pk'].visible = True
RequestConfig(request, paginate={'klass': EnhancedPaginator}).configure(child_prefix_table)

paginate = {
'klass': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(child_prefix_table)

# Compile permissions list for rendering the object table
permissions = {
Expand Down Expand Up @@ -500,7 +511,12 @@ def prefix_ipaddresses(request, pk):
ip_table = tables.IPAddressTable(ipaddresses)
if request.user.has_perm('ipam.change_ipaddress') or request.user.has_perm('ipam.delete_ipaddress'):
ip_table.base_columns['pk'].visible = True
RequestConfig(request, paginate={'klass': EnhancedPaginator}).configure(ip_table)

paginate = {
'klass': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(ip_table)

# Compile permissions list for rendering the object table
permissions = {
Expand Down
2 changes: 1 addition & 1 deletion netbox/netbox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"the documentation.")


VERSION = '1.9.3'
VERSION = '1.9.4'

# Import local configuration
for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
Expand Down
16 changes: 8 additions & 8 deletions netbox/templates/_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<div id="navbar" class="navbar-collapse collapse">
{% if request.user.is_authenticated or not settings.LOGIN_REQUIRED %}
<ul class="nav navbar-nav">
<li class="dropdown{% if request.path|startswith:'/dcim/sites/' or 'tenancy' in request.path %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/dcim/sites/,/dcim/regions/,/tenancy/' %} active{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Organization <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'dcim:site_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Sites</a></li>
Expand All @@ -54,7 +54,7 @@
{% endif %}
</ul>
</li>
<li class="dropdown{% if request.path|startswith:'/dcim/rack' %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/dcim/rack' %} active{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Racks <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'dcim:rack_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Racks</a></li>
Expand All @@ -74,7 +74,7 @@
{% endif %}
</ul>
</li>
<li class="dropdown{% if request.path|startswith:'/dcim/device' or request.path|startswith:'/dcim/manufacturers/' or request.path|startswith:'/dcim/platforms/' %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/dcim/device,/dcim/manufacturers/,/dcim/platforms/' %} active{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Devices <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'dcim:device_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Devices</a></li>
Expand Down Expand Up @@ -110,7 +110,7 @@
{% endif %}
</ul>
</li>
<li class="dropdown{% if request.path|startswith:'/dcim/console-connections/' or request.path|startswith:'/dcim/power-connections/' or request.path|startswith:'/dcim/interface-connections/' %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/dcim/console-connections/,/dcim/power-connections/,/dcim/interface-connections/' %} active{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Connections <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'dcim:console_connections_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Console Connections</a></li>
Expand All @@ -133,7 +133,7 @@
{% endif %}
</ul>
</li>
<li class="dropdown{% if request.path|startswith:'/ipam/' and not request.path|startswith:'/ipam/vlan' %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/ipam/' and not request.path|contains:'/ipam/vlan' %} 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="fa fa-search" aria-hidden="true"></i> IP Addresses</a></li>
Expand Down Expand Up @@ -179,7 +179,7 @@
{% endif %}
</ul>
</li>
<li class="dropdown{% if request.path|startswith:'/ipam/vlan' %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/ipam/vlan' %} active{% endif %}">
<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">
<li><a href="{% url 'ipam:vlan_list' %}"><i class="fa fa-search" aria-hidden="true"></i> VLANs</a></li>
Expand All @@ -199,7 +199,7 @@
{% endif %}
</ul>
</li>
<li class="dropdown{% if request.path|startswith:'/circuits/' %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/circuits/' %} active{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Circuits <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'circuits:provider_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Providers</a></li>
Expand All @@ -223,7 +223,7 @@
</ul>
</li>
{% if request.user.is_authenticated %}
<li class="dropdown{% if request.path|startswith:'/secrets/' %} active{% endif %}">
<li class="dropdown{% if request.path|contains:'/secrets/' %} active{% endif %}">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Secrets <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'secrets:secret_list' %}"><i class="fa fa-search" aria-hidden="true"></i> Secrets</a></li>
Expand Down
2 changes: 2 additions & 0 deletions netbox/templates/dcim/ipaddress_assign.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@
{% render_field form.set_as_primary %}
</div>
</div>
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
{% endif %}
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<button type="submit" name="_create" class="btn btn-primary">Create</button>
Expand Down
4 changes: 2 additions & 2 deletions netbox/templates/dcim/rack.html
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,12 @@ <h1>Rack {{ rack.name }}</h1>
<small>{{ resv.user }} &middot; {{ resv.created }}</small>
</td>
<td class="text-right">
{% if perms.change_rackreservation %}
{% if perms.dcim.change_rackreservation %}
<a href="{% url 'dcim:rackreservation_edit' pk=resv.pk %}" class="btn btn-warning btn-xs" title="Edit reservation">
<i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
</a>
{% endif %}
{% if perms.delete_rackreservation %}
{% if perms.dcim.delete_rackreservation %}
<a href="{% url 'dcim:rackreservation_delete' pk=resv.pk %}" class="btn btn-danger btn-xs" title="Delete reservation">
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
</a>
Expand Down
3 changes: 2 additions & 1 deletion netbox/utilities/paginator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
class EnhancedPaginator(Paginator):

def __init__(self, object_list, per_page, **kwargs):
per_page = getattr(settings, 'PAGINATE_COUNT', 50)
if not isinstance(per_page, int) or per_page < 1:
per_page = getattr(settings, 'PAGINATE_COUNT', 50)
super(EnhancedPaginator, self).__init__(object_list, per_page, **kwargs)

def _get_page(self, *args, **kwargs):
Expand Down
6 changes: 3 additions & 3 deletions netbox/utilities/templatetags/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ def gfm(value):


@register.filter()
def startswith(value, arg):
def contains(value, arg):
"""
Test whether a string starts with the given argument
Test whether a value contains any of a given set of strings. `arg` should be a comma-separated list of strings.
"""
return str(value).startswith(arg)
return any(s in value for s in arg.split(','))


#
Expand Down
13 changes: 11 additions & 2 deletions netbox/utilities/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections import OrderedDict
from django_tables2 import RequestConfig

from django.conf import settings
from django.contrib import messages
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
Expand Down Expand Up @@ -101,7 +102,13 @@ def get(self, request):
table = self.table(self.queryset)
if 'pk' in table.base_columns and (permissions['change'] or permissions['delete']):
table.base_columns['pk'].visible = True
RequestConfig(request, paginate={'klass': EnhancedPaginator}).configure(table)

# Apply the request context
paginate = {
'klass': EnhancedPaginator,
'per_page': request.GET.get('per_page', settings.PAGINATE_COUNT)
}
RequestConfig(request, paginate).configure(table)

context = {
'table': table,
Expand Down Expand Up @@ -327,7 +334,9 @@ def post(self, request):
form.add_error(None, e)

if not form.errors:
messages.success(request, u"Added {} {}.".format(len(new_objs), self.model._meta.verbose_name_plural))
msg = u"Added {} {}".format(len(new_objs), self.model._meta.verbose_name_plural)
messages.success(request, msg)
UserAction.objects.log_bulk_create(request.user, ContentType.objects.get_for_model(self.model), msg)
if '_addanother' in request.POST:
return redirect(request.path)
return redirect(self.default_return_url)
Expand Down

0 comments on commit 3ffe36e

Please sign in to comment.