nautobot 2.2.0b1__py3-none-any.whl → 2.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/__init__.py +31 -0
- nautobot/apps/api.py +1 -2
- nautobot/apps/utils.py +4 -0
- nautobot/apps/views.py +2 -0
- nautobot/circuits/api/urls.py +1 -2
- nautobot/circuits/api/views.py +0 -12
- nautobot/circuits/apps.py +1 -1
- nautobot/circuits/tests/test_filters.py +1 -1
- nautobot/core/api/routers.py +50 -3
- nautobot/core/api/utils.py +4 -0
- nautobot/core/api/views.py +21 -15
- nautobot/core/cli/__init__.py +18 -11
- nautobot/core/constants.py +85 -0
- nautobot/core/filters.py +7 -1
- nautobot/core/forms/widgets.py +1 -2
- nautobot/core/graphql/schema.py +1 -0
- nautobot/core/management/commands/generate_test_data.py +4 -4
- nautobot/core/models/__init__.py +1 -0
- nautobot/core/settings.py +24 -3
- nautobot/core/settings.yaml +20 -0
- nautobot/core/signals.py +1 -0
- nautobot/core/tables.py +2 -1
- nautobot/core/templates/admin/base.html +23 -94
- nautobot/core/templates/generic/object_retrieve.html +2 -2
- nautobot/core/templates/graphene/graphiql.html +18 -47
- nautobot/core/templates/inc/footer.html +5 -5
- nautobot/core/templates/inc/javascript.html +4 -4
- nautobot/core/templates/inc/media.html +2 -2
- nautobot/core/templates/inc/nav_menu.html +0 -7
- nautobot/core/templates/nautobot_config.py.j2 +14 -1
- nautobot/core/templates/rest_framework/api.html +12 -5
- nautobot/core/templatetags/helpers.py +2 -2
- nautobot/core/testing/__init__.py +1 -1
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/testing/views.py +30 -0
- nautobot/core/tests/integration/test_view_authentication.py +68 -0
- nautobot/core/tests/test_api.py +13 -6
- nautobot/core/tests/test_csv.py +5 -4
- nautobot/core/tests/test_filters.py +2 -1
- nautobot/core/tests/test_graphql.py +4 -14
- nautobot/core/tests/test_navigations.py +3 -0
- nautobot/core/tests/test_views.py +44 -16
- nautobot/core/utils/data.py +1 -2
- nautobot/core/utils/lookup.py +126 -0
- nautobot/core/views/__init__.py +3 -7
- nautobot/core/views/generic.py +20 -6
- nautobot/core/views/mixins.py +7 -1
- nautobot/core/views/renderers.py +11 -6
- nautobot/dcim/api/serializers.py +4 -4
- nautobot/dcim/api/urls.py +2 -3
- nautobot/dcim/api/views.py +7 -18
- nautobot/dcim/apps.py +8 -4
- nautobot/dcim/elevations.py +5 -1
- nautobot/dcim/factory.py +7 -7
- nautobot/dcim/filters/__init__.py +16 -17
- nautobot/dcim/forms.py +61 -45
- nautobot/dcim/homepage.py +11 -3
- nautobot/dcim/management/commands/migrate_location_contacts.py +218 -0
- nautobot/dcim/migrations/0057_controller_models.py +11 -70
- nautobot/dcim/models/__init__.py +2 -2
- nautobot/dcim/models/devices.py +14 -16
- nautobot/dcim/models/racks.py +1 -3
- nautobot/dcim/navigation.py +23 -31
- nautobot/dcim/signals.py +6 -6
- nautobot/dcim/tables/__init__.py +2 -2
- nautobot/dcim/tables/devices.py +13 -16
- nautobot/dcim/tables/template_code.py +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +70 -0
- nautobot/dcim/templates/dcim/controller_retrieve.html +35 -18
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +88 -0
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +75 -43
- nautobot/dcim/templates/dcim/device.html +11 -3
- nautobot/dcim/templates/dcim/device_edit.html +1 -1
- nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
- nautobot/dcim/tests/test_api.py +47 -6
- nautobot/dcim/tests/test_filters.py +92 -81
- nautobot/dcim/tests/test_graphql.py +11 -1
- nautobot/dcim/tests/test_models.py +15 -15
- nautobot/dcim/tests/test_signals.py +3 -1
- nautobot/dcim/tests/test_views.py +24 -12
- nautobot/dcim/urls.py +1 -1
- nautobot/dcim/views.py +25 -15
- nautobot/extras/api/serializers.py +20 -1
- nautobot/extras/api/urls.py +1 -2
- nautobot/extras/api/views.py +0 -10
- nautobot/extras/apps.py +7 -0
- nautobot/extras/context_managers.py +15 -4
- nautobot/extras/filters/__init__.py +53 -2
- nautobot/extras/filters/customfields.py +14 -9
- nautobot/extras/filters/mixins.py +6 -1
- nautobot/extras/forms/contacts.py +7 -0
- nautobot/extras/health_checks.py +1 -0
- nautobot/extras/jobs.py +1 -0
- nautobot/extras/managers.py +15 -2
- nautobot/extras/models/contacts.py +1 -0
- nautobot/extras/models/customfields.py +25 -2
- nautobot/extras/models/datasources.py +1 -0
- nautobot/extras/models/mixins.py +1 -0
- nautobot/extras/navigation.py +71 -65
- nautobot/extras/plugins/__init__.py +2 -1
- nautobot/extras/plugins/views.py +7 -11
- nautobot/extras/querysets.py +1 -2
- nautobot/extras/secrets/providers.py +1 -0
- nautobot/extras/signals.py +15 -5
- nautobot/extras/tasks.py +70 -17
- nautobot/extras/tests/test_api.py +2 -4
- nautobot/extras/tests/test_customfields.py +72 -9
- nautobot/extras/tests/test_dynamicgroups.py +2 -0
- nautobot/extras/tests/test_filters.py +89 -4
- nautobot/extras/tests/test_models.py +9 -0
- nautobot/extras/tests/test_relationships.py +10 -1
- nautobot/extras/tests/test_views.py +112 -1
- nautobot/extras/views.py +18 -17
- nautobot/ipam/api/serializers.py +10 -0
- nautobot/ipam/api/urls.py +1 -2
- nautobot/ipam/api/views.py +0 -11
- nautobot/ipam/apps.py +3 -2
- nautobot/ipam/tables.py +2 -22
- nautobot/ipam/tests/test_graphql.py +2 -3
- nautobot/ipam/tests/test_tables.py +42 -0
- nautobot/ipam/tests/test_views.py +1 -0
- nautobot/ipam/views.py +9 -9
- nautobot/project-static/css/base.css +1 -0
- nautobot/project-static/docs/404.html +126 -73
- nautobot/project-static/docs/apps/index.html +127 -71
- nautobot/project-static/docs/apps/nautobot-apps.html +127 -71
- nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +167 -73
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +165 -72
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +128 -72
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +345 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +172 -73
- nautobot/project-static/docs/development/apps/api/configuration-view.html +127 -71
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/global-search.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/graphql.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +127 -71
- nautobot/project-static/docs/development/apps/api/prometheus.html +127 -71
- nautobot/project-static/docs/development/apps/api/setup.html +127 -71
- nautobot/project-static/docs/development/apps/api/testing.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/base-template.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +141 -80
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +144 -83
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/notes.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/urls.html +127 -71
- nautobot/project-static/docs/development/apps/index.html +127 -71
- nautobot/project-static/docs/development/apps/migration/code-updates.html +127 -71
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +127 -71
- nautobot/project-static/docs/development/apps/migration/from-v1.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +127 -71
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +127 -71
- nautobot/project-static/docs/development/core/application-registry.html +127 -71
- nautobot/project-static/docs/development/core/best-practices.html +145 -79
- nautobot/project-static/docs/development/core/bootstrap-ui.html +127 -71
- nautobot/project-static/docs/development/core/caching.html +127 -71
- nautobot/project-static/docs/development/core/controllers.html +141 -275
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +127 -71
- nautobot/project-static/docs/development/core/extending-models.html +13 -8166
- nautobot/project-static/docs/development/core/generic-views.html +142 -86
- nautobot/project-static/docs/development/core/getting-started.html +146 -81
- nautobot/project-static/docs/development/core/homepage.html +145 -89
- nautobot/project-static/docs/development/core/index.html +127 -71
- nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
- nautobot/project-static/docs/development/core/model-features.html +130 -74
- nautobot/project-static/docs/development/core/natural-keys.html +127 -71
- nautobot/project-static/docs/development/core/navigation-menu.html +127 -71
- nautobot/project-static/docs/development/core/release-checklist.html +127 -71
- nautobot/project-static/docs/development/core/role-internals.html +127 -71
- nautobot/project-static/docs/development/core/settings.html +127 -71
- nautobot/project-static/docs/development/core/style-guide.html +127 -71
- nautobot/project-static/docs/development/core/templates.html +127 -71
- nautobot/project-static/docs/development/core/testing.html +127 -71
- nautobot/project-static/docs/development/core/user-preferences.html +127 -71
- nautobot/project-static/docs/development/extending-models.html +3 -3
- nautobot/project-static/docs/development/index.html +127 -71
- nautobot/project-static/docs/development/jobs/index.html +128 -72
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +127 -71
- nautobot/project-static/docs/index.html +126 -73
- nautobot/project-static/docs/models/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.0.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.1.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.2.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.3.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.4.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.5.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.6.html +127 -71
- nautobot/project-static/docs/release-notes/version-2.0.html +127 -71
- nautobot/project-static/docs/release-notes/version-2.1.html +538 -254
- nautobot/project-static/docs/release-notes/version-2.2.html +520 -101
- nautobot/project-static/docs/requirements.txt +3 -3
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +264 -259
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +192 -71
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -71
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +130 -74
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +134 -74
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +8616 -0
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +130 -74
- nautobot/project-static/docs/user-guide/administration/installation/services.html +127 -71
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +127 -71
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +127 -71
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +127 -71
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +362 -79
- nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +210 -85
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +130 -74
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +138 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +138 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/{contact-and-team.html → contacts-and-teams.html} +128 -72
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +129 -73
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +129 -73
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +127 -71
- nautobot/project-static/docs/user-guide/index.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +127 -71
- nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
- nautobot/tenancy/api/urls.py +1 -2
- nautobot/tenancy/api/views.py +0 -12
- nautobot/tenancy/tables.py +1 -1
- nautobot/tenancy/tests/test_views.py +1 -0
- nautobot/users/api/urls.py +1 -2
- nautobot/users/api/views.py +2 -65
- nautobot/users/views.py +8 -8
- nautobot/virtualization/api/urls.py +1 -2
- nautobot/virtualization/api/views.py +0 -12
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/METADATA +24 -24
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/RECORD +418 -412
- nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +0 -43
- nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
- nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
- /nautobot/dcim/templates/dcim/{controllerdevicegroup_retrieve.html → controllermanageddevicegroup_retrieve.html} +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/NOTICE +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/WHEEL +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/entry_points.txt +0 -0
nautobot/dcim/views.py
CHANGED
|
@@ -11,7 +11,7 @@ from django.forms import (
|
|
|
11
11
|
ModelMultipleChoiceField,
|
|
12
12
|
MultipleHiddenInput,
|
|
13
13
|
)
|
|
14
|
-
from django.shortcuts import get_object_or_404, redirect, render
|
|
14
|
+
from django.shortcuts import get_object_or_404, HttpResponse, redirect, render
|
|
15
15
|
from django.utils.functional import cached_property
|
|
16
16
|
from django.utils.html import format_html
|
|
17
17
|
from django.views.generic import View
|
|
@@ -48,7 +48,7 @@ from .models import (
|
|
|
48
48
|
ConsoleServerPort,
|
|
49
49
|
ConsoleServerPortTemplate,
|
|
50
50
|
Controller,
|
|
51
|
-
|
|
51
|
+
ControllerManagedDeviceGroup,
|
|
52
52
|
Device,
|
|
53
53
|
DeviceBay,
|
|
54
54
|
DeviceBayTemplate,
|
|
@@ -1459,7 +1459,7 @@ class DeviceBulkEditView(generic.BulkEditView):
|
|
|
1459
1459
|
"device_type__manufacturer",
|
|
1460
1460
|
"secrets_group",
|
|
1461
1461
|
"device_redundancy_group",
|
|
1462
|
-
"
|
|
1462
|
+
"controller_managed_device_group",
|
|
1463
1463
|
)
|
|
1464
1464
|
filterset = filters.DeviceFilterSet
|
|
1465
1465
|
table = tables.DeviceTable
|
|
@@ -2359,7 +2359,7 @@ class CableCreateView(generic.ObjectEditView):
|
|
|
2359
2359
|
"rear-port": forms.ConnectCableToRearPortForm,
|
|
2360
2360
|
"power-feed": forms.ConnectCableToPowerFeedForm,
|
|
2361
2361
|
"circuit-termination": forms.ConnectCableToCircuitTerminationForm,
|
|
2362
|
-
}
|
|
2362
|
+
}.get(kwargs.get("termination_b_type"), None)
|
|
2363
2363
|
|
|
2364
2364
|
return super().dispatch(request, *args, **kwargs)
|
|
2365
2365
|
|
|
@@ -2376,6 +2376,9 @@ class CableCreateView(generic.ObjectEditView):
|
|
|
2376
2376
|
return obj
|
|
2377
2377
|
|
|
2378
2378
|
def get(self, request, *args, **kwargs):
|
|
2379
|
+
if self.model_form is None:
|
|
2380
|
+
return HttpResponse(status_code=400)
|
|
2381
|
+
|
|
2379
2382
|
obj = self.alter_obj(self.get_object(kwargs), request, args, kwargs)
|
|
2380
2383
|
|
|
2381
2384
|
# Parse initial data manually to avoid setting field values as lists
|
|
@@ -2975,6 +2978,12 @@ class DeviceFamilyUIViewSet(NautobotUIViewSet):
|
|
|
2975
2978
|
RequestConfig(request, paginate).configure(device_type_table)
|
|
2976
2979
|
|
|
2977
2980
|
context["device_type_table"] = device_type_table
|
|
2981
|
+
|
|
2982
|
+
total_devices = 0
|
|
2983
|
+
for device_type in device_types:
|
|
2984
|
+
total_devices += device_type.device_count
|
|
2985
|
+
context["total_devices"] = total_devices
|
|
2986
|
+
|
|
2978
2987
|
return context
|
|
2979
2988
|
|
|
2980
2989
|
|
|
@@ -3021,12 +3030,13 @@ class ControllerUIViewSet(NautobotUIViewSet):
|
|
|
3021
3030
|
queryset = Controller.objects.all()
|
|
3022
3031
|
serializer_class = serializers.ControllerSerializer
|
|
3023
3032
|
table_class = tables.ControllerTable
|
|
3033
|
+
template_name = "dcim/controller_create.html"
|
|
3024
3034
|
|
|
3025
3035
|
def get_extra_context(self, request, instance):
|
|
3026
3036
|
context = super().get_extra_context(request, instance)
|
|
3027
3037
|
|
|
3028
3038
|
if self.action == "retrieve" and instance:
|
|
3029
|
-
devices = Device.objects.restrict(request.user).filter(
|
|
3039
|
+
devices = Device.objects.restrict(request.user).filter(controller_managed_device_group__controller=instance)
|
|
3030
3040
|
devices_table = tables.DeviceTable(devices)
|
|
3031
3041
|
|
|
3032
3042
|
paginate = {
|
|
@@ -3040,19 +3050,19 @@ class ControllerUIViewSet(NautobotUIViewSet):
|
|
|
3040
3050
|
return context
|
|
3041
3051
|
|
|
3042
3052
|
|
|
3043
|
-
class
|
|
3044
|
-
filterset_class = filters.
|
|
3045
|
-
filterset_form_class = forms.
|
|
3046
|
-
form_class = forms.
|
|
3047
|
-
bulk_update_form_class = forms.
|
|
3053
|
+
class ControllerManagedDeviceGroupUIViewSet(NautobotUIViewSet):
|
|
3054
|
+
filterset_class = filters.ControllerManagedDeviceGroupFilterSet
|
|
3055
|
+
filterset_form_class = forms.ControllerManagedDeviceGroupFilterForm
|
|
3056
|
+
form_class = forms.ControllerManagedDeviceGroupForm
|
|
3057
|
+
bulk_update_form_class = forms.ControllerManagedDeviceGroupBulkEditForm
|
|
3048
3058
|
queryset = (
|
|
3049
|
-
|
|
3059
|
+
ControllerManagedDeviceGroup.objects.all()
|
|
3050
3060
|
.prefetch_related("devices")
|
|
3051
|
-
.annotate(device_count=count_related(Device, "
|
|
3061
|
+
.annotate(device_count=count_related(Device, "controller_managed_device_group"))
|
|
3052
3062
|
)
|
|
3053
|
-
serializer_class = serializers.
|
|
3054
|
-
table_class = tables.
|
|
3055
|
-
template_name = "dcim/
|
|
3063
|
+
serializer_class = serializers.ControllerManagedDeviceGroupSerializer
|
|
3064
|
+
table_class = tables.ControllerManagedDeviceGroupTable
|
|
3065
|
+
template_name = "dcim/controllermanageddevicegroup_create.html"
|
|
3056
3066
|
|
|
3057
3067
|
def get_extra_context(self, request, instance):
|
|
3058
3068
|
context = super().get_extra_context(request, instance)
|
|
@@ -193,10 +193,18 @@ class ContactSerializer(NautobotModelSerializer):
|
|
|
193
193
|
class Meta:
|
|
194
194
|
model = Contact
|
|
195
195
|
fields = "__all__"
|
|
196
|
+
# https://www.django-rest-framework.org/api-guide/validators/#optional-fields
|
|
197
|
+
validators = []
|
|
198
|
+
extra_kwargs = {
|
|
199
|
+
"email": {"default": ""},
|
|
200
|
+
"phone": {"default": ""},
|
|
201
|
+
}
|
|
196
202
|
|
|
197
203
|
def validate(self, data):
|
|
198
204
|
attrs = data.copy()
|
|
199
205
|
attrs.pop("teams", None)
|
|
206
|
+
validator = UniqueTogetherValidator(queryset=Contact.objects.all(), fields=("name", "phone", "email"))
|
|
207
|
+
validator(attrs, self)
|
|
200
208
|
super().validate(attrs)
|
|
201
209
|
return data
|
|
202
210
|
|
|
@@ -946,7 +954,18 @@ class TeamSerializer(NautobotModelSerializer):
|
|
|
946
954
|
class Meta:
|
|
947
955
|
model = Team
|
|
948
956
|
fields = "__all__"
|
|
949
|
-
extra_kwargs = {
|
|
957
|
+
extra_kwargs = {
|
|
958
|
+
"contacts": {"required": False},
|
|
959
|
+
"email": {"default": ""},
|
|
960
|
+
"phone": {"default": ""},
|
|
961
|
+
}
|
|
962
|
+
# https://www.django-rest-framework.org/api-guide/validators/#optional-fields
|
|
963
|
+
validators = []
|
|
964
|
+
|
|
965
|
+
def validate(self, data):
|
|
966
|
+
validator = UniqueTogetherValidator(queryset=Team.objects.all(), fields=("name", "phone", "email"))
|
|
967
|
+
validator(data, self)
|
|
968
|
+
return super().validate(data)
|
|
950
969
|
|
|
951
970
|
|
|
952
971
|
#
|
nautobot/extras/api/urls.py
CHANGED
|
@@ -2,8 +2,7 @@ from nautobot.core.api.routers import OrderedDefaultRouter
|
|
|
2
2
|
|
|
3
3
|
from . import views
|
|
4
4
|
|
|
5
|
-
router = OrderedDefaultRouter()
|
|
6
|
-
router.APIRootView = views.ExtrasRootView
|
|
5
|
+
router = OrderedDefaultRouter(view_name="Extras")
|
|
7
6
|
|
|
8
7
|
# Computed Fields
|
|
9
8
|
router.register("computed-fields", views.ComputedFieldViewSet)
|
nautobot/extras/api/views.py
CHANGED
|
@@ -16,7 +16,6 @@ from rest_framework.exceptions import MethodNotAllowed, PermissionDenied, Valida
|
|
|
16
16
|
from rest_framework.parsers import JSONParser, MultiPartParser
|
|
17
17
|
from rest_framework.permissions import IsAuthenticated
|
|
18
18
|
from rest_framework.response import Response
|
|
19
|
-
from rest_framework.routers import APIRootView
|
|
20
19
|
|
|
21
20
|
from nautobot.core.api.authentication import TokenPermissions
|
|
22
21
|
from nautobot.core.api.utils import get_serializer_for_model
|
|
@@ -77,15 +76,6 @@ from nautobot.extras.utils import get_worker_count
|
|
|
77
76
|
from . import serializers
|
|
78
77
|
|
|
79
78
|
|
|
80
|
-
class ExtrasRootView(APIRootView):
|
|
81
|
-
"""
|
|
82
|
-
Extras API root view
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
def get_view_name(self):
|
|
86
|
-
return "Extras"
|
|
87
|
-
|
|
88
|
-
|
|
89
79
|
class NotesViewSetMixin:
|
|
90
80
|
def restrict_queryset(self, request, *args, **kwargs):
|
|
91
81
|
"""
|
nautobot/extras/apps.py
CHANGED
|
@@ -12,6 +12,13 @@ logger = logging.getLogger(__name__)
|
|
|
12
12
|
|
|
13
13
|
class ExtrasConfig(NautobotConfig):
|
|
14
14
|
name = "nautobot.extras"
|
|
15
|
+
searchable_models = [
|
|
16
|
+
"contact",
|
|
17
|
+
"dynamicgroup",
|
|
18
|
+
"externalintegration",
|
|
19
|
+
"gitrepository",
|
|
20
|
+
"team",
|
|
21
|
+
]
|
|
15
22
|
|
|
16
23
|
def ready(self):
|
|
17
24
|
super().ready()
|
|
@@ -7,7 +7,7 @@ from django.test.client import RequestFactory
|
|
|
7
7
|
|
|
8
8
|
from nautobot.extras.choices import ObjectChangeEventContextChoices
|
|
9
9
|
from nautobot.extras.models import ObjectChange
|
|
10
|
-
from nautobot.extras.signals import change_context_state
|
|
10
|
+
from nautobot.extras.signals import change_context_state, get_user_if_authenticated
|
|
11
11
|
from nautobot.extras.webhooks import enqueue_webhooks
|
|
12
12
|
|
|
13
13
|
|
|
@@ -46,11 +46,22 @@ class ChangeContext:
|
|
|
46
46
|
if self.change_id is None:
|
|
47
47
|
self.change_id = uuid.uuid4()
|
|
48
48
|
|
|
49
|
-
def get_user(self):
|
|
49
|
+
def get_user(self, instance=None):
|
|
50
50
|
"""Return self.user if set, otherwise return self.request.user"""
|
|
51
51
|
if self.user is not None:
|
|
52
|
-
return self.user
|
|
53
|
-
return self.request.user
|
|
52
|
+
return get_user_if_authenticated(self.user, instance)
|
|
53
|
+
return get_user_if_authenticated(self.request.user, instance)
|
|
54
|
+
|
|
55
|
+
def as_dict(self, instance=None):
|
|
56
|
+
"""
|
|
57
|
+
Return ChangeContext attributes in dictionary format
|
|
58
|
+
"""
|
|
59
|
+
context = {
|
|
60
|
+
"user": self.get_user(instance),
|
|
61
|
+
"change_id": self.change_id,
|
|
62
|
+
"context": self.context,
|
|
63
|
+
}
|
|
64
|
+
return context
|
|
54
65
|
|
|
55
66
|
|
|
56
67
|
class JobChangeContext(ChangeContext):
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
from difflib import get_close_matches
|
|
2
|
+
|
|
1
3
|
from django.conf import settings
|
|
2
4
|
from django.contrib.auth import get_user_model
|
|
3
5
|
from django.contrib.contenttypes.models import ContentType
|
|
6
|
+
from django.db.models import Q
|
|
4
7
|
import django_filters
|
|
8
|
+
from drf_spectacular.utils import extend_schema_field
|
|
5
9
|
|
|
6
10
|
from nautobot.core.api.exceptions import SerializerNotFound
|
|
7
11
|
from nautobot.core.api.utils import get_serializer_for_model
|
|
@@ -447,7 +451,54 @@ class NautobotFilterSet(
|
|
|
447
451
|
#
|
|
448
452
|
|
|
449
453
|
|
|
450
|
-
class
|
|
454
|
+
class ContactTeamFilterSet(NameSearchFilterSet, NautobotFilterSet):
|
|
455
|
+
"""Base filter set for Contacts and Teams."""
|
|
456
|
+
|
|
457
|
+
similar_to_location_data = NaturalKeyOrPKMultipleChoiceFilter(
|
|
458
|
+
queryset=Location.objects.all(),
|
|
459
|
+
label="Similar to location contact data",
|
|
460
|
+
method="_similar_to_location_data",
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
def generate_query__similar_to_location_data(self, queryset, locations):
|
|
464
|
+
"""Helper method used by _similar_to_location_data() method."""
|
|
465
|
+
query_params = Q()
|
|
466
|
+
for location in locations:
|
|
467
|
+
contact_name = location.contact_name
|
|
468
|
+
contact_phone = location.contact_phone
|
|
469
|
+
contact_email = location.contact_email
|
|
470
|
+
if contact_name:
|
|
471
|
+
contact_names = list(queryset.order_by().values_list("name", flat=True).distinct())
|
|
472
|
+
name_matches = get_close_matches(contact_name, contact_names, cutoff=0.8)
|
|
473
|
+
if name_matches:
|
|
474
|
+
query_params |= Q(name__in=name_matches)
|
|
475
|
+
if contact_phone:
|
|
476
|
+
contact_phones = list(queryset.order_by().values_list("phone", flat=True).distinct())
|
|
477
|
+
phone_matches = get_close_matches(contact_phone, contact_phones, cutoff=0.8)
|
|
478
|
+
if phone_matches:
|
|
479
|
+
query_params |= Q(phone__in=phone_matches)
|
|
480
|
+
if contact_email:
|
|
481
|
+
contact_emails = list(queryset.order_by().values_list("email", flat=True).distinct())
|
|
482
|
+
# fuzzy matching for emails doesn't make sense, use case insensitive match here
|
|
483
|
+
email_matches = [e for e in contact_emails if e.casefold() == contact_email.casefold()]
|
|
484
|
+
if email_matches:
|
|
485
|
+
query_params |= Q(email__in=email_matches)
|
|
486
|
+
|
|
487
|
+
return query_params
|
|
488
|
+
|
|
489
|
+
@extend_schema_field({"type": "string"})
|
|
490
|
+
def _similar_to_location_data(self, queryset, name, value):
|
|
491
|
+
"""FilterSet method for getting Contacts or Teams that are similar to the explicit contact fields of a location"""
|
|
492
|
+
if value:
|
|
493
|
+
params = self.generate_query__similar_to_location_data(queryset, value)
|
|
494
|
+
if len(params) > 0:
|
|
495
|
+
return queryset.filter(params)
|
|
496
|
+
else:
|
|
497
|
+
return queryset.none()
|
|
498
|
+
return queryset
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
class ContactFilterSet(ContactTeamFilterSet):
|
|
451
502
|
class Meta:
|
|
452
503
|
model = Contact
|
|
453
504
|
fields = "__all__"
|
|
@@ -1109,7 +1160,7 @@ class TagFilterSet(NautobotFilterSet):
|
|
|
1109
1160
|
#
|
|
1110
1161
|
|
|
1111
1162
|
|
|
1112
|
-
class TeamFilterSet(
|
|
1163
|
+
class TeamFilterSet(ContactTeamFilterSet):
|
|
1113
1164
|
class Meta:
|
|
1114
1165
|
model = Team
|
|
1115
1166
|
fields = "__all__"
|
|
@@ -8,8 +8,9 @@ from nautobot.core.filters import (
|
|
|
8
8
|
MultiValueNumberFilter,
|
|
9
9
|
)
|
|
10
10
|
from nautobot.core.forms import NullableDateField
|
|
11
|
-
from nautobot.core.
|
|
11
|
+
from nautobot.core.utils.data import is_uuid
|
|
12
12
|
from nautobot.extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices
|
|
13
|
+
from nautobot.extras.models import CustomFieldChoice
|
|
13
14
|
|
|
14
15
|
EXACT_FILTER_TYPES = (
|
|
15
16
|
CustomFieldTypeChoices.TYPE_BOOLEAN,
|
|
@@ -71,19 +72,23 @@ class CustomFieldJSONFilter(CustomFieldFilterMixin, django_filters.Filter):
|
|
|
71
72
|
"""Custom field single value filter for backwards compatibility"""
|
|
72
73
|
|
|
73
74
|
|
|
74
|
-
class
|
|
75
|
-
"""
|
|
75
|
+
class CustomFieldSelectFilter(CustomFieldFilterMixin, MultiValueCharFilter):
|
|
76
|
+
"""Filter for custom fields of type TYPE_SELECT."""
|
|
76
77
|
|
|
77
|
-
def
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
def get_filter_predicate(self, v):
|
|
79
|
+
if is_uuid(v):
|
|
80
|
+
try:
|
|
81
|
+
v = self.custom_field.custom_field_choices.get(pk=v).value
|
|
82
|
+
except CustomFieldChoice.DoesNotExist:
|
|
83
|
+
v = ""
|
|
84
|
+
return super().get_filter_predicate(v)
|
|
80
85
|
|
|
81
86
|
|
|
82
|
-
class
|
|
83
|
-
"""
|
|
87
|
+
class CustomFieldMultiSelectFilter(CustomFieldSelectFilter):
|
|
88
|
+
"""Filter for custom fields of type TYPE_MULTISELECT."""
|
|
84
89
|
|
|
85
90
|
def __init__(self, *args, **kwargs):
|
|
86
|
-
|
|
91
|
+
kwargs.setdefault("lookup_expr", "contains")
|
|
87
92
|
super().__init__(*args, **kwargs)
|
|
88
93
|
|
|
89
94
|
|
|
@@ -27,6 +27,7 @@ from nautobot.extras.filters.customfields import (
|
|
|
27
27
|
CustomFieldMultiValueDateFilter,
|
|
28
28
|
CustomFieldMultiValueNumberFilter,
|
|
29
29
|
CustomFieldNumberFilter,
|
|
30
|
+
CustomFieldSelectFilter,
|
|
30
31
|
)
|
|
31
32
|
from nautobot.extras.models import (
|
|
32
33
|
ConfigContextSchema,
|
|
@@ -61,12 +62,16 @@ class CustomFieldModelFilterSetMixin(django_filters.FilterSet):
|
|
|
61
62
|
super().__init__(*args, **kwargs)
|
|
62
63
|
|
|
63
64
|
custom_field_filter_classes = {
|
|
65
|
+
# Here, for the "base" filters for each custom field, for backwards compatibility, use single-value filters.
|
|
66
|
+
# For the "extended" filters, see below, we use multi-value filters.
|
|
67
|
+
# 3.0 TODO: switch the "base" filters to multi-value filters as well.
|
|
64
68
|
CustomFieldTypeChoices.TYPE_DATE: CustomFieldDateFilter,
|
|
65
69
|
CustomFieldTypeChoices.TYPE_BOOLEAN: CustomFieldBooleanFilter,
|
|
66
70
|
CustomFieldTypeChoices.TYPE_INTEGER: CustomFieldNumberFilter,
|
|
67
71
|
CustomFieldTypeChoices.TYPE_JSON: CustomFieldJSONFilter,
|
|
72
|
+
# The below are multi-value filters already:
|
|
68
73
|
CustomFieldTypeChoices.TYPE_MULTISELECT: CustomFieldMultiSelectFilter,
|
|
69
|
-
CustomFieldTypeChoices.TYPE_SELECT:
|
|
74
|
+
CustomFieldTypeChoices.TYPE_SELECT: CustomFieldSelectFilter,
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
custom_fields = CustomField.objects.get_for_model(self._meta.model, exclude_filter_disabled=True)
|
|
@@ -28,6 +28,13 @@ class ContactForm(NautobotModelForm):
|
|
|
28
28
|
"tags",
|
|
29
29
|
]
|
|
30
30
|
|
|
31
|
+
def __init__(self, instance=None, initial=None, **kwargs):
|
|
32
|
+
if instance is not None:
|
|
33
|
+
if initial is None:
|
|
34
|
+
initial = {}
|
|
35
|
+
initial.setdefault("teams", instance.teams.all())
|
|
36
|
+
super().__init__(instance=instance, initial=initial, **kwargs)
|
|
37
|
+
|
|
31
38
|
def save(self, *args, **kwargs):
|
|
32
39
|
"""
|
|
33
40
|
Since `teams` field on Contact Model is the reverse side of an M2M,
|
nautobot/extras/health_checks.py
CHANGED
nautobot/extras/jobs.py
CHANGED
nautobot/extras/managers.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from celery import states
|
|
2
2
|
from django.utils import timezone
|
|
3
|
-
from django_celery_beat.managers import ExtendedManager
|
|
4
3
|
from django_celery_results.managers import TaskResultManager, transaction_retry
|
|
5
4
|
|
|
6
5
|
from nautobot.core.models import BaseManager
|
|
@@ -8,6 +7,20 @@ from nautobot.core.models.querysets import RestrictedQuerySet
|
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class JobResultManager(BaseManager.from_queryset(RestrictedQuerySet), TaskResultManager):
|
|
10
|
+
def get_task(self, task_id):
|
|
11
|
+
"""Get result for task by ``task_id``.
|
|
12
|
+
|
|
13
|
+
This overloads `TaskResultManager.get_task` provided by `django-celery-results` to manage custom
|
|
14
|
+
behaviors for integration with Nautobot.
|
|
15
|
+
"""
|
|
16
|
+
try:
|
|
17
|
+
return self.get(id=task_id)
|
|
18
|
+
except self.model.DoesNotExist:
|
|
19
|
+
if self._last_id == task_id:
|
|
20
|
+
self.warn_if_repeatable_read()
|
|
21
|
+
self._last_id = task_id
|
|
22
|
+
return self.model(id=task_id)
|
|
23
|
+
|
|
11
24
|
@transaction_retry(max_retries=2)
|
|
12
25
|
def store_result(
|
|
13
26
|
self,
|
|
@@ -122,5 +135,5 @@ class JobResultManager(BaseManager.from_queryset(RestrictedQuerySet), TaskResult
|
|
|
122
135
|
return obj
|
|
123
136
|
|
|
124
137
|
|
|
125
|
-
class ScheduledJobsManager(BaseManager.from_queryset(RestrictedQuerySet)
|
|
138
|
+
class ScheduledJobsManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
126
139
|
pass
|
|
@@ -724,7 +724,16 @@ class CustomField(BaseModel, ChangeLoggedModel, NotesMixin):
|
|
|
724
724
|
|
|
725
725
|
super().delete(*args, **kwargs)
|
|
726
726
|
|
|
727
|
-
|
|
727
|
+
# Circular Import
|
|
728
|
+
from nautobot.extras.signals import change_context_state
|
|
729
|
+
|
|
730
|
+
change_context = change_context_state.get()
|
|
731
|
+
if change_context is None:
|
|
732
|
+
context = None
|
|
733
|
+
else:
|
|
734
|
+
context = change_context.as_dict(instance=self)
|
|
735
|
+
context["context_detail"] = "delete custom field data"
|
|
736
|
+
delete_custom_field_data.delay(self.key, content_types, context)
|
|
728
737
|
|
|
729
738
|
def add_prefix_to_cf_key(self):
|
|
730
739
|
return "cf_" + str(self.key)
|
|
@@ -783,8 +792,22 @@ class CustomFieldChoice(BaseModel, ChangeLoggedModel):
|
|
|
783
792
|
super().save(*args, **kwargs)
|
|
784
793
|
|
|
785
794
|
if self.value != database_object.value:
|
|
795
|
+
# Circular Import
|
|
796
|
+
from nautobot.extras.signals import change_context_state
|
|
797
|
+
|
|
798
|
+
change_context = change_context_state.get()
|
|
799
|
+
if change_context is None:
|
|
800
|
+
context = None
|
|
801
|
+
else:
|
|
802
|
+
context = change_context.as_dict(instance=self)
|
|
803
|
+
context["context_detail"] = "update custom field choice data"
|
|
786
804
|
transaction.on_commit(
|
|
787
|
-
lambda: update_custom_field_choice_data.delay(
|
|
805
|
+
lambda: update_custom_field_choice_data.delay(
|
|
806
|
+
self.custom_field.pk,
|
|
807
|
+
database_object.value,
|
|
808
|
+
self.value,
|
|
809
|
+
context,
|
|
810
|
+
)
|
|
788
811
|
)
|
|
789
812
|
|
|
790
813
|
def delete(self, *args, **kwargs):
|