nautobot 2.2.2__py3-none-any.whl → 2.2.4__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/jobs.py +2 -0
- nautobot/core/api/utils.py +12 -9
- nautobot/core/apps/__init__.py +2 -2
- nautobot/core/celery/__init__.py +79 -68
- nautobot/core/celery/backends.py +9 -1
- nautobot/core/celery/control.py +4 -7
- nautobot/core/celery/schedulers.py +4 -2
- nautobot/core/celery/task.py +78 -5
- nautobot/core/graphql/schema.py +2 -1
- nautobot/core/jobs/__init__.py +2 -1
- nautobot/core/settings.py +6 -4
- nautobot/core/settings.yaml +51 -16
- nautobot/core/templates/admin/base.html +2 -2
- nautobot/core/templates/base_django.html +2 -2
- nautobot/core/templates/buttons/export.html +47 -47
- nautobot/core/templates/generic/object_list.html +3 -3
- nautobot/core/templates/inc/javascript.html +3 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/login.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +2 -0
- nautobot/core/templatetags/helpers.py +66 -9
- nautobot/core/testing/__init__.py +6 -1
- nautobot/core/testing/api.py +12 -13
- nautobot/core/testing/mixins.py +2 -2
- nautobot/core/testing/views.py +50 -51
- nautobot/core/tests/test_api.py +23 -2
- nautobot/core/tests/test_jobs.py +79 -2
- nautobot/core/tests/test_templatetags_helpers.py +32 -0
- nautobot/core/tests/test_views.py +52 -0
- nautobot/core/tests/test_views_utils.py +22 -1
- nautobot/core/utils/module_loading.py +89 -0
- nautobot/core/views/mixins.py +4 -0
- nautobot/core/views/utils.py +3 -2
- nautobot/dcim/choices.py +14 -0
- nautobot/dcim/forms.py +51 -1
- nautobot/dcim/models/device_components.py +9 -5
- nautobot/dcim/templates/dcim/location.html +32 -13
- nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +102 -0
- nautobot/dcim/tests/test_views.py +376 -55
- nautobot/dcim/urls.py +5 -0
- nautobot/dcim/views.py +172 -21
- nautobot/extras/api/serializers.py +17 -6
- nautobot/extras/api/views.py +21 -10
- nautobot/extras/constants.py +3 -3
- nautobot/extras/datasources/git.py +47 -58
- nautobot/extras/forms/forms.py +3 -1
- nautobot/extras/jobs.py +79 -146
- nautobot/extras/models/datasources.py +0 -2
- nautobot/extras/models/jobs.py +36 -18
- nautobot/extras/plugins/__init__.py +1 -20
- nautobot/extras/signals.py +6 -9
- nautobot/extras/test_jobs/__init__.py +8 -0
- nautobot/extras/test_jobs/dry_run.py +3 -2
- nautobot/extras/test_jobs/fail.py +43 -0
- nautobot/extras/test_jobs/ipaddress_vars.py +40 -1
- nautobot/extras/test_jobs/jobs_module/__init__.py +5 -0
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/__init__.py +1 -0
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +6 -0
- nautobot/extras/test_jobs/pass.py +40 -0
- nautobot/extras/test_jobs/relative_import.py +11 -0
- nautobot/extras/tests/test_api.py +3 -0
- nautobot/extras/tests/test_context_managers.py +18 -0
- nautobot/extras/tests/test_datasources.py +125 -118
- nautobot/extras/tests/test_job_variables.py +57 -15
- nautobot/extras/tests/test_jobs.py +135 -1
- nautobot/extras/tests/test_models.py +26 -19
- nautobot/extras/tests/test_plugins.py +1 -3
- nautobot/extras/tests/test_views.py +2 -4
- nautobot/extras/utils.py +2 -1
- nautobot/extras/views.py +82 -116
- nautobot/ipam/api/views.py +8 -1
- nautobot/ipam/graphql/types.py +11 -0
- nautobot/ipam/mixins.py +32 -0
- nautobot/ipam/models.py +2 -1
- nautobot/ipam/querysets.py +6 -1
- nautobot/ipam/tests/test_models.py +82 -0
- nautobot/ipam/views.py +6 -6
- nautobot/project-static/docs/404.html +107 -51
- nautobot/project-static/docs/apps/index.html +107 -51
- nautobot/project-static/docs/apps/nautobot-apps.html +107 -51
- nautobot/project-static/docs/assets/_mkdocstrings.css +6 -1
- nautobot/project-static/docs/assets/extra.css +11 -0
- nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js +29 -0
- nautobot/project-static/docs/assets/javascripts/bundle.3220b9d7.min.js.map +7 -0
- nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.66ac8b77.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +108 -52
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +287 -262
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +107 -51
- nautobot/project-static/docs/development/apps/api/configuration-view.html +110 -54
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +107 -51
- nautobot/project-static/docs/development/apps/api/models/global-search.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/graphql.html +113 -57
- nautobot/project-static/docs/development/apps/api/models/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +113 -57
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +111 -55
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +107 -51
- nautobot/project-static/docs/development/apps/api/prometheus.html +110 -54
- nautobot/project-static/docs/development/apps/api/setup.html +107 -51
- nautobot/project-static/docs/development/apps/api/testing.html +113 -57
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/base-template.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +122 -66
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/notes.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/urls.html +107 -51
- nautobot/project-static/docs/development/apps/index.html +128 -72
- nautobot/project-static/docs/development/apps/migration/code-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/from-v1.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +107 -51
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +110 -54
- nautobot/project-static/docs/development/core/application-registry.html +242 -144
- nautobot/project-static/docs/development/core/best-practices.html +122 -66
- nautobot/project-static/docs/development/core/bootstrap-ui.html +107 -51
- nautobot/project-static/docs/development/core/caching.html +107 -51
- nautobot/project-static/docs/development/core/controllers.html +107 -51
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +113 -57
- nautobot/project-static/docs/development/core/generic-views.html +110 -54
- nautobot/project-static/docs/development/core/getting-started.html +135 -79
- nautobot/project-static/docs/development/core/homepage.html +110 -54
- nautobot/project-static/docs/development/core/index.html +107 -51
- nautobot/project-static/docs/development/core/model-checklist.html +156 -52
- nautobot/project-static/docs/development/core/model-features.html +108 -52
- nautobot/project-static/docs/development/core/natural-keys.html +110 -54
- nautobot/project-static/docs/development/core/navigation-menu.html +107 -51
- nautobot/project-static/docs/development/core/release-checklist.html +107 -51
- nautobot/project-static/docs/development/core/role-internals.html +107 -51
- nautobot/project-static/docs/development/core/settings.html +107 -51
- nautobot/project-static/docs/development/core/style-guide.html +110 -54
- nautobot/project-static/docs/development/core/templates.html +113 -57
- nautobot/project-static/docs/development/core/testing.html +125 -69
- nautobot/project-static/docs/development/core/user-preferences.html +107 -51
- nautobot/project-static/docs/development/index.html +107 -51
- nautobot/project-static/docs/development/jobs/index.html +504 -172
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +111 -55
- nautobot/project-static/docs/docker/index.html +3 -3
- nautobot/project-static/docs/index.html +125 -69
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.0.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.2.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.3.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.4.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.5.html +116 -60
- nautobot/project-static/docs/release-notes/version-1.6.html +107 -51
- nautobot/project-static/docs/release-notes/version-2.0.html +110 -54
- nautobot/project-static/docs/release-notes/version-2.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-2.2.html +500 -114
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +262 -262
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +251 -164
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +113 -57
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +107 -51
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +171 -112
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +13 -8626
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +117 -61
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +13 -8614
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +252 -165
- nautobot/project-static/docs/user-guide/administration/installation/index.html +165 -192
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +411 -691
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +248 -229
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +13 -8118
- nautobot/project-static/docs/user-guide/administration/installation/services.html +350 -240
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +8684 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +8672 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +8176 -0
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +110 -54
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +110 -54
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +155 -99
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +109 -53
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +117 -58
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +116 -60
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +119 -63
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +125 -69
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +128 -72
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +227 -60
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +107 -51
- nautobot/project-static/docs/user-guide/index.html +109 -53
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +128 -72
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +143 -100
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +123 -67
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +131 -75
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +149 -93
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +119 -63
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +137 -81
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +110 -54
- nautobot/project-static/js/forms.js +18 -11
- nautobot/tenancy/views.py +2 -6
- nautobot/virtualization/views.py +5 -9
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/METADATA +4 -4
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/RECORD +357 -348
- nautobot/extras/test_jobs/job_variables.py +0 -93
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js +0 -29
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js.map +0 -7
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +0 -1
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/NOTICE +0 -0
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/WHEEL +0 -0
- {nautobot-2.2.2.dist-info → nautobot-2.2.4.dist-info}/entry_points.txt +0 -0
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
{% if not is_popup %}
|
|
57
57
|
{% if "BANNER_TOP"|settings_or_config %}
|
|
58
58
|
<div class="alert alert-info text-center" role="alert">
|
|
59
|
-
{{ "BANNER_TOP"|settings_or_config|
|
|
59
|
+
{{ "BANNER_TOP"|settings_or_config|render_markdown }}
|
|
60
60
|
</div>
|
|
61
61
|
{% endif %}
|
|
62
62
|
{% if settings.MAINTENANCE_MODE %}
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
<div class="push"></div>
|
|
108
108
|
{% if "BANNER_BOTTOM"|settings_or_config %}
|
|
109
109
|
<div class="alert alert-info text-center banner-bottom" role="alert">
|
|
110
|
-
{{ "BANNER_BOTTOM"|settings_or_config|
|
|
110
|
+
{{ "BANNER_BOTTOM"|settings_or_config|render_markdown }}
|
|
111
111
|
</div>
|
|
112
112
|
{% endif %}
|
|
113
113
|
</div>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{% if request.user.is_authenticated %}
|
|
17
17
|
{% if "BANNER_TOP"|settings_or_config %}
|
|
18
18
|
<div class="alert alert-info text-center" role="alert">
|
|
19
|
-
{{ "BANNER_TOP"|settings_or_config|
|
|
19
|
+
{{ "BANNER_TOP"|settings_or_config|render_markdown }}
|
|
20
20
|
</div>
|
|
21
21
|
{% endif %}
|
|
22
22
|
{% endif %}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
{% if request.user.is_authenticated %}
|
|
43
43
|
{% if "BANNER_BOTTOM"|settings_or_config %}
|
|
44
44
|
<div class="alert alert-info text-center banner-bottom" role="alert">
|
|
45
|
-
{{ "BANNER_BOTTOM"|settings_or_config|
|
|
45
|
+
{{ "BANNER_BOTTOM"|settings_or_config|render_markdown }}
|
|
46
46
|
</div>
|
|
47
47
|
{% endif %}
|
|
48
48
|
{% endif %}
|
|
@@ -1,60 +1,60 @@
|
|
|
1
1
|
{% if export_url %}
|
|
2
2
|
{% if export_templates or include_yaml_option %}
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
</
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
</
|
|
3
|
+
<div class="btn-group">
|
|
4
|
+
<button type="submit" class="btn btn-success" form="export_default">
|
|
5
|
+
<span class="mdi mdi-database-export" aria-hidden="true"></span>
|
|
6
|
+
Export
|
|
7
|
+
</button>
|
|
8
|
+
<form id="export_default" style="display: inline-block" action="{{ export_url }}" method="post">
|
|
9
|
+
{% csrf_token %}
|
|
10
|
+
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
11
|
+
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
12
|
+
<input type="hidden" name="export_format"
|
|
13
|
+
value="{% if include_yaml_option %}yaml{% else %}csv{% endif %}">
|
|
14
|
+
<input type="hidden" name="_schedule_type" value="immediately">
|
|
15
|
+
</form>
|
|
16
|
+
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
17
|
+
<span class="caret"></span>
|
|
18
|
+
<span class="sr-only">Toggle Dropdown</span>
|
|
19
|
+
</button>
|
|
20
|
+
<ul class="dropdown-menu dropdown-menu-right">
|
|
21
|
+
{% if include_yaml_option %}
|
|
22
|
+
<li>
|
|
23
|
+
<button type="submit" class="btn btn-link" form="export_default">YAML format</button>
|
|
24
|
+
</li>
|
|
25
|
+
<li>
|
|
26
|
+
<form action="{{ export_url }}" method="post">
|
|
27
|
+
{% csrf_token %}
|
|
28
|
+
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
29
|
+
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
30
|
+
<input type="hidden" name="_schedule_type" value="immediately">
|
|
31
|
+
<button type="submit" class="btn btn-link">CSV format</button>
|
|
32
|
+
</form>
|
|
33
|
+
</li>
|
|
34
|
+
{% else %}
|
|
35
|
+
<li>
|
|
36
|
+
<button type="submit" class="btn btn-link" form="export_default">CSV format</button>
|
|
37
|
+
</li>
|
|
38
|
+
{% endif %}
|
|
39
|
+
{% if export_templates %}
|
|
40
|
+
<li class="divider"></li>
|
|
41
|
+
{% for et in export_templates %}
|
|
24
42
|
<li>
|
|
25
43
|
<form action="{{ export_url }}" method="post">
|
|
26
44
|
{% csrf_token %}
|
|
27
45
|
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
46
|
+
<input type="hidden" name="export_template" value="{{ et.pk }}">
|
|
28
47
|
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
29
48
|
<input type="hidden" name="_schedule_type" value="immediately">
|
|
30
|
-
<button type="submit" class="btn btn-link"
|
|
49
|
+
<button type="submit" class="btn btn-link"
|
|
50
|
+
{% if et.description %}title="{{ et.description }}"{% endif %}
|
|
51
|
+
>{{ et.name }}</button>
|
|
31
52
|
</form>
|
|
32
53
|
</li>
|
|
33
|
-
{%
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{% endif %}
|
|
38
|
-
{% if export_templates %}
|
|
39
|
-
<li class="divider"></li>
|
|
40
|
-
{% for et in export_templates %}
|
|
41
|
-
<li>
|
|
42
|
-
<form action="{{ export_url }}" method="post">
|
|
43
|
-
{% csrf_token %}
|
|
44
|
-
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
45
|
-
<input type="hidden" name="export_template" value="{{ et.pk }}">
|
|
46
|
-
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
47
|
-
<input type="hidden" name="_schedule_type" value="immediately">
|
|
48
|
-
<button type="submit" class="btn btn-link"
|
|
49
|
-
{% if et.description %}title="{{ et.description }}"{% endif %}
|
|
50
|
-
>{{ et.name }}</button>
|
|
51
|
-
</form>
|
|
52
|
-
</li>
|
|
53
|
-
{% endfor %}
|
|
54
|
-
{% endif %}
|
|
55
|
-
</ul>
|
|
56
|
-
</div>
|
|
57
|
-
</form>
|
|
54
|
+
{% endfor %}
|
|
55
|
+
{% endif %}
|
|
56
|
+
</ul>
|
|
57
|
+
</div>
|
|
58
58
|
{% else %}
|
|
59
59
|
<form style="display: inline-block" action="{{ export_url }}" method="post">
|
|
60
60
|
{% csrf_token %}
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
class="remove-filter-param"
|
|
75
75
|
title="Remove all items"
|
|
76
76
|
data-field-type="parent"
|
|
77
|
-
data-field-value={{ field.name }}
|
|
77
|
+
data-field-value="{{ field.name }}"
|
|
78
78
|
>×</span>
|
|
79
79
|
<ul class="filter-selection-rendered">
|
|
80
80
|
{% for value in field.values %}
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
<span
|
|
86
86
|
class="filter-selection-choice-remove remove-filter-param"
|
|
87
87
|
data-field-type="child"
|
|
88
|
-
data-field-parent={{ field.name }}
|
|
89
|
-
data-field-value={{ value.name }}
|
|
88
|
+
data-field-parent="{{ field.name }}"
|
|
89
|
+
data-field-value="{{ value.name }}"
|
|
90
90
|
>×</span>{{ value.display }}
|
|
91
91
|
</li>
|
|
92
92
|
{% endfor %}
|
|
@@ -40,3 +40,6 @@
|
|
|
40
40
|
hljs.configure({ cssSelector: '.language-graphql, .language-json, .language-xml, .language-yaml' });
|
|
41
41
|
hljs.highlightAll();
|
|
42
42
|
</script>
|
|
43
|
+
{% if settings.BRANDING_FILEPATHS.javascript %}
|
|
44
|
+
<script src="{% custom_branding_or_static 'javascript' None %}"></script>
|
|
45
|
+
{% endif %}
|
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
<link rel="stylesheet" id="base-theme"
|
|
35
35
|
href="{% versioned_static 'css/base.css' %}"
|
|
36
36
|
onerror="window.location='{% url 'media_failure' %}?filename=css/base.css'">
|
|
37
|
+
{% if settings.BRANDING_FILEPATHS.css %}
|
|
38
|
+
<link rel="stylesheet" id="custom-css" href="{% custom_branding_or_static 'css' None %}">
|
|
39
|
+
{% endif %}
|
|
37
40
|
<link rel="apple-touch-icon" sizes="180x180" href="{% custom_branding_or_static 'icon_180' 'img/nautobot_icon_180x180.png' %}">
|
|
38
41
|
<link rel="icon" type="image/png" sizes="32x32" href="{% custom_branding_or_static 'icon_32' 'img/nautobot_icon_32x32.png' %}">
|
|
39
42
|
<link rel="icon" type="image/png" sizes="16x16" href="{% custom_branding_or_static 'icon_16' 'img/nautobot_icon_16x16.png' %}">
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
<div class="row" style="margin-top: {% if 'BANNER_LOGIN'|settings_or_config %}100{% else %}150{% endif %}px;">
|
|
54
54
|
<div class="col-sm-4 col-sm-offset-4">
|
|
55
55
|
{% if "BANNER_LOGIN"|settings_or_config %}
|
|
56
|
-
<div
|
|
57
|
-
{{ "BANNER_LOGIN"|settings_or_config|
|
|
56
|
+
<div class="alert alert-info text-center" role="alert">
|
|
57
|
+
{{ "BANNER_LOGIN"|settings_or_config|render_markdown }}
|
|
58
58
|
</div>
|
|
59
59
|
{% endif %}
|
|
60
60
|
{% if form.non_field_errors %}
|
|
@@ -248,6 +248,8 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
|
|
|
248
248
|
# "NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET", None
|
|
249
249
|
# ), # bullet image used for various view headers
|
|
250
250
|
# "nav_bullet": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET", None), # bullet image used for nav menu headers
|
|
251
|
+
# "css": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_CSS", None), # Custom global CSS
|
|
252
|
+
# "javascript": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT", None), # Custom global JavaScript
|
|
251
253
|
# }
|
|
252
254
|
|
|
253
255
|
# Prepended to CSV, YAML and export template filenames (i.e. `nautobot_device.yml`)
|
|
@@ -8,7 +8,7 @@ from django.conf import settings
|
|
|
8
8
|
from django.contrib.staticfiles.finders import find
|
|
9
9
|
from django.templatetags.static import static, StaticNode
|
|
10
10
|
from django.urls import NoReverseMatch, reverse
|
|
11
|
-
from django.utils.html import format_html
|
|
11
|
+
from django.utils.html import format_html, format_html_join
|
|
12
12
|
from django.utils.safestring import mark_safe
|
|
13
13
|
from django.utils.text import slugify as django_slugify
|
|
14
14
|
from django_jinja import library
|
|
@@ -71,14 +71,7 @@ def hyperlinked_object(value, field="display"):
|
|
|
71
71
|
>>> hyperlinked_object(location, "name")
|
|
72
72
|
'<a href="/dcim/locations/leaf/">Leaf</a>'
|
|
73
73
|
"""
|
|
74
|
-
|
|
75
|
-
return placeholder(value)
|
|
76
|
-
display = getattr(value, field) if hasattr(value, field) else str(value)
|
|
77
|
-
if hasattr(value, "get_absolute_url"):
|
|
78
|
-
if hasattr(value, "description") and value.description:
|
|
79
|
-
return format_html('<a href="{}" title="{}">{}</a>', value.get_absolute_url(), value.description, display)
|
|
80
|
-
return format_html('<a href="{}">{}</a>', value.get_absolute_url(), display)
|
|
81
|
-
return format_html("{}", display)
|
|
74
|
+
return _build_hyperlink(value, field)
|
|
82
75
|
|
|
83
76
|
|
|
84
77
|
@library.filter()
|
|
@@ -822,3 +815,67 @@ def queryset_to_pks(obj):
|
|
|
822
815
|
result = list(obj.values_list("pk", flat=True)) if obj else []
|
|
823
816
|
result = [str(entry) for entry in result]
|
|
824
817
|
return ",".join(result)
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
@library.filter()
|
|
821
|
+
@register.filter()
|
|
822
|
+
def hyperlinked_object_target_new_tab(value, field="display"):
|
|
823
|
+
"""Render and link to a Django model instance, if any, or render a placeholder if not.
|
|
824
|
+
|
|
825
|
+
Similar to the hyperlinked_object filter, but passes attributes needed to open the link in new tab.
|
|
826
|
+
|
|
827
|
+
Uses the specified object field if available, otherwise uses the string representation of the object.
|
|
828
|
+
If the object defines `get_absolute_url()` this will be used to hyperlink the displayed object;
|
|
829
|
+
additionally if there is an `object.description` this will be used as the title of the hyperlink.
|
|
830
|
+
|
|
831
|
+
Args:
|
|
832
|
+
value (Union[django.db.models.Model, None]): Instance of a Django model or None.
|
|
833
|
+
field (Optional[str]): Name of the field to use for the display value. Defaults to "display".
|
|
834
|
+
|
|
835
|
+
Returns:
|
|
836
|
+
(str): String representation of the value (hyperlinked if it defines get_absolute_url()) or a placeholder.
|
|
837
|
+
|
|
838
|
+
Examples:
|
|
839
|
+
>>> hyperlinked_object_target_new_tab(device)
|
|
840
|
+
'<a href="/dcim/devices/3faafe8c-bdd6-4317-88dc-f791e6988caa/" target="_blank" rel="noreferrer">Device 1</a>'
|
|
841
|
+
>>> hyperlinked_object_target_new_tab(device_role)
|
|
842
|
+
'<a href="/dcim/device-roles/router/" title="Devices that are routers, not switches" target="_blank" rel="noreferrer">Router</a>'
|
|
843
|
+
>>> hyperlinked_object_target_new_tab(None)
|
|
844
|
+
'<span class="text-muted">—</span>'
|
|
845
|
+
>>> hyperlinked_object_target_new_tab("Hello")
|
|
846
|
+
'Hello'
|
|
847
|
+
>>> hyperlinked_object_target_new_tab(location)
|
|
848
|
+
'<a href="/dcim/locations/leaf/" target="_blank" rel="noreferrer">Root → Intermediate → Leaf</a>'
|
|
849
|
+
>>> hyperlinked_object_target_new_tab(location, "name")
|
|
850
|
+
'<a href="/dcim/locations/leaf/" target="_blank" rel="noreferrer">Leaf</a>'
|
|
851
|
+
"""
|
|
852
|
+
return _build_hyperlink(value, field, target="_blank", rel="noreferrer")
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
def _build_hyperlink(value, field="", target="", rel=""):
|
|
856
|
+
"""Internal function used by filters to build hyperlinks.
|
|
857
|
+
|
|
858
|
+
Args:
|
|
859
|
+
value (Union[django.db.models.Model, None]): Instance of a Django model or None.
|
|
860
|
+
field (Optional[str]): Name of the field to use for the display value. Defaults to "display".
|
|
861
|
+
target (Optional[str]): Location to open the linked document. Defaults to "" which is _self.
|
|
862
|
+
rel (Optional[str]): Relationship between current document and linked document. Defaults to "".
|
|
863
|
+
|
|
864
|
+
Returns:
|
|
865
|
+
(str): String representation of the value (hyperlinked if it defines get_absolute_url()) or a placeholder.
|
|
866
|
+
"""
|
|
867
|
+
if value is None:
|
|
868
|
+
return placeholder(value)
|
|
869
|
+
|
|
870
|
+
attributes = {}
|
|
871
|
+
display = getattr(value, field) if hasattr(value, field) else str(value)
|
|
872
|
+
if hasattr(value, "get_absolute_url"):
|
|
873
|
+
attributes["href"] = value.get_absolute_url()
|
|
874
|
+
if hasattr(value, "description") and value.description:
|
|
875
|
+
attributes["title"] = value.description
|
|
876
|
+
if target:
|
|
877
|
+
attributes["target"] = target
|
|
878
|
+
if rel:
|
|
879
|
+
attributes["rel"] = rel
|
|
880
|
+
return format_html("<a {}>{}</a>", format_html_join(" ", '{}="{}"', attributes.items()), display)
|
|
881
|
+
return format_html("{}", display)
|
|
@@ -102,7 +102,12 @@ def get_job_class_and_model(module, name, source="local"):
|
|
|
102
102
|
(JobClassInfo): Named 2-tuple of (job_class, job_model)
|
|
103
103
|
"""
|
|
104
104
|
job_class = get_job(f"{module}.{name}")
|
|
105
|
-
|
|
105
|
+
try:
|
|
106
|
+
job_model = Job.objects.get(module_name=module, job_class_name=name)
|
|
107
|
+
except Job.DoesNotExist:
|
|
108
|
+
raise RuntimeError(
|
|
109
|
+
f"Job database record for {module}.{name} not found. Known jobs are: {list(Job.objects.all())}"
|
|
110
|
+
)
|
|
106
111
|
job_model.enabled = True
|
|
107
112
|
job_model.validated_save()
|
|
108
113
|
return JobClassInfo(job_class, job_model)
|
nautobot/core/testing/api.py
CHANGED
|
@@ -13,12 +13,11 @@ from rest_framework import status
|
|
|
13
13
|
from rest_framework.relations import ManyRelatedField
|
|
14
14
|
from rest_framework.test import APITransactionTestCase as _APITransactionTestCase
|
|
15
15
|
|
|
16
|
-
from nautobot.core import testing
|
|
17
16
|
from nautobot.core.api.utils import get_serializer_for_model
|
|
18
17
|
from nautobot.core.models import fields as core_fields
|
|
19
18
|
from nautobot.core.models.tree_queries import TreeModel
|
|
20
19
|
from nautobot.core.templatetags.helpers import bettertitle
|
|
21
|
-
from nautobot.core.testing import mixins, views
|
|
20
|
+
from nautobot.core.testing import mixins, utils, views
|
|
22
21
|
from nautobot.core.utils import lookup
|
|
23
22
|
from nautobot.core.utils.data import is_uuid
|
|
24
23
|
from nautobot.extras import choices as extras_choices, models as extras_models, registry
|
|
@@ -111,7 +110,7 @@ class APIViewTestCases:
|
|
|
111
110
|
self.model._meta.model_name,
|
|
112
111
|
) in settings.EXEMPT_EXCLUDE_MODELS:
|
|
113
112
|
# Models listed in EXEMPT_EXCLUDE_MODELS should not be accessible to anonymous users
|
|
114
|
-
with
|
|
113
|
+
with utils.disable_warnings("django.request"):
|
|
115
114
|
self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
|
|
116
115
|
else:
|
|
117
116
|
response = self.client.get(url, **self.header)
|
|
@@ -125,7 +124,7 @@ class APIViewTestCases:
|
|
|
125
124
|
url = self._get_detail_url(self._get_queryset().first())
|
|
126
125
|
|
|
127
126
|
# Try GET without permission
|
|
128
|
-
with
|
|
127
|
+
with utils.disable_warnings("django.request"):
|
|
129
128
|
self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
|
|
130
129
|
|
|
131
130
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
|
|
@@ -303,7 +302,7 @@ class APIViewTestCases:
|
|
|
303
302
|
self.model._meta.model_name,
|
|
304
303
|
) in settings.EXEMPT_EXCLUDE_MODELS:
|
|
305
304
|
# Models listed in EXEMPT_EXCLUDE_MODELS should not be accessible to anonymous users
|
|
306
|
-
with
|
|
305
|
+
with utils.disable_warnings("django.request"):
|
|
307
306
|
self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
|
|
308
307
|
else:
|
|
309
308
|
# TODO(Glenn): if we're passing **self.header, we are *by definition* **NOT** anonymous!!
|
|
@@ -389,7 +388,7 @@ class APIViewTestCases:
|
|
|
389
388
|
url = self._get_list_url()
|
|
390
389
|
|
|
391
390
|
# Try GET without permission
|
|
392
|
-
with
|
|
391
|
+
with utils.disable_warnings("django.request"):
|
|
393
392
|
self.assertHttpStatus(self.client.get(url, **self.header), status.HTTP_403_FORBIDDEN)
|
|
394
393
|
|
|
395
394
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
|
|
@@ -490,7 +489,7 @@ class APIViewTestCases:
|
|
|
490
489
|
GET a list of objects with an unknown filter parameter and strict filtering, expect a 400 response.
|
|
491
490
|
"""
|
|
492
491
|
self.add_permissions(f"{self.model._meta.app_label}.view_{self.model._meta.model_name}")
|
|
493
|
-
with
|
|
492
|
+
with utils.disable_warnings("django.request"):
|
|
494
493
|
response = self.client.get(f"{self._get_list_url()}?ice_cream_flavor=rocky-road", **self.header)
|
|
495
494
|
self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
|
|
496
495
|
self.assertIsInstance(response.data, dict)
|
|
@@ -606,7 +605,7 @@ class APIViewTestCases:
|
|
|
606
605
|
url = self._get_list_url()
|
|
607
606
|
|
|
608
607
|
# Try POST without permission
|
|
609
|
-
with
|
|
608
|
+
with utils.disable_warnings("django.request"):
|
|
610
609
|
response = self.client.post(url, self.create_data[0], format="json", **self.header)
|
|
611
610
|
self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
|
|
612
611
|
|
|
@@ -679,7 +678,7 @@ class APIViewTestCases:
|
|
|
679
678
|
instance = self.get_deletable_object()
|
|
680
679
|
else:
|
|
681
680
|
# try to do it ourselves
|
|
682
|
-
instance =
|
|
681
|
+
instance = utils.get_deletable_objects(self.model, self._get_queryset()).first()
|
|
683
682
|
if instance is None:
|
|
684
683
|
self.fail("Couldn't find a single deletable object!")
|
|
685
684
|
|
|
@@ -776,7 +775,7 @@ class APIViewTestCases:
|
|
|
776
775
|
update_data = self.update_data or getattr(self, "create_data")[0]
|
|
777
776
|
|
|
778
777
|
# Try PATCH without permission
|
|
779
|
-
with
|
|
778
|
+
with utils.disable_warnings("django.request"):
|
|
780
779
|
response = self.client.patch(url, update_data, format="json", **self.header)
|
|
781
780
|
self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
|
|
782
781
|
|
|
@@ -983,7 +982,7 @@ class APIViewTestCases:
|
|
|
983
982
|
For some models this may just be any random object, but when we have FKs with `on_delete=models.PROTECT`
|
|
984
983
|
(as is often the case) we need to find or create an instance that doesn't have such entanglements.
|
|
985
984
|
"""
|
|
986
|
-
instance =
|
|
985
|
+
instance = utils.get_deletable_objects(self.model, self._get_queryset()).first()
|
|
987
986
|
if instance is None:
|
|
988
987
|
self.fail("Couldn't find a single deletable object!")
|
|
989
988
|
return instance
|
|
@@ -995,7 +994,7 @@ class APIViewTestCases:
|
|
|
995
994
|
For some models this may just be any random objects, but when we have FKs with `on_delete=models.PROTECT`
|
|
996
995
|
(as is often the case) we need to find or create an instance that doesn't have such entanglements.
|
|
997
996
|
"""
|
|
998
|
-
instances =
|
|
997
|
+
instances = utils.get_deletable_objects(self.model, self._get_queryset()).values_list("pk", flat=True)[:3]
|
|
999
998
|
if len(instances) < 3:
|
|
1000
999
|
self.fail(f"Couldn't find 3 deletable objects, only found {len(instances)}!")
|
|
1001
1000
|
return instances
|
|
@@ -1007,7 +1006,7 @@ class APIViewTestCases:
|
|
|
1007
1006
|
url = self._get_detail_url(self.get_deletable_object())
|
|
1008
1007
|
|
|
1009
1008
|
# Try DELETE without permission
|
|
1010
|
-
with
|
|
1009
|
+
with utils.disable_warnings("django.request"):
|
|
1011
1010
|
response = self.client.delete(url, **self.header)
|
|
1012
1011
|
self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
|
|
1013
1012
|
|
nautobot/core/testing/mixins.py
CHANGED
|
@@ -11,8 +11,8 @@ from django.forms.models import model_to_dict
|
|
|
11
11
|
from netaddr import IPNetwork
|
|
12
12
|
from rest_framework.test import APIClient, APIRequestFactory
|
|
13
13
|
|
|
14
|
-
from nautobot.core import testing
|
|
15
14
|
from nautobot.core.models import fields as core_fields
|
|
15
|
+
from nautobot.core.testing import utils
|
|
16
16
|
from nautobot.core.utils import permissions
|
|
17
17
|
from nautobot.extras import management, models as extras_models
|
|
18
18
|
from nautobot.users import models as users_models
|
|
@@ -169,7 +169,7 @@ class NautobotTestCaseMixin:
|
|
|
169
169
|
# REST API response; pass the response data through directly
|
|
170
170
|
err_message += f"\n{response.data}"
|
|
171
171
|
# Attempt to extract form validation errors from the response HTML
|
|
172
|
-
form_errors =
|
|
172
|
+
form_errors = utils.extract_form_failures(response.content.decode(response.charset))
|
|
173
173
|
err_message += "\n" + str(form_errors or response.content.decode(response.charset) or "No data")
|
|
174
174
|
if msg:
|
|
175
175
|
err_message = f"{msg}\n{err_message}"
|