nautobot 2.2.0b1__py3-none-any.whl → 2.2.2__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/__init__.py +31 -0
- nautobot/apps/api.py +1 -2
- nautobot/apps/utils.py +4 -0
- nautobot/apps/views.py +2 -0
- nautobot/circuits/api/urls.py +1 -2
- nautobot/circuits/api/views.py +0 -12
- nautobot/circuits/apps.py +1 -1
- nautobot/circuits/tests/test_filters.py +1 -1
- nautobot/core/api/routers.py +50 -3
- nautobot/core/api/utils.py +4 -0
- nautobot/core/api/views.py +21 -15
- nautobot/core/cli/__init__.py +18 -11
- nautobot/core/constants.py +85 -0
- nautobot/core/filters.py +7 -1
- nautobot/core/forms/widgets.py +1 -2
- nautobot/core/graphql/schema.py +1 -0
- nautobot/core/management/commands/generate_test_data.py +4 -4
- nautobot/core/models/__init__.py +1 -0
- nautobot/core/settings.py +24 -3
- nautobot/core/settings.yaml +20 -0
- nautobot/core/signals.py +1 -0
- nautobot/core/tables.py +2 -1
- nautobot/core/templates/admin/base.html +23 -94
- nautobot/core/templates/generic/object_retrieve.html +2 -2
- nautobot/core/templates/graphene/graphiql.html +18 -47
- nautobot/core/templates/inc/footer.html +5 -5
- nautobot/core/templates/inc/javascript.html +4 -4
- nautobot/core/templates/inc/media.html +2 -2
- nautobot/core/templates/inc/nav_menu.html +0 -7
- nautobot/core/templates/nautobot_config.py.j2 +14 -1
- nautobot/core/templates/rest_framework/api.html +12 -5
- nautobot/core/templatetags/helpers.py +2 -2
- nautobot/core/testing/__init__.py +1 -1
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/testing/views.py +30 -0
- nautobot/core/tests/integration/test_view_authentication.py +68 -0
- nautobot/core/tests/test_api.py +13 -6
- nautobot/core/tests/test_csv.py +5 -4
- nautobot/core/tests/test_filters.py +2 -1
- nautobot/core/tests/test_graphql.py +4 -14
- nautobot/core/tests/test_navigations.py +3 -0
- nautobot/core/tests/test_views.py +45 -16
- nautobot/core/utils/data.py +1 -2
- nautobot/core/utils/lookup.py +126 -0
- nautobot/core/views/__init__.py +3 -7
- nautobot/core/views/generic.py +24 -10
- nautobot/core/views/mixins.py +11 -4
- nautobot/core/views/renderers.py +11 -6
- nautobot/core/wsgi.py +9 -2
- nautobot/dcim/api/serializers.py +4 -4
- nautobot/dcim/api/urls.py +2 -3
- nautobot/dcim/api/views.py +7 -18
- nautobot/dcim/apps.py +8 -4
- nautobot/dcim/elevations.py +5 -1
- nautobot/dcim/factory.py +7 -7
- nautobot/dcim/filters/__init__.py +16 -17
- nautobot/dcim/forms.py +69 -48
- nautobot/dcim/homepage.py +11 -3
- nautobot/dcim/management/commands/migrate_location_contacts.py +218 -0
- nautobot/dcim/migrations/0057_controller_models.py +11 -70
- nautobot/dcim/models/__init__.py +2 -2
- nautobot/dcim/models/devices.py +14 -16
- nautobot/dcim/models/racks.py +1 -3
- nautobot/dcim/navigation.py +23 -31
- nautobot/dcim/signals.py +6 -6
- nautobot/dcim/tables/__init__.py +2 -2
- nautobot/dcim/tables/devices.py +13 -16
- nautobot/dcim/tables/template_code.py +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +70 -0
- nautobot/dcim/templates/dcim/controller_retrieve.html +35 -18
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +88 -0
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +74 -42
- nautobot/dcim/templates/dcim/device.html +11 -3
- nautobot/dcim/templates/dcim/device_edit.html +1 -1
- nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
- nautobot/dcim/tests/test_api.py +47 -6
- nautobot/dcim/tests/test_filters.py +92 -81
- nautobot/dcim/tests/test_forms.py +49 -2
- nautobot/dcim/tests/test_graphql.py +11 -1
- nautobot/dcim/tests/test_models.py +15 -15
- nautobot/dcim/tests/test_signals.py +3 -1
- nautobot/dcim/tests/test_views.py +24 -12
- nautobot/dcim/urls.py +1 -1
- nautobot/dcim/views.py +25 -15
- nautobot/extras/api/serializers.py +20 -1
- nautobot/extras/api/urls.py +1 -2
- nautobot/extras/api/views.py +0 -10
- nautobot/extras/apps.py +7 -0
- nautobot/extras/context_managers.py +71 -4
- nautobot/extras/filters/__init__.py +53 -2
- nautobot/extras/filters/customfields.py +14 -9
- nautobot/extras/filters/mixins.py +6 -1
- nautobot/extras/forms/contacts.py +7 -0
- nautobot/extras/health_checks.py +1 -0
- nautobot/extras/jobs.py +1 -0
- nautobot/extras/managers.py +15 -2
- nautobot/extras/models/contacts.py +1 -0
- nautobot/extras/models/customfields.py +25 -2
- nautobot/extras/models/datasources.py +1 -0
- nautobot/extras/models/mixins.py +1 -0
- nautobot/extras/navigation.py +71 -65
- nautobot/extras/plugins/__init__.py +2 -1
- nautobot/extras/plugins/views.py +7 -11
- nautobot/extras/querysets.py +1 -2
- nautobot/extras/secrets/providers.py +1 -0
- nautobot/extras/signals.py +95 -51
- nautobot/extras/tasks.py +70 -17
- nautobot/extras/tests/test_api.py +2 -4
- nautobot/extras/tests/test_context_managers.py +98 -1
- nautobot/extras/tests/test_customfields.py +72 -9
- nautobot/extras/tests/test_dynamicgroups.py +2 -0
- nautobot/extras/tests/test_filters.py +89 -4
- nautobot/extras/tests/test_models.py +9 -0
- nautobot/extras/tests/test_relationships.py +10 -1
- nautobot/extras/tests/test_views.py +112 -1
- nautobot/extras/utils.py +37 -0
- nautobot/extras/views.py +18 -17
- nautobot/ipam/api/serializers.py +10 -0
- nautobot/ipam/api/urls.py +1 -2
- nautobot/ipam/api/views.py +0 -11
- nautobot/ipam/apps.py +3 -2
- nautobot/ipam/tables.py +3 -23
- nautobot/ipam/tests/test_graphql.py +2 -3
- nautobot/ipam/tests/test_tables.py +42 -0
- nautobot/ipam/tests/test_views.py +1 -0
- nautobot/ipam/views.py +9 -9
- nautobot/project-static/css/base.css +1 -0
- nautobot/project-static/docs/404.html +126 -73
- nautobot/project-static/docs/apps/index.html +127 -71
- nautobot/project-static/docs/apps/nautobot-apps.html +127 -71
- nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +167 -73
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +165 -72
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +128 -72
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +345 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +172 -73
- nautobot/project-static/docs/development/apps/api/configuration-view.html +127 -71
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/global-search.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/graphql.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +127 -71
- nautobot/project-static/docs/development/apps/api/prometheus.html +127 -71
- nautobot/project-static/docs/development/apps/api/setup.html +127 -71
- nautobot/project-static/docs/development/apps/api/testing.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/base-template.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +141 -80
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +144 -83
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/notes.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/urls.html +127 -71
- nautobot/project-static/docs/development/apps/index.html +127 -71
- nautobot/project-static/docs/development/apps/migration/code-updates.html +127 -71
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +127 -71
- nautobot/project-static/docs/development/apps/migration/from-v1.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +127 -71
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +127 -71
- nautobot/project-static/docs/development/core/application-registry.html +127 -71
- nautobot/project-static/docs/development/core/best-practices.html +145 -79
- nautobot/project-static/docs/development/core/bootstrap-ui.html +127 -71
- nautobot/project-static/docs/development/core/caching.html +127 -71
- nautobot/project-static/docs/development/core/controllers.html +141 -275
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +127 -71
- nautobot/project-static/docs/development/core/extending-models.html +13 -8166
- nautobot/project-static/docs/development/core/generic-views.html +142 -86
- nautobot/project-static/docs/development/core/getting-started.html +146 -81
- nautobot/project-static/docs/development/core/homepage.html +145 -89
- nautobot/project-static/docs/development/core/index.html +127 -71
- nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
- nautobot/project-static/docs/development/core/model-features.html +130 -74
- nautobot/project-static/docs/development/core/natural-keys.html +127 -71
- nautobot/project-static/docs/development/core/navigation-menu.html +127 -71
- nautobot/project-static/docs/development/core/release-checklist.html +127 -71
- nautobot/project-static/docs/development/core/role-internals.html +127 -71
- nautobot/project-static/docs/development/core/settings.html +127 -71
- nautobot/project-static/docs/development/core/style-guide.html +127 -71
- nautobot/project-static/docs/development/core/templates.html +127 -71
- nautobot/project-static/docs/development/core/testing.html +127 -71
- nautobot/project-static/docs/development/core/user-preferences.html +127 -71
- nautobot/project-static/docs/development/extending-models.html +3 -3
- nautobot/project-static/docs/development/index.html +127 -71
- nautobot/project-static/docs/development/jobs/index.html +128 -72
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +127 -71
- nautobot/project-static/docs/index.html +126 -73
- nautobot/project-static/docs/models/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.0.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.1.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.2.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.3.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.4.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.5.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.6.html +663 -304
- nautobot/project-static/docs/release-notes/version-2.0.html +127 -71
- nautobot/project-static/docs/release-notes/version-2.1.html +538 -254
- nautobot/project-static/docs/release-notes/version-2.2.html +711 -125
- nautobot/project-static/docs/requirements.txt +3 -3
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +264 -259
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +192 -71
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -71
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +130 -74
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +134 -74
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +8616 -0
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +130 -74
- nautobot/project-static/docs/user-guide/administration/installation/services.html +127 -71
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +127 -71
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +127 -71
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +127 -71
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +362 -79
- nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +210 -85
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +130 -74
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +138 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +138 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/{contact-and-team.html → contacts-and-teams.html} +128 -72
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +129 -73
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +129 -73
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +127 -71
- nautobot/project-static/docs/user-guide/index.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +127 -71
- nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
- nautobot/tenancy/api/urls.py +1 -2
- nautobot/tenancy/api/views.py +0 -12
- nautobot/tenancy/tables.py +1 -1
- nautobot/tenancy/tests/test_views.py +1 -0
- nautobot/users/api/urls.py +1 -2
- nautobot/users/api/views.py +2 -65
- nautobot/users/views.py +8 -8
- nautobot/virtualization/api/urls.py +1 -2
- nautobot/virtualization/api/views.py +0 -12
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/METADATA +24 -24
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/RECORD +422 -416
- nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +0 -43
- nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
- nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
- /nautobot/dcim/templates/dcim/{controllerdevicegroup_retrieve.html → controllermanageddevicegroup_retrieve.html} +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/NOTICE +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/WHEEL +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.2.dist-info}/entry_points.txt +0 -0
|
@@ -724,7 +724,16 @@ class CustomField(BaseModel, ChangeLoggedModel, NotesMixin):
|
|
|
724
724
|
|
|
725
725
|
super().delete(*args, **kwargs)
|
|
726
726
|
|
|
727
|
-
|
|
727
|
+
# Circular Import
|
|
728
|
+
from nautobot.extras.signals import change_context_state
|
|
729
|
+
|
|
730
|
+
change_context = change_context_state.get()
|
|
731
|
+
if change_context is None:
|
|
732
|
+
context = None
|
|
733
|
+
else:
|
|
734
|
+
context = change_context.as_dict(instance=self)
|
|
735
|
+
context["context_detail"] = "delete custom field data"
|
|
736
|
+
delete_custom_field_data.delay(self.key, content_types, context)
|
|
728
737
|
|
|
729
738
|
def add_prefix_to_cf_key(self):
|
|
730
739
|
return "cf_" + str(self.key)
|
|
@@ -783,8 +792,22 @@ class CustomFieldChoice(BaseModel, ChangeLoggedModel):
|
|
|
783
792
|
super().save(*args, **kwargs)
|
|
784
793
|
|
|
785
794
|
if self.value != database_object.value:
|
|
795
|
+
# Circular Import
|
|
796
|
+
from nautobot.extras.signals import change_context_state
|
|
797
|
+
|
|
798
|
+
change_context = change_context_state.get()
|
|
799
|
+
if change_context is None:
|
|
800
|
+
context = None
|
|
801
|
+
else:
|
|
802
|
+
context = change_context.as_dict(instance=self)
|
|
803
|
+
context["context_detail"] = "update custom field choice data"
|
|
786
804
|
transaction.on_commit(
|
|
787
|
-
lambda: update_custom_field_choice_data.delay(
|
|
805
|
+
lambda: update_custom_field_choice_data.delay(
|
|
806
|
+
self.custom_field.pk,
|
|
807
|
+
database_object.value,
|
|
808
|
+
self.value,
|
|
809
|
+
context,
|
|
810
|
+
)
|
|
788
811
|
)
|
|
789
812
|
|
|
790
813
|
def delete(self, *args, **kwargs):
|
nautobot/extras/models/mixins.py
CHANGED
nautobot/extras/navigation.py
CHANGED
|
@@ -14,8 +14,50 @@ menu_items = (
|
|
|
14
14
|
weight=100,
|
|
15
15
|
groups=(
|
|
16
16
|
NavMenuGroup(
|
|
17
|
-
name="
|
|
17
|
+
name="Contacts",
|
|
18
18
|
weight=400,
|
|
19
|
+
items=(
|
|
20
|
+
NavMenuItem(
|
|
21
|
+
link="extras:contact_list",
|
|
22
|
+
name="Contacts",
|
|
23
|
+
weight=100,
|
|
24
|
+
permissions=["extras.view_contact"],
|
|
25
|
+
buttons=[NavMenuAddButton(link="extras:contact_add", permissions=["extras.add_contact"])],
|
|
26
|
+
),
|
|
27
|
+
NavMenuItem(
|
|
28
|
+
link="extras:team_list",
|
|
29
|
+
name="Teams",
|
|
30
|
+
weight=200,
|
|
31
|
+
permissions=["extras.view_team"],
|
|
32
|
+
buttons=[NavMenuAddButton(link="extras:team_add", permissions=["extras.add_team"])],
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
NavMenuGroup(
|
|
37
|
+
name="Groups",
|
|
38
|
+
weight=500,
|
|
39
|
+
items=(
|
|
40
|
+
NavMenuItem(
|
|
41
|
+
link="extras:dynamicgroup_list",
|
|
42
|
+
name="Dynamic Groups",
|
|
43
|
+
weight=100,
|
|
44
|
+
permissions=[
|
|
45
|
+
"extras.view_dynamicgroup",
|
|
46
|
+
],
|
|
47
|
+
buttons=(
|
|
48
|
+
NavMenuAddButton(
|
|
49
|
+
link="extras:dynamicgroup_add",
|
|
50
|
+
permissions=[
|
|
51
|
+
"extras.add_dynamicgroup",
|
|
52
|
+
],
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
NavMenuGroup(
|
|
59
|
+
name="Metadata", # TODO: is there a better name for this grouping?
|
|
60
|
+
weight=600,
|
|
19
61
|
items=(
|
|
20
62
|
NavMenuItem(
|
|
21
63
|
link="extras:tag_list",
|
|
@@ -65,42 +107,6 @@ menu_items = (
|
|
|
65
107
|
),
|
|
66
108
|
),
|
|
67
109
|
),
|
|
68
|
-
NavMenuItem(
|
|
69
|
-
link="extras:contact_list",
|
|
70
|
-
name="Contacts",
|
|
71
|
-
weight=400,
|
|
72
|
-
permissions=["extras.view_contact"],
|
|
73
|
-
buttons=[NavMenuAddButton(link="extras:contact_add", permissions=["extras.add_contact"])],
|
|
74
|
-
),
|
|
75
|
-
NavMenuItem(
|
|
76
|
-
link="extras:team_list",
|
|
77
|
-
name="Teams",
|
|
78
|
-
weight=500,
|
|
79
|
-
permissions=["extras.view_team"],
|
|
80
|
-
buttons=[NavMenuAddButton(link="extras:team_add", permissions=["extras.add_team"])],
|
|
81
|
-
),
|
|
82
|
-
),
|
|
83
|
-
),
|
|
84
|
-
NavMenuGroup(
|
|
85
|
-
name="Dynamic Groups",
|
|
86
|
-
weight=500,
|
|
87
|
-
items=(
|
|
88
|
-
NavMenuItem(
|
|
89
|
-
link="extras:dynamicgroup_list",
|
|
90
|
-
name="Dynamic Groups",
|
|
91
|
-
weight=100,
|
|
92
|
-
permissions=[
|
|
93
|
-
"extras.view_dynamicgroup",
|
|
94
|
-
],
|
|
95
|
-
buttons=(
|
|
96
|
-
NavMenuAddButton(
|
|
97
|
-
link="extras:dynamicgroup_add",
|
|
98
|
-
permissions=[
|
|
99
|
-
"extras.add_dynamicgroup",
|
|
100
|
-
],
|
|
101
|
-
),
|
|
102
|
-
),
|
|
103
|
-
),
|
|
104
110
|
),
|
|
105
111
|
),
|
|
106
112
|
),
|
|
@@ -276,22 +282,6 @@ menu_items = (
|
|
|
276
282
|
),
|
|
277
283
|
),
|
|
278
284
|
),
|
|
279
|
-
NavMenuItem(
|
|
280
|
-
link="extras:relationship_list",
|
|
281
|
-
name="Relationships",
|
|
282
|
-
weight=200,
|
|
283
|
-
permissions=[
|
|
284
|
-
"extras.view_relationship",
|
|
285
|
-
],
|
|
286
|
-
buttons=(
|
|
287
|
-
NavMenuAddButton(
|
|
288
|
-
link="extras:relationship_add",
|
|
289
|
-
permissions=[
|
|
290
|
-
"extras.add_relationship",
|
|
291
|
-
],
|
|
292
|
-
),
|
|
293
|
-
),
|
|
294
|
-
),
|
|
295
285
|
NavMenuItem(
|
|
296
286
|
link="extras:note_list",
|
|
297
287
|
name="Notes",
|
|
@@ -389,37 +379,53 @@ menu_items = (
|
|
|
389
379
|
),
|
|
390
380
|
),
|
|
391
381
|
NavMenuGroup(
|
|
392
|
-
name="
|
|
382
|
+
name="Data Model",
|
|
393
383
|
weight=600,
|
|
394
384
|
items=(
|
|
395
385
|
NavMenuItem(
|
|
396
|
-
link="extras:
|
|
397
|
-
name="
|
|
386
|
+
link="extras:customfield_list",
|
|
387
|
+
name="Custom Fields",
|
|
398
388
|
weight=100,
|
|
399
389
|
permissions=[
|
|
400
|
-
"extras.
|
|
390
|
+
"extras.view_customfield",
|
|
401
391
|
],
|
|
402
392
|
buttons=(
|
|
403
393
|
NavMenuAddButton(
|
|
404
|
-
link="extras:
|
|
394
|
+
link="extras:customfield_add",
|
|
405
395
|
permissions=[
|
|
406
|
-
"extras.
|
|
396
|
+
"extras.add_customfield",
|
|
407
397
|
],
|
|
408
398
|
),
|
|
409
399
|
),
|
|
410
400
|
),
|
|
411
401
|
NavMenuItem(
|
|
412
|
-
link="extras:
|
|
413
|
-
name="
|
|
402
|
+
link="extras:relationship_list",
|
|
403
|
+
name="Relationships",
|
|
414
404
|
weight=200,
|
|
415
405
|
permissions=[
|
|
416
|
-
"extras.
|
|
406
|
+
"extras.view_relationship",
|
|
417
407
|
],
|
|
418
408
|
buttons=(
|
|
419
409
|
NavMenuAddButton(
|
|
420
|
-
link="extras:
|
|
410
|
+
link="extras:relationship_add",
|
|
421
411
|
permissions=[
|
|
422
|
-
"extras.
|
|
412
|
+
"extras.add_relationship",
|
|
413
|
+
],
|
|
414
|
+
),
|
|
415
|
+
),
|
|
416
|
+
),
|
|
417
|
+
NavMenuItem(
|
|
418
|
+
link="extras:computedfield_list",
|
|
419
|
+
name="Computed Fields",
|
|
420
|
+
weight=300,
|
|
421
|
+
permissions=[
|
|
422
|
+
"extras.view_computedfield",
|
|
423
|
+
],
|
|
424
|
+
buttons=(
|
|
425
|
+
NavMenuAddButton(
|
|
426
|
+
link="extras:computedfield_add",
|
|
427
|
+
permissions=[
|
|
428
|
+
"extras.add_computedfield",
|
|
423
429
|
],
|
|
424
430
|
),
|
|
425
431
|
),
|
|
@@ -427,7 +433,7 @@ menu_items = (
|
|
|
427
433
|
NavMenuItem(
|
|
428
434
|
link="extras:customlink_list",
|
|
429
435
|
name="Custom Links",
|
|
430
|
-
weight=
|
|
436
|
+
weight=400,
|
|
431
437
|
permissions=[
|
|
432
438
|
"extras.view_customlink",
|
|
433
439
|
],
|
|
@@ -4,6 +4,7 @@ from importlib import import_module
|
|
|
4
4
|
import inspect
|
|
5
5
|
from logging import getLogger
|
|
6
6
|
|
|
7
|
+
from django.conf import settings
|
|
7
8
|
from django.core.exceptions import ValidationError
|
|
8
9
|
from django.template.loader import get_template
|
|
9
10
|
from django.urls import get_resolver, URLPattern
|
|
@@ -147,7 +148,7 @@ class NautobotAppConfig(NautobotConfig):
|
|
|
147
148
|
|
|
148
149
|
# Import metrics (if present)
|
|
149
150
|
metrics = import_object(f"{self.__module__}.{self.metrics}")
|
|
150
|
-
if metrics is not None:
|
|
151
|
+
if metrics is not None and self.name not in settings.METRICS_DISABLED_APPS:
|
|
151
152
|
register_metrics(metrics)
|
|
152
153
|
self.features["metrics"] = [] # Initialize as empty, to be filled by the signal handler
|
|
153
154
|
# Inject the metrics to discover into the signal handler.
|
nautobot/extras/plugins/views.py
CHANGED
|
@@ -2,11 +2,9 @@ from collections import OrderedDict
|
|
|
2
2
|
|
|
3
3
|
from django.apps import apps
|
|
4
4
|
from django.conf import settings
|
|
5
|
-
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
6
5
|
from django.http import Http404
|
|
7
6
|
from django.shortcuts import render
|
|
8
7
|
from django.urls.exceptions import NoReverseMatch
|
|
9
|
-
from django.views.generic import View
|
|
10
8
|
from django_tables2 import RequestConfig
|
|
11
9
|
from drf_spectacular.utils import extend_schema
|
|
12
10
|
from rest_framework import permissions
|
|
@@ -14,13 +12,14 @@ from rest_framework.response import Response
|
|
|
14
12
|
from rest_framework.reverse import reverse
|
|
15
13
|
from rest_framework.views import APIView
|
|
16
14
|
|
|
17
|
-
from nautobot.core.api.views import NautobotAPIVersionMixin
|
|
15
|
+
from nautobot.core.api.views import AuthenticatedAPIRootView, NautobotAPIVersionMixin
|
|
18
16
|
from nautobot.core.forms import TableConfigForm
|
|
17
|
+
from nautobot.core.views.generic import GenericView
|
|
19
18
|
from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
20
19
|
from nautobot.extras.plugins.tables import InstalledAppsTable
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
class InstalledAppsView(
|
|
22
|
+
class InstalledAppsView(GenericView):
|
|
24
23
|
"""
|
|
25
24
|
View for listing all installed Apps.
|
|
26
25
|
"""
|
|
@@ -66,7 +65,7 @@ class InstalledAppsView(LoginRequiredMixin, View):
|
|
|
66
65
|
)
|
|
67
66
|
|
|
68
67
|
|
|
69
|
-
class InstalledAppDetailView(
|
|
68
|
+
class InstalledAppDetailView(GenericView):
|
|
70
69
|
"""
|
|
71
70
|
View for showing details of an installed App.
|
|
72
71
|
"""
|
|
@@ -93,7 +92,6 @@ class InstalledAppsAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
93
92
|
"""
|
|
94
93
|
|
|
95
94
|
permission_classes = [permissions.IsAdminUser]
|
|
96
|
-
_ignore_model_permissions = True
|
|
97
95
|
|
|
98
96
|
def get_view_name(self):
|
|
99
97
|
return "Installed Apps"
|
|
@@ -129,11 +127,9 @@ class InstalledAppsAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
129
127
|
return Response([self._get_app_data(apps.get_app_config(app)) for app in settings.PLUGINS])
|
|
130
128
|
|
|
131
129
|
|
|
132
|
-
class AppsAPIRootView(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def get_view_name(self):
|
|
136
|
-
return "Apps"
|
|
130
|
+
class AppsAPIRootView(AuthenticatedAPIRootView):
|
|
131
|
+
name = "Apps"
|
|
132
|
+
description = "API extension point for installed Nautobot Apps"
|
|
137
133
|
|
|
138
134
|
@staticmethod
|
|
139
135
|
def _get_app_entry(app_config, request, format_):
|
nautobot/extras/querysets.py
CHANGED
|
@@ -3,7 +3,6 @@ from django.contrib.contenttypes.models import ContentType
|
|
|
3
3
|
from django.core.cache import cache
|
|
4
4
|
from django.db.models import F, Model, OuterRef, Q, Subquery
|
|
5
5
|
from django.db.models.functions import JSONObject
|
|
6
|
-
from django_celery_beat.managers import ExtendedQuerySet
|
|
7
6
|
|
|
8
7
|
from nautobot.core.models.query_functions import EmptyGroupByJSONBAgg
|
|
9
8
|
from nautobot.core.models.querysets import RestrictedQuerySet
|
|
@@ -272,7 +271,7 @@ class JobQuerySet(RestrictedQuerySet):
|
|
|
272
271
|
)
|
|
273
272
|
|
|
274
273
|
|
|
275
|
-
class ScheduledJobExtendedQuerySet(RestrictedQuerySet
|
|
274
|
+
class ScheduledJobExtendedQuerySet(RestrictedQuerySet):
|
|
276
275
|
"""
|
|
277
276
|
Base queryset used for the ScheduledJob class
|
|
278
277
|
"""
|
nautobot/extras/signals.py
CHANGED
|
@@ -52,7 +52,7 @@ logger = logging.getLogger(__name__)
|
|
|
52
52
|
#
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def
|
|
55
|
+
def get_user_if_authenticated(user, instance):
|
|
56
56
|
"""Return the user object associated with the request if the user is defined.
|
|
57
57
|
|
|
58
58
|
If the user is not defined, log a warning to indicate that the user couldn't be retrived from the request
|
|
@@ -103,7 +103,9 @@ def _handle_changed_object(sender, instance, raw=False, **kwargs):
|
|
|
103
103
|
if raw:
|
|
104
104
|
return
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
change_context = change_context_state.get()
|
|
107
|
+
|
|
108
|
+
if change_context is None:
|
|
107
109
|
return
|
|
108
110
|
|
|
109
111
|
# Determine the type of change being made
|
|
@@ -119,36 +121,49 @@ def _handle_changed_object(sender, instance, raw=False, **kwargs):
|
|
|
119
121
|
|
|
120
122
|
# Record an ObjectChange if applicable
|
|
121
123
|
if hasattr(instance, "to_objectchange"):
|
|
122
|
-
user =
|
|
124
|
+
user = change_context.get_user(instance)
|
|
123
125
|
# save a copy of this instance's field cache so it can be restored after serialization
|
|
124
126
|
# to prevent unexpected behavior when chaining multiple signal handlers
|
|
125
127
|
original_cache = instance._state.fields_cache.copy()
|
|
126
128
|
|
|
129
|
+
changed_object_type = ContentType.objects.get_for_model(instance)
|
|
130
|
+
changed_object_id = instance.id
|
|
131
|
+
|
|
132
|
+
# Generate a unique identifier for this change to stash in the change context
|
|
133
|
+
# This is used for deferred change logging and for looking up related changes without querying the database
|
|
134
|
+
unique_object_change_id = f"{changed_object_type.pk}__{changed_object_id}__{user.pk}"
|
|
135
|
+
|
|
127
136
|
# If a change already exists for this change_id, user, and object, update it instead of creating a new one.
|
|
128
137
|
# If the object was deleted then recreated with the same pk (don't do this), change the action to update.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
if unique_object_change_id in change_context.deferred_object_changes:
|
|
139
|
+
related_changes = ObjectChange.objects.filter(
|
|
140
|
+
changed_object_type=changed_object_type,
|
|
141
|
+
changed_object_id=changed_object_id,
|
|
142
|
+
user=user,
|
|
143
|
+
request_id=change_context.change_id,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Skip the database check when deferring object changes
|
|
147
|
+
if not change_context.defer_object_changes and related_changes.exists():
|
|
148
|
+
objectchange = instance.to_objectchange(action)
|
|
149
|
+
most_recent_change = related_changes.order_by("-time").first()
|
|
150
|
+
if most_recent_change.action == ObjectChangeActionChoices.ACTION_DELETE:
|
|
151
|
+
most_recent_change.action = ObjectChangeActionChoices.ACTION_UPDATE
|
|
152
|
+
most_recent_change.object_data = objectchange.object_data
|
|
153
|
+
most_recent_change.object_data_v2 = objectchange.object_data_v2
|
|
154
|
+
most_recent_change.save()
|
|
155
|
+
|
|
144
156
|
else:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
objectchange.change_context = change_context_state.get().context
|
|
148
|
-
objectchange.change_context_detail = change_context_state.get().context_detail[
|
|
149
|
-
:CHANGELOG_MAX_CHANGE_CONTEXT_DETAIL
|
|
157
|
+
change_context.deferred_object_changes[unique_object_change_id] = [
|
|
158
|
+
{"action": action, "instance": instance, "user": user}
|
|
150
159
|
]
|
|
151
|
-
|
|
160
|
+
if not change_context.defer_object_changes:
|
|
161
|
+
objectchange = instance.to_objectchange(action)
|
|
162
|
+
objectchange.user = user
|
|
163
|
+
objectchange.request_id = change_context.change_id
|
|
164
|
+
objectchange.change_context = change_context.context
|
|
165
|
+
objectchange.change_context_detail = change_context.context_detail[:CHANGELOG_MAX_CHANGE_CONTEXT_DETAIL]
|
|
166
|
+
objectchange.save()
|
|
152
167
|
|
|
153
168
|
# restore field cache
|
|
154
169
|
instance._state.fields_cache = original_cache
|
|
@@ -171,7 +186,9 @@ def _handle_deleted_object(sender, instance, **kwargs):
|
|
|
171
186
|
"""
|
|
172
187
|
Fires when an object is deleted.
|
|
173
188
|
"""
|
|
174
|
-
|
|
189
|
+
change_context = change_context_state.get()
|
|
190
|
+
|
|
191
|
+
if change_context is None:
|
|
175
192
|
return
|
|
176
193
|
|
|
177
194
|
if isinstance(instance, BaseModel):
|
|
@@ -186,41 +203,58 @@ def _handle_deleted_object(sender, instance, **kwargs):
|
|
|
186
203
|
|
|
187
204
|
# Record an ObjectChange if applicable
|
|
188
205
|
if hasattr(instance, "to_objectchange"):
|
|
189
|
-
user =
|
|
206
|
+
user = change_context.get_user(instance)
|
|
190
207
|
|
|
191
208
|
# save a copy of this instance's field cache so it can be restored after serialization
|
|
192
209
|
# to prevent unexpected behavior when chaining multiple signal handlers
|
|
193
210
|
original_cache = instance._state.fields_cache.copy()
|
|
194
211
|
|
|
212
|
+
changed_object_type = ContentType.objects.get_for_model(instance)
|
|
213
|
+
changed_object_id = instance.id
|
|
214
|
+
|
|
215
|
+
# Generate a unique identifier for this change to stash in the change context
|
|
216
|
+
# This is used for deferred change logging and for looking up related changes without querying the database
|
|
217
|
+
unique_object_change_id = f"{changed_object_type.pk}__{changed_object_id}__{user.pk}"
|
|
218
|
+
save_new_objectchange = True
|
|
219
|
+
|
|
195
220
|
# if a change already exists for this change_id, user, and object, update it instead of creating a new one
|
|
196
221
|
# except in the case that the object was created and deleted in the same change_id
|
|
197
222
|
# we don't want to create a delete change for an object that never existed
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
request_id=change_context_state.get().change_id,
|
|
203
|
-
)
|
|
204
|
-
objectchange = instance.to_objectchange(ObjectChangeActionChoices.ACTION_DELETE)
|
|
205
|
-
save_new_objectchange = True
|
|
206
|
-
if related_changes.exists():
|
|
207
|
-
most_recent_change = related_changes.order_by("-time").first()
|
|
208
|
-
if most_recent_change.action != ObjectChangeActionChoices.ACTION_CREATE:
|
|
209
|
-
most_recent_change.action = ObjectChangeActionChoices.ACTION_DELETE
|
|
210
|
-
most_recent_change.object_data = objectchange.object_data
|
|
211
|
-
most_recent_change.object_data_v2 = objectchange.object_data_v2
|
|
212
|
-
most_recent_change.save()
|
|
213
|
-
objectchange = most_recent_change
|
|
223
|
+
if unique_object_change_id in change_context.deferred_object_changes:
|
|
224
|
+
cached_related_change = change_context.deferred_object_changes[unique_object_change_id][-1]
|
|
225
|
+
if cached_related_change["action"] != ObjectChangeActionChoices.ACTION_CREATE:
|
|
226
|
+
cached_related_change["action"] = ObjectChangeActionChoices.ACTION_DELETE
|
|
214
227
|
save_new_objectchange = False
|
|
215
228
|
|
|
229
|
+
related_changes = ObjectChange.objects.filter(
|
|
230
|
+
changed_object_type=changed_object_type,
|
|
231
|
+
changed_object_id=changed_object_id,
|
|
232
|
+
user=user,
|
|
233
|
+
request_id=change_context.change_id,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Skip the database check when deferring object changes
|
|
237
|
+
if not change_context.defer_object_changes and related_changes.exists():
|
|
238
|
+
objectchange = instance.to_objectchange(ObjectChangeActionChoices.ACTION_DELETE)
|
|
239
|
+
most_recent_change = related_changes.order_by("-time").first()
|
|
240
|
+
if most_recent_change.action != ObjectChangeActionChoices.ACTION_CREATE:
|
|
241
|
+
most_recent_change.action = ObjectChangeActionChoices.ACTION_DELETE
|
|
242
|
+
most_recent_change.object_data = objectchange.object_data
|
|
243
|
+
most_recent_change.object_data_v2 = objectchange.object_data_v2
|
|
244
|
+
most_recent_change.save()
|
|
245
|
+
save_new_objectchange = False
|
|
246
|
+
|
|
216
247
|
if save_new_objectchange:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
248
|
+
change_context.deferred_object_changes.setdefault(unique_object_change_id, []).append(
|
|
249
|
+
{"action": ObjectChangeActionChoices.ACTION_DELETE, "instance": instance, "user": user}
|
|
250
|
+
)
|
|
251
|
+
if not change_context.defer_object_changes:
|
|
252
|
+
objectchange = instance.to_objectchange(ObjectChangeActionChoices.ACTION_DELETE)
|
|
253
|
+
objectchange.user = user
|
|
254
|
+
objectchange.request_id = change_context.change_id
|
|
255
|
+
objectchange.change_context = change_context.context
|
|
256
|
+
objectchange.change_context_detail = change_context.context_detail[:CHANGELOG_MAX_CHANGE_CONTEXT_DETAIL]
|
|
257
|
+
objectchange.save()
|
|
224
258
|
|
|
225
259
|
# restore field cache
|
|
226
260
|
instance._state.fields_cache = original_cache
|
|
@@ -238,13 +272,23 @@ def handle_cf_removed_obj_types(instance, action, pk_set, **kwargs):
|
|
|
238
272
|
"""
|
|
239
273
|
Handle the cleanup of old custom field data when a CustomField is removed from one or more ContentTypes.
|
|
240
274
|
"""
|
|
275
|
+
|
|
276
|
+
change_context = change_context_state.get()
|
|
277
|
+
if change_context is None:
|
|
278
|
+
context = None
|
|
279
|
+
else:
|
|
280
|
+
context = change_context.as_dict(instance=instance)
|
|
241
281
|
if action == "post_remove":
|
|
242
282
|
# Existing content types have been removed from the custom field, delete their data
|
|
243
|
-
|
|
283
|
+
if context:
|
|
284
|
+
context["context_detail"] = "delete custom field data from existing content types"
|
|
285
|
+
transaction.on_commit(lambda: delete_custom_field_data.delay(instance.key, pk_set, context))
|
|
244
286
|
|
|
245
287
|
elif action == "post_add":
|
|
246
288
|
# New content types have been added to the custom field, provision them
|
|
247
|
-
|
|
289
|
+
if context:
|
|
290
|
+
context["context_detail"] = "provision custom field data for new content types"
|
|
291
|
+
transaction.on_commit(lambda: provision_field.delay(instance.pk, pk_set, context))
|
|
248
292
|
|
|
249
293
|
|
|
250
294
|
m2m_changed.connect(handle_cf_removed_obj_types, sender=CustomField.content_types.through)
|