nautobot 2.4.0b1__py3-none-any.whl → 2.4.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/apps/__init__.py +1 -1
- nautobot/apps/api.py +8 -8
- nautobot/apps/change_logging.py +2 -2
- nautobot/apps/choices.py +4 -4
- nautobot/apps/events.py +3 -3
- nautobot/apps/factory.py +2 -2
- nautobot/apps/filters.py +1 -1
- nautobot/apps/forms.py +20 -20
- nautobot/apps/graphql.py +2 -2
- nautobot/apps/jobs.py +8 -8
- nautobot/apps/models.py +19 -19
- nautobot/apps/tables.py +1 -1
- nautobot/apps/testing.py +10 -10
- nautobot/apps/ui.py +2 -2
- nautobot/apps/utils.py +7 -7
- nautobot/apps/views.py +7 -7
- nautobot/circuits/api/serializers.py +1 -0
- nautobot/circuits/api/views.py +4 -8
- nautobot/circuits/tables.py +2 -1
- nautobot/circuits/templates/circuits/circuit_create.html +1 -7
- nautobot/circuits/views.py +3 -3
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/views.py +0 -16
- nautobot/core/api/constants.py +11 -0
- nautobot/core/api/fields.py +5 -5
- nautobot/core/api/filter_backends.py +3 -9
- nautobot/core/api/schema.py +13 -2
- nautobot/core/api/serializers.py +40 -34
- nautobot/core/api/views.py +56 -4
- nautobot/core/celery/log.py +4 -4
- nautobot/core/celery/schedulers.py +2 -2
- nautobot/core/choices.py +2 -2
- nautobot/core/events/__init__.py +3 -3
- nautobot/core/filters.py +67 -35
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +14 -11
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +28 -7
- nautobot/core/jobs/bulk_actions.py +285 -0
- nautobot/core/jobs/cleanup.py +48 -12
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/models/__init__.py +3 -1
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +6 -3
- nautobot/core/settings.py +29 -2
- nautobot/core/settings.yaml +21 -0
- nautobot/core/tables.py +79 -61
- nautobot/core/templates/about.html +67 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/inc/nav_menu.html +1 -0
- nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
- nautobot/core/templates/inc/tenant_table_row.html +11 -0
- nautobot/core/templates/nautobot_config.py.j2 +13 -0
- nautobot/core/templates/search.html +7 -0
- nautobot/core/templates/utilities/render_jinja2.html +1 -1
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +7 -0
- nautobot/core/templatetags/helpers.py +11 -2
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +170 -15
- nautobot/core/testing/filters.py +45 -10
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/integration.py +86 -4
- nautobot/core/testing/mixins.py +7 -2
- nautobot/core/testing/views.py +44 -29
- nautobot/core/tests/integration/test_app_home.py +0 -1
- nautobot/core/tests/integration/test_app_navbar.py +0 -1
- nautobot/core/tests/integration/test_filters.py +0 -2
- nautobot/core/tests/integration/test_home.py +0 -1
- nautobot/core/tests/integration/test_navbar.py +0 -1
- nautobot/core/tests/integration/test_view_authentication.py +1 -0
- nautobot/core/tests/runner.py +1 -1
- nautobot/core/tests/test_api.py +98 -1
- nautobot/core/tests/test_csv.py +25 -3
- nautobot/core/tests/test_filters.py +209 -246
- nautobot/core/tests/test_forms.py +1 -0
- nautobot/core/tests/test_jobs.py +460 -1
- nautobot/core/tests/test_models.py +9 -0
- nautobot/core/tests/test_settings_schema.py +7 -0
- nautobot/core/tests/test_tables.py +100 -0
- nautobot/core/tests/test_utils.py +63 -1
- nautobot/core/tests/test_views.py +30 -3
- nautobot/core/ui/nav.py +1 -0
- nautobot/core/ui/object_detail.py +15 -1
- nautobot/core/urls.py +11 -0
- nautobot/core/utils/lookup.py +11 -8
- nautobot/core/utils/querysets.py +64 -0
- nautobot/core/utils/requests.py +24 -9
- nautobot/core/views/__init__.py +42 -0
- nautobot/core/views/generic.py +131 -197
- nautobot/core/views/mixins.py +126 -38
- nautobot/core/views/renderers.py +6 -6
- nautobot/dcim/api/serializers.py +56 -64
- nautobot/dcim/api/views.py +47 -113
- nautobot/dcim/constants.py +6 -13
- nautobot/dcim/factory.py +6 -1
- nautobot/dcim/filters/__init__.py +31 -2
- nautobot/dcim/forms.py +36 -17
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
- nautobot/dcim/models/__init__.py +1 -1
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +22 -20
- nautobot/dcim/models/devices.py +10 -1
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +6 -5
- nautobot/dcim/models/racks.py +4 -4
- nautobot/dcim/tables/__init__.py +3 -3
- nautobot/dcim/tables/devices.py +7 -5
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +1 -7
- nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
- nautobot/dcim/templates/dcim/device.html +1 -9
- nautobot/dcim/templates/dcim/device_edit.html +36 -37
- nautobot/dcim/templates/dcim/location.html +1 -9
- nautobot/dcim/templates/dcim/location_edit.html +1 -7
- nautobot/dcim/templates/dcim/rack.html +1 -9
- nautobot/dcim/templates/dcim/rack_edit.html +1 -7
- nautobot/dcim/templates/dcim/rackreservation.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
- nautobot/dcim/tests/integration/test_controller.py +62 -0
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
- nautobot/dcim/tests/integration/test_device_bulk_delete.py +189 -0
- nautobot/dcim/tests/integration/test_device_bulk_edit.py +181 -0
- nautobot/dcim/tests/test_api.py +16 -5
- nautobot/dcim/tests/test_filters.py +33 -0
- nautobot/dcim/tests/test_forms.py +51 -2
- nautobot/dcim/tests/test_graphql.py +52 -0
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +52 -9
- nautobot/dcim/tests/test_views.py +21 -83
- nautobot/dcim/views.py +1 -13
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +90 -85
- nautobot/extras/api/views.py +22 -27
- nautobot/extras/constants.py +2 -0
- nautobot/extras/filters/__init__.py +8 -6
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +139 -31
- nautobot/extras/forms/mixins.py +14 -6
- nautobot/extras/group_sync.py +3 -3
- nautobot/extras/health_checks.py +1 -2
- nautobot/extras/jobs.py +85 -18
- nautobot/extras/managers.py +3 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
- nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
- nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
- nautobot/extras/models/__init__.py +1 -1
- nautobot/extras/models/contacts.py +1 -1
- nautobot/extras/models/customfields.py +12 -11
- nautobot/extras/models/groups.py +11 -9
- nautobot/extras/models/jobs.py +23 -4
- nautobot/extras/models/models.py +2 -2
- nautobot/extras/plugins/__init__.py +13 -2
- nautobot/extras/plugins/marketplace_manifest.yml +84 -79
- nautobot/extras/plugins/tables.py +16 -14
- nautobot/extras/plugins/views.py +65 -69
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/tables.py +7 -5
- nautobot/extras/templates/extras/dynamicgroup.html +1 -9
- nautobot/extras/templates/extras/job_detail.html +16 -0
- nautobot/extras/templates/extras/job_edit.html +1 -0
- nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
- nautobot/extras/templates/extras/marketplace.html +29 -11
- nautobot/extras/templates/extras/plugin_detail.html +32 -15
- nautobot/extras/templates/extras/plugins_tiles.html +21 -10
- nautobot/extras/templatetags/job_buttons.py +4 -4
- nautobot/extras/test_jobs/api_test_job.py +1 -1
- nautobot/extras/test_jobs/atomic_transaction.py +2 -2
- nautobot/extras/test_jobs/dry_run.py +1 -1
- nautobot/extras/test_jobs/fail.py +5 -5
- nautobot/extras/test_jobs/file_output.py +1 -1
- nautobot/extras/test_jobs/file_upload_fail.py +1 -1
- nautobot/extras/test_jobs/file_upload_pass.py +1 -1
- nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
- nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
- nautobot/extras/test_jobs/log_redaction.py +1 -1
- nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
- nautobot/extras/test_jobs/modify_db.py +1 -1
- nautobot/extras/test_jobs/object_var_optional.py +1 -1
- nautobot/extras/test_jobs/object_var_required.py +1 -1
- nautobot/extras/test_jobs/object_vars.py +1 -1
- nautobot/extras/test_jobs/pass.py +3 -3
- nautobot/extras/test_jobs/profiling.py +1 -1
- nautobot/extras/test_jobs/relative_import.py +3 -3
- nautobot/extras/test_jobs/singleton.py +16 -0
- nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
- nautobot/extras/test_jobs/task_queues.py +1 -1
- nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
- nautobot/extras/tests/test_api.py +13 -13
- nautobot/extras/tests/test_customfields.py +1 -1
- nautobot/extras/tests/test_datasources.py +2 -1
- nautobot/extras/tests/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/test_filters.py +6 -6
- nautobot/extras/tests/test_forms.py +33 -1
- nautobot/extras/tests/test_jobs.py +178 -32
- nautobot/extras/tests/test_models.py +16 -10
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +120 -9
- nautobot/extras/tests/test_views.py +56 -194
- nautobot/extras/utils.py +3 -2
- nautobot/extras/views.py +30 -98
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +41 -33
- nautobot/ipam/api/views.py +68 -117
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +3 -2
- nautobot/ipam/lookups.py +101 -62
- nautobot/ipam/models.py +66 -16
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +23 -7
- nautobot/ipam/templates/ipam/ipaddress.html +1 -9
- nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
- nautobot/ipam/templates/ipam/prefix.html +1 -9
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
- nautobot/ipam/templates/ipam/vlan.html +1 -9
- nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
- nautobot/ipam/tests/test_api.py +436 -3
- nautobot/ipam/tests/test_forms.py +49 -47
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +95 -34
- nautobot/ipam/tests/test_querysets.py +63 -1
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/utils/__init__.py +36 -6
- nautobot/ipam/views.py +61 -87
- 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.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
- 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/docs/404.html +46 -4
- nautobot/project-static/docs/apps/index.html +46 -4
- nautobot/project-static/docs/apps/nautobot-apps.html +47 -6
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +62 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +59 -7
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +374 -122
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +90 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +95 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +53 -6
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +52 -5
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +79 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +102 -28
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +108 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +131 -38
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +239 -65
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +581 -165
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +109 -36
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +453 -167
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +493 -211
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +60 -8
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +71 -15
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +407 -55
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +620 -205
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +858 -412
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +59 -7
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +448 -186
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +365 -147
- nautobot/project-static/docs/development/apps/api/configuration-view.html +46 -4
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/global-search.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/graphql.html +46 -4
- nautobot/project-static/docs/development/apps/api/models/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +46 -4
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +68 -7
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +46 -4
- nautobot/project-static/docs/development/apps/api/prometheus.html +46 -4
- nautobot/project-static/docs/development/apps/api/setup.html +46 -4
- nautobot/project-static/docs/development/apps/api/testing.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +46 -4
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/base-template.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/index.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/notes.html +46 -4
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +52 -6
- nautobot/project-static/docs/development/apps/api/views/urls.html +46 -4
- nautobot/project-static/docs/development/apps/index.html +46 -4
- nautobot/project-static/docs/development/apps/migration/code-updates.html +46 -4
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +46 -4
- nautobot/project-static/docs/development/apps/migration/from-v1.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +46 -4
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +46 -4
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +50 -8
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +46 -4
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +211 -14
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +46 -4
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +46 -4
- nautobot/project-static/docs/development/core/application-registry.html +46 -4
- nautobot/project-static/docs/development/core/best-practices.html +46 -4
- nautobot/project-static/docs/development/core/bootstrap-ui.html +46 -4
- nautobot/project-static/docs/development/core/caching.html +46 -4
- nautobot/project-static/docs/development/core/controllers.html +46 -4
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +73 -74
- nautobot/project-static/docs/development/core/generic-views.html +46 -4
- nautobot/project-static/docs/development/core/getting-started.html +249 -224
- nautobot/project-static/docs/development/core/homepage.html +49 -7
- nautobot/project-static/docs/development/core/index.html +46 -4
- nautobot/project-static/docs/development/core/{local-k8s.html → minikube-dev-environment-for-k8s-jobs.html} +469 -168
- nautobot/project-static/docs/development/core/model-checklist.html +56 -12
- nautobot/project-static/docs/development/core/model-features.html +46 -4
- nautobot/project-static/docs/development/core/natural-keys.html +46 -4
- nautobot/project-static/docs/development/core/navigation-menu.html +46 -4
- nautobot/project-static/docs/development/core/release-checklist.html +49 -7
- nautobot/project-static/docs/development/core/role-internals.html +46 -4
- nautobot/project-static/docs/development/core/settings.html +46 -4
- nautobot/project-static/docs/development/core/style-guide.html +49 -7
- nautobot/project-static/docs/development/core/templates.html +46 -4
- nautobot/project-static/docs/development/core/testing.html +46 -4
- nautobot/project-static/docs/development/core/ui-component-framework.html +369 -273
- nautobot/project-static/docs/development/core/user-preferences.html +46 -4
- nautobot/project-static/docs/development/index.html +46 -4
- nautobot/project-static/docs/development/jobs/index.html +216 -122
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +46 -4
- nautobot/project-static/docs/index.html +54 -23
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +47 -7
- nautobot/project-static/docs/overview/design_philosophy.html +46 -4
- nautobot/project-static/docs/release-notes/index.html +52 -12
- nautobot/project-static/docs/release-notes/version-1.0.html +234 -193
- nautobot/project-static/docs/release-notes/version-1.1.html +231 -190
- nautobot/project-static/docs/release-notes/version-1.2.html +306 -265
- nautobot/project-static/docs/release-notes/version-1.3.html +332 -291
- nautobot/project-static/docs/release-notes/version-1.4.html +417 -377
- nautobot/project-static/docs/release-notes/version-1.5.html +605 -566
- nautobot/project-static/docs/release-notes/version-1.6.html +904 -447
- nautobot/project-static/docs/release-notes/version-2.0.html +528 -489
- nautobot/project-static/docs/release-notes/version-2.1.html +363 -324
- nautobot/project-static/docs/release-notes/version-2.2.html +356 -317
- nautobot/project-static/docs/release-notes/version-2.3.html +997 -352
- nautobot/project-static/docs/release-notes/version-2.4.html +525 -101
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +295 -287
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +48 -6
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +46 -4
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +110 -8
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +46 -4
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -6
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +66 -8
- nautobot/project-static/docs/user-guide/administration/installation/index.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +47 -5
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +46 -4
- nautobot/project-static/docs/user-guide/administration/installation/services.html +46 -4
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +46 -4
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +46 -4
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +46 -4
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +49 -8
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +46 -4
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +50 -12
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +49 -7
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +46 -4
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +51 -7
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +46 -4
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +49 -7
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
- nautobot/project-static/docs/user-guide/index.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +50 -8
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +50 -7
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +49 -7
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +47 -5
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +94 -25
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +74 -5
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +46 -4
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +46 -4
- nautobot/project-static/js/forms.js +1 -1
- nautobot/tenancy/api/views.py +9 -13
- nautobot/tenancy/views.py +4 -2
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +5 -4
- nautobot/users/api/views.py +3 -3
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/api/views.py +5 -24
- nautobot/virtualization/filters.py +20 -3
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
- nautobot/virtualization/tests/test_filters.py +17 -0
- nautobot/wireless/filters.py +2 -2
- nautobot/wireless/forms.py +1 -1
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
- nautobot/wireless/tests/test_filters.py +29 -1
- nautobot/wireless/tests/test_views.py +22 -1
- nautobot/wireless/views.py +0 -10
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/METADATA +6 -6
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/RECORD +600 -550
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/WHEEL +1 -1
- nautobot/core/fixtures/user-data.json +0 -59
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/NOTICE +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/entry_points.txt +0 -0
|
@@ -116,6 +116,7 @@ from nautobot.extras.models import (
|
|
|
116
116
|
CustomField,
|
|
117
117
|
CustomFieldChoice,
|
|
118
118
|
ExternalIntegration,
|
|
119
|
+
JobResult,
|
|
119
120
|
Relationship,
|
|
120
121
|
RelationshipAssociation,
|
|
121
122
|
Role,
|
|
@@ -128,6 +129,7 @@ from nautobot.ipam.choices import IPAddressTypeChoices
|
|
|
128
129
|
from nautobot.ipam.models import IPAddress, Namespace, Prefix, VLAN, VLANGroup, VRF
|
|
129
130
|
from nautobot.tenancy.models import Tenant
|
|
130
131
|
from nautobot.users.models import ObjectPermission
|
|
132
|
+
from nautobot.virtualization.models import Cluster, ClusterType
|
|
131
133
|
|
|
132
134
|
# Use the proper swappable User model
|
|
133
135
|
User = get_user_model()
|
|
@@ -1150,9 +1152,15 @@ module-bays:
|
|
|
1150
1152
|
}
|
|
1151
1153
|
|
|
1152
1154
|
response = self.client.post(url, data)
|
|
1155
|
+
job_result = JobResult.objects.filter(name="Bulk Edit Objects").first()
|
|
1156
|
+
# Assert successfull redirect to Job Results; whcih means no form validation error was raised
|
|
1157
|
+
self.assertRedirects(
|
|
1158
|
+
response,
|
|
1159
|
+
reverse("extras:jobresult", args=[job_result.pk]),
|
|
1160
|
+
status_code=302,
|
|
1161
|
+
target_status_code=200,
|
|
1162
|
+
)
|
|
1153
1163
|
self.assertHttpStatus(response, 302)
|
|
1154
|
-
for instance in self._get_queryset().filter(pk__in=pk_list):
|
|
1155
|
-
self.assertEqual(instance.u_height, data["u_height"])
|
|
1156
1164
|
|
|
1157
1165
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
1158
1166
|
def test_rack_height_bulk_edit_invalid(self):
|
|
@@ -1168,7 +1176,12 @@ module-bays:
|
|
|
1168
1176
|
}
|
|
1169
1177
|
|
|
1170
1178
|
response = self.client.post(url, data)
|
|
1171
|
-
|
|
1179
|
+
response_content = response.content.decode(response.charset)
|
|
1180
|
+
self.assertHttpStatus(response, 200)
|
|
1181
|
+
self.assertInHTML(
|
|
1182
|
+
'<strong class="panel-title">U height</strong>: <ul class="errorlist"><li>Ensure this value is greater than or equal to 0.</li></ul>',
|
|
1183
|
+
response_content,
|
|
1184
|
+
)
|
|
1172
1185
|
|
|
1173
1186
|
|
|
1174
1187
|
class ModuleTypeTestCase(
|
|
@@ -2045,6 +2058,9 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
2045
2058
|
|
|
2046
2059
|
rack_group = RackGroup.objects.create(location=locations[0], name="Rack Group 1")
|
|
2047
2060
|
|
|
2061
|
+
cluster_type = ClusterType.objects.create(name="Cluster Type 1")
|
|
2062
|
+
cluster = Cluster.objects.create(name="Cluster 1", cluster_type=cluster_type)
|
|
2063
|
+
|
|
2048
2064
|
rack_status = Status.objects.get_for_model(Rack).first()
|
|
2049
2065
|
racks = (
|
|
2050
2066
|
Rack.objects.create(
|
|
@@ -2216,6 +2232,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
2216
2232
|
"status": statuses[2].pk,
|
|
2217
2233
|
"location": locations[1].pk,
|
|
2218
2234
|
"rack": racks[1].pk,
|
|
2235
|
+
"cluster": cluster.pk,
|
|
2236
|
+
"comments": "An older device",
|
|
2219
2237
|
"position": None,
|
|
2220
2238
|
"face": DeviceFaceChoices.FACE_FRONT,
|
|
2221
2239
|
"secrets_group": secrets_groups[1].pk,
|
|
@@ -4574,46 +4592,6 @@ class SoftwareImageFileTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
4574
4592
|
"download_url": "https://example.com/software_image_file_test_case.bin",
|
|
4575
4593
|
}
|
|
4576
4594
|
|
|
4577
|
-
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
4578
|
-
def test_correct_handling_for_model_protected_error(self):
|
|
4579
|
-
platform = Platform.objects.first()
|
|
4580
|
-
software_version_status = Status.objects.get_for_model(SoftwareVersion).first()
|
|
4581
|
-
software_image_file_status = Status.objects.get_for_model(SoftwareImageFile).first()
|
|
4582
|
-
software_version = SoftwareVersion.objects.create(
|
|
4583
|
-
platform=platform, version="Test version 1.0.0", status=software_version_status
|
|
4584
|
-
)
|
|
4585
|
-
software_image_file = SoftwareImageFile.objects.create(
|
|
4586
|
-
software_version=software_version,
|
|
4587
|
-
image_file_name="software_image_file_qs_test_1.bin",
|
|
4588
|
-
status=software_image_file_status,
|
|
4589
|
-
)
|
|
4590
|
-
device_type = DeviceType.objects.first()
|
|
4591
|
-
device_role = Role.objects.get_for_model(Device).first()
|
|
4592
|
-
device_status = Status.objects.get_for_model(Device).first()
|
|
4593
|
-
location = Location.objects.filter(location_type__name="Campus").first()
|
|
4594
|
-
Device.objects.create(
|
|
4595
|
-
device_type=device_type,
|
|
4596
|
-
role=device_role,
|
|
4597
|
-
name="Device 1",
|
|
4598
|
-
location=location,
|
|
4599
|
-
status=device_status,
|
|
4600
|
-
software_version=software_version,
|
|
4601
|
-
)
|
|
4602
|
-
device_type_to_software_image_file = DeviceTypeToSoftwareImageFile.objects.create(
|
|
4603
|
-
device_type=device_type, software_image_file=software_image_file
|
|
4604
|
-
)
|
|
4605
|
-
|
|
4606
|
-
self.add_permissions("dcim.delete_softwareimagefile")
|
|
4607
|
-
pk_list = [software_image_file.pk]
|
|
4608
|
-
data = {
|
|
4609
|
-
"pk": pk_list,
|
|
4610
|
-
"confirm": True,
|
|
4611
|
-
"_confirm": True, # Form button
|
|
4612
|
-
}
|
|
4613
|
-
response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
|
|
4614
|
-
# Assert protected error message included in the response body
|
|
4615
|
-
self.assertBodyContains(response, f"<span>{device_type_to_software_image_file}</span>", html=True)
|
|
4616
|
-
|
|
4617
4595
|
|
|
4618
4596
|
class SoftwareVersionTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
4619
4597
|
model = SoftwareVersion
|
|
@@ -4652,46 +4630,6 @@ class SoftwareVersionTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
4652
4630
|
"pre_release": True,
|
|
4653
4631
|
}
|
|
4654
4632
|
|
|
4655
|
-
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
4656
|
-
def test_correct_handling_for_model_protected_error(self):
|
|
4657
|
-
platform = Platform.objects.first()
|
|
4658
|
-
software_version_status = Status.objects.get_for_model(SoftwareVersion).first()
|
|
4659
|
-
software_image_file_status = Status.objects.get_for_model(SoftwareImageFile).first()
|
|
4660
|
-
software_version = SoftwareVersion.objects.create(
|
|
4661
|
-
platform=platform, version="Test version 1.0.0", status=software_version_status
|
|
4662
|
-
)
|
|
4663
|
-
software_image_file = SoftwareImageFile.objects.create(
|
|
4664
|
-
software_version=software_version,
|
|
4665
|
-
image_file_name="software_image_file_qs_test_1.bin",
|
|
4666
|
-
status=software_image_file_status,
|
|
4667
|
-
)
|
|
4668
|
-
device_type = DeviceType.objects.first()
|
|
4669
|
-
device_role = Role.objects.get_for_model(Device).first()
|
|
4670
|
-
device_status = Status.objects.get_for_model(Device).first()
|
|
4671
|
-
location = Location.objects.filter(location_type__name="Campus").first()
|
|
4672
|
-
Device.objects.create(
|
|
4673
|
-
device_type=device_type,
|
|
4674
|
-
role=device_role,
|
|
4675
|
-
name="Device 1",
|
|
4676
|
-
location=location,
|
|
4677
|
-
status=device_status,
|
|
4678
|
-
software_version=software_version,
|
|
4679
|
-
)
|
|
4680
|
-
device_type_to_software_image_file = DeviceTypeToSoftwareImageFile.objects.create(
|
|
4681
|
-
device_type=device_type, software_image_file=software_image_file
|
|
4682
|
-
)
|
|
4683
|
-
|
|
4684
|
-
self.add_permissions("dcim.delete_softwareversion")
|
|
4685
|
-
pk_list = [software_version.pk]
|
|
4686
|
-
data = {
|
|
4687
|
-
"pk": pk_list,
|
|
4688
|
-
"confirm": True,
|
|
4689
|
-
"_confirm": True, # Form button
|
|
4690
|
-
}
|
|
4691
|
-
response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
|
|
4692
|
-
# Assert protected error message included in the response body
|
|
4693
|
-
self.assertBodyContains(response, f"<span>{device_type_to_software_image_file}</span>", html=True)
|
|
4694
|
-
|
|
4695
4633
|
|
|
4696
4634
|
class ControllerTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
4697
4635
|
model = Controller
|
nautobot/dcim/views.py
CHANGED
|
@@ -697,7 +697,7 @@ class RackReservationEditView(generic.ObjectEditView):
|
|
|
697
697
|
model_form = forms.RackReservationForm
|
|
698
698
|
template_name = "dcim/rackreservation_edit.html"
|
|
699
699
|
|
|
700
|
-
def alter_obj(self, obj, request,
|
|
700
|
+
def alter_obj(self, obj, request, url_args, url_kwargs):
|
|
701
701
|
if not obj.present_in_database:
|
|
702
702
|
if "rack" in request.GET:
|
|
703
703
|
obj.rack = get_object_or_404(Rack, pk=request.GET.get("rack"))
|
|
@@ -4502,12 +4502,6 @@ class ControllerManagedDeviceGroupUIViewSet(NautobotUIViewSet):
|
|
|
4502
4502
|
|
|
4503
4503
|
return obj
|
|
4504
4504
|
|
|
4505
|
-
def extra_post_save_action(self, obj, form):
|
|
4506
|
-
if form.cleaned_data.get("add_radio_profiles", None):
|
|
4507
|
-
obj.radio_profiles.add(*form.cleaned_data["add_radio_profiles"])
|
|
4508
|
-
if form.cleaned_data.get("remove_radio_profiles", None):
|
|
4509
|
-
obj.radio_profiles.remove(*form.cleaned_data["remove_radio_profiles"])
|
|
4510
|
-
|
|
4511
4505
|
|
|
4512
4506
|
#
|
|
4513
4507
|
# Virtual Device Context
|
|
@@ -4534,9 +4528,3 @@ class VirtualDeviceContextUIViewSet(NautobotUIViewSet):
|
|
|
4534
4528
|
**super().get_extra_context(request, instance),
|
|
4535
4529
|
}
|
|
4536
4530
|
return super().get_extra_context(request, instance)
|
|
4537
|
-
|
|
4538
|
-
def extra_post_save_action(self, obj, form):
|
|
4539
|
-
if form.cleaned_data.get("add_interfaces", None):
|
|
4540
|
-
obj.prefixes.add(*form.cleaned_data["add_interfaces"])
|
|
4541
|
-
if form.cleaned_data.get("remove_interfaces", None):
|
|
4542
|
-
obj.prefixes.remove(*form.cleaned_data["remove_interfaces"])
|
|
@@ -42,8 +42,8 @@ class CustomFieldsDataField(Field):
|
|
|
42
42
|
def custom_field_keys(self):
|
|
43
43
|
return CustomField.objects.keys_for_model(self.parent.Meta.model)
|
|
44
44
|
|
|
45
|
-
def to_representation(self,
|
|
46
|
-
return {key:
|
|
45
|
+
def to_representation(self, value):
|
|
46
|
+
return {key: value.get(key) for key in self.custom_field_keys}
|
|
47
47
|
|
|
48
48
|
def to_internal_value(self, data):
|
|
49
49
|
"""Support updates to individual fields on an existing instance without needing to provide the entire dict."""
|
|
@@ -19,7 +19,6 @@ from nautobot.core.api import (
|
|
|
19
19
|
ValidatedModelSerializer,
|
|
20
20
|
)
|
|
21
21
|
from nautobot.core.api.exceptions import SerializerNotFound
|
|
22
|
-
from nautobot.core.api.fields import NautobotHyperlinkedRelatedField
|
|
23
22
|
from nautobot.core.api.serializers import PolymorphicProxySerializer
|
|
24
23
|
from nautobot.core.api.utils import (
|
|
25
24
|
get_nested_serializer_depth,
|
|
@@ -136,12 +135,12 @@ class ConfigContextSerializer(ValidatedModelSerializer, TaggedModelSerializerMix
|
|
|
136
135
|
owner = serializers.SerializerMethodField(read_only=True)
|
|
137
136
|
|
|
138
137
|
# Conditional enablement of dynamic groups filtering
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
@property
|
|
139
|
+
def fields(self):
|
|
140
|
+
fields = super().fields
|
|
142
141
|
if not settings.CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED:
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
fields.pop("dynamic_groups", None)
|
|
143
|
+
return fields
|
|
145
144
|
|
|
146
145
|
class Meta:
|
|
147
146
|
model = ConfigContext
|
|
@@ -200,10 +199,7 @@ class ConfigContextSchemaSerializer(NautobotModelSerializer):
|
|
|
200
199
|
#
|
|
201
200
|
|
|
202
201
|
|
|
203
|
-
class ContactSerializer(NautobotModelSerializer):
|
|
204
|
-
# needed since this is the reverse side of the M2M field.
|
|
205
|
-
teams = NautobotHyperlinkedRelatedField(queryset=Team.objects.all(), many=True, required=False)
|
|
206
|
-
|
|
202
|
+
class ContactSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
|
|
207
203
|
class Meta:
|
|
208
204
|
model = Contact
|
|
209
205
|
fields = "__all__"
|
|
@@ -212,15 +208,22 @@ class ContactSerializer(NautobotModelSerializer):
|
|
|
212
208
|
extra_kwargs = {
|
|
213
209
|
"email": {"default": ""},
|
|
214
210
|
"phone": {"default": ""},
|
|
211
|
+
"teams": {"required": False},
|
|
215
212
|
}
|
|
216
213
|
|
|
217
|
-
def
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
def get_field_names(self, declared_fields, info):
|
|
215
|
+
"""Add reverse M2M for teams to the fields for this serializer."""
|
|
216
|
+
field_names = list(super().get_field_names(declared_fields, info))
|
|
217
|
+
self.extend_field_names(field_names, "teams")
|
|
218
|
+
return field_names
|
|
219
|
+
|
|
220
|
+
def validate(self, attrs):
|
|
221
|
+
local_attrs = attrs.copy()
|
|
222
|
+
local_attrs.pop("teams", None)
|
|
220
223
|
validator = UniqueTogetherValidator(queryset=Contact.objects.all(), fields=("name", "phone", "email"))
|
|
221
|
-
validator(
|
|
222
|
-
super().validate(
|
|
223
|
-
return
|
|
224
|
+
validator(local_attrs, self)
|
|
225
|
+
super().validate(local_attrs)
|
|
226
|
+
return attrs
|
|
224
227
|
|
|
225
228
|
|
|
226
229
|
class ContactAssociationSerializer(NautobotModelSerializer):
|
|
@@ -235,18 +238,18 @@ class ContactAssociationSerializer(NautobotModelSerializer):
|
|
|
235
238
|
"team": {"required": False},
|
|
236
239
|
}
|
|
237
240
|
|
|
238
|
-
def validate(self,
|
|
241
|
+
def validate(self, attrs):
|
|
239
242
|
# Validate uniqueness of (associated object, associated object type, contact/team, role)
|
|
240
243
|
unique_together_fields = None
|
|
241
244
|
|
|
242
|
-
if
|
|
245
|
+
if attrs.get("contact") and attrs.get("role"):
|
|
243
246
|
unique_together_fields = (
|
|
244
247
|
"associated_object_type",
|
|
245
248
|
"associated_object_id",
|
|
246
249
|
"contact",
|
|
247
250
|
"role",
|
|
248
251
|
)
|
|
249
|
-
elif
|
|
252
|
+
elif attrs.get("team") and attrs.get("role"):
|
|
250
253
|
unique_together_fields = (
|
|
251
254
|
"associated_object_type",
|
|
252
255
|
"associated_object_id",
|
|
@@ -259,11 +262,11 @@ class ContactAssociationSerializer(NautobotModelSerializer):
|
|
|
259
262
|
queryset=ContactAssociation.objects.all(),
|
|
260
263
|
fields=unique_together_fields,
|
|
261
264
|
)
|
|
262
|
-
validator(
|
|
265
|
+
validator(attrs, self)
|
|
263
266
|
|
|
264
|
-
super().validate(
|
|
267
|
+
super().validate(attrs)
|
|
265
268
|
|
|
266
|
-
return
|
|
269
|
+
return attrs
|
|
267
270
|
|
|
268
271
|
|
|
269
272
|
#
|
|
@@ -272,6 +275,7 @@ class ContactAssociationSerializer(NautobotModelSerializer):
|
|
|
272
275
|
|
|
273
276
|
|
|
274
277
|
class ContentTypeSerializer(BaseModelSerializer):
|
|
278
|
+
id = serializers.IntegerField(read_only=True)
|
|
275
279
|
url = serializers.HyperlinkedIdentityField(view_name="extras-api:contenttype-detail")
|
|
276
280
|
display = serializers.SerializerMethodField()
|
|
277
281
|
|
|
@@ -280,8 +284,8 @@ class ContentTypeSerializer(BaseModelSerializer):
|
|
|
280
284
|
fields = "__all__"
|
|
281
285
|
|
|
282
286
|
@extend_schema_field(serializers.CharField)
|
|
283
|
-
def get_display(self,
|
|
284
|
-
return
|
|
287
|
+
def get_display(self, instance):
|
|
288
|
+
return instance.app_labeled_name
|
|
285
289
|
|
|
286
290
|
|
|
287
291
|
#
|
|
@@ -433,7 +437,7 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
|
|
|
433
437
|
#
|
|
434
438
|
|
|
435
439
|
|
|
436
|
-
class ExternalIntegrationSerializer(NautobotModelSerializer):
|
|
440
|
+
class ExternalIntegrationSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
|
|
437
441
|
class Meta:
|
|
438
442
|
model = ExternalIntegration
|
|
439
443
|
fields = "__all__"
|
|
@@ -455,7 +459,7 @@ class FileProxySerializer(BaseModelSerializer):
|
|
|
455
459
|
#
|
|
456
460
|
|
|
457
461
|
|
|
458
|
-
class GitRepositorySerializer(NautobotModelSerializer):
|
|
462
|
+
class GitRepositorySerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
|
|
459
463
|
"""Git repositories defined as a data source."""
|
|
460
464
|
|
|
461
465
|
provided_contents = MultipleChoiceJSONField(
|
|
@@ -502,17 +506,17 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
|
|
|
502
506
|
model = ImageAttachment
|
|
503
507
|
fields = "__all__"
|
|
504
508
|
|
|
505
|
-
def validate(self,
|
|
509
|
+
def validate(self, attrs):
|
|
506
510
|
# Validate that the parent object exists
|
|
507
511
|
try:
|
|
508
|
-
|
|
512
|
+
attrs["content_type"].get_object_for_this_type(id=attrs["object_id"])
|
|
509
513
|
except ObjectDoesNotExist:
|
|
510
|
-
raise serializers.ValidationError(f"Invalid parent object: {
|
|
514
|
+
raise serializers.ValidationError(f"Invalid parent object: {attrs['content_type']} ID {attrs['object_id']}")
|
|
511
515
|
|
|
512
516
|
# Enforce model validation
|
|
513
|
-
super().validate(
|
|
517
|
+
super().validate(attrs)
|
|
514
518
|
|
|
515
|
-
return
|
|
519
|
+
return attrs
|
|
516
520
|
|
|
517
521
|
@extend_schema_field(
|
|
518
522
|
PolymorphicProxySerializer(
|
|
@@ -544,24 +548,24 @@ class JobSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
|
544
548
|
model = Job
|
|
545
549
|
fields = "__all__"
|
|
546
550
|
|
|
547
|
-
def validate(self,
|
|
551
|
+
def validate(self, attrs):
|
|
548
552
|
# note no validation for on creation of jobs because we do not support user creation of Job records via API
|
|
549
553
|
if self.instance:
|
|
550
|
-
has_sensitive_variables =
|
|
551
|
-
approval_required =
|
|
554
|
+
has_sensitive_variables = attrs.get("has_sensitive_variables", self.instance.has_sensitive_variables)
|
|
555
|
+
approval_required = attrs.get("approval_required", self.instance.approval_required)
|
|
552
556
|
|
|
553
557
|
if approval_required and has_sensitive_variables:
|
|
554
558
|
error_message = "A job with sensitive variables cannot also be marked as requiring approval"
|
|
555
559
|
errors = {}
|
|
556
560
|
|
|
557
|
-
if "approval_required" in
|
|
561
|
+
if "approval_required" in attrs:
|
|
558
562
|
errors["approval_required"] = [error_message]
|
|
559
|
-
if "has_sensitive_variables" in
|
|
563
|
+
if "has_sensitive_variables" in attrs:
|
|
560
564
|
errors["has_sensitive_variables"] = [error_message]
|
|
561
565
|
|
|
562
566
|
raise serializers.ValidationError(errors)
|
|
563
567
|
|
|
564
|
-
return super().validate(
|
|
568
|
+
return super().validate(attrs)
|
|
565
569
|
|
|
566
570
|
|
|
567
571
|
class JobQueueSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
@@ -687,22 +691,22 @@ class JobHookSerializer(NautobotModelSerializer):
|
|
|
687
691
|
model = JobHook
|
|
688
692
|
fields = "__all__"
|
|
689
693
|
|
|
690
|
-
def validate(self,
|
|
691
|
-
|
|
694
|
+
def validate(self, attrs):
|
|
695
|
+
validated_attrs = super().validate(attrs)
|
|
692
696
|
|
|
693
697
|
conflicts = JobHook.check_for_conflicts(
|
|
694
698
|
instance=self.instance,
|
|
695
|
-
content_types=
|
|
696
|
-
job=
|
|
697
|
-
type_create=
|
|
698
|
-
type_update=
|
|
699
|
-
type_delete=
|
|
699
|
+
content_types=attrs.get("content_types"),
|
|
700
|
+
job=attrs.get("job"),
|
|
701
|
+
type_create=attrs.get("type_create"),
|
|
702
|
+
type_update=attrs.get("type_update"),
|
|
703
|
+
type_delete=attrs.get("type_delete"),
|
|
700
704
|
)
|
|
701
705
|
|
|
702
706
|
if conflicts:
|
|
703
707
|
raise serializers.ValidationError(conflicts)
|
|
704
708
|
|
|
705
|
-
return
|
|
709
|
+
return validated_attrs
|
|
706
710
|
|
|
707
711
|
|
|
708
712
|
class JobCreationSerializer(BaseModelSerializer):
|
|
@@ -721,15 +725,15 @@ class JobCreationSerializer(BaseModelSerializer):
|
|
|
721
725
|
model = ScheduledJob
|
|
722
726
|
fields = ["url", "name", "start_time", "interval", "crontab"]
|
|
723
727
|
|
|
724
|
-
def validate(self,
|
|
725
|
-
|
|
728
|
+
def validate(self, attrs):
|
|
729
|
+
attrs = super().validate(attrs)
|
|
726
730
|
|
|
727
|
-
if
|
|
728
|
-
if "name" not in
|
|
731
|
+
if attrs["interval"] in choices.JobExecutionType.SCHEDULE_CHOICES:
|
|
732
|
+
if "name" not in attrs:
|
|
729
733
|
raise serializers.ValidationError({"name": "Please provide a name for the job schedule."})
|
|
730
734
|
|
|
731
|
-
if ("start_time" not in
|
|
732
|
-
"start_time" in
|
|
735
|
+
if ("start_time" not in attrs and attrs["interval"] != choices.JobExecutionType.TYPE_CUSTOM) or (
|
|
736
|
+
"start_time" in attrs and attrs["start_time"] < models.ScheduledJob.earliest_possible_time()
|
|
733
737
|
):
|
|
734
738
|
raise serializers.ValidationError(
|
|
735
739
|
{
|
|
@@ -737,15 +741,15 @@ class JobCreationSerializer(BaseModelSerializer):
|
|
|
737
741
|
}
|
|
738
742
|
)
|
|
739
743
|
|
|
740
|
-
if
|
|
741
|
-
if
|
|
744
|
+
if attrs["interval"] == choices.JobExecutionType.TYPE_CUSTOM:
|
|
745
|
+
if attrs.get("crontab") is None:
|
|
742
746
|
raise serializers.ValidationError({"crontab": "Please enter a valid crontab."})
|
|
743
747
|
try:
|
|
744
|
-
models.ScheduledJob.get_crontab(
|
|
748
|
+
models.ScheduledJob.get_crontab(attrs["crontab"])
|
|
745
749
|
except Exception as e:
|
|
746
750
|
raise serializers.ValidationError({"crontab": e})
|
|
747
751
|
|
|
748
|
-
return
|
|
752
|
+
return attrs
|
|
749
753
|
|
|
750
754
|
|
|
751
755
|
class JobInputSerializer(serializers.Serializer):
|
|
@@ -765,15 +769,18 @@ class JobMultiPartInputSerializer(serializers.Serializer):
|
|
|
765
769
|
_task_queue = serializers.CharField(required=False, allow_blank=True)
|
|
766
770
|
_job_queue = serializers.CharField(required=False, allow_blank=True)
|
|
767
771
|
|
|
768
|
-
def validate(self,
|
|
769
|
-
|
|
772
|
+
def validate(self, attrs):
|
|
773
|
+
attrs = super().validate(attrs)
|
|
770
774
|
|
|
771
|
-
if "_schedule_interval" in
|
|
772
|
-
if "_schedule_name" not in
|
|
775
|
+
if "_schedule_interval" in attrs and attrs["_schedule_interval"] != JobExecutionType.TYPE_IMMEDIATELY:
|
|
776
|
+
if "_schedule_name" not in attrs:
|
|
773
777
|
raise serializers.ValidationError({"_schedule_name": "Please provide a name for the job schedule."})
|
|
774
778
|
|
|
775
|
-
if (
|
|
776
|
-
"_schedule_start_time" in
|
|
779
|
+
if (
|
|
780
|
+
"_schedule_start_time" not in attrs and attrs["_schedule_interval"] != JobExecutionType.TYPE_CUSTOM
|
|
781
|
+
) or (
|
|
782
|
+
"_schedule_start_time" in attrs
|
|
783
|
+
and attrs["_schedule_start_time"] < ScheduledJob.earliest_possible_time()
|
|
777
784
|
):
|
|
778
785
|
raise serializers.ValidationError(
|
|
779
786
|
{
|
|
@@ -781,15 +788,15 @@ class JobMultiPartInputSerializer(serializers.Serializer):
|
|
|
781
788
|
}
|
|
782
789
|
)
|
|
783
790
|
|
|
784
|
-
if
|
|
785
|
-
if
|
|
791
|
+
if attrs["_schedule_interval"] == JobExecutionType.TYPE_CUSTOM:
|
|
792
|
+
if attrs.get("_schedule_crontab") is None:
|
|
786
793
|
raise serializers.ValidationError({"_schedule_crontab": "Please enter a valid crontab."})
|
|
787
794
|
try:
|
|
788
|
-
ScheduledJob.get_crontab(
|
|
795
|
+
ScheduledJob.get_crontab(attrs["_schedule_crontab"])
|
|
789
796
|
except Exception as e:
|
|
790
797
|
raise serializers.ValidationError({"_schedule_crontab": e})
|
|
791
798
|
|
|
792
|
-
return
|
|
799
|
+
return attrs
|
|
793
800
|
|
|
794
801
|
|
|
795
802
|
class JobLogEntrySerializer(BaseModelSerializer):
|
|
@@ -816,7 +823,7 @@ class JobButtonSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
816
823
|
#
|
|
817
824
|
|
|
818
825
|
|
|
819
|
-
class MetadataTypeSerializer(NautobotModelSerializer):
|
|
826
|
+
class MetadataTypeSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
|
|
820
827
|
content_types = ContentTypeField(
|
|
821
828
|
queryset=ContentType.objects.filter(FeatureQuery("metadata").get_query()),
|
|
822
829
|
many=True,
|
|
@@ -1073,18 +1080,18 @@ class TagSerializer(NautobotModelSerializer):
|
|
|
1073
1080
|
"color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
|
|
1074
1081
|
}
|
|
1075
1082
|
|
|
1076
|
-
def validate(self,
|
|
1077
|
-
|
|
1083
|
+
def validate(self, attrs):
|
|
1084
|
+
attrs = super().validate(attrs)
|
|
1078
1085
|
|
|
1079
1086
|
# check if tag is assigned to any of the removed content_types
|
|
1080
|
-
if self.instance is not None and self.instance.present_in_database and "content_types" in
|
|
1081
|
-
content_types_id = [content_type.id for content_type in
|
|
1087
|
+
if self.instance is not None and self.instance.present_in_database and "content_types" in attrs:
|
|
1088
|
+
content_types_id = [content_type.id for content_type in attrs["content_types"]]
|
|
1082
1089
|
errors = self.instance.validate_content_types_removal(content_types_id)
|
|
1083
1090
|
|
|
1084
1091
|
if errors:
|
|
1085
1092
|
raise serializers.ValidationError(errors)
|
|
1086
1093
|
|
|
1087
|
-
return
|
|
1094
|
+
return attrs
|
|
1088
1095
|
|
|
1089
1096
|
|
|
1090
1097
|
#
|
|
@@ -1092,9 +1099,7 @@ class TagSerializer(NautobotModelSerializer):
|
|
|
1092
1099
|
#
|
|
1093
1100
|
|
|
1094
1101
|
|
|
1095
|
-
class TeamSerializer(NautobotModelSerializer):
|
|
1096
|
-
contacts = NautobotHyperlinkedRelatedField(queryset=Contact.objects.all(), many=True, required=False)
|
|
1097
|
-
|
|
1102
|
+
class TeamSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
|
|
1098
1103
|
class Meta:
|
|
1099
1104
|
model = Team
|
|
1100
1105
|
fields = "__all__"
|
|
@@ -1106,10 +1111,10 @@ class TeamSerializer(NautobotModelSerializer):
|
|
|
1106
1111
|
# https://www.django-rest-framework.org/api-guide/validators/#optional-fields
|
|
1107
1112
|
validators = []
|
|
1108
1113
|
|
|
1109
|
-
def validate(self,
|
|
1114
|
+
def validate(self, attrs):
|
|
1110
1115
|
validator = UniqueTogetherValidator(queryset=Team.objects.all(), fields=("name", "phone", "email"))
|
|
1111
|
-
validator(
|
|
1112
|
-
return super().validate(
|
|
1116
|
+
validator(attrs, self)
|
|
1117
|
+
return super().validate(attrs)
|
|
1113
1118
|
|
|
1114
1119
|
|
|
1115
1120
|
#
|
|
@@ -1127,19 +1132,19 @@ class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
1127
1132
|
model = Webhook
|
|
1128
1133
|
fields = "__all__"
|
|
1129
1134
|
|
|
1130
|
-
def validate(self,
|
|
1131
|
-
|
|
1135
|
+
def validate(self, attrs):
|
|
1136
|
+
validated_attrs = super().validate(attrs)
|
|
1132
1137
|
|
|
1133
1138
|
conflicts = Webhook.check_for_conflicts(
|
|
1134
1139
|
instance=self.instance,
|
|
1135
|
-
content_types=
|
|
1136
|
-
payload_url=
|
|
1137
|
-
type_create=
|
|
1138
|
-
type_update=
|
|
1139
|
-
type_delete=
|
|
1140
|
+
content_types=attrs.get("content_types"),
|
|
1141
|
+
payload_url=attrs.get("payload_url"),
|
|
1142
|
+
type_create=attrs.get("type_create"),
|
|
1143
|
+
type_update=attrs.get("type_update"),
|
|
1144
|
+
type_delete=attrs.get("type_delete"),
|
|
1140
1145
|
)
|
|
1141
1146
|
|
|
1142
1147
|
if conflicts:
|
|
1143
1148
|
raise serializers.ValidationError(conflicts)
|
|
1144
1149
|
|
|
1145
|
-
return
|
|
1150
|
+
return validated_attrs
|