nautobot 2.0.5__py3-none-any.whl → 2.1.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/circuits/navigation.py +0 -25
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -9
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
- nautobot/circuits/tests/test_filters.py +1 -0
- nautobot/core/api/serializers.py +15 -5
- nautobot/core/api/views.py +18 -19
- nautobot/core/choices.py +1 -1
- nautobot/core/filters.py +12 -4
- nautobot/core/jobs/__init__.py +125 -3
- nautobot/core/management/commands/generate_test_data.py +4 -1
- nautobot/core/models/fields.py +12 -2
- nautobot/core/settings.py +8 -7
- nautobot/core/templates/base_django.html +2 -2
- nautobot/core/templates/buttons/export.html +57 -30
- nautobot/core/templates/generic/object_list.html +2 -2
- nautobot/core/templates/generic/object_retrieve.html +8 -1
- nautobot/core/templates/home.html +5 -5
- nautobot/core/templates/inc/created_updated.html +2 -2
- nautobot/core/templates/inc/footer.html +2 -2
- nautobot/core/templates/inc/javascript.html +0 -10
- nautobot/core/templates/inc/media.html +2 -0
- nautobot/core/templates/inc/nav_menu.html +66 -68
- nautobot/core/templates/inc/object_details_advanced_panel.html +19 -0
- nautobot/core/templates/nautobot_config.py.j2 +10 -4
- nautobot/core/templates/panel_table.html +1 -1
- nautobot/core/templates/template.css +89 -0
- nautobot/core/templates/utilities/templatetags/table_config_form.html +1 -0
- nautobot/core/templatetags/buttons.py +7 -2
- nautobot/core/testing/views.py +34 -4
- nautobot/core/tests/integration/test_home.py +1 -43
- nautobot/core/tests/integration/test_navbar.py +10 -64
- nautobot/core/tests/integration/test_plugin_home.py +4 -5
- nautobot/core/tests/integration/test_plugin_navbar.py +20 -16
- nautobot/core/tests/integration/test_theme.py +4 -0
- nautobot/core/tests/test_api.py +14 -66
- nautobot/core/tests/test_filters.py +127 -0
- nautobot/core/tests/test_forms.py +1 -1
- nautobot/core/tests/test_graphql.py +165 -2
- nautobot/core/tests/test_jobs.py +112 -0
- nautobot/core/tests/test_openapi.py +6 -0
- nautobot/core/tests/test_views.py +11 -85
- nautobot/core/urls.py +6 -1
- nautobot/core/utils/lookup.py +28 -0
- nautobot/core/utils/requests.py +2 -3
- nautobot/core/views/__init__.py +3 -4
- nautobot/core/views/generic.py +9 -4
- nautobot/core/views/mixins.py +4 -2
- nautobot/core/views/renderers.py +5 -0
- nautobot/dcim/models/device_components.py +1 -0
- nautobot/dcim/navigation.py +10 -165
- nautobot/dcim/templates/dcim/location.html +1 -1
- nautobot/dcim/tests/features/locations.feature +143 -0
- nautobot/dcim/tests/test_api.py +1 -1
- nautobot/dcim/tests/test_filters.py +11 -3
- nautobot/extras/admin.py +1 -1
- nautobot/extras/api/serializers.py +33 -0
- nautobot/extras/api/urls.py +6 -0
- nautobot/extras/api/views.py +45 -6
- nautobot/extras/factory.py +28 -2
- nautobot/extras/filters/__init__.py +52 -0
- nautobot/extras/filters/mixins.py +4 -29
- nautobot/extras/forms/forms.py +43 -0
- nautobot/extras/jobs.py +31 -9
- nautobot/extras/migrations/0100_fileproxy_job_result.py +32 -0
- nautobot/extras/migrations/0101_externalintegration.py +61 -0
- nautobot/extras/migrations/0102_set_null_objectchange_contenttype.py +32 -0
- nautobot/extras/models/__init__.py +2 -0
- nautobot/extras/models/change_logging.py +2 -2
- nautobot/extras/models/models.py +96 -16
- nautobot/extras/navigation.py +17 -29
- nautobot/extras/signals.py +15 -0
- nautobot/extras/tables.py +27 -0
- nautobot/extras/templates/extras/externalintegration_retrieve.html +37 -0
- nautobot/extras/templates/extras/inc/jobresult.html +24 -0
- nautobot/extras/templates/extras/jobresult.html +24 -0
- nautobot/extras/test_jobs/file_output.py +16 -0
- nautobot/extras/tests/test_api.py +92 -0
- nautobot/extras/tests/test_filters.py +64 -2
- nautobot/extras/tests/test_jobs.py +39 -0
- nautobot/extras/tests/test_models.py +34 -0
- nautobot/extras/tests/test_views.py +22 -2
- nautobot/extras/urls.py +1 -0
- nautobot/extras/views.py +15 -0
- nautobot/ipam/forms.py +16 -0
- nautobot/ipam/models.py +3 -0
- nautobot/ipam/navigation.py +2 -59
- nautobot/ipam/templates/ipam/ipaddress.html +0 -9
- nautobot/ipam/templates/ipam/prefix.html +0 -9
- nautobot/ipam/tests/features/prefixes.feature +134 -0
- nautobot/ipam/tests/test_filters.py +5 -10
- nautobot/ipam/tests/test_views.py +8 -1
- nautobot/ipam/views.py +3 -0
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css +191 -191
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +874 -881
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
- nautobot/project-static/css/base.css +135 -99
- nautobot/project-static/css/dark.css +65 -6
- nautobot/project-static/docs/404.html +44 -16
- nautobot/project-static/docs/apps/index.html +44 -16
- nautobot/project-static/docs/apps/nautobot-apps.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1597 -1457
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +45 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +353 -432
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +66 -38
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2154 -2307
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +807 -691
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +58 -30
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +3600 -3456
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +44 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +101 -75
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +3083 -3019
- nautobot/project-static/docs/development/apps/api/configuration-view.html +44 -16
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/global-search.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/graphql.html +44 -16
- nautobot/project-static/docs/development/apps/api/models/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +44 -16
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +44 -16
- nautobot/project-static/docs/development/apps/api/prometheus.html +44 -16
- nautobot/project-static/docs/development/apps/api/setup.html +44 -16
- nautobot/project-static/docs/development/apps/api/testing.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-detail-views.html +44 -16
- nautobot/project-static/docs/development/apps/api/ui-extensions/tabs.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/base-template.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/index.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/notes.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/urls.html +44 -16
- nautobot/project-static/docs/development/apps/api/views/view-overrides.html +44 -16
- nautobot/project-static/docs/development/apps/index.html +44 -16
- nautobot/project-static/docs/development/apps/migration/code-updates.html +44 -16
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +44 -16
- nautobot/project-static/docs/development/apps/migration/from-v1.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +44 -16
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +44 -16
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +44 -16
- nautobot/project-static/docs/development/core/application-registry.html +44 -16
- nautobot/project-static/docs/development/core/best-practices.html +44 -16
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +44 -16
- nautobot/project-static/docs/development/core/extending-models.html +44 -16
- nautobot/project-static/docs/development/core/generic-views.html +44 -16
- nautobot/project-static/docs/development/core/getting-started.html +44 -16
- nautobot/project-static/docs/development/core/homepage.html +44 -16
- nautobot/project-static/docs/development/core/index.html +44 -16
- nautobot/project-static/docs/development/core/model-features.html +44 -16
- nautobot/project-static/docs/development/core/natural-keys.html +44 -16
- nautobot/project-static/docs/development/core/navigation-menu.html +44 -21
- nautobot/project-static/docs/development/core/react-ui.html +44 -16
- nautobot/project-static/docs/development/core/release-checklist.html +44 -16
- nautobot/project-static/docs/development/core/role-internals.html +44 -16
- nautobot/project-static/docs/development/core/style-guide.html +44 -16
- nautobot/project-static/docs/development/core/templates.html +44 -16
- nautobot/project-static/docs/development/core/testing.html +44 -16
- nautobot/project-static/docs/development/core/user-preferences.html +44 -16
- nautobot/project-static/docs/development/index.html +44 -16
- nautobot/project-static/docs/development/jobs/index.html +280 -234
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +44 -16
- nautobot/project-static/docs/index.html +44 -16
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +47 -19
- nautobot/project-static/docs/release-notes/version-1.0.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.1.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.2.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.3.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.4.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.5.html +44 -16
- nautobot/project-static/docs/release-notes/version-1.6.html +44 -16
- nautobot/project-static/docs/release-notes/version-2.0.html +47 -19
- nautobot/project-static/docs/release-notes/version-2.1.html +5724 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +247 -237
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/node-configuration.html +44 -16
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +109 -43
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +44 -16
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -19
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/index.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +44 -16
- nautobot/project-static/docs/user-guide/administration/installation/services.html +44 -16
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +44 -16
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +44 -16
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +44 -16
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +44 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +44 -16
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +44 -16
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +44 -16
- nautobot/project-static/docs/user-guide/index.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +110 -16
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +47 -19
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +5359 -0
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +47 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +113 -44
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +44 -16
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +44 -16
- nautobot/project-static/fonts/UFL.txt +96 -0
- nautobot/project-static/fonts/Ubuntu-Bold.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-BoldItalic.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-Italic.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-Medium.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-MediumItalic.woff2 +0 -0
- nautobot/project-static/fonts/Ubuntu-Regular.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-Bold.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-BoldItalic.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-Italic.woff2 +0 -0
- nautobot/project-static/fonts/UbuntuMono-Regular.woff2 +0 -0
- nautobot/project-static/img/dark-theme.png +0 -0
- nautobot/project-static/img/light-theme.png +0 -0
- nautobot/project-static/img/nautobot_chevron.svg +5 -0
- nautobot/project-static/img/nautobot_chevron_header.svg +5 -0
- nautobot/project-static/img/system-theme.png +0 -0
- nautobot/tenancy/navigation.py +0 -13
- nautobot/ui/package-lock.json +2 -2
- nautobot/ui/package.json +1 -1
- nautobot/users/admin.py +44 -0
- nautobot/users/migrations/0007_alter_objectpermission_object_types.py +33 -0
- nautobot/users/models.py +3 -2
- nautobot/virtualization/navigation.py +1 -33
- nautobot/virtualization/tests/test_api.py +1 -1
- nautobot/virtualization/tests/test_filters.py +1 -1
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/METADATA +1 -1
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/RECORD +376 -351
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/WHEEL +0 -0
- {nautobot-2.0.5.dist-info → nautobot-2.1.0b1.dist-info}/entry_points.txt +0 -0
nautobot/circuits/navigation.py
CHANGED
|
@@ -5,7 +5,6 @@ from nautobot.core.apps import (
|
|
|
5
5
|
NavMenuAddButton,
|
|
6
6
|
NavMenuGroup,
|
|
7
7
|
NavMenuItem,
|
|
8
|
-
NavMenuImportButton,
|
|
9
8
|
NavMenuTab,
|
|
10
9
|
)
|
|
11
10
|
|
|
@@ -33,12 +32,6 @@ menu_items = (
|
|
|
33
32
|
"circuits.add_circuit",
|
|
34
33
|
],
|
|
35
34
|
),
|
|
36
|
-
NavMenuImportButton(
|
|
37
|
-
link="circuits:circuit_import",
|
|
38
|
-
permissions=[
|
|
39
|
-
"circuits.add_circuit",
|
|
40
|
-
],
|
|
41
|
-
),
|
|
42
35
|
),
|
|
43
36
|
),
|
|
44
37
|
NavMenuItem(
|
|
@@ -55,12 +48,6 @@ menu_items = (
|
|
|
55
48
|
"circuits.add_circuittype",
|
|
56
49
|
],
|
|
57
50
|
),
|
|
58
|
-
NavMenuImportButton(
|
|
59
|
-
link="circuits:circuittype_import",
|
|
60
|
-
permissions=[
|
|
61
|
-
"circuits.add_circuittype",
|
|
62
|
-
],
|
|
63
|
-
),
|
|
64
51
|
),
|
|
65
52
|
),
|
|
66
53
|
),
|
|
@@ -83,12 +70,6 @@ menu_items = (
|
|
|
83
70
|
"circuits.add_provider",
|
|
84
71
|
],
|
|
85
72
|
),
|
|
86
|
-
NavMenuImportButton(
|
|
87
|
-
link="circuits:provider_import",
|
|
88
|
-
permissions=[
|
|
89
|
-
"circuits.add_provider",
|
|
90
|
-
],
|
|
91
|
-
),
|
|
92
73
|
),
|
|
93
74
|
),
|
|
94
75
|
NavMenuItem(
|
|
@@ -105,12 +86,6 @@ menu_items = (
|
|
|
105
86
|
"circuits.add_providernetwork",
|
|
106
87
|
],
|
|
107
88
|
),
|
|
108
|
-
NavMenuImportButton(
|
|
109
|
-
link="circuits:providernetwork_import",
|
|
110
|
-
permissions=[
|
|
111
|
-
"circuits.add_providernetwork",
|
|
112
|
-
],
|
|
113
|
-
),
|
|
114
89
|
),
|
|
115
90
|
),
|
|
116
91
|
),
|
|
@@ -5,15 +5,6 @@
|
|
|
5
5
|
<li><a href="{% url 'circuits:circuit_list' %}?provider={{ object.provider.pk }}">{{ object.provider }}</a></li>
|
|
6
6
|
{% endblock extra_breadcrumbs %}
|
|
7
7
|
|
|
8
|
-
{% block masthead %}
|
|
9
|
-
<h1>
|
|
10
|
-
<span class="hover_copy"><span id="copy_title">{{ object }}</span><button type="button" class="btn btn-inline btn-default hover_copy_button" data-clipboard-target="#copy_title">
|
|
11
|
-
<span class="mdi mdi-content-copy"></span>
|
|
12
|
-
</button>
|
|
13
|
-
</span>
|
|
14
|
-
</h1>
|
|
15
|
-
{% endblock masthead %}
|
|
16
|
-
|
|
17
8
|
{% block content_left_page %}
|
|
18
9
|
<div class="panel panel-default">
|
|
19
10
|
<div class="panel-heading">
|
|
@@ -91,6 +91,7 @@ class CircuitTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFil
|
|
|
91
91
|
["provider_network", "circuit_terminations__provider_network__name"],
|
|
92
92
|
["circuit_type", "circuit_type__id"],
|
|
93
93
|
["circuit_type", "circuit_type__name"],
|
|
94
|
+
["status", "status__id"],
|
|
94
95
|
["status", "status__name"],
|
|
95
96
|
["circuit_termination_a"],
|
|
96
97
|
["circuit_termination_z"],
|
nautobot/core/api/serializers.py
CHANGED
|
@@ -134,7 +134,15 @@ class BaseModelSerializer(OptInFieldsMixin, serializers.HyperlinkedModelSerializ
|
|
|
134
134
|
natural_keys_values = None
|
|
135
135
|
natural_slug = serializers.SerializerMethodField()
|
|
136
136
|
|
|
137
|
-
def __init__(self, *args, **kwargs):
|
|
137
|
+
def __init__(self, *args, force_csv=False, **kwargs):
|
|
138
|
+
"""
|
|
139
|
+
Instantiate a BaseModelSerializer.
|
|
140
|
+
|
|
141
|
+
The force_csv kwarg allows you to force _is_csv_request() to evaluate True without passing a Request object,
|
|
142
|
+
which is necessary to be able to export appropriately structured CSV from a Job that doesn't have a Request.
|
|
143
|
+
"""
|
|
144
|
+
self._force_csv = force_csv
|
|
145
|
+
|
|
138
146
|
super().__init__(*args, **kwargs)
|
|
139
147
|
# If it is not a Nested Serializer, we should set the depth argument to whatever is in the request's context
|
|
140
148
|
if not self.is_nested:
|
|
@@ -270,6 +278,8 @@ class BaseModelSerializer(OptInFieldsMixin, serializers.HyperlinkedModelSerializ
|
|
|
270
278
|
|
|
271
279
|
def _is_csv_request(self):
|
|
272
280
|
"""Return True if this a CSV export request"""
|
|
281
|
+
if self._force_csv:
|
|
282
|
+
return True
|
|
273
283
|
request = self.context.get("request")
|
|
274
284
|
return hasattr(request, "accepted_media_type") and "text/csv" in request.accepted_media_type
|
|
275
285
|
|
|
@@ -361,10 +371,10 @@ class BaseModelSerializer(OptInFieldsMixin, serializers.HyperlinkedModelSerializ
|
|
|
361
371
|
self.extend_field_names(fields, "id", at_start=True)
|
|
362
372
|
|
|
363
373
|
# Move these fields to the end
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
374
|
+
fields_to_include = ["created", "last_updated"]
|
|
375
|
+
for field in fields_to_include:
|
|
376
|
+
if hasattr(self.Meta.model, field):
|
|
377
|
+
self.extend_field_names(fields, field)
|
|
368
378
|
|
|
369
379
|
def filter_field(field):
|
|
370
380
|
# Eliminate all field names that start with "_" as those fields are not user-facing
|
nautobot/core/api/views.py
CHANGED
|
@@ -494,7 +494,7 @@ class NautobotSpectacularSwaggerView(APIVersioningGetSchemaURLMixin, Spectacular
|
|
|
494
494
|
@extend_schema(exclude=True)
|
|
495
495
|
def get(self, request, *args, **kwargs):
|
|
496
496
|
"""Fix up the rendering of the Swagger UI to work with Nautobot's UI."""
|
|
497
|
-
if not request.user.is_authenticated
|
|
497
|
+
if not request.user.is_authenticated:
|
|
498
498
|
doc_url = reverse("api_docs")
|
|
499
499
|
login_url = reverse(settings.LOGIN_URL)
|
|
500
500
|
return redirect(f"{login_url}?next={doc_url}")
|
|
@@ -721,18 +721,16 @@ class GetMenuAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
721
721
|
|
|
722
722
|
permission_classes = [IsAuthenticated]
|
|
723
723
|
|
|
724
|
-
def format_and_remove_hidden_menu(self, request, data
|
|
724
|
+
def format_and_remove_hidden_menu(self, request, data):
|
|
725
725
|
"""
|
|
726
726
|
Formats the menu data and removes hidden menu items based on user permissions.
|
|
727
727
|
|
|
728
728
|
Args:
|
|
729
729
|
request (HttpRequest): The request object.
|
|
730
|
-
data (
|
|
731
|
-
hide_restricted_ui (bool): Flag indicating whether to hide restricted menu items.
|
|
730
|
+
data (dict): The menu data to format and filter.
|
|
732
731
|
|
|
733
732
|
Returns:
|
|
734
|
-
(
|
|
735
|
-
`dict`, otherwise returns a string.
|
|
733
|
+
(dict): The formatted menu data without hidden items.
|
|
736
734
|
|
|
737
735
|
Example:
|
|
738
736
|
Input:
|
|
@@ -747,15 +745,18 @@ class GetMenuAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
747
745
|
Output:
|
|
748
746
|
{"Devices": "data value"}
|
|
749
747
|
"""
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
return_value[name] =
|
|
757
|
-
|
|
758
|
-
|
|
748
|
+
return_value = {}
|
|
749
|
+
for name, value in data.items():
|
|
750
|
+
if "permissions" in value:
|
|
751
|
+
permissions = value["permissions"]
|
|
752
|
+
user_has_permission = any(request.user.has_perm(permission) for permission in permissions)
|
|
753
|
+
if user_has_permission:
|
|
754
|
+
return_value[name] = value["data"]
|
|
755
|
+
else:
|
|
756
|
+
return_data = self.format_and_remove_hidden_menu(request, value["data"])
|
|
757
|
+
if return_data:
|
|
758
|
+
return_value[name] = return_data
|
|
759
|
+
return return_value
|
|
759
760
|
|
|
760
761
|
@extend_schema(exclude=True)
|
|
761
762
|
def get(self, request):
|
|
@@ -796,8 +797,7 @@ class GetMenuAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
796
797
|
}
|
|
797
798
|
"""
|
|
798
799
|
base_menu = registry["new_ui_nav_menu"]
|
|
799
|
-
|
|
800
|
-
formatted_data = self.format_and_remove_hidden_menu(request, base_menu, HIDE_RESTRICTED_UI)
|
|
800
|
+
formatted_data = self.format_and_remove_hidden_menu(request, base_menu)
|
|
801
801
|
return Response(formatted_data)
|
|
802
802
|
|
|
803
803
|
|
|
@@ -838,13 +838,12 @@ class GetObjectCountsView(NautobotAPIVersionMixin, APIView):
|
|
|
838
838
|
{"model": "extras.role"},
|
|
839
839
|
],
|
|
840
840
|
}
|
|
841
|
-
HIDE_RESTRICTED_UI = get_settings_or_config("HIDE_RESTRICTED_UI")
|
|
842
841
|
|
|
843
842
|
for entry in itertools.chain(*object_counts.values()):
|
|
844
843
|
app_label, model_name = entry["model"].split(".")
|
|
845
844
|
model = apps.get_model(app_label, model_name)
|
|
846
845
|
permission = get_permission_for_model(model, "view")
|
|
847
|
-
if
|
|
846
|
+
if not request.user.has_perm(permission):
|
|
848
847
|
continue
|
|
849
848
|
data = {"name": model._meta.verbose_name_plural}
|
|
850
849
|
try:
|
nautobot/core/choices.py
CHANGED
nautobot/core/filters.py
CHANGED
|
@@ -630,15 +630,23 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
630
630
|
if field is None:
|
|
631
631
|
return magic_filters
|
|
632
632
|
|
|
633
|
+
# If the field allows null values, add an `isnull`` check
|
|
634
|
+
if getattr(field, "null", None):
|
|
635
|
+
# Use this method vs extend as the `lookup_map` variable is generally one of
|
|
636
|
+
# the constants which we do not want to update
|
|
637
|
+
lookup_map = dict(lookup_map, **{"isnull": "isnull"})
|
|
638
|
+
|
|
633
639
|
# Create new filters for each lookup expression in the map
|
|
634
640
|
for lookup_name, lookup_expr in lookup_map.items():
|
|
635
641
|
new_filter_name = f"{filter_name}__{lookup_name}"
|
|
636
642
|
|
|
637
643
|
try:
|
|
638
|
-
if filter_name in cls.declared_filters:
|
|
639
|
-
# The filter field has been
|
|
644
|
+
if filter_name in cls.declared_filters and lookup_expr not in {"isnull"}:
|
|
645
|
+
# The filter field has been explicitly defined on the filterset class so we must manually
|
|
640
646
|
# create the new filter with the same type because there is no guarantee the defined type
|
|
641
|
-
# is the same as the default type for the field
|
|
647
|
+
# is the same as the default type for the field. This does not apply if the filter
|
|
648
|
+
# should retain the original lookup_expr type, such as `isnull` using a boolean field on a
|
|
649
|
+
# char or date object.
|
|
642
650
|
resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid
|
|
643
651
|
new_filter = type(filter_field)(
|
|
644
652
|
field_name=field_name,
|
|
@@ -649,7 +657,7 @@ class BaseFilterSet(django_filters.FilterSet):
|
|
|
649
657
|
**filter_field.extra,
|
|
650
658
|
)
|
|
651
659
|
else:
|
|
652
|
-
# The filter field is listed in Meta.fields so we can safely rely on default
|
|
660
|
+
# The filter field is listed in Meta.fields so we can safely rely on default behavior
|
|
653
661
|
# Will raise FieldLookupError if the lookup is invalid
|
|
654
662
|
new_filter = cls.filter_for_field(field, field_name, lookup_expr)
|
|
655
663
|
except django_filters.exceptions.FieldLookupError:
|
nautobot/core/jobs/__init__.py
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
from django.conf import settings
|
|
2
|
+
from django.contrib.contenttypes.models import ContentType
|
|
3
|
+
from django.core.exceptions import PermissionDenied
|
|
4
|
+
from django.http import QueryDict
|
|
5
|
+
|
|
6
|
+
from nautobot.core.api.renderers import NautobotCSVRenderer
|
|
7
|
+
from nautobot.core.api.utils import get_serializer_for_model
|
|
1
8
|
from nautobot.core.celery import app, register_jobs
|
|
9
|
+
from nautobot.core.utils.lookup import get_filterset_for_model
|
|
10
|
+
from nautobot.core.utils.requests import get_filterable_params_from_filter_params
|
|
2
11
|
from nautobot.extras.datasources import ensure_git_repository, git_repository_dry_run, refresh_datasource_content
|
|
3
|
-
from nautobot.extras.jobs import Job, ObjectVar
|
|
4
|
-
from nautobot.extras.models import GitRepository
|
|
12
|
+
from nautobot.extras.jobs import ChoiceVar, Job, ObjectVar, RunJobTaskFailed, StringVar
|
|
13
|
+
from nautobot.extras.models import ExportTemplate, GitRepository
|
|
5
14
|
|
|
6
15
|
name = "System Jobs"
|
|
7
16
|
|
|
@@ -59,5 +68,118 @@ class GitRepositoryDryRun(Job):
|
|
|
59
68
|
self.logger.info(f"Repository dry run completed in {job_result.duration}")
|
|
60
69
|
|
|
61
70
|
|
|
62
|
-
|
|
71
|
+
class ExportObjectList(Job):
|
|
72
|
+
"""System Job to export a list of objects via CSV or ExportTemplate."""
|
|
73
|
+
|
|
74
|
+
content_type = ObjectVar(
|
|
75
|
+
model=ContentType,
|
|
76
|
+
description="Type of objects to export",
|
|
77
|
+
label="Content Type",
|
|
78
|
+
)
|
|
79
|
+
query_string = StringVar(
|
|
80
|
+
description='Filterset parameters to apply, in URL query parameter format e.g. "name=test&status=Active"',
|
|
81
|
+
label="Filterset Parameters",
|
|
82
|
+
default="",
|
|
83
|
+
required=False,
|
|
84
|
+
)
|
|
85
|
+
export_format = ChoiceVar(
|
|
86
|
+
choices=(("csv", "CSV"), ("yaml", "YAML")),
|
|
87
|
+
description="Format to export to if not using an Export Template<br>"
|
|
88
|
+
"(note, in core only <code>dcim | device type</code> supports YAML export at present)",
|
|
89
|
+
default="csv",
|
|
90
|
+
required=False,
|
|
91
|
+
)
|
|
92
|
+
export_template = ObjectVar(
|
|
93
|
+
model=ExportTemplate,
|
|
94
|
+
query_params={"content_type": "$content_type"},
|
|
95
|
+
display_field="name",
|
|
96
|
+
description="Export Template to use (if unspecified, will export to CSV/YAML as specified above)",
|
|
97
|
+
label="Export Template",
|
|
98
|
+
default=None,
|
|
99
|
+
required=False,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
class Meta:
|
|
103
|
+
name = "Export Object List"
|
|
104
|
+
has_sensitive_variables = False
|
|
105
|
+
# Exporting large querysets may take substantial processing time
|
|
106
|
+
soft_time_limit = 1800
|
|
107
|
+
time_limit = 2000
|
|
108
|
+
|
|
109
|
+
def run(self, *, content_type, query_string="", export_format="csv", export_template=None):
|
|
110
|
+
if not self.user.has_perm(f"{content_type.app_label}.view_{content_type.model}"):
|
|
111
|
+
self.logger.error('User "%s" does not have permission to view %s objects', self.user, content_type.model)
|
|
112
|
+
raise PermissionDenied("User does not have view permissions on the requested content-type")
|
|
113
|
+
|
|
114
|
+
model = content_type.model_class()
|
|
115
|
+
|
|
116
|
+
# Start with all objects of the requested type
|
|
117
|
+
queryset = model.objects.all()
|
|
118
|
+
# Enforce user permissions
|
|
119
|
+
queryset = queryset.restrict(self.user, "view")
|
|
120
|
+
|
|
121
|
+
# Filter the queryset based on the provided query_string
|
|
122
|
+
filterset_class = get_filterset_for_model(model)
|
|
123
|
+
self.logger.debug("Found filterset class: `%s`", filterset_class.__name__)
|
|
124
|
+
# TODO: ideally the ObjectListView should strip its non_filter_params (which may vary by view!)
|
|
125
|
+
# such that they never are even seen here.
|
|
126
|
+
query_params = QueryDict(query_string)
|
|
127
|
+
self.logger.debug("Parsed query_params: `%s`", query_params.dict())
|
|
128
|
+
default_non_filter_params = ("export", "page", "per_page", "sort")
|
|
129
|
+
filter_params = get_filterable_params_from_filter_params(
|
|
130
|
+
query_params, default_non_filter_params, filterset_class()
|
|
131
|
+
)
|
|
132
|
+
self.logger.debug("Filterset params: `%s`", filter_params)
|
|
133
|
+
filterset = filterset_class(filter_params, queryset)
|
|
134
|
+
if not filterset.is_valid():
|
|
135
|
+
self.logger.error("Invalid filters were specified: %s", filterset.errors)
|
|
136
|
+
raise RunJobTaskFailed("Invalid query_string value for this content_type")
|
|
137
|
+
queryset = filterset.qs
|
|
138
|
+
object_count = queryset.count()
|
|
139
|
+
|
|
140
|
+
filename = f"{settings.BRANDING_PREPENDED_FILENAME}{model._meta.verbose_name_plural.lower().replace(' ', '_')}"
|
|
141
|
+
|
|
142
|
+
if export_template is not None:
|
|
143
|
+
# Export templates
|
|
144
|
+
if export_template.content_type != content_type:
|
|
145
|
+
self.logger.error("ExportTemplate %s doesn't apply to %s", export_template, content_type)
|
|
146
|
+
raise RunJobTaskFailed("ExportTemplate ContentType mismatch")
|
|
147
|
+
self.logger.info(
|
|
148
|
+
"Exporting %d objects via ExportTemplate. This may take some time.",
|
|
149
|
+
object_count,
|
|
150
|
+
extra={"object": export_template},
|
|
151
|
+
)
|
|
152
|
+
try:
|
|
153
|
+
# export_template.render() consumes the whole queryset, so we don't have any way to do a progress bar.
|
|
154
|
+
output = export_template.render(queryset)
|
|
155
|
+
except Exception as err:
|
|
156
|
+
self.logger.error("Error when rendering ExportTemplate: %s", err)
|
|
157
|
+
raise
|
|
158
|
+
if export_template.file_extension:
|
|
159
|
+
filename += f".{export_template.file_extension}"
|
|
160
|
+
self.create_file(filename, output)
|
|
161
|
+
|
|
162
|
+
elif export_format == "yaml":
|
|
163
|
+
# Device-type (etc.) YAML export
|
|
164
|
+
if not hasattr(model, "to_yaml"):
|
|
165
|
+
self.logger.error("Model %s doesn't support YAML export", content_type.model)
|
|
166
|
+
raise ValueError("YAML export not supported for this content-type")
|
|
167
|
+
self.logger.info("Exporting %d objects to YAML. This may take some time.", object_count)
|
|
168
|
+
yaml_data = [obj.to_yaml() for obj in queryset]
|
|
169
|
+
self.create_file(filename + ".yaml", "---\n".join(yaml_data))
|
|
170
|
+
|
|
171
|
+
else:
|
|
172
|
+
# Generic CSV export
|
|
173
|
+
serializer_class = get_serializer_for_model(model)
|
|
174
|
+
self.logger.debug("Found serializer class: `%s`", serializer_class.__name__)
|
|
175
|
+
renderer = NautobotCSVRenderer()
|
|
176
|
+
self.logger.info("Exporting %d objects to CSV. This may take some time.", object_count)
|
|
177
|
+
# The force_csv=True attribute is a hack, but much easier than trying to construct a valid HttpRequest
|
|
178
|
+
# object from scratch that passes all implicit and explicit assumptions in Django and DRF.
|
|
179
|
+
serializer = serializer_class(queryset, many=True, context={"request": None}, force_csv=True)
|
|
180
|
+
csv_data = renderer.render(serializer.data)
|
|
181
|
+
self.create_file(filename + ".csv", csv_data)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
jobs = [ExportObjectList, GitRepositorySync, GitRepositoryDryRun]
|
|
63
185
|
register_jobs(*jobs)
|
|
@@ -63,7 +63,7 @@ class Command(BaseCommand):
|
|
|
63
63
|
ManufacturerFactory,
|
|
64
64
|
PlatformFactory,
|
|
65
65
|
)
|
|
66
|
-
from nautobot.extras.factory import RoleFactory, StatusFactory, TagFactory
|
|
66
|
+
from nautobot.extras.factory import ExternalIntegrationFactory, RoleFactory, StatusFactory, TagFactory
|
|
67
67
|
from nautobot.extras.management import populate_status_choices
|
|
68
68
|
from nautobot.dcim.factory import (
|
|
69
69
|
LocationTypeFactory,
|
|
@@ -172,6 +172,9 @@ class Command(BaseCommand):
|
|
|
172
172
|
has_description=True,
|
|
173
173
|
using=db_name,
|
|
174
174
|
)
|
|
175
|
+
self.stdout.write("Creating ExternalIntegrations...")
|
|
176
|
+
ExternalIntegrationFactory.create_batch(20, using=db_name)
|
|
177
|
+
# make sure we have some tenants that have null relationships to make filter tests happy
|
|
175
178
|
self.stdout.write("Creating Tenants without Circuits, Locations, IPAddresses, or Prefixes...")
|
|
176
179
|
TenantFactory.create_batch(10, using=db_name)
|
|
177
180
|
# TODO: nautobot.tenancy.tests.test_filters currently calls the following additional factories:
|
nautobot/core/models/fields.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import re
|
|
3
3
|
|
|
4
|
-
from django.contrib.contenttypes.models import ContentType
|
|
5
4
|
from django.core import exceptions
|
|
6
5
|
from django.core.validators import RegexValidator, MaxLengthValidator
|
|
7
6
|
from django.db import models
|
|
@@ -187,7 +186,18 @@ class ForeignKeyLimitedByContentTypes(ForeignKeyWithAutoRelatedName):
|
|
|
187
186
|
"""
|
|
188
187
|
|
|
189
188
|
def get_limit_choices_to(self):
|
|
190
|
-
|
|
189
|
+
"""
|
|
190
|
+
Limit this field to only objects which are assigned to this model's content-type.
|
|
191
|
+
|
|
192
|
+
Note that this is implemented via specifying `content_types__app_label=` and `content_types__model=`
|
|
193
|
+
rather than via the more obvious `content_types=ContentType.objects.get_for_model(self.model)`
|
|
194
|
+
because the latter approach would involve a database query, and in some cases
|
|
195
|
+
(most notably FilterSet definition) this function is called **before** database migrations can be run.
|
|
196
|
+
"""
|
|
197
|
+
return {
|
|
198
|
+
"content_types__app_label": self.model._meta.app_label,
|
|
199
|
+
"content_types__model": self.model._meta.model_name,
|
|
200
|
+
}
|
|
191
201
|
|
|
192
202
|
def formfield(self, **kwargs):
|
|
193
203
|
"""Return a prepped formfield for use in model forms."""
|
nautobot/core/settings.py
CHANGED
|
@@ -87,6 +87,9 @@ HTTP_PROXIES = None
|
|
|
87
87
|
# Send anonymized installation metrics when post_upgrade or send_installation_metrics management commands are run
|
|
88
88
|
INSTALLATION_METRICS_ENABLED = is_truthy(os.getenv("NAUTOBOT_INSTALLATION_METRICS_ENABLED", "True"))
|
|
89
89
|
|
|
90
|
+
# The storage backend to use for Job input files and Job output files
|
|
91
|
+
JOB_FILE_IO_STORAGE = os.getenv("NAUTOBOT_JOB_FILE_IO_STORAGE", "db_file_storage.storage.DatabaseFileStorage")
|
|
92
|
+
|
|
90
93
|
# The file path to a directory where locally installed Jobs can be discovered
|
|
91
94
|
JOBS_ROOT = os.getenv("NAUTOBOT_JOBS_ROOT", os.path.join(NAUTOBOT_ROOT, "jobs").rstrip("/"))
|
|
92
95
|
|
|
@@ -611,12 +614,6 @@ CONSTANCE_CONFIG = {
|
|
|
611
614
|
help_text="Whether to show the Feedback button in the new UI sidebar.",
|
|
612
615
|
field_type=bool,
|
|
613
616
|
),
|
|
614
|
-
"HIDE_RESTRICTED_UI": ConstanceConfigItem(
|
|
615
|
-
default=False,
|
|
616
|
-
help_text="If set to True, users with limited permissions will not be shown menu items and home-page elements that "
|
|
617
|
-
"they do not have permission to access.",
|
|
618
|
-
field_type=bool,
|
|
619
|
-
),
|
|
620
617
|
"LOCATION_NAME_AS_NATURAL_KEY": ConstanceConfigItem(
|
|
621
618
|
default=False,
|
|
622
619
|
help_text="Location names are not guaranteed globally-unique by Nautobot but in practice they often are. "
|
|
@@ -700,7 +697,7 @@ CONSTANCE_CONFIG_FIELDSETS = {
|
|
|
700
697
|
"Performance": ["DYNAMIC_GROUPS_MEMBER_CACHE_TIMEOUT"],
|
|
701
698
|
"Rack Elevation Rendering": ["RACK_ELEVATION_DEFAULT_UNIT_HEIGHT", "RACK_ELEVATION_DEFAULT_UNIT_WIDTH"],
|
|
702
699
|
"Release Checking": ["RELEASE_CHECK_URL", "RELEASE_CHECK_TIMEOUT"],
|
|
703
|
-
"User Interface": ["
|
|
700
|
+
"User Interface": ["FEEDBACK_BUTTON_ENABLED", "SUPPORT_MESSAGE"],
|
|
704
701
|
}
|
|
705
702
|
|
|
706
703
|
#
|
|
@@ -839,6 +836,10 @@ BRANDING_FILEPATHS = {
|
|
|
839
836
|
"icon_mask": os.getenv(
|
|
840
837
|
"NAUTOBOT_BRANDING_FILEPATHS_ICON_MASK", None
|
|
841
838
|
), # mono-chrome icon used for the mask-icon header
|
|
839
|
+
"header_bullet": os.getenv(
|
|
840
|
+
"NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET", None
|
|
841
|
+
), # bullet image used for various view headers
|
|
842
|
+
"nav_bullet": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET", None), # bullet image used for nav menu headers
|
|
842
843
|
}
|
|
843
844
|
|
|
844
845
|
# Title to use in place of "Nautobot"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<body>
|
|
13
13
|
{% include 'inc/nav_menu.html' %}
|
|
14
14
|
<div class="container-fluid wrapper">
|
|
15
|
-
{% if request.user.is_authenticated
|
|
15
|
+
{% if request.user.is_authenticated %}
|
|
16
16
|
{% if "BANNER_TOP"|settings_or_config %}
|
|
17
17
|
<div class="alert alert-info text-center" role="alert">
|
|
18
18
|
{{ "BANNER_TOP"|settings_or_config|safe }}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
{% block header %}{% endblock header %}
|
|
38
38
|
{% block content %}{% endblock content %}
|
|
39
39
|
<div class="push"></div>
|
|
40
|
-
{% if request.user.is_authenticated
|
|
40
|
+
{% if request.user.is_authenticated %}
|
|
41
41
|
{% if "BANNER_BOTTOM"|settings_or_config %}
|
|
42
42
|
<div class="alert alert-info text-center banner-bottom" role="alert">
|
|
43
43
|
{{ "BANNER_BOTTOM"|settings_or_config|safe }}
|
|
@@ -1,33 +1,60 @@
|
|
|
1
|
-
{% if
|
|
2
|
-
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
{% if export_url %}
|
|
2
|
+
{% if export_templates or include_yaml_option %}
|
|
3
|
+
<div class="btn-group">
|
|
4
|
+
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
5
|
+
<span class="mdi mdi-database-export" aria-hidden="true"></span>
|
|
6
|
+
Export <span class="caret"></span>
|
|
7
|
+
</button>
|
|
8
|
+
<ul class="dropdown-menu dropdown-menu-right">
|
|
9
9
|
<li>
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
<form action="{{ export_url }}" method="post">
|
|
11
|
+
{% csrf_token %}
|
|
12
|
+
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
13
|
+
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
14
|
+
<input type="hidden" name="_schedule_type" value="immediately">
|
|
15
|
+
<button type="submit" class="btn btn-link">CSV format</button>
|
|
16
|
+
</form>
|
|
13
17
|
</li>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
18
|
+
{% if include_yaml_option %}
|
|
19
|
+
<li>
|
|
20
|
+
<form action="{{ export_url }}" method="post">
|
|
21
|
+
{% csrf_token %}
|
|
22
|
+
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
23
|
+
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
24
|
+
<input type="hidden" name="export_format" value="yaml">
|
|
25
|
+
<input type="hidden" name="_schedule_type" value="immediately">
|
|
26
|
+
<button type="submit" class="btn btn-link">YAML format</button>
|
|
27
|
+
</form>
|
|
28
|
+
</li>
|
|
29
|
+
{% endif %}
|
|
30
|
+
{% if export_templates %}
|
|
31
|
+
<li class="divider"></li>
|
|
32
|
+
{% for et in export_templates %}
|
|
33
|
+
<li>
|
|
34
|
+
<form action="{{ export_url }}" method="post">
|
|
35
|
+
{% csrf_token %}
|
|
36
|
+
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
37
|
+
<input type="hidden" name="export_template" value="{{ et.pk }}">
|
|
38
|
+
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
39
|
+
<input type="hidden" name="_schedule_type" value="immediately">
|
|
40
|
+
<button type="submit" class="btn btn-link"
|
|
41
|
+
{% if et.description %}title="{{ et.description }}"{% endif %}
|
|
42
|
+
>{{ et.name }}</button>
|
|
43
|
+
</form>
|
|
44
|
+
</li>
|
|
45
|
+
{% endfor %}
|
|
46
|
+
{% endif %}
|
|
47
|
+
</ul>
|
|
48
|
+
</div>
|
|
49
|
+
{% else %}
|
|
50
|
+
<form style="display: inline-block" action="{{ export_url }}" method="post">
|
|
51
|
+
{% csrf_token %}
|
|
52
|
+
<input type="hidden" name="content_type" value="{{ content_type.pk }}">
|
|
53
|
+
<input type="hidden" name="query_string" value="{{ query_string }}">
|
|
54
|
+
<input type="hidden" name="_schedule_type" value="immediately">
|
|
55
|
+
<button type="submit" class="btn btn-success">
|
|
56
|
+
<span class="mdi mdi-database-export" aria-hidden="true"></span> Export
|
|
57
|
+
</button>
|
|
58
|
+
</form>
|
|
59
|
+
{% endif %}
|
|
33
60
|
{% endif %}
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
</div>
|
|
127
127
|
</div>
|
|
128
128
|
{% endif %}
|
|
129
|
-
{% include table_template|default:'
|
|
129
|
+
{% include table_template|default:'panel_table.html' %}
|
|
130
130
|
<div class="pull-left noprint">
|
|
131
131
|
{% block bulk_buttons %}{% endblock %}
|
|
132
132
|
{% if bulk_edit_url and permissions.change %}
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
</div>
|
|
143
143
|
</form>
|
|
144
144
|
{% else %}
|
|
145
|
-
{% include table_template|default:'
|
|
145
|
+
{% include table_template|default:'panel_table.html' %}
|
|
146
146
|
{% endif %}
|
|
147
147
|
{% endwith %}
|
|
148
148
|
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
|
@@ -58,7 +58,14 @@
|
|
|
58
58
|
</div>
|
|
59
59
|
|
|
60
60
|
{% block masthead %}
|
|
61
|
-
<h1>
|
|
61
|
+
<h1>
|
|
62
|
+
<span class="hover_copy">
|
|
63
|
+
<span id="copy_title">{% block title %}{{object.display|default:object}}{% endblock %}</span>
|
|
64
|
+
<button type="button" class="btn btn-inline btn-default hover_copy_button" data-clipboard-target="#copy_title">
|
|
65
|
+
<span class="mdi mdi-content-copy"></span>
|
|
66
|
+
</button>
|
|
67
|
+
</span>
|
|
68
|
+
</h1>
|
|
62
69
|
{% endblock masthead %}
|
|
63
70
|
{% include 'inc/created_updated.html' %}
|
|
64
71
|
<div class="pull-right noprint">
|