nautobot 2.2.0__py3-none-any.whl → 2.2.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/api.py +2 -1
- nautobot/apps/utils.py +0 -4
- nautobot/apps/views.py +0 -2
- nautobot/circuits/api/urls.py +2 -1
- nautobot/circuits/api/views.py +12 -0
- nautobot/circuits/tests/test_filters.py +1 -1
- nautobot/core/api/routers.py +3 -25
- nautobot/core/api/utils.py +0 -4
- nautobot/core/api/views.py +15 -21
- nautobot/core/filters.py +1 -7
- nautobot/core/management/commands/generate_test_data.py +4 -4
- nautobot/core/settings.py +0 -1
- nautobot/core/tables.py +1 -2
- nautobot/core/templates/admin/base.html +94 -23
- nautobot/core/templates/graphene/graphiql.html +47 -18
- nautobot/core/templates/inc/footer.html +5 -5
- nautobot/core/templates/inc/nav_menu.html +7 -0
- nautobot/core/templates/rest_framework/api.html +5 -12
- nautobot/core/templatetags/helpers.py +2 -2
- nautobot/core/testing/views.py +0 -30
- nautobot/core/tests/test_api.py +6 -13
- nautobot/core/tests/test_csv.py +4 -5
- nautobot/core/tests/test_filters.py +1 -2
- nautobot/core/tests/test_graphql.py +14 -4
- nautobot/core/tests/test_navigations.py +0 -3
- nautobot/core/tests/test_views.py +16 -22
- nautobot/core/utils/lookup.py +0 -124
- nautobot/core/views/__init__.py +7 -3
- nautobot/core/views/generic.py +3 -19
- nautobot/core/views/mixins.py +0 -7
- nautobot/core/views/renderers.py +1 -4
- nautobot/dcim/api/serializers.py +4 -4
- nautobot/dcim/api/urls.py +3 -2
- nautobot/dcim/api/views.py +18 -7
- nautobot/dcim/factory.py +7 -7
- nautobot/dcim/filters/__init__.py +17 -16
- nautobot/dcim/forms.py +45 -61
- nautobot/dcim/homepage.py +3 -11
- nautobot/dcim/migrations/0057_controller_models.py +70 -11
- nautobot/dcim/models/__init__.py +2 -2
- nautobot/dcim/models/devices.py +16 -14
- nautobot/dcim/models/racks.py +3 -1
- nautobot/dcim/navigation.py +31 -23
- nautobot/dcim/signals.py +6 -6
- nautobot/dcim/tables/__init__.py +2 -2
- nautobot/dcim/tables/devices.py +15 -12
- nautobot/dcim/tables/template_code.py +1 -1
- nautobot/dcim/templates/dcim/controller_retrieve.html +18 -35
- nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +43 -0
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +43 -67
- nautobot/dcim/templates/dcim/device.html +2 -10
- nautobot/dcim/templates/dcim/device_edit.html +1 -1
- nautobot/dcim/tests/test_api.py +6 -11
- nautobot/dcim/tests/test_filters.py +81 -92
- nautobot/dcim/tests/test_graphql.py +1 -11
- nautobot/dcim/tests/test_models.py +15 -15
- nautobot/dcim/tests/test_signals.py +0 -2
- nautobot/dcim/tests/test_views.py +12 -24
- nautobot/dcim/urls.py +1 -1
- nautobot/dcim/views.py +15 -19
- nautobot/extras/api/urls.py +2 -1
- nautobot/extras/api/views.py +10 -0
- nautobot/extras/filters/__init__.py +2 -53
- nautobot/extras/forms/contacts.py +0 -7
- nautobot/extras/managers.py +0 -14
- nautobot/extras/navigation.py +65 -71
- nautobot/extras/plugins/views.py +11 -7
- nautobot/extras/tests/test_api.py +0 -2
- nautobot/extras/tests/test_dynamicgroups.py +0 -2
- nautobot/extras/tests/test_filters.py +4 -89
- nautobot/extras/tests/test_models.py +0 -9
- nautobot/extras/tests/test_relationships.py +1 -10
- nautobot/extras/tests/test_views.py +1 -112
- nautobot/extras/views.py +10 -10
- nautobot/ipam/api/urls.py +2 -1
- nautobot/ipam/api/views.py +11 -0
- nautobot/ipam/tables.py +22 -2
- nautobot/ipam/tests/test_graphql.py +3 -2
- nautobot/ipam/tests/test_views.py +0 -1
- nautobot/ipam/views.py +9 -9
- nautobot/project-static/css/base.css +0 -1
- nautobot/project-static/docs/404.html +3 -24
- nautobot/project-static/docs/apps/index.html +3 -24
- nautobot/project-static/docs/apps/nautobot-apps.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +5 -26
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +3 -24
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +3 -242
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +5 -69
- nautobot/project-static/docs/development/apps/api/configuration-view.html +3 -24
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +3 -24
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +3 -24
- nautobot/project-static/docs/development/apps/api/models/global-search.html +3 -24
- nautobot/project-static/docs/development/apps/api/models/graphql.html +3 -24
- nautobot/project-static/docs/development/apps/api/models/index.html +3 -24
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +3 -24
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +3 -24
- nautobot/project-static/docs/development/apps/api/prometheus.html +3 -24
- nautobot/project-static/docs/development/apps/api/setup.html +3 -24
- nautobot/project-static/docs/development/apps/api/testing.html +3 -24
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +3 -24
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +3 -24
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +3 -24
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +3 -24
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/base-template.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +12 -38
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +15 -41
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/index.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/notes.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +3 -24
- nautobot/project-static/docs/development/apps/api/views/urls.html +3 -24
- nautobot/project-static/docs/development/apps/index.html +3 -24
- nautobot/project-static/docs/development/apps/migration/code-updates.html +3 -24
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +3 -24
- nautobot/project-static/docs/development/apps/migration/from-v1.html +3 -24
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +3 -24
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +3 -24
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +3 -24
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +3 -24
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +3 -24
- nautobot/project-static/docs/development/core/application-registry.html +3 -24
- nautobot/project-static/docs/development/core/best-practices.html +3 -24
- nautobot/project-static/docs/development/core/bootstrap-ui.html +3 -24
- nautobot/project-static/docs/development/core/caching.html +3 -24
- nautobot/project-static/docs/development/core/controllers.html +204 -35
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +3 -24
- nautobot/project-static/docs/development/core/extending-models.html +3 -24
- nautobot/project-static/docs/development/core/generic-views.html +3 -24
- nautobot/project-static/docs/development/core/getting-started.html +13 -43
- nautobot/project-static/docs/development/core/homepage.html +3 -24
- nautobot/project-static/docs/development/core/index.html +3 -24
- nautobot/project-static/docs/development/core/model-features.html +3 -24
- nautobot/project-static/docs/development/core/natural-keys.html +3 -24
- nautobot/project-static/docs/development/core/navigation-menu.html +3 -24
- nautobot/project-static/docs/development/core/release-checklist.html +3 -24
- nautobot/project-static/docs/development/core/role-internals.html +3 -24
- nautobot/project-static/docs/development/core/settings.html +3 -24
- nautobot/project-static/docs/development/core/style-guide.html +3 -24
- nautobot/project-static/docs/development/core/templates.html +3 -24
- nautobot/project-static/docs/development/core/testing.html +3 -24
- nautobot/project-static/docs/development/core/user-preferences.html +3 -24
- nautobot/project-static/docs/development/index.html +3 -24
- nautobot/project-static/docs/development/jobs/index.html +3 -24
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +3 -24
- nautobot/project-static/docs/index.html +3 -24
- nautobot/project-static/docs/models/dcim/{controllermanageddevicegroup.html → controllerdevicegroup.html} +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +3 -24
- nautobot/project-static/docs/release-notes/version-1.0.html +3 -24
- nautobot/project-static/docs/release-notes/version-1.1.html +3 -24
- nautobot/project-static/docs/release-notes/version-1.2.html +3 -24
- nautobot/project-static/docs/release-notes/version-1.3.html +3 -24
- nautobot/project-static/docs/release-notes/version-1.4.html +3 -24
- nautobot/project-static/docs/release-notes/version-1.5.html +3 -24
- nautobot/project-static/docs/release-notes/version-1.6.html +3 -24
- nautobot/project-static/docs/release-notes/version-2.0.html +3 -24
- nautobot/project-static/docs/release-notes/version-2.1.html +162 -411
- nautobot/project-static/docs/release-notes/version-2.2.html +30 -212
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +255 -260
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +3 -24
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +3 -24
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +3 -24
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +3 -24
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +3 -24
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +3 -24
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +3 -24
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +3 -24
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +3 -24
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +6 -31
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +3 -24
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +3 -24
- nautobot/project-static/docs/user-guide/administration/installation/index.html +3 -24
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +3 -24
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +3 -24
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +6 -27
- nautobot/project-static/docs/user-guide/administration/installation/services.html +3 -24
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +3 -24
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +3 -24
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +3 -24
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +3 -24
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +11 -259
- nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllermanageddevicegroup.html → controllerdevicegroup.html} +17 -107
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +6 -27
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +3 -24
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/{contacts-and-teams.html → contact-and-team.html} +4 -25
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +5 -26
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +5 -26
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +3 -24
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +3 -24
- nautobot/project-static/docs/user-guide/index.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +3 -24
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +3 -24
- nautobot/tenancy/api/urls.py +2 -1
- nautobot/tenancy/api/views.py +12 -0
- nautobot/tenancy/tables.py +1 -1
- nautobot/tenancy/tests/test_views.py +0 -1
- nautobot/users/api/urls.py +2 -1
- nautobot/users/api/views.py +65 -2
- nautobot/users/views.py +8 -8
- nautobot/virtualization/api/urls.py +2 -1
- nautobot/virtualization/api/views.py +12 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/METADATA +3 -3
- {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/RECORD +356 -361
- nautobot/core/tests/integration/test_view_authentication.py +0 -67
- nautobot/dcim/management/commands/migrate_location_contacts.py +0 -218
- nautobot/dcim/templates/dcim/controller_create.html +0 -70
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +0 -88
- nautobot/ipam/tests/test_tables.py +0 -42
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +0 -8581
- /nautobot/dcim/templates/dcim/{controllermanageddevicegroup_retrieve.html → controllerdevicegroup_retrieve.html} +0 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/NOTICE +0 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/WHEEL +0 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -85,7 +85,7 @@ def hyperlinked_object(value, field="display"):
|
|
|
85
85
|
@register.filter()
|
|
86
86
|
def hyperlinked_email(value):
|
|
87
87
|
"""Render an email address as a `mailto:` hyperlink."""
|
|
88
|
-
if
|
|
88
|
+
if value is None:
|
|
89
89
|
return placeholder(value)
|
|
90
90
|
return format_html('<a href="mailto:{}">{}</a>', value, value)
|
|
91
91
|
|
|
@@ -94,7 +94,7 @@ def hyperlinked_email(value):
|
|
|
94
94
|
@register.filter()
|
|
95
95
|
def hyperlinked_phone_number(value):
|
|
96
96
|
"""Render a phone number as a `tel:` hyperlink."""
|
|
97
|
-
if
|
|
97
|
+
if value is None:
|
|
98
98
|
return placeholder(value)
|
|
99
99
|
return format_html('<a href="tel:{}">{}</a>', value, value)
|
|
100
100
|
|
nautobot/core/testing/views.py
CHANGED
|
@@ -17,7 +17,6 @@ from tree_queries.models import TreeNode
|
|
|
17
17
|
|
|
18
18
|
from nautobot.core import testing
|
|
19
19
|
from nautobot.core.models.generics import PrimaryModel
|
|
20
|
-
from nautobot.core.models.tree_queries import TreeModel
|
|
21
20
|
from nautobot.core.templatetags import helpers
|
|
22
21
|
from nautobot.core.testing import mixins
|
|
23
22
|
from nautobot.core.utils import lookup
|
|
@@ -25,7 +24,6 @@ from nautobot.extras import choices as extras_choices, models as extras_models,
|
|
|
25
24
|
from nautobot.extras.forms import CustomFieldModelFormMixin, RelationshipModelFormMixin
|
|
26
25
|
from nautobot.extras.models import CustomFieldModel, RelationshipModel
|
|
27
26
|
from nautobot.extras.models.mixins import NotesMixin
|
|
28
|
-
from nautobot.ipam.models import Prefix
|
|
29
27
|
from nautobot.users import models as users_models
|
|
30
28
|
|
|
31
29
|
__all__ = (
|
|
@@ -724,8 +722,6 @@ class ViewTestCases:
|
|
|
724
722
|
"""
|
|
725
723
|
|
|
726
724
|
filterset = None
|
|
727
|
-
filter_on_field = "name"
|
|
728
|
-
sort_on_field = "tags"
|
|
729
725
|
|
|
730
726
|
def get_filterset(self):
|
|
731
727
|
return self.filterset or lookup.get_filterset_for_model(self.model)
|
|
@@ -741,32 +737,6 @@ class ViewTestCases:
|
|
|
741
737
|
def get_list_view(self):
|
|
742
738
|
return lookup.get_view_for_model(self.model, view_type="List")
|
|
743
739
|
|
|
744
|
-
def test_table_with_indentation_is_removed_on_filter_or_sort(self):
|
|
745
|
-
self.user.is_superuser = True
|
|
746
|
-
self.user.save()
|
|
747
|
-
|
|
748
|
-
if not issubclass(self.model, (TreeModel)) and self.model is not Prefix:
|
|
749
|
-
self.skipTest("Skipping Non TreeModels")
|
|
750
|
-
|
|
751
|
-
with self.subTest("Assert indentation is present"):
|
|
752
|
-
response = self.client.get(f"{self._get_url('list')}")
|
|
753
|
-
response_body = response.content.decode(response.charset)
|
|
754
|
-
self.assertInHTML('<i class="mdi mdi-circle-small"></i>', response_body)
|
|
755
|
-
|
|
756
|
-
with self.subTest("Assert indentation is removed on filter"):
|
|
757
|
-
queryset = (
|
|
758
|
-
self._get_queryset().filter(parent__isnull=False).values_list(self.filter_on_field, flat=True)[:5]
|
|
759
|
-
)
|
|
760
|
-
filter_values = "&".join([f"{self.filter_on_field}={instance_value}" for instance_value in queryset])
|
|
761
|
-
response = self.client.get(f"{self._get_url('list')}?{filter_values}")
|
|
762
|
-
response_body = response.content.decode(response.charset)
|
|
763
|
-
self.assertNotIn('<i class="mdi mdi-circle-small"></i>', response_body)
|
|
764
|
-
|
|
765
|
-
with self.subTest("Assert indentation is removed on sort"):
|
|
766
|
-
response = self.client.get(f"{self._get_url('list')}?sort={self.sort_on_field}")
|
|
767
|
-
response_body = response.content.decode(response.charset)
|
|
768
|
-
self.assertNotIn('<i class="mdi mdi-circle-small"></i>', response_body)
|
|
769
|
-
|
|
770
740
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
771
741
|
def test_list_objects_anonymous(self):
|
|
772
742
|
# Make the request as an unauthenticated user
|
nautobot/core/tests/test_api.py
CHANGED
|
@@ -770,7 +770,6 @@ class APIOrderingTestCase(testing.APITestCase):
|
|
|
770
770
|
"TextField": "admin_contact",
|
|
771
771
|
"DateTimeField": "created",
|
|
772
772
|
}
|
|
773
|
-
cls.maxDiff = None
|
|
774
773
|
|
|
775
774
|
def _validate_sorted_response(self, response, queryset, field_name, is_fk_field=False):
|
|
776
775
|
self.assertHttpStatus(response, 200)
|
|
@@ -795,24 +794,18 @@ class APIOrderingTestCase(testing.APITestCase):
|
|
|
795
794
|
"""Tests that results are returned in the expected ascending order."""
|
|
796
795
|
|
|
797
796
|
for field_type, field_name in self.field_type_map.items():
|
|
798
|
-
with self.subTest(f"Testing {field_type}
|
|
799
|
-
|
|
800
|
-
response
|
|
801
|
-
self._validate_sorted_response(
|
|
802
|
-
response, Provider.objects.all().order_by(field_name, "name"), field_name
|
|
803
|
-
)
|
|
797
|
+
with self.subTest(f"Testing {field_type}"):
|
|
798
|
+
response = self.client.get(f"{self.url}?sort={field_name}&limit=10", **self.header)
|
|
799
|
+
self._validate_sorted_response(response, Provider.objects.all().order_by(field_name), field_name)
|
|
804
800
|
|
|
805
801
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
806
802
|
def test_descending_sort(self):
|
|
807
803
|
"""Tests that results are returned in the expected descending order."""
|
|
808
804
|
|
|
809
805
|
for field_type, field_name in self.field_type_map.items():
|
|
810
|
-
with self.subTest(f"Testing {field_type}
|
|
811
|
-
|
|
812
|
-
response
|
|
813
|
-
self._validate_sorted_response(
|
|
814
|
-
response, Provider.objects.all().order_by(f"-{field_name}", "name"), field_name
|
|
815
|
-
)
|
|
806
|
+
with self.subTest(f"Testing {field_type}"):
|
|
807
|
+
response = self.client.get(f"{self.url}?sort=-{field_name}&limit=10", **self.header)
|
|
808
|
+
self._validate_sorted_response(response, Provider.objects.all().order_by(f"-{field_name}"), field_name)
|
|
816
809
|
|
|
817
810
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
818
811
|
def test_sorting_tree_node_models(self):
|
nautobot/core/tests/test_csv.py
CHANGED
|
@@ -4,7 +4,7 @@ from django.urls import reverse
|
|
|
4
4
|
|
|
5
5
|
from nautobot.core.constants import CSV_NO_OBJECT, CSV_NULL_TYPE, VARBINARY_IP_FIELD_REPR_OF_CSV_NO_OBJECT
|
|
6
6
|
from nautobot.dcim.api.serializers import DeviceSerializer
|
|
7
|
-
from nautobot.dcim.models.devices import
|
|
7
|
+
from nautobot.dcim.models.devices import Device, DeviceType
|
|
8
8
|
from nautobot.dcim.models.locations import Location
|
|
9
9
|
from nautobot.extras.models.roles import Role
|
|
10
10
|
from nautobot.extras.models.statuses import Status
|
|
@@ -25,7 +25,6 @@ class CSVParsingRelatedTestCase(TestCase):
|
|
|
25
25
|
devicerole = Role.objects.get_for_model(Device).first()
|
|
26
26
|
device_status = Status.objects.get_for_model(Device).first()
|
|
27
27
|
tags = Tag.objects.get_for_model(Device).all()[:3]
|
|
28
|
-
Controller.objects.filter(controller_device__isnull=False).delete()
|
|
29
28
|
Device.objects.all().delete()
|
|
30
29
|
self.device = Device.objects.create(
|
|
31
30
|
device_type=devicetype,
|
|
@@ -93,7 +92,7 @@ class CSVParsingRelatedTestCase(TestCase):
|
|
|
93
92
|
"primary_ip6__host",
|
|
94
93
|
"cluster__name",
|
|
95
94
|
"virtual_chassis__name",
|
|
96
|
-
"
|
|
95
|
+
"controller_device_group__name",
|
|
97
96
|
"device_redundancy_group__name",
|
|
98
97
|
"software_version__platform__name",
|
|
99
98
|
"software_version__version",
|
|
@@ -120,7 +119,7 @@ class CSVParsingRelatedTestCase(TestCase):
|
|
|
120
119
|
"primary_ip6",
|
|
121
120
|
"cluster",
|
|
122
121
|
"virtual_chassis",
|
|
123
|
-
"
|
|
122
|
+
"controller_device_group",
|
|
124
123
|
"device_redundancy_group",
|
|
125
124
|
"secrets_group",
|
|
126
125
|
]
|
|
@@ -225,7 +224,7 @@ class CSVParsingRelatedTestCase(TestCase):
|
|
|
225
224
|
"primary_ip6__host": CSV_NO_OBJECT,
|
|
226
225
|
"cluster__name": CSV_NO_OBJECT,
|
|
227
226
|
"virtual_chassis__name": CSV_NO_OBJECT,
|
|
228
|
-
"
|
|
227
|
+
"controller_device_group__name": CSV_NO_OBJECT,
|
|
229
228
|
"device_redundancy_group__name": CSV_NO_OBJECT,
|
|
230
229
|
"software_version__platform__name": CSV_NO_OBJECT,
|
|
231
230
|
"software_version__version": CSV_NO_OBJECT,
|
|
@@ -17,7 +17,7 @@ from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
|
17
17
|
from nautobot.core.models import fields as core_fields
|
|
18
18
|
from nautobot.core.utils import lookup
|
|
19
19
|
from nautobot.dcim import choices as dcim_choices, filters as dcim_filters, models as dcim_models
|
|
20
|
-
from nautobot.dcim.models import
|
|
20
|
+
from nautobot.dcim.models import Device
|
|
21
21
|
from nautobot.extras import models as extras_models
|
|
22
22
|
from nautobot.extras.utils import FeatureQuery
|
|
23
23
|
from nautobot.ipam import models as ipam_models
|
|
@@ -830,7 +830,6 @@ class DynamicFilterLookupExpressionTest(TestCase):
|
|
|
830
830
|
@classmethod
|
|
831
831
|
def setUpTestData(cls):
|
|
832
832
|
manufacturers = dcim_models.Manufacturer.objects.all()[:3]
|
|
833
|
-
Controller.objects.filter(controller_device__isnull=False).delete()
|
|
834
833
|
Device.objects.all().delete()
|
|
835
834
|
|
|
836
835
|
device_types = (
|
|
@@ -43,7 +43,6 @@ from nautobot.dcim.models import (
|
|
|
43
43
|
Cable,
|
|
44
44
|
ConsolePort,
|
|
45
45
|
ConsoleServerPort,
|
|
46
|
-
Controller,
|
|
47
46
|
Device,
|
|
48
47
|
DeviceType,
|
|
49
48
|
FrontPort,
|
|
@@ -631,9 +630,21 @@ class GraphQLAPIPermissionTest(GraphQLTestCaseBase):
|
|
|
631
630
|
self.assertEqual(names, ["Rack 1-1", "Rack 1-2", "Rack 2-1", "Rack 2-2"])
|
|
632
631
|
|
|
633
632
|
def test_graphql_api_no_token(self):
|
|
634
|
-
"""Validate unauthenticated users are not able to query anything."""
|
|
633
|
+
"""Validate unauthenticated users are not able to query anything by default."""
|
|
635
634
|
response = self.client.post(self.api_url, {"query": self.get_racks_query}, format="json")
|
|
636
|
-
self.assertEqual(response.status_code, status.
|
|
635
|
+
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
636
|
+
self.assertIsInstance(response.data["data"]["racks"], list)
|
|
637
|
+
names = [item["name"] for item in response.data["data"]["racks"]]
|
|
638
|
+
self.assertEqual(names, [])
|
|
639
|
+
|
|
640
|
+
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
641
|
+
def test_graphql_api_no_token_exempt(self):
|
|
642
|
+
"""Validate unauthenticated users are able to query based on the exempt permissions."""
|
|
643
|
+
response = self.client.post(self.api_url, {"query": self.get_racks_query}, format="json")
|
|
644
|
+
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
645
|
+
self.assertIsInstance(response.data["data"]["racks"], list)
|
|
646
|
+
names = [item["name"] for item in response.data["data"]["racks"]]
|
|
647
|
+
self.assertEqual(names, ["Rack 1-1", "Rack 1-2", "Rack 2-1", "Rack 2-2"])
|
|
637
648
|
|
|
638
649
|
def test_graphql_api_wrong_token(self):
|
|
639
650
|
"""Validate a wrong token return 403."""
|
|
@@ -710,7 +721,6 @@ class GraphQLQueryTest(GraphQLTestCaseBase):
|
|
|
710
721
|
|
|
711
722
|
# Remove random IPAddress and Device fixtures for this custom test
|
|
712
723
|
IPAddress.objects.all().delete()
|
|
713
|
-
Controller.objects.filter(controller_device__isnull=False).delete()
|
|
714
724
|
Device.objects.all().delete()
|
|
715
725
|
|
|
716
726
|
# Initialize fake request that will be required to execute GraphQL query
|
|
@@ -44,8 +44,6 @@ class NavMenuTestCase(TestCase):
|
|
|
44
44
|
expected_name = "Interfaces"
|
|
45
45
|
elif expected_name == "Object Changes":
|
|
46
46
|
expected_name = "Change Log"
|
|
47
|
-
elif expected_name == "Controller Managed Device Groups":
|
|
48
|
-
expected_name = "Managed Device Groups"
|
|
49
47
|
self.assertEqual(item_details["name"], expected_name)
|
|
50
48
|
if item_url == get_route_for_model(view_model, "list"):
|
|
51
49
|
# Not assertEqual as some menu items have additional permissions defined.
|
|
@@ -89,7 +87,6 @@ class NavMenuTestCase(TestCase):
|
|
|
89
87
|
self.assertEqual(expected_perms[tab_name], tab_details["permissions"])
|
|
90
88
|
|
|
91
89
|
|
|
92
|
-
@tag("unit")
|
|
93
90
|
class NewUINavTest(TestCase):
|
|
94
91
|
@patch.dict(registry, values={"new_ui_nav_menu": {}}, clear=True)
|
|
95
92
|
def test_build_new_ui_nav_menu(self):
|
|
@@ -305,31 +305,25 @@ class LoginUITestCase(TestCase):
|
|
|
305
305
|
sso_login_search_result = self.make_request()
|
|
306
306
|
self.assertIsNotNone(sso_login_search_result)
|
|
307
307
|
|
|
308
|
-
|
|
309
|
-
|
|
308
|
+
@override_settings(BANNER_TOP="Hello, Banner Top", BANNER_BOTTOM="Hello, Banner Bottom")
|
|
309
|
+
def test_routes_redirect_back_to_login_unauthenticated(self):
|
|
310
|
+
"""Assert that api docs and graphql redirects to login page if user is unauthenticated."""
|
|
310
311
|
self.client.logout()
|
|
311
312
|
headers = {"HTTP_ACCEPT": "text/html"}
|
|
312
|
-
|
|
313
|
-
response = self.client.get(url, follow=True, **headers)
|
|
314
|
-
self.assertHttpStatus(response, 200)
|
|
315
|
-
self.assertRedirects(response, f"/login/?next={url}")
|
|
316
|
-
response_content = response.content.decode(response.charset).replace("\n", "")
|
|
317
|
-
for footer_text in self.footer_elements:
|
|
318
|
-
self.assertNotIn(footer_text, response_content)
|
|
319
|
-
|
|
320
|
-
def test_api_docs_403_unauthenticated(self):
|
|
321
|
-
"""Assert that api docs return a 403 Forbidden if user is unauthenticated."""
|
|
322
|
-
self.client.logout()
|
|
323
|
-
urls = [
|
|
324
|
-
reverse("api_docs"),
|
|
325
|
-
reverse("api_redocs"),
|
|
326
|
-
reverse("schema"),
|
|
327
|
-
reverse("schema_json"),
|
|
328
|
-
reverse("schema_yaml"),
|
|
329
|
-
]
|
|
313
|
+
urls = [reverse("api_docs"), reverse("graphql")]
|
|
330
314
|
for url in urls:
|
|
331
|
-
response = self.client.get(url)
|
|
332
|
-
self.assertHttpStatus(response,
|
|
315
|
+
response = self.client.get(url, follow=True, **headers)
|
|
316
|
+
self.assertHttpStatus(response, 200)
|
|
317
|
+
redirect_chain = [(f"/login/?next={url}", 302)]
|
|
318
|
+
self.assertEqual(response.redirect_chain, redirect_chain)
|
|
319
|
+
response_content = response.content.decode(response.charset).replace("\n", "")
|
|
320
|
+
# Assert Footer items(`self.footer_elements`), Banner and Banner Top is hidden
|
|
321
|
+
for footer_text in self.footer_elements:
|
|
322
|
+
self.assertNotIn(footer_text, response_content)
|
|
323
|
+
# Only API Docs implements BANNERS
|
|
324
|
+
if url == urls[0]:
|
|
325
|
+
self.assertNotIn("Hello, Banner Top", response_content)
|
|
326
|
+
self.assertNotIn("Hello, Banner Bottom", response_content)
|
|
333
327
|
|
|
334
328
|
|
|
335
329
|
class MetricsViewTestCase(TestCase):
|
nautobot/core/utils/lookup.py
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
"""Utilities for looking up related classes and information."""
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
|
-
import re
|
|
5
4
|
|
|
6
5
|
from django.apps import apps
|
|
7
6
|
from django.conf import settings
|
|
8
7
|
from django.contrib.auth.models import Group
|
|
9
8
|
from django.contrib.contenttypes.models import ContentType
|
|
10
9
|
from django.db.models import Model
|
|
11
|
-
from django.urls import get_resolver, URLPattern, URLResolver
|
|
12
10
|
from django.utils.module_loading import import_string
|
|
13
11
|
|
|
14
12
|
|
|
@@ -234,125 +232,3 @@ def get_created_and_last_updated_usernames_for_model(instance):
|
|
|
234
232
|
last_updated_by = last_updated_by_record.user_name
|
|
235
233
|
|
|
236
234
|
return created_by, last_updated_by
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
def get_url_patterns(urlconf=None, patterns_list=None, base_path="/"):
|
|
240
|
-
"""
|
|
241
|
-
Recursively yield a list of registered URL patterns.
|
|
242
|
-
|
|
243
|
-
Args:
|
|
244
|
-
urlconf (URLConf): Python module such as `nautobot.core.urls`.
|
|
245
|
-
Default if unspecified is the value of `settings.ROOT_URLCONF`, i.e. the `nautobot.core.urls` module.
|
|
246
|
-
patterns_list (list): Used in recursion. Generally can be omitted on initial call.
|
|
247
|
-
Default if unspecified is the `url_patterns` attribute of the given `urlconf` module.
|
|
248
|
-
base_path (str): String to prepend to all URL patterns yielded.
|
|
249
|
-
Default if unspecified is the string `"/"`.
|
|
250
|
-
|
|
251
|
-
Yields:
|
|
252
|
-
(str): Each URL pattern defined in the given urlconf and its descendants
|
|
253
|
-
|
|
254
|
-
Examples:
|
|
255
|
-
>>> generator = get_url_patterns()
|
|
256
|
-
>>> next(generator)
|
|
257
|
-
'/'
|
|
258
|
-
>>> next(generator)
|
|
259
|
-
'/search/'
|
|
260
|
-
>>> next(generator)
|
|
261
|
-
'/login/'
|
|
262
|
-
>>> next(generator)
|
|
263
|
-
'/logout/'
|
|
264
|
-
>>> next(generator)
|
|
265
|
-
'/circuits/circuits/<uuid:pk>/terminations/swap/'
|
|
266
|
-
|
|
267
|
-
>>> import example_plugin.urls as example_urls
|
|
268
|
-
>>> for url_pattern in get_url_patterns(example_urls, base_path="/plugins/example-app/"):
|
|
269
|
-
... print(url_pattern)
|
|
270
|
-
...
|
|
271
|
-
/plugins/example-app/
|
|
272
|
-
/plugins/example-app/config/
|
|
273
|
-
/plugins/example-app/models/<uuid:pk>/dynamic-groups/
|
|
274
|
-
/plugins/example-app/other-models/<uuid:pk>/dynamic-groups/
|
|
275
|
-
/plugins/example-app/docs/
|
|
276
|
-
/plugins/example-app/circuits/<uuid:pk>/example-app-tab/
|
|
277
|
-
/plugins/example-app/devices/<uuid:pk>/example-app-tab-1/
|
|
278
|
-
/plugins/example-app/devices/<uuid:pk>/example-app-tab-2/
|
|
279
|
-
/plugins/example-app/override-target/
|
|
280
|
-
/plugins/example-app/^models/$
|
|
281
|
-
/plugins/example-app/^models/add/$
|
|
282
|
-
/plugins/example-app/^models/import/$
|
|
283
|
-
/plugins/example-app/^models/edit/$
|
|
284
|
-
/plugins/example-app/^models/delete/$
|
|
285
|
-
/plugins/example-app/^models/all-names/$
|
|
286
|
-
/plugins/example-app/^models/(?P<pk>[^/.]+)/$
|
|
287
|
-
/plugins/example-app/^models/(?P<pk>[^/.]+)/delete/$
|
|
288
|
-
/plugins/example-app/^models/(?P<pk>[^/.]+)/edit/$
|
|
289
|
-
/plugins/example-app/^models/(?P<pk>[^/.]+)/changelog/$
|
|
290
|
-
/plugins/example-app/^models/(?P<pk>[^/.]+)/notes/$
|
|
291
|
-
/plugins/example-app/^other-models/$
|
|
292
|
-
/plugins/example-app/^other-models/add/$
|
|
293
|
-
/plugins/example-app/^other-models/edit/$
|
|
294
|
-
/plugins/example-app/^other-models/delete/$
|
|
295
|
-
/plugins/example-app/^other-models/(?P<pk>[^/.]+)/$
|
|
296
|
-
/plugins/example-app/^other-models/(?P<pk>[^/.]+)/delete/$
|
|
297
|
-
/plugins/example-app/^other-models/(?P<pk>[^/.]+)/edit/$
|
|
298
|
-
/plugins/example-app/^other-models/(?P<pk>[^/.]+)/changelog/$
|
|
299
|
-
/plugins/example-app/^other-models/(?P<pk>[^/.]+)/notes/$
|
|
300
|
-
"""
|
|
301
|
-
if urlconf is None:
|
|
302
|
-
urlconf = settings.ROOT_URLCONF
|
|
303
|
-
if patterns_list is None:
|
|
304
|
-
patterns_list = get_resolver(urlconf).url_patterns
|
|
305
|
-
|
|
306
|
-
for item in patterns_list:
|
|
307
|
-
if isinstance(item, URLPattern):
|
|
308
|
-
yield base_path + str(item.pattern)
|
|
309
|
-
elif isinstance(item, URLResolver):
|
|
310
|
-
# Recurse!
|
|
311
|
-
yield from get_url_patterns(urlconf, item.url_patterns, base_path + str(item.pattern))
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
def get_url_for_url_pattern(url_pattern):
|
|
315
|
-
"""
|
|
316
|
-
Given a URL pattern, construct a URL string that would match that pattern.
|
|
317
|
-
|
|
318
|
-
Examples:
|
|
319
|
-
>>> get_url_for_url_pattern("/plugins/example-app/^models/(?P<pk>[^/.]+)/$")
|
|
320
|
-
'/plugins/example-app/models/00000000-0000-0000-0000-000000000000/'
|
|
321
|
-
>>> get_url_for_url_pattern("/circuits/circuit-terminations/<uuid:termination_a_id>/connect/<str:termination_b_type>/")
|
|
322
|
-
'/circuits/circuit-terminations/00000000-0000-0000-0000-000000000000/connect/string/'
|
|
323
|
-
"""
|
|
324
|
-
url = url_pattern
|
|
325
|
-
# Fixup tokens in path-style "classic" view URLs:
|
|
326
|
-
# "/admin/users/user/<id>/password/"
|
|
327
|
-
url = re.sub(r"<id>", "00000000-0000-0000-0000-000000000000", url)
|
|
328
|
-
# "/silk/request/<uuid:request_id>/profile/<int:profile_id>/"
|
|
329
|
-
url = re.sub(r"<int:\w+>", "1", url)
|
|
330
|
-
# "/admin/admin/logentry/<path:object_id>/"
|
|
331
|
-
url = re.sub(r"<path:\w+>", "1", url)
|
|
332
|
-
# "/dcim/sites/<slug:slug>/"
|
|
333
|
-
url = re.sub(r"<slug:\w+>", "slug", url)
|
|
334
|
-
# "/apps/installed-apps/<str:app>/"
|
|
335
|
-
url = re.sub(r"<str:\w+>", "string", url)
|
|
336
|
-
# "/dcim/locations/<uuid:pk>/"
|
|
337
|
-
url = re.sub(r"<uuid:\w+>", "00000000-0000-0000-0000-000000000000", url)
|
|
338
|
-
# tokens in regexp-style router urls, including REST and NautobotUIViewSet:
|
|
339
|
-
# "/extras/^external-integrations/(?P<pk>[^/.]+)/$"
|
|
340
|
-
# "/api/virtualization/^interfaces/(?P<pk>[^/.]+)/$"
|
|
341
|
-
# "/api/virtualization/^interfaces/(?P<pk>[^/.]+)\\.(?P<format>[a-z0-9]+)/?$"
|
|
342
|
-
url = re.sub(r"[$^]", "", url)
|
|
343
|
-
url = re.sub(r"/\?", "/", url)
|
|
344
|
-
url = re.sub(r"\(\?P<app_label>[^)]+\)", "users", url)
|
|
345
|
-
url = re.sub(r"\(\?P<class_path>[^)]+\)", "foo/bar/baz", url)
|
|
346
|
-
url = re.sub(r"\(\?P<format>[^)]+\)", "json", url)
|
|
347
|
-
url = re.sub(r"\(\?P<name>[^)]+\)", "string", url)
|
|
348
|
-
url = re.sub(r"\(\?P<pk>[^)]+\)", "00000000-0000-0000-0000-000000000000", url)
|
|
349
|
-
url = re.sub(r"\(\?P<slug>[^)]+\)", "string", url)
|
|
350
|
-
url = re.sub(r"\(\?P<url>[^)]+\)", "any", url)
|
|
351
|
-
# Fallthru for generic URL parameters
|
|
352
|
-
url = re.sub(r"\(\?P<\w+>[^)]+\)\??", "unknown", url)
|
|
353
|
-
url = re.sub(r"\\", "", url)
|
|
354
|
-
|
|
355
|
-
if any(char in url for char in "<>[]()?+^$"):
|
|
356
|
-
raise RuntimeError(f"Unhandled token in URL {url} derived from {url_pattern}")
|
|
357
|
-
|
|
358
|
-
return url
|
nautobot/core/views/__init__.py
CHANGED
|
@@ -11,7 +11,7 @@ from django.contrib.auth.decorators import permission_required
|
|
|
11
11
|
from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin
|
|
12
12
|
from django.contrib.contenttypes.models import ContentType
|
|
13
13
|
from django.http import HttpResponseForbidden, HttpResponseServerError, JsonResponse
|
|
14
|
-
from django.shortcuts import get_object_or_404, render
|
|
14
|
+
from django.shortcuts import get_object_or_404, redirect, render
|
|
15
15
|
from django.template import loader, RequestContext, Template
|
|
16
16
|
from django.template.exceptions import TemplateDoesNotExist
|
|
17
17
|
from django.urls import resolve, reverse
|
|
@@ -210,7 +210,7 @@ class SearchView(AccessMixin, View):
|
|
|
210
210
|
)
|
|
211
211
|
|
|
212
212
|
|
|
213
|
-
class StaticMediaFailureView(View):
|
|
213
|
+
class StaticMediaFailureView(View):
|
|
214
214
|
"""
|
|
215
215
|
Display a user-friendly error message with troubleshooting tips when a static media file fails to load.
|
|
216
216
|
"""
|
|
@@ -265,8 +265,12 @@ def csrf_failure(request, reason="", template_name="403_csrf_failure.html"):
|
|
|
265
265
|
return HttpResponseForbidden(t.render(context), content_type="text/html")
|
|
266
266
|
|
|
267
267
|
|
|
268
|
-
class CustomGraphQLView(
|
|
268
|
+
class CustomGraphQLView(GraphQLView):
|
|
269
269
|
def render_graphiql(self, request, **data):
|
|
270
|
+
if not request.user.is_authenticated:
|
|
271
|
+
graphql_url = reverse("graphql")
|
|
272
|
+
login_url = reverse(settings.LOGIN_URL)
|
|
273
|
+
return redirect(f"{login_url}?next={graphql_url}")
|
|
270
274
|
query_name = request.GET.get("name")
|
|
271
275
|
if query_name:
|
|
272
276
|
data["obj"] = GraphQLQuery.objects.get(name=query_name)
|
nautobot/core/views/generic.py
CHANGED
|
@@ -4,7 +4,6 @@ import re
|
|
|
4
4
|
|
|
5
5
|
from django.conf import settings
|
|
6
6
|
from django.contrib import messages
|
|
7
|
-
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
8
7
|
from django.contrib.contenttypes.models import ContentType
|
|
9
8
|
from django.core.exceptions import (
|
|
10
9
|
FieldDoesNotExist,
|
|
@@ -59,14 +58,6 @@ from nautobot.extras.tables import AssociatedContactsTable
|
|
|
59
58
|
from nautobot.extras.utils import remove_prefix_from_cf_key
|
|
60
59
|
|
|
61
60
|
|
|
62
|
-
class GenericView(LoginRequiredMixin, View):
|
|
63
|
-
"""
|
|
64
|
-
Base class for non-object-related views.
|
|
65
|
-
|
|
66
|
-
Enforces authentication, which Django's base View does not by default.
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
-
|
|
70
61
|
class ObjectView(ObjectPermissionRequiredMixin, View):
|
|
71
62
|
"""
|
|
72
63
|
Retrieve a single object for display.
|
|
@@ -229,7 +220,6 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
229
220
|
display_filter_params = []
|
|
230
221
|
dynamic_filter_form = None
|
|
231
222
|
filter_form = None
|
|
232
|
-
hide_hierarchy_ui = False
|
|
233
223
|
|
|
234
224
|
if self.filterset:
|
|
235
225
|
filter_params = self.get_filter_params(request)
|
|
@@ -242,12 +232,6 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
242
232
|
)
|
|
243
233
|
self.queryset = self.queryset.none()
|
|
244
234
|
|
|
245
|
-
# If a valid filterset is applied, we have to hide the hierarchy indentation in the UI for tables that support hierarchy indentation.
|
|
246
|
-
# NOTE: An empty filterset query-param is also valid filterset and we dont want to hide hierarchy indentation if no filter query-param is provided
|
|
247
|
-
# hence `filterset.data`.
|
|
248
|
-
if filterset.is_valid() and filterset.data:
|
|
249
|
-
hide_hierarchy_ui = True
|
|
250
|
-
|
|
251
235
|
display_filter_params = [
|
|
252
236
|
check_filter_for_display(filterset.filters, field_name, values)
|
|
253
237
|
for field_name, values in filter_params.items()
|
|
@@ -299,9 +283,9 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
299
283
|
table_config_form = None
|
|
300
284
|
if self.table:
|
|
301
285
|
# Construct the objects table
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
table = self.table(self.queryset, user=request.user,
|
|
286
|
+
# Order By is needed in the table `__init__` method
|
|
287
|
+
order_by = self.request.GET.getlist("sort")
|
|
288
|
+
table = self.table(self.queryset, user=request.user, order_by=order_by)
|
|
305
289
|
if "pk" in table.base_columns and (permissions["change"] or permissions["delete"]):
|
|
306
290
|
table.columns.show("pk")
|
|
307
291
|
|
nautobot/core/views/mixins.py
CHANGED
|
@@ -608,7 +608,6 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
|
|
|
608
608
|
action_buttons = ("add", "import", "export")
|
|
609
609
|
filterset_class = None
|
|
610
610
|
filterset_form_class = None
|
|
611
|
-
hide_hierarchy_ui = False
|
|
612
611
|
non_filter_params = (
|
|
613
612
|
"export", # trigger for CSV/export-template/YAML export # 3.0 TODO: remove, irrelevant after #4746
|
|
614
613
|
"page", # used by django-tables2.RequestConfig
|
|
@@ -630,12 +629,6 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
|
|
|
630
629
|
format_html("Invalid filters were specified: {}", self.filterset.errors),
|
|
631
630
|
)
|
|
632
631
|
queryset = queryset.none()
|
|
633
|
-
|
|
634
|
-
# If a valid filterset is applied, we have to hide the hierarchy indentation in the UI for tables that support hierarchy indentation.
|
|
635
|
-
# NOTE: An empty filterset query-param is also valid filterset and we dont want to hide hierarchy indentation if no filter query-param is provided
|
|
636
|
-
# hence `filterset.data`.
|
|
637
|
-
if self.filterset.is_valid() and self.filterset.data:
|
|
638
|
-
self.hide_hierarchy_ui = True
|
|
639
632
|
return queryset
|
|
640
633
|
|
|
641
634
|
# 3.0 TODO: remove, irrelevant after #4746
|
nautobot/core/views/renderers.py
CHANGED
|
@@ -65,13 +65,10 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
|
|
|
65
65
|
table_class = view.get_table_class()
|
|
66
66
|
request = kwargs.get("request", view.request)
|
|
67
67
|
queryset = view.alter_queryset(request)
|
|
68
|
-
|
|
69
68
|
if view.action in ["list", "notes", "changelog"]:
|
|
70
69
|
if view.action == "list":
|
|
71
70
|
permissions = kwargs.get("permissions", {})
|
|
72
|
-
|
|
73
|
-
view.hide_hierarchy_ui = True # hide tree hierarchy if custom sort is used
|
|
74
|
-
table = table_class(queryset, user=request.user, hide_hierarchy_ui=view.hide_hierarchy_ui)
|
|
71
|
+
table = table_class(queryset, user=request.user)
|
|
75
72
|
if "pk" in table.base_columns and (permissions["change"] or permissions["delete"]):
|
|
76
73
|
table.columns.show("pk")
|
|
77
74
|
elif view.action == "notes":
|
nautobot/dcim/api/serializers.py
CHANGED
|
@@ -55,7 +55,7 @@ from nautobot.dcim.models import (
|
|
|
55
55
|
ConsoleServerPort,
|
|
56
56
|
ConsoleServerPortTemplate,
|
|
57
57
|
Controller,
|
|
58
|
-
|
|
58
|
+
ControllerDeviceGroup,
|
|
59
59
|
Device,
|
|
60
60
|
DeviceBay,
|
|
61
61
|
DeviceBayTemplate,
|
|
@@ -598,7 +598,7 @@ class DeviceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
|
598
598
|
"secrets_group",
|
|
599
599
|
"device_redundancy_group",
|
|
600
600
|
"device_redundancy_group_priority",
|
|
601
|
-
"
|
|
601
|
+
"controller_device_group",
|
|
602
602
|
]
|
|
603
603
|
},
|
|
604
604
|
},
|
|
@@ -1049,7 +1049,7 @@ class ControllerSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
|
1049
1049
|
fields = "__all__"
|
|
1050
1050
|
|
|
1051
1051
|
|
|
1052
|
-
class
|
|
1052
|
+
class ControllerDeviceGroupSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
1053
1053
|
class Meta:
|
|
1054
|
-
model =
|
|
1054
|
+
model = ControllerDeviceGroup
|
|
1055
1055
|
fields = "__all__"
|
nautobot/dcim/api/urls.py
CHANGED
|
@@ -2,7 +2,8 @@ from nautobot.core.api.routers import OrderedDefaultRouter
|
|
|
2
2
|
|
|
3
3
|
from . import views
|
|
4
4
|
|
|
5
|
-
router = OrderedDefaultRouter(
|
|
5
|
+
router = OrderedDefaultRouter()
|
|
6
|
+
router.APIRootView = views.DCIMRootView
|
|
6
7
|
|
|
7
8
|
# Locations
|
|
8
9
|
router.register("location-types", views.LocationTypeViewSet)
|
|
@@ -79,7 +80,7 @@ router.register("connected-device", views.ConnectedDeviceViewSet, basename="conn
|
|
|
79
80
|
|
|
80
81
|
# Controllers
|
|
81
82
|
router.register("controllers", views.ControllerViewSet)
|
|
82
|
-
router.register("controller-
|
|
83
|
+
router.register("controller-device-groups", views.ControllerDeviceGroupViewSet)
|
|
83
84
|
|
|
84
85
|
app_name = "dcim-api"
|
|
85
86
|
urlpatterns = router.urls
|