diff --git a/docs/configuration/optional-settings.md b/docs/configuration/optional-settings.md index 05e60dcacb..83b289b9aa 100644 --- a/docs/configuration/optional-settings.md +++ b/docs/configuration/optional-settings.md @@ -135,11 +135,53 @@ An API consumer can request an arbitrary number of objects by appending the "lim --- -## NETBOX_USERNAME +## NAPALM_USERNAME -## NETBOX_PASSWORD +## NAPALM_PASSWORD -If provided, NetBox will use these credentials to authenticate against devices when collecting data. +NetBox will use these credentials when authenticating to remote devices via the [NAPALM library](https://napalm-automation.net/), if installed. Both parameters are optional. + +Note: If SSH public key authentication has been set up for the system account under which NetBox runs, these parameters are not needed. + +--- + +## NAPALM_ARGS + +A dictionary of optional arguments to pass to NAPALM when instantiating a network driver. See the NAPALM documentation for a [complete list of optional arguments](http://napalm.readthedocs.io/en/latest/support/#optional-arguments). An example: + +``` +NAPALM_ARGS = { + 'api_key': '472071a93b60a1bd1fafb401d9f8ef41', + 'port': 2222, +} +``` + +Note: Some platforms (e.g. Cisco IOS) require an argument named `secret` to be passed in addition to the normal password. If desired, you can use the configured `NAPALM_PASSWORD` as the value for this argument: + +``` +NAPALM_USERNAME = 'username' +NAPALM_PASSWORD = 'MySecretPassword' +NAPALM_ARGS = { + 'secret': NAPALM_PASSWORD, + # Include any additional args here +} +``` + +--- + +## NAPALM_TIMEOUT + +Default: 30 seconds + +The amount of time (in seconds) to wait for NAPALM to connect to a device. + +--- + +## NETBOX_USERNAME (Deprecated) + +## NETBOX_PASSWORD (Deprecated) + +These settings have been deprecated and will be removed in NetBox v2.2. Please use `NAPALM_USERNAME` and `NAPALM_PASSWORD` instead. --- diff --git a/docs/installation/ldap.md b/docs/installation/ldap.md index 0d546863ee..b43105b8bb 100644 --- a/docs/installation/ldap.md +++ b/docs/installation/ldap.md @@ -72,7 +72,8 @@ AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,dc=example,dc=com" # You can map user attributes to Django attributes as so. AUTH_LDAP_USER_ATTR_MAP = { "first_name": "givenName", - "last_name": "sn" + "last_name": "sn", + "email": "mail" } ``` @@ -108,12 +109,3 @@ AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 * `is_active` - All users must be mapped to at least this group to enable authentication. Without this, users cannot log in. * `is_staff` - Users mapped to this group are enabled for access to the administration tools; this is the equivalent of checking the "staff status" box on a manually created user. This doesn't grant any specific permissions. * `is_superuser` - Users mapped to this group will be granted superuser status. Superusers are implicitly granted all permissions. - -It is also possible map user attributes to Django attributes: - -```python -AUTH_LDAP_USER_ATTR_MAP = { - "first_name": "givenName", - "last_name": "sn", -} -``` diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index d32c63bfa6..56d4221da7 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -3,7 +3,6 @@ from rest_framework.decorators import detail_route from rest_framework.mixins import ListModelMixin -from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet, ModelViewSet, ViewSet @@ -21,7 +20,7 @@ from extras.api.serializers import RenderedGraphSerializer from extras.api.views import CustomFieldModelViewSet from extras.models import Graph, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE -from utilities.api import ServiceUnavailable, WritableSerializerMixin +from utilities.api import IsAuthenticatedOrLoginNotRequired, ServiceUnavailable, WritableSerializerMixin from .exceptions import MissingFilterException from . import serializers @@ -272,15 +271,17 @@ def napalm(self, request, pk): ip_address = str(device.primary_ip.address.ip) d = driver( hostname=ip_address, - username=settings.NETBOX_USERNAME, - password=settings.NETBOX_PASSWORD + username=settings.NAPALM_USERNAME, + password=settings.NAPALM_PASSWORD, + timeout=settings.NAPALM_TIMEOUT, + optional_args=settings.NAPALM_ARGS ) try: d.open() for method in napalm_methods: response[method] = getattr(d, method)() except Exception as e: - raise ServiceUnavailable("Error connecting to the device: {}".format(e)) + raise ServiceUnavailable("Error connecting to the device at {}: {}".format(ip_address, e)) d.close() return Response(response) @@ -385,7 +386,7 @@ class ConnectedDeviceViewSet(ViewSet): * `peer-device`: The name of the peer device * `peer-interface`: The name of the peer interface """ - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticatedOrLoginNotRequired] def get_view_name(self): return "Connected Device Locator" diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index e3579085a0..dcd6c6d2e3 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals import django_filters +from netaddr import EUI from netaddr.core import AddrFormatError from django.contrib.auth.models import User @@ -8,7 +9,7 @@ from extras.filters import CustomFieldFilterSet from tenancy.models import Tenant -from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter +from utilities.filters import NullableCharFieldFilter, NullableModelMultipleChoiceFilter, NumericInFilter from .models import ( ConsolePort, ConsolePortTemplate, ConsoleServerPort, ConsoleServerPortTemplate, Device, DeviceBay, DeviceBayTemplate, DeviceRole, DeviceType, STATUS_CHOICES, IFACE_FF_LAG, Interface, InterfaceConnection, @@ -113,6 +114,7 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet): method='search', label='Search', ) + facility_id = NullableCharFieldFilter() site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), label='Site (ID)', @@ -156,7 +158,7 @@ class RackFilter(CustomFieldFilterSet, django_filters.FilterSet): class Meta: model = Rack - fields = ['facility_id', 'type', 'width', 'u_height', 'desc_units'] + fields = ['type', 'width', 'u_height', 'desc_units'] def search(self, queryset, name, value): if not value.strip(): @@ -383,6 +385,8 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet): to_field_name='slug', label='Platform (slug)', ) + name = NullableCharFieldFilter() + asset_tag = NullableCharFieldFilter() site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), label='Site (ID)', @@ -439,25 +443,33 @@ class DeviceFilter(CustomFieldFilterSet, django_filters.FilterSet): class Meta: model = Device - fields = ['name', 'serial', 'asset_tag'] + fields = ['serial'] def search(self, queryset, name, value): if not value.strip(): return queryset - return queryset.filter( + qs_filter = ( Q(name__icontains=value) | Q(serial__icontains=value.strip()) | Q(inventory_items__serial__icontains=value.strip()) | Q(asset_tag=value.strip()) | Q(comments__icontains=value) - ).distinct() + ) + # If the query value looks like a MAC address, search interfaces as well. + try: + mac = EUI(value.strip()) + qs_filter |= Q(interfaces__mac_address=mac) + except AddrFormatError: + pass + return queryset.filter(qs_filter).distinct() def _mac_address(self, queryset, name, value): value = value.strip() if not value: return queryset try: - return queryset.filter(interfaces__mac_address=value).distinct() + mac = EUI(value.strip()) + return queryset.filter(interfaces__mac_address=mac).distinct() except AddrFormatError: return queryset.none() @@ -569,7 +581,8 @@ def _mac_address(self, queryset, name, value): if not value: return queryset try: - return queryset.filter(mac_address=value) + mac = EUI(value.strip()) + return queryset.filter(mac_address=mac) except AddrFormatError: return queryset.none() @@ -596,10 +609,11 @@ class InventoryItemFilter(DeviceComponentFilterSet): to_field_name='slug', label='Manufacturer (slug)', ) + asset_tag = NullableCharFieldFilter() class Meta: model = InventoryItem - fields = ['name', 'part_id', 'serial', 'asset_tag', 'discovered'] + fields = ['name', 'part_id', 'serial', 'discovered'] class ConsoleConnectionFilter(django_filters.FilterSet): diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 8dd11e6636..3719c7c250 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -357,6 +357,16 @@ def get_available_units(self, u_height=1, rack_face=None, exclude=list()): return list(reversed(available_units)) + def get_reserved_units(self): + """ + Return a dictionary mapping all reserved units within the rack to their reservation. + """ + reserved_units = {} + for r in self.reservations.all(): + for u in r.units: + reserved_units[u] = r + return reserved_units + def get_0u_devices(self): return self.devices.filter(position=0) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index ea07138d58..78881c2009 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -417,15 +417,10 @@ def get(self, request, pk): prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first() reservations = RackReservation.objects.filter(rack=rack) - reserved_units = {} - for r in reservations: - for u in r.units: - reserved_units[u] = r return render(request, 'dcim/rack.html', { 'rack': rack, 'reservations': reservations, - 'reserved_units': reserved_units, 'nonracked_devices': nonracked_devices, 'next_rack': next_rack, 'prev_rack': prev_rack, diff --git a/netbox/extras/management/commands/run_inventory.py b/netbox/extras/management/commands/run_inventory.py index 1e52b5c8f4..335cdb7837 100644 --- a/netbox/extras/management/commands/run_inventory.py +++ b/netbox/extras/management/commands/run_inventory.py @@ -13,8 +13,8 @@ class Command(BaseCommand): help = "Update inventory information for specified devices" - username = settings.NETBOX_USERNAME - password = settings.NETBOX_PASSWORD + username = settings.NAPALM_USERNAME + password = settings.NAPALM_PASSWORD def add_arguments(self, parser): parser.add_argument('-u', '--username', dest='username', help="Specify the username to use") diff --git a/netbox/netbox/configuration.docker.py b/netbox/netbox/configuration.docker.py index c57aca6f47..56f9da3664 100644 --- a/netbox/netbox/configuration.docker.py +++ b/netbox/netbox/configuration.docker.py @@ -60,8 +60,8 @@ MAINTENANCE_MODE = os.environ.get('MAINTENANCE_MODE', False) # Credentials that NetBox will use to access live devices. -NETBOX_USERNAME = os.environ.get('NETBOX_USERNAME', '') -NETBOX_PASSWORD = os.environ.get('NETBOX_PASSWORD', '') +NAPALM_USERNAME = os.environ.get('NAPALM_USERNAME', '') +NAPALM_PASSWORD = os.environ.get('NAPALM_PASSWORD', '') # Determine how many objects to display per page within a list. (Default: 50) PAGINATE_COUNT = os.environ.get('PAGINATE_COUNT', 50) diff --git a/netbox/netbox/configuration.example.py b/netbox/netbox/configuration.example.py index 2e08090c70..78e870072e 100644 --- a/netbox/netbox/configuration.example.py +++ b/netbox/netbox/configuration.example.py @@ -93,9 +93,16 @@ # all objects by specifying "?limit=0". MAX_PAGE_SIZE = 1000 -# Credentials that NetBox will use to access live devices (future use). -NETBOX_USERNAME = '' -NETBOX_PASSWORD = '' +# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM. +NAPALM_USERNAME = '' +NAPALM_PASSWORD = '' + +# NAPALM timeout (in seconds). (Default: 30) +NAPALM_TIMEOUT = 30 + +# NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must +# be provided as a dictionary. +NAPALM_ARGS = {} # Determine how many objects to display per page within a list. (Default: 50) PAGINATE_COUNT = 50 diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 28d98acf15..c97c9bbc50 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -13,7 +13,7 @@ ) -VERSION = '2.1.0' +VERSION = '2.1.1' # Import required configuration parameters ALLOWED_HOSTS = DATABASE = SECRET_KEY = None @@ -46,8 +46,12 @@ MAX_PAGE_SIZE = getattr(configuration, 'MAX_PAGE_SIZE', 1000) PAGINATE_COUNT = getattr(configuration, 'PAGINATE_COUNT', 50) PREFER_IPV4 = getattr(configuration, 'PREFER_IPV4', False) -NETBOX_USERNAME = getattr(configuration, 'NETBOX_USERNAME', '') -NETBOX_PASSWORD = getattr(configuration, 'NETBOX_PASSWORD', '') +NAPALM_USERNAME = getattr(configuration, 'NAPALM_USERNAME', '') +NAPALM_PASSWORD = getattr(configuration, 'NAPALM_PASSWORD', '') +NAPALM_TIMEOUT = getattr(configuration, 'NAPALM_TIMEOUT', 30) +NAPALM_ARGS = getattr(configuration, 'NAPALM_ARGS', {}) +NETBOX_USERNAME = getattr(configuration, 'NETBOX_USERNAME', '') # Deprecated +NETBOX_PASSWORD = getattr(configuration, 'NETBOX_PASSWORD', '') # Deprecated SHORT_DATE_FORMAT = getattr(configuration, 'SHORT_DATE_FORMAT', 'Y-m-d') SHORT_DATETIME_FORMAT = getattr(configuration, 'SHORT_DATETIME_FORMAT', 'Y-m-d H:i') SHORT_TIME_FORMAT = getattr(configuration, 'SHORT_TIME_FORMAT', 'H:i:s') @@ -56,6 +60,19 @@ CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS +# Check for deprecated configuration parameters +config_logger = logging.getLogger('configuration') +config_logger.addHandler(logging.StreamHandler()) +config_logger.setLevel(logging.WARNING) +if NETBOX_USERNAME: + config_logger.warning('NETBOX_USERNAME is deprecated and will be removed in v2.2. Please use NAPALM_USERNAME instead.') + if not NAPALM_USERNAME: + NAPALM_USERNAME = NETBOX_USERNAME +if NETBOX_PASSWORD: + config_logger.warning('NETBOX_PASSWORD is deprecated and will be removed in v2.2. Please use NAPALM_PASSWORD instead.') + if not NAPALM_PASSWORD: + NAPALM_PASSWORD = NETBOX_PASSWORD + # Attempt to import LDAP configuration if it has been defined LDAP_IGNORE_CERT_ERRORS = False try: @@ -78,9 +95,9 @@ if LDAP_IGNORE_CERT_ERRORS: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # Enable logging for django_auth_ldap - logger = logging.getLogger('django_auth_ldap') - logger.addHandler(logging.StreamHandler()) - logger.setLevel(logging.DEBUG) + ldap_logger = logging.getLogger('django_auth_ldap') + ldap_logger.addHandler(logging.StreamHandler()) + ldap_logger.setLevel(logging.DEBUG) except ImportError: raise ImproperlyConfigured( "LDAP authentication has been configured, but django-auth-ldap is not installed. You can remove " diff --git a/netbox/templates/circuits/circuit.html b/netbox/templates/circuits/circuit.html index f311ccb73a..383d3bb7a2 100644 --- a/netbox/templates/circuits/circuit.html +++ b/netbox/templates/circuits/circuit.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}{{ circuit.provider }} - {{ circuit.cid }}{% endblock %} - {% block content %}
@@ -39,7 +37,7 @@ {% endif %}
-

{{ circuit.provider }} - {{ circuit.cid }}

+

{% block title %}{{ circuit.provider }} - {{ circuit.cid }}{% endblock %}

{% include 'inc/created_updated.html' with obj=circuit %}
diff --git a/netbox/templates/circuits/circuit_list.html b/netbox/templates/circuits/circuit_list.html index 63ee92f2d7..418459a15d 100644 --- a/netbox/templates/circuits/circuit_list.html +++ b/netbox/templates/circuits/circuit_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Circuits{% endblock %} - {% block content %}
{% if perms.circuits.add_circuit %} @@ -17,7 +15,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='circuits' %}
-

Circuits

+

{% block title %}Circuits{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='circuits:circuit_bulk_edit' bulk_delete_url='circuits:circuit_bulk_delete' %} diff --git a/netbox/templates/circuits/circuittermination_edit.html b/netbox/templates/circuits/circuittermination_edit.html index 13aa7e5b66..13052966be 100644 --- a/netbox/templates/circuits/circuittermination_edit.html +++ b/netbox/templates/circuits/circuittermination_edit.html @@ -2,10 +2,6 @@ {% load staticfiles %} {% load form_helpers %} -{% block title %} - Circuit {{ obj.circuit }} - Side {{ form.term_side.value }} -{% endblock %} - {% block content %}
{% csrf_token %} @@ -14,7 +10,7 @@ {% endfor %}
-

Circuit {{ obj.circuit }} - Side {{ form.term_side.value }}

+

{% block title %}Circuit {{ obj.circuit }} - {{ form.term_side.value }} Side{% endblock %}

{% if form.non_field_errors %}
Errors
diff --git a/netbox/templates/circuits/circuittype_list.html b/netbox/templates/circuits/circuittype_list.html index d59a5b82fb..f545b1a1e6 100644 --- a/netbox/templates/circuits/circuittype_list.html +++ b/netbox/templates/circuits/circuittype_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Circuit Types{% endblock %} - {% block content %}
{% if perms.circuits.add_circuittype %} @@ -12,7 +10,7 @@ {% endif %}
-

Circuit Types

+

{% block title %}Circuit Types{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='circuits:circuittype_bulk_delete' %} diff --git a/netbox/templates/circuits/provider.html b/netbox/templates/circuits/provider.html index 35562a7a30..6dcccfd8d8 100644 --- a/netbox/templates/circuits/provider.html +++ b/netbox/templates/circuits/provider.html @@ -2,8 +2,6 @@ {% load static from staticfiles %} {% load helpers %} -{% block title %}{{ provider }}{% endblock %} - {% block content %}
@@ -45,7 +43,7 @@ {% endif %}
-

{{ provider }}

+

{% block title %}{{ provider }}{% endblock %}

{% include 'inc/created_updated.html' with obj=provider %}
diff --git a/netbox/templates/circuits/provider_list.html b/netbox/templates/circuits/provider_list.html index 36438d66b0..9ba8bb8382 100644 --- a/netbox/templates/circuits/provider_list.html +++ b/netbox/templates/circuits/provider_list.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}Providers{% endblock %} - {% block content %}
{% if perms.circuits.add_provider %} @@ -16,7 +14,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='providers' %}
-

Providers

+

{% block title %}Providers{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='circuits:provider_bulk_edit' bulk_delete_url='circuits:provider_bulk_delete' %} diff --git a/netbox/templates/dcim/console_connections_list.html b/netbox/templates/dcim/console_connections_list.html index fc2cbb7627..57d3435e54 100644 --- a/netbox/templates/dcim/console_connections_list.html +++ b/netbox/templates/dcim/console_connections_list.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}Console Connections{% endblock %} - {% block content %}
{% if perms.dcim.change_consoleport %} @@ -12,7 +10,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='connections' %}
-

Console Connections

+

{% block title %}Console Connections{% endblock %}

{% include 'responsive_table.html' %} diff --git a/netbox/templates/dcim/consoleport_connect.html b/netbox/templates/dcim/consoleport_connect.html index e06bf45ec4..679540960c 100644 --- a/netbox/templates/dcim/consoleport_connect.html +++ b/netbox/templates/dcim/consoleport_connect.html @@ -2,8 +2,6 @@ {% load static from staticfiles %} {% load form_helpers %} -{% block title %}Connect {{ consoleport.device }} {{ consoleport }}{% endblock %} - {% block content %} {% csrf_token %} @@ -21,7 +19,7 @@
{% endif %}
-
Connect {{ consoleport.device }} {{ consoleport }}
+
{% block title %}Connect {{ consoleport.device }} {{ consoleport }}{% endblock %}
{% endif %}
-
Connect {{ consoleserverport.device }} {{ consoleserverport }}
+
{% block title %}Connect {{ consoleserverport.device }} {{ consoleserverport }}{% endblock %}
- {% elif not obj.device_type.is_child_device %} + {% else %} {% render_field form.face %} {% render_field form.position %} {% endif %} diff --git a/netbox/templates/dcim/device_list.html b/netbox/templates/dcim/device_list.html index 392679348b..34b143fc54 100644 --- a/netbox/templates/dcim/device_list.html +++ b/netbox/templates/dcim/device_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Devices{% endblock %} - {% block content %}
{% if perms.dcim.add_device %} @@ -17,7 +15,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='devices' %}
-

Devices

+

{% block title %}Devices{% endblock %}

{% include 'dcim/inc/device_table.html' with bulk_edit_url='dcim:device_bulk_edit' bulk_delete_url='dcim:device_bulk_delete' %} diff --git a/netbox/templates/dcim/devicebay_populate.html b/netbox/templates/dcim/devicebay_populate.html index 94a4ef0d0a..d328d557d1 100644 --- a/netbox/templates/dcim/devicebay_populate.html +++ b/netbox/templates/dcim/devicebay_populate.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load form_helpers %} -{% block title %}Populate {{ device_bay }}{% endblock %} - {% block content %} {% csrf_token %} @@ -17,7 +15,7 @@
{% endif %}
-
Populate {{ device_bay }}
+
{% block title %}Populate {{ device_bay }}{% endblock %}
diff --git a/netbox/templates/dcim/devicerole_list.html b/netbox/templates/dcim/devicerole_list.html index 67ff32979d..2e81890178 100644 --- a/netbox/templates/dcim/devicerole_list.html +++ b/netbox/templates/dcim/devicerole_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Device Roles{% endblock %} - {% block content %}
{% if perms.dcim.add_devicerole %} @@ -12,7 +10,7 @@ {% endif %}
-

Device Roles

+

{% block title %}Device Roles{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='dcim:devicerole_bulk_delete' %} diff --git a/netbox/templates/dcim/devicetype.html b/netbox/templates/dcim/devicetype.html index aac7a0622f..9eb3e0a5e3 100644 --- a/netbox/templates/dcim/devicetype.html +++ b/netbox/templates/dcim/devicetype.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}{{ devicetype.manufacturer }} {{ devicetype.model }}{% endblock %} - {% block content %}
@@ -31,7 +29,7 @@
{% endif %} -

{{ devicetype.manufacturer }} {{ devicetype.model }}

+

{% block title %}{{ devicetype.manufacturer }} {{ devicetype.model }}{% endblock %}

diff --git a/netbox/templates/dcim/devicetype_list.html b/netbox/templates/dcim/devicetype_list.html index 5ab97a4816..46d41782ad 100644 --- a/netbox/templates/dcim/devicetype_list.html +++ b/netbox/templates/dcim/devicetype_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Device Types{% endblock %} - {% block content %}
{% if perms.dcim.add_devicetype %} @@ -12,7 +10,7 @@ {% endif %}
-

Device Types

+

{% block title %}Device Types{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='dcim:devicetype_bulk_edit' bulk_delete_url='dcim:devicetype_bulk_delete' %} diff --git a/netbox/templates/dcim/interface_connections_list.html b/netbox/templates/dcim/interface_connections_list.html index a37028624a..a7355a449e 100644 --- a/netbox/templates/dcim/interface_connections_list.html +++ b/netbox/templates/dcim/interface_connections_list.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}Interface Connections{% endblock %} - {% block content %}
{% if perms.dcim.add_interfaceconnection %} @@ -12,7 +10,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='connections' %}
-

Interface Connections

+

{% block title %}Interface Connections{% endblock %}

{% include 'responsive_table.html' %} diff --git a/netbox/templates/dcim/ipaddress_assign.html b/netbox/templates/dcim/ipaddress_assign.html deleted file mode 100644 index e8596158c5..0000000000 --- a/netbox/templates/dcim/ipaddress_assign.html +++ /dev/null @@ -1,64 +0,0 @@ -{% extends '_base.html' %} -{% load form_helpers %} - -{% block title %}Assign a New IP Address{% endblock %} - -{% block content %} - - {% csrf_token %} -
-
- {% if form.non_field_errors %} -
-
Errors
-
- {{ form.non_field_errors }} -
-
- {% endif %} -
-
- IP Address -
-
- {% render_field form.address %} - {% render_field form.vrf %} - {% render_field form.tenant %} - {% render_field form.status %} - {% render_field form.description %} -
-
-
-
- Interface Assignment -
-
-
- -
-

{{ device }}

-
-
- {% render_field form.interface %} - {% render_field form.set_as_primary %} -
-
- {% if form.custom_fields %} -
-
Custom Fields
-
- {% render_custom_fields form %} -
-
- {% endif %} -
-
- - - Cancel -
-
-
-
- -{% endblock %} diff --git a/netbox/templates/dcim/manufacturer_list.html b/netbox/templates/dcim/manufacturer_list.html index d535e11e81..c697127b16 100644 --- a/netbox/templates/dcim/manufacturer_list.html +++ b/netbox/templates/dcim/manufacturer_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Manufacturers{% endblock %} - {% block content %}
{% if perms.dcim.add_manufacturer %} @@ -12,7 +10,7 @@ {% endif %}
-

Manufacturers

+

{% block title %}Manufacturers{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='dcim:manufacturer_bulk_delete' %} diff --git a/netbox/templates/dcim/platform_list.html b/netbox/templates/dcim/platform_list.html index 3324479775..124277d0b5 100644 --- a/netbox/templates/dcim/platform_list.html +++ b/netbox/templates/dcim/platform_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Platforms{% endblock %} - {% block content %}
{% if perms.dcim.add_platform %} @@ -12,7 +10,7 @@ {% endif %}
-

Platforms

+

{% block title %}Platforms{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='dcim:platform_bulk_delete' %} diff --git a/netbox/templates/dcim/power_connections_list.html b/netbox/templates/dcim/power_connections_list.html index 79001fe408..50e983bece 100644 --- a/netbox/templates/dcim/power_connections_list.html +++ b/netbox/templates/dcim/power_connections_list.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}Power Connections{% endblock %} - {% block content %}
{% if perms.dcim.change_powerport %} @@ -12,7 +10,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='connections' %}
-

Power Connections

+

{% block title %}Power Connections{% endblock %}

{% include 'responsive_table.html' %} diff --git a/netbox/templates/dcim/poweroutlet_connect.html b/netbox/templates/dcim/poweroutlet_connect.html index 839027db23..6c7cef4498 100644 --- a/netbox/templates/dcim/poweroutlet_connect.html +++ b/netbox/templates/dcim/poweroutlet_connect.html @@ -2,8 +2,6 @@ {% load static from staticfiles %} {% load form_helpers %} -{% block title %}Connect {{ poweroutlet.device }} {{ poweroutlet }}{% endblock %} - {% block content %}
{% csrf_token %} @@ -21,7 +19,7 @@
{% endif %}
-
Connect {{ poweroutlet.device }} {{ poweroutlet }}
+
{% block title %}Connect {{ poweroutlet.device }} {{ poweroutlet }}{% endblock %}
{% endif %}
-
Connect {{ powerport.device }} {{ powerport }}
+
{% block title %}Connect {{ powerport.device }} {{ powerport }}{% endblock %}
{% if face_id %} - {% include 'dcim/inc/rack_elevation.html' with primary_face=rack.get_rear_elevation secondary_face=rack.get_front_elevation face_id=1 %} + {% include 'dcim/inc/rack_elevation.html' with primary_face=rack.get_rear_elevation secondary_face=rack.get_front_elevation face_id=1 reserved_units=rack.get_reserved_units %} {% else %} - {% include 'dcim/inc/rack_elevation.html' with primary_face=rack.get_front_elevation secondary_face=rack.get_rear_elevation face_id=0 %} + {% include 'dcim/inc/rack_elevation.html' with primary_face=rack.get_front_elevation secondary_face=rack.get_rear_elevation face_id=0 reserved_units=rack.get_reserved_units %} {% endif %}
diff --git a/netbox/templates/dcim/rack_list.html b/netbox/templates/dcim/rack_list.html index fa5371f6ff..1de08d37a5 100644 --- a/netbox/templates/dcim/rack_list.html +++ b/netbox/templates/dcim/rack_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Racks{% endblock %} - {% block content %}
{% if perms.dcim.add_rack %} @@ -17,7 +15,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='racks' %}
-

Racks

+

{% block title %}Racks{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='dcim:rack_bulk_edit' bulk_delete_url='dcim:rack_bulk_delete' %} diff --git a/netbox/templates/dcim/rackgroup_list.html b/netbox/templates/dcim/rackgroup_list.html index dee6472fba..cf19005b73 100644 --- a/netbox/templates/dcim/rackgroup_list.html +++ b/netbox/templates/dcim/rackgroup_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Rack Groups{% endblock %} - {% block content %}
{% if perms.dcim.add_rackgroup %} @@ -12,7 +10,7 @@ {% endif %}
-

Rack Groups

+

{% block title %}Rack Groups{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='dcim:rackgroup_bulk_delete' %} diff --git a/netbox/templates/dcim/rackrole_list.html b/netbox/templates/dcim/rackrole_list.html index 3cdf331642..1133cf9b28 100644 --- a/netbox/templates/dcim/rackrole_list.html +++ b/netbox/templates/dcim/rackrole_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Rack Role{% endblock %} - {% block content %}
{% if perms.dcim.add_rackrole %} @@ -12,7 +10,7 @@ {% endif %}
-

Rack Roles

+

{% block title %}Rack Roles{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='dcim:rackrole_bulk_delete' %} diff --git a/netbox/templates/dcim/region_list.html b/netbox/templates/dcim/region_list.html index b54201a344..df7da82c86 100644 --- a/netbox/templates/dcim/region_list.html +++ b/netbox/templates/dcim/region_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Regions{% endblock %} - {% block content %}
{% if perms.dcim.add_region %} @@ -12,7 +10,7 @@ {% endif %}
-

{{ block.title }}

+

{% block title %}Regions{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='dcim:region_bulk_delete' %} diff --git a/netbox/templates/dcim/site.html b/netbox/templates/dcim/site.html index f86565bf84..c178fbf643 100644 --- a/netbox/templates/dcim/site.html +++ b/netbox/templates/dcim/site.html @@ -2,8 +2,6 @@ {% load static from staticfiles %} {% load helpers %} -{% block title %}{{ site }}{% endblock %} - {% block content %}
@@ -50,7 +48,7 @@ {% endif %}
-

{{ site.name }}

+

{% block title %}{{ site }}{% endblock %}

{% include 'inc/created_updated.html' with obj=site %}
diff --git a/netbox/templates/dcim/site_list.html b/netbox/templates/dcim/site_list.html index 895f908045..6d3e2f7f70 100644 --- a/netbox/templates/dcim/site_list.html +++ b/netbox/templates/dcim/site_list.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}Sites{% endblock %} - {% block content %}
{% if perms.dcim.add_site %} @@ -16,7 +14,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='sites' %}
-

Sites

+

{% block title %}Sites{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='dcim:site_bulk_edit' %} diff --git a/netbox/templates/home.html b/netbox/templates/home.html index f553ed9c87..0c3c7d13b6 100644 --- a/netbox/templates/home.html +++ b/netbox/templates/home.html @@ -1,6 +1,14 @@ {% extends '_base.html' %} {% block content %} +{% if settings.NETBOX_USERNAME or settings.NETBOX_PASSWORD %} + +{% endif %} {% include 'search_form.html' %}
diff --git a/netbox/templates/ipam/aggregate.html b/netbox/templates/ipam/aggregate.html index 82961d3bf4..63731755c7 100644 --- a/netbox/templates/ipam/aggregate.html +++ b/netbox/templates/ipam/aggregate.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}Aggregate: {{ aggregate }}{% endblock %} - {% block content %}
@@ -38,7 +36,7 @@ {% endif %}
-

{{ aggregate }}

+

{% block title %}{{ aggregate }}{% endblock %}

{% include 'inc/created_updated.html' with obj=aggregate %}
diff --git a/netbox/templates/ipam/aggregate_list.html b/netbox/templates/ipam/aggregate_list.html index f432748764..fde53a7904 100644 --- a/netbox/templates/ipam/aggregate_list.html +++ b/netbox/templates/ipam/aggregate_list.html @@ -2,8 +2,6 @@ {% load humanize %} {% load helpers %} -{% block title %}Aggregates{% endblock %} - {% block content %}
{% if perms.ipam.add_aggregate %} @@ -18,7 +16,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='aggregates' %}
-

Aggregates

+

{% block title %}Aggregates{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='ipam:aggregate_bulk_edit' bulk_delete_url='ipam:aggregate_bulk_delete' %} diff --git a/netbox/templates/ipam/ipaddress.html b/netbox/templates/ipam/ipaddress.html index 44c5ec5fff..789e892738 100644 --- a/netbox/templates/ipam/ipaddress.html +++ b/netbox/templates/ipam/ipaddress.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}{{ ipaddress }}{% endblock %} - {% block content %}
@@ -40,10 +38,10 @@ {% endif %}
-

{{ ipaddress }}

+

{% block title %}{{ ipaddress }}{% endblock %}

{% include 'inc/created_updated.html' with obj=ipaddress %}
-
+
IP Address @@ -137,7 +135,7 @@

{{ ipaddress }}

{% include 'inc/custom_fields_panel.html' %} {% endwith %}
-
+
{% include 'panel_table.html' with table=parent_prefixes_table heading='Parent Prefixes' %} {% if duplicate_ips_table.rows %} {% include 'panel_table.html' with table=duplicate_ips_table heading='Duplicate IP Addresses' panel_class='danger' %} diff --git a/netbox/templates/ipam/ipaddress_assign.html b/netbox/templates/ipam/ipaddress_assign.html index 03ec181ffd..02eebf4e20 100644 --- a/netbox/templates/ipam/ipaddress_assign.html +++ b/netbox/templates/ipam/ipaddress_assign.html @@ -2,8 +2,6 @@ {% load static from staticfiles %} {% load form_helpers %} -{% block title %}Assign an IP Address{% endblock %} - {% block content %} {% csrf_token %} @@ -19,7 +17,7 @@ {% endif %}
- Assign an IP Address + {% block title %}Assign an IP Address{% endblock %}
diff --git a/netbox/templates/ipam/ipaddress_list.html b/netbox/templates/ipam/ipaddress_list.html index ac1d980a2a..2d273145dc 100644 --- a/netbox/templates/ipam/ipaddress_list.html +++ b/netbox/templates/ipam/ipaddress_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}IP Addresses{% endblock %} - {% block content %}
{% if perms.ipam.add_ipaddress %} @@ -17,7 +15,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='IPs' %}
-

IP Addresses

+

{% block title %}IP Addresses{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='ipam:ipaddress_bulk_edit' bulk_delete_url='ipam:ipaddress_bulk_delete' %} diff --git a/netbox/templates/ipam/prefix_ipaddresses.html b/netbox/templates/ipam/prefix_ipaddresses.html index a3554da39e..1b777417d5 100644 --- a/netbox/templates/ipam/prefix_ipaddresses.html +++ b/netbox/templates/ipam/prefix_ipaddresses.html @@ -1,6 +1,6 @@ {% extends '_base.html' %} -{% block title %}{{ prefix }}{% endblock %} +{% block title %}{{ prefix }} - IP Addresses{% endblock %} {% block content %} {% include 'ipam/inc/prefix_header.html' with active_tab='ip-addresses' %} diff --git a/netbox/templates/ipam/prefix_list.html b/netbox/templates/ipam/prefix_list.html index fd25af00d3..4747731f8b 100644 --- a/netbox/templates/ipam/prefix_list.html +++ b/netbox/templates/ipam/prefix_list.html @@ -2,8 +2,6 @@ {% load helpers %} {% load form_helpers %} -{% block title %}Prefixes{% endblock %} - {% block content %}
@@ -22,7 +20,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='prefixes' %}
-

Prefixes

+

{% block title %}Prefixes{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='ipam:prefix_bulk_edit' bulk_delete_url='ipam:prefix_bulk_delete' %} diff --git a/netbox/templates/ipam/rir_list.html b/netbox/templates/ipam/rir_list.html index 33bef6d99f..df97aec883 100644 --- a/netbox/templates/ipam/rir_list.html +++ b/netbox/templates/ipam/rir_list.html @@ -2,8 +2,6 @@ {% load humanize %} {% load helpers %} -{% block title %}RIRs{% endblock %} - {% block content %}
{% if request.GET.family == '6' %} @@ -24,7 +22,7 @@ {% endif %}
-

RIRs

+

{% block title %}RIRs{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='ipam:rir_bulk_delete' %} diff --git a/netbox/templates/ipam/role_list.html b/netbox/templates/ipam/role_list.html index 4ee83ad4f5..6d59bc6973 100644 --- a/netbox/templates/ipam/role_list.html +++ b/netbox/templates/ipam/role_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Prefix/VLAN Roles{% endblock %} - {% block content %}
{% if perms.dcim.add_devicerole %} @@ -12,7 +10,7 @@ {% endif %}
-

Prefix/VLAN Roles

+

{% block title %}Prefix/VLAN Roles{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='ipam:role_bulk_delete' %} diff --git a/netbox/templates/ipam/vlan.html b/netbox/templates/ipam/vlan.html index 0401e75cb5..4298e9b463 100644 --- a/netbox/templates/ipam/vlan.html +++ b/netbox/templates/ipam/vlan.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}VLAN {{ vlan.display_name }}{% endblock %} - {% block content %}
@@ -43,7 +41,7 @@ {% endif %}
-

VLAN {{ vlan.display_name }}

+

{% block title %}VLAN {{ vlan.display_name }}{% endblock %}

{% include 'inc/created_updated.html' with obj=vlan %}
diff --git a/netbox/templates/ipam/vlan_list.html b/netbox/templates/ipam/vlan_list.html index 2db914721a..b5db84e526 100644 --- a/netbox/templates/ipam/vlan_list.html +++ b/netbox/templates/ipam/vlan_list.html @@ -2,8 +2,6 @@ {% load helpers %} {% load form_helpers %} -{% block title %}VLANs{% endblock %} - {% block content %}
{% if perms.ipam.add_vlan %} @@ -18,7 +16,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='VLANs' %}
-

VLANs

+

{% block title %}VLANs{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='ipam:vlan_bulk_edit' bulk_delete_url='ipam:vlan_bulk_delete' %} diff --git a/netbox/templates/ipam/vlangroup_list.html b/netbox/templates/ipam/vlangroup_list.html index b6e1d45790..2a9e7e3ae9 100644 --- a/netbox/templates/ipam/vlangroup_list.html +++ b/netbox/templates/ipam/vlangroup_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}VLAN Groups{% endblock %} - {% block content %}
{% if perms.ipam.add_vlangroup %} @@ -12,7 +10,7 @@ {% endif %}
-

VLAN Groups

+

{% block title %}VLAN Groups{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='ipam:vlangroup_bulk_delete' %} diff --git a/netbox/templates/ipam/vrf.html b/netbox/templates/ipam/vrf.html index a726bb1474..e041ce73a5 100644 --- a/netbox/templates/ipam/vrf.html +++ b/netbox/templates/ipam/vrf.html @@ -1,7 +1,5 @@ {% extends '_base.html' %} -{% block title %}VRF {{ vrf }}{% endblock %} - {% block content %}
@@ -37,7 +35,7 @@ {% endif %}
-

{{ vrf }}

+

{% block title %}VRF {{ vrf }}{% endblock %}

{% include 'inc/created_updated.html' with obj=vrf %}
diff --git a/netbox/templates/ipam/vrf_list.html b/netbox/templates/ipam/vrf_list.html index 12f0b6bc30..029426a143 100644 --- a/netbox/templates/ipam/vrf_list.html +++ b/netbox/templates/ipam/vrf_list.html @@ -2,8 +2,6 @@ {% load helpers %} {% load form_helpers %} -{% block title %}VRFs{% endblock %} - {% block content %}
{% if perms.ipam.add_vrf %} @@ -18,7 +16,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='VRFs' %}
-

VRFs

+

{% block title %}VRFs{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='ipam:vrf_bulk_edit' bulk_delete_url='ipam:vrf_bulk_delete' %} diff --git a/netbox/templates/secrets/secret.html b/netbox/templates/secrets/secret.html index 016015cbef..66c844ebf0 100644 --- a/netbox/templates/secrets/secret.html +++ b/netbox/templates/secrets/secret.html @@ -2,8 +2,6 @@ {% load static from staticfiles %} {% load secret_helpers %} -{% block title %}Secret: {{ secret }}{% endblock %} - {% block content %}
@@ -28,7 +26,7 @@ {% endif %}
-

{{ secret }}

+

{% block title %}{{ secret }}{% endblock %}

{% include 'inc/created_updated.html' with obj=secret %}
diff --git a/netbox/templates/secrets/secret_edit.html b/netbox/templates/secrets/secret_edit.html index 4a56bb368a..9204091779 100644 --- a/netbox/templates/secrets/secret_edit.html +++ b/netbox/templates/secrets/secret_edit.html @@ -2,15 +2,13 @@ {% load static from staticfiles %} {% load form_helpers %} -{% block title %}{% if secret.pk %}Editing {{ secret }}{% else %}Add a Secret{% endif %}{% endblock %} - {% block content %} {% csrf_token %} {{ form.private_key }}
-

{% if secret.pk %}Editing {{ secret }}{% else %}Add a Secret{% endif %}

+

{% block title %}{% if secret.pk %}Editing {{ secret }}{% else %}Add a Secret{% endif %}{% endblock %}

{% if form.non_field_errors %}
Errors
diff --git a/netbox/templates/secrets/secret_import.html b/netbox/templates/secrets/secret_import.html index edc308d06d..1f12494ec0 100644 --- a/netbox/templates/secrets/secret_import.html +++ b/netbox/templates/secrets/secret_import.html @@ -2,10 +2,8 @@ {% load static from staticfiles %} {% load form_helpers %} -{% block title %}Secret Import{% endblock %} - {% block content %} -

Secret Import

+

{% block title %}Secret Import{% endblock %}

{% if form.non_field_errors %} diff --git a/netbox/templates/secrets/secret_list.html b/netbox/templates/secrets/secret_list.html index 29657d3f3c..5293b5a6d7 100644 --- a/netbox/templates/secrets/secret_list.html +++ b/netbox/templates/secrets/secret_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Secrets{% endblock %} - {% block content %}
{% if perms.secrets.add_secret %} @@ -12,7 +10,7 @@ {% endif %}
-

Secrets

+

{% block title %}Secrets{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='secrets:secret_bulk_edit' bulk_delete_url='secrets:secret_bulk_delete' %} diff --git a/netbox/templates/secrets/secretrole_list.html b/netbox/templates/secrets/secretrole_list.html index 4b1ee0399f..936445dec6 100644 --- a/netbox/templates/secrets/secretrole_list.html +++ b/netbox/templates/secrets/secretrole_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Secret Roles{% endblock %} - {% block content %}
{% if perms.dcim.add_devicerole %} @@ -12,7 +10,7 @@ {% endif %}
-

Secret Roles

+

{% block title %}Secret Roles{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='secrets:secretrole_bulk_delete' %} diff --git a/netbox/templates/tenancy/tenant.html b/netbox/templates/tenancy/tenant.html index bc00e399ee..2c893adaec 100644 --- a/netbox/templates/tenancy/tenant.html +++ b/netbox/templates/tenancy/tenant.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}{{ tenant }}{% endblock %} - {% block content %}
@@ -41,7 +39,7 @@ {% endif %}
-

{{ tenant }}

+

{% block title %}{{ tenant }}{% endblock %}

{% include 'inc/created_updated.html' with obj=tenant %}
diff --git a/netbox/templates/tenancy/tenant_list.html b/netbox/templates/tenancy/tenant_list.html index 81173b3685..afc1a154fa 100644 --- a/netbox/templates/tenancy/tenant_list.html +++ b/netbox/templates/tenancy/tenant_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Tenants{% endblock %} - {% block content %}
{% if perms.tenancy.add_tenant %} @@ -17,7 +15,7 @@ {% endif %} {% include 'inc/export_button.html' with obj_type='tenants' %}
-

Tenants

+

{% block title %}Tenants{% endblock %}

{% include 'utilities/obj_table.html' with bulk_edit_url='tenancy:tenant_bulk_edit' bulk_delete_url='tenancy:tenant_bulk_delete' %} diff --git a/netbox/templates/tenancy/tenantgroup_list.html b/netbox/templates/tenancy/tenantgroup_list.html index 7be881b002..f487122aba 100644 --- a/netbox/templates/tenancy/tenantgroup_list.html +++ b/netbox/templates/tenancy/tenantgroup_list.html @@ -1,8 +1,6 @@ {% extends '_base.html' %} {% load helpers %} -{% block title %}Tenant Groups{% endblock %} - {% block content %}
{% if perms.tenancy.add_tenantgroup %} @@ -12,7 +10,7 @@ {% endif %}
-

Tenant Groups

+

{% block title %}Tenant Groups{% endblock %}

{% include 'utilities/obj_table.html' with bulk_delete_url='tenancy:tenantgroup_bulk_delete' %} diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index 5774584a69..6a515b21d6 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -4,9 +4,10 @@ from django.contrib.contenttypes.models import ContentType from rest_framework import authentication, exceptions +from rest_framework.compat import is_authenticated from rest_framework.exceptions import APIException from rest_framework.pagination import LimitOffsetPagination -from rest_framework.permissions import DjangoModelPermissions, SAFE_METHODS +from rest_framework.permissions import BasePermission, DjangoModelPermissions, SAFE_METHODS from rest_framework.serializers import Field, ValidationError from users.models import Token @@ -20,6 +21,10 @@ class ServiceUnavailable(APIException): default_detail = "Service temporarily unavailable, please try again later." +# +# Authentication +# + class TokenAuthentication(authentication.TokenAuthentication): """ A custom authentication scheme which enforces Token expiration times. @@ -61,6 +66,20 @@ def has_permission(self, request, view): return super(TokenPermissions, self).has_permission(request, view) +class IsAuthenticatedOrLoginNotRequired(BasePermission): + """ + Returns True if the user is authenticated or LOGIN_REQUIRED is False. + """ + def has_permission(self, request, view): + if not settings.LOGIN_REQUIRED: + return True + return request.user and is_authenticated(request.user) + + +# +# Serializers +# + class ChoiceFieldSerializer(Field): """ Represent a ChoiceField as {'value': , 'label': }. @@ -98,6 +117,10 @@ def to_internal_value(self, data): raise ValidationError("Invalid content type") +# +# Mixins +# + class ModelValidationMixin(object): """ Enforce a model's validation through clean() when validating serializer data. This is necessary to ensure we're @@ -119,6 +142,10 @@ def get_serializer_class(self): return self.serializer_class +# +# Pagination +# + class OptionalLimitOffsetPagination(LimitOffsetPagination): """ Override the stock paginator to allow setting limit=0 to disable pagination for a request. This returns all objects diff --git a/netbox/utilities/filters.py b/netbox/utilities/filters.py index 5929c3ff18..5bd635a462 100644 --- a/netbox/utilities/filters.py +++ b/netbox/utilities/filters.py @@ -19,6 +19,16 @@ class NumericInFilter(django_filters.BaseInFilter, django_filters.NumberFilter): pass +class NullableCharFieldFilter(django_filters.CharFilter): + null_value = 'NULL' + + def filter(self, qs, value): + if value != self.null_value: + return super(NullableCharFieldFilter, self).filter(qs, value) + qs = self.get_method(qs)(**{'{}__isnull'.format(self.name): True}) + return qs.distinct() if self.distinct else qs + + class NullableModelMultipleChoiceField(forms.ModelMultipleChoiceField): """ This field operates like a normal ModelMultipleChoiceField except that it allows for one additional choice which is