mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-27 02:48:38 -06:00
Merge f114ffd10d
into e92f60afda
This commit is contained in:
commit
cedf4785d9
@ -1,4 +1,5 @@
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.db.models import Count
|
||||
|
||||
from dcim.models import Site, Device, Interface, Rack, IFACE_FF_VIRTUAL
|
||||
@ -9,6 +10,10 @@ from utilities.forms import (
|
||||
|
||||
from .models import Circuit, CircuitType, Provider
|
||||
|
||||
url_prefix = ''
|
||||
if settings.URL_PREFIX.strip('/'):
|
||||
url_prefix = '/{0}'.format(settings.URL_PREFIX.strip('/'))
|
||||
|
||||
|
||||
#
|
||||
# Providers
|
||||
@ -82,16 +87,16 @@ class CircuitTypeBulkDeleteForm(ConfirmationForm):
|
||||
class CircuitForm(forms.ModelForm, BootstrapMixin):
|
||||
site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.Select(attrs={'filter-for': 'rack'}))
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), required=False, label='Rack',
|
||||
widget=APISelect(api_url='/api/dcim/racks/?site_id={{site}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/racks/?site_id={{site}}',
|
||||
attrs={'filter-for': 'device'}))
|
||||
device = forms.ModelChoiceField(queryset=Device.objects.all(), required=False, label='Device',
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}',
|
||||
attrs={'filter-for': 'interface'}))
|
||||
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
|
||||
)
|
||||
interface = forms.ModelChoiceField(queryset=Interface.objects.all(), required=False, label='Interface',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{device}}/interfaces/?type=physical',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device}}/interfaces/?type=physical',
|
||||
disabled_indicator='is_connected'))
|
||||
comments = CommentField()
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import re
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.db.models import Count, Q
|
||||
|
||||
from ipam.models import IPAddress
|
||||
@ -25,6 +26,10 @@ FORM_STATUS_CHOICES += STATUS_CHOICES
|
||||
|
||||
DEVICE_BY_PK_RE = '{\d+\}'
|
||||
|
||||
url_prefix = ''
|
||||
if settings.URL_PREFIX.strip('/'):
|
||||
url_prefix = '/{0}'.format(settings.URL_PREFIX.strip('/'))
|
||||
|
||||
|
||||
def get_device_by_name_or_pk(name):
|
||||
"""
|
||||
@ -105,7 +110,7 @@ class RackGroupFilterForm(forms.Form, BootstrapMixin):
|
||||
|
||||
class RackForm(forms.ModelForm, BootstrapMixin):
|
||||
group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False, label='Group', widget=APISelect(
|
||||
api_url='/api/dcim/rack-groups/?site_id={{site}}',
|
||||
api_url=url_prefix + '/api/dcim/rack-groups/?site_id={{site}}',
|
||||
))
|
||||
comments = CommentField()
|
||||
|
||||
@ -330,18 +335,18 @@ class PlatformBulkDeleteForm(ConfirmationForm):
|
||||
class DeviceForm(forms.ModelForm, BootstrapMixin):
|
||||
site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.Select(attrs={'filter-for': 'rack'}))
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), widget=APISelect(
|
||||
api_url='/api/dcim/racks/?site_id={{site}}',
|
||||
api_url=url_prefix + '/api/dcim/racks/?site_id={{site}}',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'position'}
|
||||
))
|
||||
position = forms.TypedChoiceField(required=False, empty_value=None,
|
||||
help_text="For multi-U devices, this is the lowest occupied rack unit.",
|
||||
widget=APISelect(api_url='/api/dcim/racks/{{rack}}/rack-units/?face={{face}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/racks/{{rack}}/rack-units/?face={{face}}',
|
||||
disabled_indicator='device'))
|
||||
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(),
|
||||
widget=forms.Select(attrs={'filter-for': 'device_type'}))
|
||||
device_type = forms.ModelChoiceField(queryset=DeviceType.objects.all(), label='Device type', widget=APISelect(
|
||||
api_url='/api/dcim/device-types/?manufacturer_id={{manufacturer}}',
|
||||
api_url=url_prefix + '/api/dcim/device-types/?manufacturer_id={{manufacturer}}',
|
||||
display_field='model'
|
||||
))
|
||||
comments = CommentField()
|
||||
@ -614,13 +619,13 @@ class ConsolePortConnectionForm(forms.ModelForm, BootstrapMixin):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'console_server'}))
|
||||
console_server = forms.ModelChoiceField(queryset=Device.objects.all(), label='Console Server', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_console_server=True',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}&is_console_server=True',
|
||||
attrs={'filter-for': 'cs_port'}))
|
||||
livesearch = forms.CharField(required=False, label='Console Server', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='console_server')
|
||||
)
|
||||
cs_port = forms.ModelChoiceField(queryset=ConsoleServerPort.objects.all(), label='Port',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{console_server}}/console-server-ports/',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{console_server}}/console-server-ports/',
|
||||
disabled_indicator='connected_console'))
|
||||
|
||||
class Meta:
|
||||
@ -681,13 +686,13 @@ class ConsoleServerPortConnectionForm(forms.Form, BootstrapMixin):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'device'}))
|
||||
device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}',
|
||||
attrs={'filter-for': 'port'}))
|
||||
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
|
||||
)
|
||||
port = forms.ModelChoiceField(queryset=ConsolePort.objects.all(), label='Port',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{device}}/console-ports/',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device}}/console-ports/',
|
||||
disabled_indicator='cs_port'))
|
||||
connection_status = forms.BooleanField(required=False, initial=CONNECTION_STATUS_CONNECTED, label='Status',
|
||||
widget=forms.Select(choices=CONNECTION_STATUS_CHOICES))
|
||||
@ -810,13 +815,13 @@ class PowerPortConnectionForm(forms.ModelForm, BootstrapMixin):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'pdu'}))
|
||||
pdu = forms.ModelChoiceField(queryset=Device.objects.all(), label='PDU', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_pdu=True',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}&is_pdu=True',
|
||||
attrs={'filter-for': 'power_outlet'}))
|
||||
livesearch = forms.CharField(required=False, label='PDU', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='pdu')
|
||||
)
|
||||
power_outlet = forms.ModelChoiceField(queryset=PowerOutlet.objects.all(), label='Outlet',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{pdu}}/power-outlets/',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{pdu}}/power-outlets/',
|
||||
disabled_indicator='connected_port'))
|
||||
|
||||
class Meta:
|
||||
@ -877,13 +882,13 @@ class PowerOutletConnectionForm(forms.Form, BootstrapMixin):
|
||||
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'device'}))
|
||||
device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}',
|
||||
attrs={'filter-for': 'port'}))
|
||||
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
|
||||
)
|
||||
port = forms.ModelChoiceField(queryset=PowerPort.objects.all(), label='Port',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{device}}/power-ports/',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device}}/power-ports/',
|
||||
disabled_indicator='power_outlet'))
|
||||
connection_status = forms.BooleanField(required=False, initial=CONNECTION_STATUS_CONNECTED, label='Status',
|
||||
widget=forms.Select(choices=CONNECTION_STATUS_CHOICES))
|
||||
@ -952,13 +957,13 @@ class InterfaceConnectionForm(forms.ModelForm, BootstrapMixin):
|
||||
rack_b = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
|
||||
widget=forms.Select(attrs={'filter-for': 'device_b'}))
|
||||
device_b = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
|
||||
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack_b}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack_b}}',
|
||||
attrs={'filter-for': 'interface_b'}))
|
||||
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
|
||||
query_key='q', query_url='dcim-api:device_list', field_to_update='device_b')
|
||||
)
|
||||
interface_b = forms.ModelChoiceField(queryset=Interface.objects.all(), label='Interface',
|
||||
widget=APISelect(api_url='/api/dcim/devices/{{device_b}}/interfaces/?type=physical',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device_b}}/interfaces/?type=physical',
|
||||
disabled_indicator='is_connected'))
|
||||
|
||||
class Meta:
|
||||
|
@ -1,6 +1,7 @@
|
||||
from netaddr import IPNetwork
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.db.models import Count
|
||||
|
||||
from dcim.models import Site, Device, Interface
|
||||
@ -16,6 +17,10 @@ from .models import (
|
||||
FORM_PREFIX_STATUS_CHOICES = (('', '---------'),) + PREFIX_STATUS_CHOICES
|
||||
FORM_VLAN_STATUS_CHOICES = (('', '---------'),) + VLAN_STATUS_CHOICES
|
||||
|
||||
url_prefix = ''
|
||||
if settings.URL_PREFIX.strip('/'):
|
||||
url_prefix = '/{0}'.format(settings.URL_PREFIX.strip('/'))
|
||||
|
||||
|
||||
#
|
||||
# VRFs
|
||||
@ -144,7 +149,7 @@ class PrefixForm(forms.ModelForm, BootstrapMixin):
|
||||
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, label='Site',
|
||||
widget=forms.Select(attrs={'filter-for': 'vlan'}))
|
||||
vlan = forms.ModelChoiceField(queryset=VLAN.objects.all(), required=False, label='VLAN',
|
||||
widget=APISelect(api_url='/api/ipam/vlans/?site_id={{site}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/ipam/vlans/?site_id={{site}}',
|
||||
display_field='display_name'))
|
||||
|
||||
class Meta:
|
||||
@ -270,13 +275,13 @@ class IPAddressForm(forms.ModelForm, BootstrapMixin):
|
||||
nat_site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, label='Site',
|
||||
widget=forms.Select(attrs={'filter-for': 'nat_device'}))
|
||||
nat_device = forms.ModelChoiceField(queryset=Device.objects.all(), required=False, label='Device',
|
||||
widget=APISelect(api_url='/api/dcim/devices/?site_id={{nat_site}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?site_id={{nat_site}}',
|
||||
attrs={'filter-for': 'nat_inside'}))
|
||||
livesearch = forms.CharField(required=False, label='IP Address', widget=Livesearch(
|
||||
query_key='q', query_url='ipam-api:ipaddress_list', field_to_update='nat_inside', obj_label='address')
|
||||
)
|
||||
nat_inside = forms.ModelChoiceField(queryset=IPAddress.objects.all(), required=False, label='NAT (Inside)',
|
||||
widget=APISelect(api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}',
|
||||
widget=APISelect(api_url=url_prefix + '/api/ipam/ip-addresses/?device_id={{nat_device}}',
|
||||
display_field='address'))
|
||||
|
||||
class Meta:
|
||||
|
@ -32,6 +32,15 @@ SECRET_KEY = ''
|
||||
# #
|
||||
#########################
|
||||
|
||||
# URL prefix if NetBox is served from non-root location, e.g. http://mysite/netbox/
|
||||
# By default, URL_PREFIX = '/', i.e. NetBox is served from root location
|
||||
# URL_PREFIX = '/netbox'
|
||||
|
||||
# Directory and URL from which static files will be served
|
||||
# for more info, see https://docs.djangoproject.com/en/1.9/howto/static-files/
|
||||
# STATIC_ROOT = '/var/www/htdocs/netbox/static/'
|
||||
# STATIC_URL = '/static/netbox/'
|
||||
|
||||
# Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of
|
||||
# application errors (assuming correct email settings are provided).
|
||||
ADMINS = [
|
||||
|
@ -22,7 +22,15 @@ for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
|
||||
raise ImproperlyConfigured("Mandatory setting {} is missing from configuration.py. Please define it per the "
|
||||
"documentation.".format(setting))
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Default configurations
|
||||
URL_PREFIX = getattr(configuration, 'URL_PREFIX', '/')
|
||||
url_prefix = ''
|
||||
if URL_PREFIX.strip('/'):
|
||||
url_prefix = '/{0}'.format(URL_PREFIX.strip('/'))
|
||||
STATIC_ROOT = getattr(configuration, 'STATIC_ROOT', BASE_DIR + '/static/')
|
||||
STATIC_URL = getattr(configuration, 'STATIC_URL', '/static' + url_prefix + '/')
|
||||
ADMINS = getattr(configuration, 'ADMINS', [])
|
||||
DEBUG = getattr(configuration, 'DEBUG', False)
|
||||
EMAIL = getattr(configuration, 'EMAIL', {})
|
||||
@ -71,8 +79,6 @@ if LDAP_CONFIGURED:
|
||||
raise ImproperlyConfigured("LDAP authentication has been configured, but django-auth-ldap is not installed. "
|
||||
"You can remove netbox/ldap.py to disable LDAP.")
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Database
|
||||
configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'})
|
||||
DATABASES = {
|
||||
@ -155,9 +161,7 @@ USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/1.8/howto/static-files/
|
||||
STATIC_ROOT = BASE_DIR + '/static/'
|
||||
STATIC_URL = '/static/'
|
||||
# https://docs.djangoproject.com/en/1.9/howto/static-files/
|
||||
STATICFILES_DIRS = (
|
||||
os.path.join(BASE_DIR, "project-static"),
|
||||
)
|
||||
@ -168,9 +172,9 @@ MESSAGE_TAGS = {
|
||||
}
|
||||
|
||||
# Authentication URLs
|
||||
LOGIN_URL = '/login/'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
LOGOUT_URL = '/logout/'
|
||||
LOGIN_URL = url_prefix + '/login/'
|
||||
LOGIN_REDIRECT_URL = url_prefix + '/'
|
||||
LOGOUT_URL = url_prefix + '/logout/'
|
||||
|
||||
# Secrets
|
||||
SECRETS_MIN_PUBKEY_SIZE = 2048
|
||||
@ -182,7 +186,7 @@ REST_FRAMEWORK = {
|
||||
|
||||
# Swagger settings (API docs)
|
||||
SWAGGER_SETTINGS = {
|
||||
'base_path': '{}/api/docs'.format(ALLOWED_HOSTS[0]),
|
||||
'base_path': '{}'.format(ALLOWED_HOSTS[0]) + url_prefix + '/api/docs',
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib import admin
|
||||
from django.views.defaults import page_not_found
|
||||
@ -5,36 +6,40 @@ from django.views.defaults import page_not_found
|
||||
from views import home, trigger_500
|
||||
from users.views import login, logout
|
||||
|
||||
url_prefix = ''
|
||||
if settings.URL_PREFIX.strip('/'):
|
||||
url_prefix = '{0}/'.format(settings.URL_PREFIX.strip('/'))
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^{0}'.format(url_prefix),
|
||||
include([
|
||||
# Default page
|
||||
url(r'^$', home, name='home'),
|
||||
|
||||
# Default page
|
||||
url(r'^$', home, name='home'),
|
||||
# Login/logout
|
||||
url(r'^login/$', login, name='login'),
|
||||
url(r'^logout/$', logout, name='logout'),
|
||||
|
||||
# Login/logout
|
||||
url(r'^login/$', login, name='login'),
|
||||
url(r'^logout/$', logout, name='logout'),
|
||||
# Apps
|
||||
url(r'^circuits/', include('circuits.urls', namespace='circuits')),
|
||||
url(r'^dcim/', include('dcim.urls', namespace='dcim')),
|
||||
url(r'^ipam/', include('ipam.urls', namespace='ipam')),
|
||||
url(r'^secrets/', include('secrets.urls', namespace='secrets')),
|
||||
url(r'^profile/', include('users.urls', namespace='users')),
|
||||
|
||||
# Apps
|
||||
url(r'^circuits/', include('circuits.urls', namespace='circuits')),
|
||||
url(r'^dcim/', include('dcim.urls', namespace='dcim')),
|
||||
url(r'^ipam/', include('ipam.urls', namespace='ipam')),
|
||||
url(r'^secrets/', include('secrets.urls', namespace='secrets')),
|
||||
url(r'^profile/', include('users.urls', namespace='users')),
|
||||
# API
|
||||
url(r'^api/circuits/', include('circuits.api.urls', namespace='circuits-api')),
|
||||
url(r'^api/dcim/', include('dcim.api.urls', namespace='dcim-api')),
|
||||
url(r'^api/ipam/', include('ipam.api.urls', namespace='ipam-api')),
|
||||
url(r'^api/secrets/', include('secrets.api.urls', namespace='secrets-api')),
|
||||
url(r'^api/docs/', include('rest_framework_swagger.urls')),
|
||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
|
||||
# API
|
||||
url(r'^api/circuits/', include('circuits.api.urls', namespace='circuits-api')),
|
||||
url(r'^api/dcim/', include('dcim.api.urls', namespace='dcim-api')),
|
||||
url(r'^api/ipam/', include('ipam.api.urls', namespace='ipam-api')),
|
||||
url(r'^api/secrets/', include('secrets.api.urls', namespace='secrets-api')),
|
||||
url(r'^api/docs/', include('rest_framework_swagger.urls')),
|
||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
|
||||
# Error testing
|
||||
url(r'^404/$', page_not_found),
|
||||
url(r'^500/$', trigger_500),
|
||||
|
||||
# Admin
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
# Error testing
|
||||
url(r'^404/$', page_not_found),
|
||||
url(r'^500/$', trigger_500),
|
||||
|
||||
# Admin
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
])),
|
||||
]
|
||||
|
@ -19,7 +19,7 @@
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="/">NetBox</a>
|
||||
<a href="{% url 'home' %}" class="navbar-brand">NetBox</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
{% if request.user.is_authenticated or not settings.LOGIN_REQUIRED %}
|
||||
@ -263,7 +263,7 @@
|
||||
<div class="col-xs-4 text-right">
|
||||
<p class="text-muted">
|
||||
<i class="fa fa-fw fa-book text-primary"></i> <a href="http://netbox.readthedocs.io/" target="_blank">Docs</a> ·
|
||||
<i class="fa fa-fw fa-cloud text-primary"></i> <a href="/api/docs/">API</a> ·
|
||||
<i class="fa fa-fw fa-cloud text-primary"></i> <a href="{% url 'home' %}api/docs/">API</a> ·
|
||||
<i class="fa fa-fw fa-code text-primary"></i> <a href="https://github.com/digitalocean/netbox">Code</a>
|
||||
</p>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user