nautobot 2.3.15b1__py3-none-any.whl → 2.4.0__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 +15 -0
- nautobot/apps/__init__.py +1 -1
- nautobot/apps/api.py +8 -10
- nautobot/apps/change_logging.py +2 -2
- nautobot/apps/choices.py +4 -4
- nautobot/apps/config.py +32 -3
- nautobot/apps/events.py +19 -0
- nautobot/apps/exceptions.py +0 -2
- 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 +44 -9
- nautobot/apps/utils.py +7 -15
- nautobot/apps/views.py +8 -6
- nautobot/circuits/api/serializers.py +1 -0
- nautobot/circuits/api/views.py +4 -8
- nautobot/circuits/navigation.py +0 -57
- nautobot/circuits/templates/circuits/circuit_create.html +1 -7
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
- nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
- nautobot/circuits/tests/integration/test_relationships.py +33 -24
- nautobot/circuits/tests/test_filters.py +4 -8
- nautobot/circuits/views.py +143 -26
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/factory.py +4 -1
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/tests/test_filters.py +5 -4
- 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/metadata.py +28 -256
- nautobot/core/api/pagination.py +3 -2
- nautobot/core/api/renderers.py +3 -0
- nautobot/core/api/schema.py +13 -2
- nautobot/core/api/serializers.py +54 -268
- nautobot/core/api/urls.py +3 -4
- nautobot/core/api/utils.py +0 -62
- nautobot/core/api/views.py +102 -159
- nautobot/core/apps/__init__.py +22 -575
- nautobot/core/celery/__init__.py +13 -0
- nautobot/core/celery/schedulers.py +48 -3
- nautobot/core/choices.py +2 -2
- nautobot/core/cli/__init__.py +8 -0
- nautobot/core/constants.py +7 -0
- nautobot/core/events/__init__.py +116 -0
- nautobot/core/events/base.py +27 -0
- nautobot/core/events/exceptions.py +10 -0
- nautobot/core/events/redis_broker.py +48 -0
- nautobot/core/events/syslog_broker.py +19 -0
- nautobot/core/exceptions.py +0 -6
- nautobot/core/filters.py +19 -16
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +62 -14
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/forms/utils.py +2 -1
- nautobot/core/graphql/schema.py +3 -1
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +28 -7
- nautobot/core/jobs/bulk_actions.py +248 -0
- nautobot/core/jobs/cleanup.py +2 -2
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +21 -0
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/middleware.py +16 -0
- nautobot/core/models/__init__.py +1 -1
- nautobot/core/models/fields.py +11 -7
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +2 -2
- nautobot/core/settings.py +71 -4
- nautobot/core/settings.yaml +107 -0
- nautobot/core/tables.py +15 -51
- nautobot/core/tasks.py +1 -1
- nautobot/core/templates/about.html +67 -0
- nautobot/core/templates/components/button/default.html +7 -0
- nautobot/core/templates/components/button/dropdown.html +20 -0
- nautobot/core/templates/components/layout/one_over_two.html +19 -0
- nautobot/core/templates/components/layout/two_over_one.html +19 -0
- nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
- nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
- nautobot/core/templates/components/panel/body_content_tags.html +6 -0
- nautobot/core/templates/components/panel/body_content_text.html +12 -0
- nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
- nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
- nautobot/core/templates/components/panel/footer_content_table.html +14 -0
- nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
- nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
- nautobot/core/templates/components/panel/panel.html +16 -0
- nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
- nautobot/core/templates/components/tab/content_wrapper.html +3 -0
- nautobot/core/templates/components/tab/label_wrapper.html +5 -0
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
- nautobot/core/templates/generic/object_retrieve.html +28 -17
- nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/custom_fields/panel.html +2 -2
- nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/inc/nav_menu.html +2 -1
- nautobot/core/templates/inc/relationships_panel.html +1 -1
- 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 +16 -0
- nautobot/core/templates/panel_table.html +12 -0
- nautobot/core/templates/utilities/render_jinja2.html +117 -0
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +7 -0
- nautobot/core/templatetags/helpers.py +104 -6
- nautobot/core/templatetags/ui_framework.py +40 -0
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +187 -137
- nautobot/core/testing/context.py +18 -0
- nautobot/core/testing/filters.py +44 -34
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/views.py +68 -146
- 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 +2 -1
- nautobot/core/tests/nautobot_config.py +198 -0
- nautobot/core/tests/runner.py +3 -3
- nautobot/core/tests/test_api.py +154 -176
- nautobot/core/tests/test_events.py +214 -0
- nautobot/core/tests/test_forms.py +1 -0
- nautobot/core/tests/test_jinja_filters.py +1 -0
- nautobot/core/tests/test_jobs.py +387 -14
- nautobot/core/tests/test_navigations.py +7 -241
- nautobot/core/tests/test_settings_schema.py +7 -0
- nautobot/core/tests/test_tables.py +100 -0
- nautobot/core/tests/test_templatetags_helpers.py +16 -0
- nautobot/core/tests/test_ui.py +150 -0
- nautobot/core/tests/test_utils.py +55 -18
- nautobot/core/tests/test_views.py +153 -5
- nautobot/core/ui/__init__.py +0 -0
- nautobot/core/ui/base.py +11 -0
- nautobot/core/ui/choices.py +44 -0
- nautobot/core/ui/homepage.py +167 -0
- nautobot/core/ui/nav.py +280 -0
- nautobot/core/ui/object_detail.py +1855 -0
- nautobot/core/ui/utils.py +36 -0
- nautobot/core/urls.py +15 -0
- nautobot/core/utils/config.py +30 -3
- nautobot/core/utils/lookup.py +12 -2
- nautobot/core/utils/querysets.py +64 -0
- nautobot/core/utils/requests.py +24 -9
- nautobot/core/views/__init__.py +48 -1
- nautobot/core/views/generic.py +82 -177
- nautobot/core/views/mixins.py +98 -38
- nautobot/core/views/paginator.py +8 -5
- nautobot/core/views/renderers.py +9 -9
- nautobot/core/views/utils.py +11 -0
- nautobot/core/wsgi.py +3 -3
- nautobot/dcim/api/serializers.py +82 -189
- nautobot/dcim/api/urls.py +5 -0
- nautobot/dcim/api/views.py +57 -110
- nautobot/dcim/apps.py +1 -0
- nautobot/dcim/choices.py +28 -0
- nautobot/dcim/factory.py +58 -0
- nautobot/dcim/filters/__init__.py +204 -2
- nautobot/dcim/forms.py +221 -9
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
- nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
- nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
- nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
- nautobot/dcim/models/__init__.py +5 -1
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +22 -20
- nautobot/dcim/models/devices.py +181 -3
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +6 -5
- nautobot/dcim/models/racks.py +6 -6
- nautobot/dcim/navigation.py +25 -224
- nautobot/dcim/signals.py +44 -0
- nautobot/dcim/tables/__init__.py +5 -3
- nautobot/dcim/tables/devices.py +103 -7
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/controller/base.html +10 -0
- nautobot/dcim/templates/dcim/controller_create.html +2 -7
- nautobot/dcim/templates/dcim/controller_retrieve.html +6 -10
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +51 -0
- nautobot/dcim/templates/dcim/device/base.html +6 -42
- nautobot/dcim/templates/dcim/device/wireless.html +73 -0
- nautobot/dcim/templates/dcim/device.html +4 -10
- nautobot/dcim/templates/dcim/device_edit.html +36 -37
- nautobot/dcim/templates/dcim/interface.html +1 -0
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/location.html +1 -9
- nautobot/dcim/templates/dcim/location_edit.html +1 -7
- nautobot/dcim/templates/dcim/locationtype.html +0 -107
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
- 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 +68 -0
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +28 -0
- nautobot/dcim/tests/integration/test_controller.py +62 -0
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
- nautobot/dcim/tests/test_api.py +188 -64
- nautobot/dcim/tests/test_filters.py +172 -76
- nautobot/dcim/tests/test_graphql.py +52 -0
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +159 -5
- nautobot/dcim/tests/test_signals.py +1 -0
- nautobot/dcim/tests/test_views.py +118 -88
- nautobot/dcim/urls.py +72 -27
- nautobot/dcim/utils.py +2 -2
- nautobot/dcim/views.py +357 -62
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +111 -87
- nautobot/extras/api/urls.py +4 -0
- nautobot/extras/api/views.py +93 -35
- nautobot/extras/choices.py +13 -0
- nautobot/extras/constants.py +2 -1
- nautobot/extras/context_managers.py +23 -6
- nautobot/extras/datasources/git.py +4 -1
- nautobot/extras/factory.py +27 -0
- nautobot/extras/filters/__init__.py +66 -5
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +262 -59
- nautobot/extras/forms/mixins.py +3 -3
- nautobot/extras/graphql/types.py +25 -1
- nautobot/extras/health_checks.py +1 -2
- nautobot/extras/jobs.py +114 -20
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/runjob.py +7 -79
- nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
- nautobot/extras/management/utils.py +87 -0
- nautobot/extras/managers.py +3 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
- nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
- nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
- nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
- 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 +5 -1
- nautobot/extras/models/change_logging.py +7 -3
- 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 +237 -37
- nautobot/extras/models/models.py +2 -2
- nautobot/extras/models/relationships.py +69 -1
- nautobot/extras/models/secrets.py +5 -0
- nautobot/extras/navigation.py +20 -262
- nautobot/extras/plugins/__init__.py +54 -19
- nautobot/extras/plugins/marketplace_manifest.yml +455 -0
- nautobot/extras/plugins/tables.py +16 -14
- nautobot/extras/plugins/urls.py +1 -0
- nautobot/extras/plugins/views.py +104 -61
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/signals.py +39 -1
- nautobot/extras/tables.py +42 -6
- nautobot/extras/templates/extras/dynamicgroup.html +1 -9
- nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
- nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
- nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
- nautobot/extras/templates/extras/job_detail.html +52 -6
- nautobot/extras/templates/extras/job_edit.html +6 -2
- nautobot/extras/templates/extras/job_list.html +2 -7
- nautobot/extras/templates/extras/jobqueue_retrieve.html +36 -0
- nautobot/extras/templates/extras/marketplace.html +296 -0
- nautobot/extras/templates/extras/plugin_detail.html +32 -15
- nautobot/extras/templates/extras/plugins_list.html +35 -1
- nautobot/extras/templates/extras/plugins_tiles.html +90 -0
- nautobot/extras/templates/extras/role_retrieve.html +16 -0
- nautobot/extras/templates/extras/secret.html +0 -65
- nautobot/extras/templates/extras/secret_check.js +16 -0
- nautobot/extras/templates/extras/secret_create.html +114 -0
- nautobot/extras/templates/extras/secret_edit.html +1 -114
- nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
- nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
- nautobot/extras/templatetags/job_buttons.py +5 -4
- nautobot/extras/templatetags/plugins.py +69 -6
- 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 +157 -55
- nautobot/extras/tests/test_context_managers.py +4 -1
- 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 +219 -535
- nautobot/extras/tests/test_forms.py +20 -1
- nautobot/extras/tests/test_job_variables.py +73 -152
- nautobot/extras/tests/test_jobs.py +192 -62
- nautobot/extras/tests/test_models.py +71 -16
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +124 -10
- nautobot/extras/tests/test_utils.py +23 -2
- nautobot/extras/tests/test_views.py +162 -161
- nautobot/extras/tests/test_webhooks.py +2 -1
- nautobot/extras/urls.py +2 -20
- nautobot/extras/utils.py +119 -4
- nautobot/extras/views.py +188 -141
- nautobot/extras/webhooks.py +5 -2
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +44 -137
- nautobot/ipam/api/views.py +68 -110
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +3 -2
- nautobot/ipam/models.py +10 -12
- nautobot/ipam/navigation.py +0 -90
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +3 -1
- 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/routetarget.html +0 -28
- nautobot/ipam/templates/ipam/vlan.html +1 -9
- nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
- nautobot/ipam/templates/ipam/vrf.html +0 -47
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
- nautobot/ipam/tests/test_api.py +19 -6
- nautobot/ipam/tests/test_filters.py +39 -119
- nautobot/ipam/tests/test_forms.py +49 -47
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +56 -36
- nautobot/ipam/tests/test_querysets.py +14 -0
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/urls.py +3 -69
- nautobot/ipam/utils/__init__.py +16 -10
- nautobot/ipam/views.py +91 -162
- 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/css/base.css +38 -3
- nautobot/project-static/docs/404.html +463 -19
- nautobot/project-static/docs/apps/index.html +463 -19
- nautobot/project-static/docs/apps/nautobot-apps.html +464 -21
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/extra.css +5 -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 +479 -25
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +476 -22
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +792 -291
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +507 -33
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +512 -36
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +473 -22
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +469 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +499 -35
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9883 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +525 -77
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +548 -53
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +672 -96
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1033 -180
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +526 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +876 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +957 -237
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +477 -23
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +488 -30
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +663 -101
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +949 -481
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6427 -1236
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +476 -22
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +879 -346
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +830 -173
- nautobot/project-static/docs/development/apps/api/configuration-view.html +463 -19
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/global-search.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/graphql.html +463 -19
- nautobot/project-static/docs/development/apps/api/models/index.html +463 -19
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +463 -19
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +463 -19
- nautobot/project-static/docs/development/apps/api/prometheus.html +463 -19
- nautobot/project-static/docs/development/apps/api/setup.html +467 -155
- nautobot/project-static/docs/development/apps/api/testing.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +463 -19
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +743 -130
- nautobot/project-static/docs/development/apps/api/views/base-template.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/index.html +465 -20
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +467 -19
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +493 -19
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/notes.html +463 -19
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +469 -21
- nautobot/project-static/docs/development/apps/api/views/urls.html +463 -19
- nautobot/project-static/docs/development/apps/index.html +463 -19
- nautobot/project-static/docs/development/apps/migration/code-updates.html +464 -52
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +464 -20
- nautobot/project-static/docs/development/apps/migration/from-v1.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +463 -19
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +466 -22
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9261 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9375 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9671 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9559 -0
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +466 -22
- nautobot/project-static/docs/development/core/application-registry.html +463 -19
- nautobot/project-static/docs/development/core/best-practices.html +463 -19
- nautobot/project-static/docs/development/core/bootstrap-ui.html +463 -19
- nautobot/project-static/docs/development/core/caching.html +463 -19
- nautobot/project-static/docs/development/core/controllers.html +465 -19
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +491 -90
- nautobot/project-static/docs/development/core/generic-views.html +463 -19
- nautobot/project-static/docs/development/core/getting-started.html +541 -129
- nautobot/project-static/docs/development/core/homepage.html +474 -30
- nautobot/project-static/docs/development/core/index.html +463 -19
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9754 -0
- nautobot/project-static/docs/development/core/model-checklist.html +473 -27
- nautobot/project-static/docs/development/core/model-features.html +463 -19
- nautobot/project-static/docs/development/core/natural-keys.html +463 -19
- nautobot/project-static/docs/development/core/navigation-menu.html +480 -26
- nautobot/project-static/docs/development/core/release-checklist.html +480 -48
- nautobot/project-static/docs/development/core/role-internals.html +463 -19
- nautobot/project-static/docs/development/core/settings.html +463 -19
- nautobot/project-static/docs/development/core/style-guide.html +466 -22
- nautobot/project-static/docs/development/core/templates.html +473 -22
- nautobot/project-static/docs/development/core/testing.html +463 -19
- nautobot/project-static/docs/development/core/ui-component-framework.html +11116 -0
- nautobot/project-static/docs/development/core/user-preferences.html +466 -22
- nautobot/project-static/docs/development/index.html +463 -19
- nautobot/project-static/docs/development/jobs/index.html +501 -21
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +463 -19
- nautobot/project-static/docs/index.html +471 -38
- 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/basic-panel-layout.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.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/dropdown-button-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-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/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
- nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
- nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
- nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
- nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
- nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +469 -23
- nautobot/project-static/docs/overview/design_philosophy.html +463 -19
- nautobot/project-static/docs/release-notes/index.html +485 -22
- nautobot/project-static/docs/release-notes/version-1.0.html +651 -208
- nautobot/project-static/docs/release-notes/version-1.1.html +648 -205
- nautobot/project-static/docs/release-notes/version-1.2.html +723 -280
- nautobot/project-static/docs/release-notes/version-1.3.html +749 -306
- nautobot/project-static/docs/release-notes/version-1.4.html +834 -392
- nautobot/project-static/docs/release-notes/version-1.5.html +1022 -581
- nautobot/project-static/docs/release-notes/version-1.6.html +942 -518
- nautobot/project-static/docs/release-notes/version-2.0.html +945 -504
- nautobot/project-static/docs/release-notes/version-2.1.html +780 -339
- nautobot/project-static/docs/release-notes/version-2.2.html +773 -332
- nautobot/project-static/docs/release-notes/version-2.3.html +1142 -448
- nautobot/project-static/docs/release-notes/version-2.4.html +10323 -0
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +342 -270
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +475 -32
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +463 -19
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +894 -180
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +476 -29
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +465 -21
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +483 -23
- nautobot/project-static/docs/user-guide/administration/installation/index.html +468 -20
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +464 -20
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +463 -19
- nautobot/project-static/docs/user-guide/administration/installation/services.html +463 -19
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +463 -19
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +484 -41
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +477 -66
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +477 -66
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +466 -23
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +463 -19
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +469 -21
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +499 -20
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +489 -22
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9375 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +470 -30
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +466 -22
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +463 -19
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +466 -22
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9313 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9217 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9211 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9277 -0
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +468 -22
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +463 -19
- 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 +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +463 -19
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +466 -22
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
- nautobot/project-static/docs/user-guide/index.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +467 -23
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +9617 -0
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +472 -23
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9224 -0
- 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 +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +467 -23
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9292 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +511 -40
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +494 -23
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +466 -22
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +531 -56
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +463 -19
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +463 -19
- nautobot/project-static/img/jinja_logo.svg +97 -0
- nautobot/project-static/js/forms.js +6 -1
- nautobot/project-static/js/nav_menu.js +2 -1
- nautobot/tenancy/api/serializers.py +0 -2
- nautobot/tenancy/api/views.py +9 -13
- nautobot/tenancy/factory.py +1 -1
- nautobot/tenancy/navigation.py +0 -29
- nautobot/tenancy/templates/tenancy/tenant.html +4 -91
- nautobot/tenancy/tests/test_filters.py +29 -134
- nautobot/tenancy/views.py +35 -24
- nautobot/users/admin.py +3 -1
- nautobot/users/api/serializers.py +4 -4
- nautobot/users/api/views.py +3 -3
- nautobot/users/forms.py +19 -0
- nautobot/users/templates/users/preferences.html +22 -0
- nautobot/users/tests/test_filters.py +1 -19
- nautobot/users/tests/test_views.py +57 -0
- nautobot/users/utils.py +8 -0
- nautobot/users/views.py +48 -11
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/api/views.py +5 -24
- nautobot/virtualization/filters.py +1 -2
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/navigation.py +0 -48
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
- nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
- nautobot/virtualization/tests/test_filters.py +57 -166
- nautobot/virtualization/views.py +18 -15
- nautobot/wireless/__init__.py +0 -0
- nautobot/wireless/api/__init__.py +0 -0
- nautobot/wireless/api/serializers.py +44 -0
- nautobot/wireless/api/urls.py +20 -0
- nautobot/wireless/api/views.py +34 -0
- nautobot/wireless/apps.py +8 -0
- nautobot/wireless/choices.py +345 -0
- nautobot/wireless/factory.py +138 -0
- nautobot/wireless/filters.py +167 -0
- nautobot/wireless/forms.py +283 -0
- nautobot/wireless/homepage.py +19 -0
- nautobot/wireless/migrations/0001_initial.py +223 -0
- nautobot/wireless/migrations/__init__.py +0 -0
- nautobot/wireless/models.py +207 -0
- nautobot/wireless/navigation.py +105 -0
- nautobot/wireless/tables.py +244 -0
- nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
- nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +56 -0
- nautobot/wireless/tests/__init__.py +0 -0
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
- nautobot/wireless/tests/test_api.py +247 -0
- nautobot/wireless/tests/test_filters.py +82 -0
- nautobot/wireless/tests/test_models.py +22 -0
- nautobot/wireless/tests/test_views.py +378 -0
- nautobot/wireless/urls.py +13 -0
- nautobot/wireless/views.py +119 -0
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/METADATA +11 -13
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/RECORD +783 -613
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/WHEEL +1 -1
- nautobot/core/fixtures/user-data.json +0 -59
- nautobot/core/utils/navigation.py +0 -54
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/NOTICE +0 -0
- {nautobot-2.3.15b1.dist-info → nautobot-2.4.0.dist-info}/entry_points.txt +0 -0
nautobot/core/testing/filters.py
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import random
|
|
2
2
|
import string
|
|
3
|
+
from typing import ClassVar, Iterable
|
|
3
4
|
|
|
4
5
|
from django.contrib.contenttypes.models import ContentType
|
|
5
|
-
from django.db.models import Count, Q
|
|
6
|
+
from django.db.models import Count, Q, QuerySet
|
|
6
7
|
from django.db.models.fields import CharField, TextField
|
|
7
8
|
from django.db.models.fields.related import ManyToManyField
|
|
8
9
|
from django.db.models.fields.reverse_related import ManyToManyRel, ManyToOneRel
|
|
9
10
|
from django.test import tag
|
|
11
|
+
from django_filters import FilterSet
|
|
10
12
|
|
|
11
13
|
from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
12
14
|
from nautobot.core.filters import (
|
|
@@ -18,6 +20,7 @@ from nautobot.core.filters import (
|
|
|
18
20
|
)
|
|
19
21
|
from nautobot.core.models.generics import PrimaryModel
|
|
20
22
|
from nautobot.core.testing import views
|
|
23
|
+
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
21
24
|
from nautobot.extras.models import Contact, ContactAssociation, Role, Status, Tag, Team
|
|
22
25
|
from nautobot.tenancy import models
|
|
23
26
|
|
|
@@ -27,6 +30,8 @@ class FilterTestCases:
|
|
|
27
30
|
class BaseFilterTestCase(views.TestCase):
|
|
28
31
|
"""Base class for testing of FilterSets."""
|
|
29
32
|
|
|
33
|
+
queryset: ClassVar[QuerySet]
|
|
34
|
+
|
|
30
35
|
def get_filterset_test_values(self, field_name, queryset=None):
|
|
31
36
|
"""Returns a list of distinct values from the requested queryset field to use in filterset tests.
|
|
32
37
|
|
|
@@ -68,8 +73,7 @@ class FilterTestCases:
|
|
|
68
73
|
class FilterTestCase(BaseFilterTestCase):
|
|
69
74
|
"""Add common tests for all FilterSets."""
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
filterset = None
|
|
76
|
+
filterset: ClassVar[type[FilterSet]]
|
|
73
77
|
|
|
74
78
|
# filter predicate fields that should be excluded from q test case
|
|
75
79
|
exclude_q_filter_predicates = []
|
|
@@ -81,7 +85,13 @@ class FilterTestCases:
|
|
|
81
85
|
# ["filter1"],
|
|
82
86
|
# ["filter2", "field2__name"],
|
|
83
87
|
# ]
|
|
84
|
-
generic_filter_tests
|
|
88
|
+
generic_filter_tests: ClassVar[Iterable]
|
|
89
|
+
|
|
90
|
+
def setUp(self):
|
|
91
|
+
for attr in ["queryset", "filterset", "generic_filter_tests"]:
|
|
92
|
+
if not hasattr(self, attr):
|
|
93
|
+
raise NotImplementedError(f'{self} is missing a value for required attribute "{attr}"')
|
|
94
|
+
super().setUp()
|
|
85
95
|
|
|
86
96
|
def get_q_filter(self):
|
|
87
97
|
"""Helper method to return q filter."""
|
|
@@ -137,15 +147,22 @@ class FilterTestCases:
|
|
|
137
147
|
)
|
|
138
148
|
This expects a field named `devices` on the model and a filter named `devices` on the filterset.
|
|
139
149
|
"""
|
|
150
|
+
if not any(test[0] == "id" for test in self.generic_filter_tests):
|
|
151
|
+
self.generic_filter_tests = (["id"], *self.generic_filter_tests)
|
|
152
|
+
|
|
140
153
|
if getattr(self.queryset.model, "is_contact_associable_model", False):
|
|
141
|
-
for
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
if not any(test[0] == "contacts" for test in self.generic_filter_tests):
|
|
155
|
+
self.generic_filter_tests = (
|
|
156
|
+
*self.generic_filter_tests,
|
|
157
|
+
["contacts", "associated_contacts__contact__name"],
|
|
158
|
+
["contacts", "associated_contacts__contact__id"],
|
|
159
|
+
)
|
|
160
|
+
if not any(test[0] == "teams" for test in self.generic_filter_tests):
|
|
161
|
+
self.generic_filter_tests = (
|
|
162
|
+
*self.generic_filter_tests,
|
|
163
|
+
["teams", "associated_contacts__team__name"],
|
|
164
|
+
["teams", "associated_contacts__team__id"],
|
|
165
|
+
)
|
|
149
166
|
|
|
150
167
|
# Make sure we have at least 3 contacts and 3 teams in the database
|
|
151
168
|
if Contact.objects.count() < 3:
|
|
@@ -173,9 +190,6 @@ class FilterTestCases:
|
|
|
173
190
|
status=Status.objects.get_for_model(ContactAssociation).last(),
|
|
174
191
|
)
|
|
175
192
|
|
|
176
|
-
if not self.generic_filter_tests:
|
|
177
|
-
self.skipTest("No generic_filter_tests defined?")
|
|
178
|
-
|
|
179
193
|
for test in self.generic_filter_tests:
|
|
180
194
|
filter_name = test[0]
|
|
181
195
|
field_name = test[-1] # default to filter_name if a second list item was not supplied
|
|
@@ -234,10 +248,6 @@ class FilterTestCases:
|
|
|
234
248
|
qs_result = self.queryset.filter(tags=tags[0]).filter(tags=tags[1]).distinct()
|
|
235
249
|
self.assertQuerysetEqualAndNotEmpty(filterset_result, qs_result)
|
|
236
250
|
|
|
237
|
-
def test_q_filter_exists(self):
|
|
238
|
-
"""Test the `q` filter exists on a filterset, does not validate the filter works as expected."""
|
|
239
|
-
self.assertIn("q", self.filterset.declared_filters)
|
|
240
|
-
|
|
241
251
|
def _assert_valid_filter_predicates(self, obj, field_name):
|
|
242
252
|
self.assertTrue(
|
|
243
253
|
hasattr(obj, field_name),
|
|
@@ -373,27 +383,27 @@ class FilterTestCases:
|
|
|
373
383
|
filter_field, (ContentTypeFilter, ContentTypeMultipleChoiceFilter, ContentTypeChoiceFilter)
|
|
374
384
|
)
|
|
375
385
|
|
|
386
|
+
# Test cases should just explicitly include `name` as a generic_filter_tests entry
|
|
387
|
+
@class_deprecated_in_favor_of(FilterTestCase) # pylint: disable=undefined-variable
|
|
376
388
|
class NameOnlyFilterTestCase(FilterTestCase):
|
|
377
389
|
"""Add simple tests for filtering by name."""
|
|
378
390
|
|
|
379
|
-
def
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
self.assertTrue(filterset.is_valid())
|
|
384
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
385
|
-
filterset.qs.order_by("name"), self.queryset.filter(name__in=params["name"]).order_by("name")
|
|
386
|
-
)
|
|
391
|
+
def test_filters_generic(self):
|
|
392
|
+
if not any(test[0] == "name" for test in self.generic_filter_tests):
|
|
393
|
+
self.generic_filter_tests = (["name"], *self.generic_filter_tests)
|
|
394
|
+
super().test_filters_generic()
|
|
387
395
|
|
|
388
|
-
|
|
396
|
+
# Test cases should just explicitly include `name` and `slug` as generic_filter_tests entries
|
|
397
|
+
@class_deprecated_in_favor_of(FilterTestCase) # pylint: disable=undefined-variable
|
|
398
|
+
class NameSlugFilterTestCase(FilterTestCase):
|
|
389
399
|
"""Add simple tests for filtering by name and by slug."""
|
|
390
400
|
|
|
391
|
-
def
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
401
|
+
def test_filters_generic(self):
|
|
402
|
+
if not any(test[0] == "slug" for test in self.generic_filter_tests):
|
|
403
|
+
self.generic_filter_tests = (["slug"], *self.generic_filter_tests)
|
|
404
|
+
if not any(test[0] == "name" for test in self.generic_filter_tests):
|
|
405
|
+
self.generic_filter_tests = (["name"], *self.generic_filter_tests)
|
|
406
|
+
super().test_filters_generic()
|
|
397
407
|
|
|
398
408
|
class TenancyFilterTestCaseMixin(views.TestCase):
|
|
399
409
|
"""Add test cases for tenant and tenant-group filters."""
|
nautobot/core/testing/forms.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from django.test import tag, TestCase
|
|
2
2
|
|
|
3
|
+
from nautobot.core.api.constants import NON_FILTER_QUERY_PARAMS
|
|
3
4
|
from nautobot.core.forms.fields import DynamicModelChoiceMixin
|
|
4
5
|
from nautobot.core.utils.lookup import get_filterset_for_model
|
|
5
6
|
|
|
@@ -18,6 +19,7 @@ class FormTestCases:
|
|
|
18
19
|
continue
|
|
19
20
|
with self.subTest(f"Assert {self.form_class.__name__}.{field_name} query_params are valid."):
|
|
20
21
|
query_params_fields = set(field_class.query_params.keys())
|
|
22
|
+
query_params_fields = query_params_fields - set(NON_FILTER_QUERY_PARAMS)
|
|
21
23
|
if not query_params_fields:
|
|
22
24
|
self.skipTest(f"{self.form_class.__name__}.{field_name} has no query_params")
|
|
23
25
|
field_model = field_class.queryset.model
|
nautobot/core/testing/views.py
CHANGED
|
@@ -21,17 +21,19 @@ from nautobot.core.models.tree_queries import TreeModel
|
|
|
21
21
|
from nautobot.core.templatetags import helpers
|
|
22
22
|
from nautobot.core.testing import mixins, utils
|
|
23
23
|
from nautobot.core.utils import lookup
|
|
24
|
+
from nautobot.dcim.models.device_components import ComponentModel
|
|
24
25
|
from nautobot.extras import choices as extras_choices, models as extras_models, querysets as extras_querysets
|
|
25
26
|
from nautobot.extras.forms import CustomFieldModelFormMixin, RelationshipModelFormMixin
|
|
26
27
|
from nautobot.extras.models import CustomFieldModel, RelationshipModel
|
|
28
|
+
from nautobot.extras.models.jobs import JobResult
|
|
27
29
|
from nautobot.extras.models.mixins import NotesMixin
|
|
28
30
|
from nautobot.ipam.models import Prefix
|
|
29
31
|
from nautobot.users import models as users_models
|
|
30
32
|
|
|
31
33
|
__all__ = (
|
|
32
|
-
"TestCase",
|
|
33
34
|
"ModelTestCase",
|
|
34
35
|
"ModelViewTestCase",
|
|
36
|
+
"TestCase",
|
|
35
37
|
"ViewTestCases",
|
|
36
38
|
)
|
|
37
39
|
|
|
@@ -171,10 +173,7 @@ class ViewTestCases:
|
|
|
171
173
|
instance = self._get_queryset().first()
|
|
172
174
|
|
|
173
175
|
# Add model-level permission
|
|
174
|
-
|
|
175
|
-
obj_perm.save()
|
|
176
|
-
obj_perm.users.add(self.user)
|
|
177
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
176
|
+
self.add_permissions(f"{self.model._meta.app_label}.view_{self.model._meta.model_name}")
|
|
178
177
|
|
|
179
178
|
# Try GET with model-level permission
|
|
180
179
|
response = self.client.get(instance.get_absolute_url())
|
|
@@ -323,10 +322,7 @@ class ViewTestCases:
|
|
|
323
322
|
initial_count = self._get_queryset().count()
|
|
324
323
|
|
|
325
324
|
# Assign unconstrained permission
|
|
326
|
-
|
|
327
|
-
obj_perm.save()
|
|
328
|
-
obj_perm.users.add(self.user)
|
|
329
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
325
|
+
self.add_permissions(f"{self.model._meta.app_label}.add_{self.model._meta.model_name}")
|
|
330
326
|
|
|
331
327
|
# Try GET with model-level permission
|
|
332
328
|
self.assertHttpStatus(self.client.get(self._get_url("add")), 200)
|
|
@@ -433,32 +429,6 @@ class ViewTestCases:
|
|
|
433
429
|
if isinstance(model_class, PrimaryModel):
|
|
434
430
|
self.assertIsNotNone(fields.get("tags"))
|
|
435
431
|
|
|
436
|
-
def test_slug_autocreation(self):
|
|
437
|
-
"""Test that slug is autocreated through ORM."""
|
|
438
|
-
# This really should go on a models test page, but we don't have test structures for models.
|
|
439
|
-
if getattr(self.model, "slug_source", None) is not None:
|
|
440
|
-
obj = self.model.objects.get(**{self.slug_source: self.slug_test_object})
|
|
441
|
-
expected_slug = self.slugify_function(getattr(obj, self.slug_source))
|
|
442
|
-
self.assertEqual(obj.slug, expected_slug)
|
|
443
|
-
|
|
444
|
-
def test_slug_not_modified(self):
|
|
445
|
-
"""Ensure save method does not modify slug that is passed in."""
|
|
446
|
-
# This really should go on a models test page, but we don't have test structures for models.
|
|
447
|
-
if getattr(self.model, "slug_source", None) is not None:
|
|
448
|
-
new_slug_source_value = "kwyjibo"
|
|
449
|
-
|
|
450
|
-
obj = self.model.objects.get(**{self.slug_source: self.slug_test_object})
|
|
451
|
-
expected_slug = self.slugify_function(getattr(obj, self.slug_source))
|
|
452
|
-
# Update slug source field str
|
|
453
|
-
filter_ = self.slug_source + "__exact"
|
|
454
|
-
self.model.objects.filter(**{filter_: self.slug_test_object}).update(
|
|
455
|
-
**{self.slug_source: new_slug_source_value}
|
|
456
|
-
)
|
|
457
|
-
|
|
458
|
-
obj.refresh_from_db()
|
|
459
|
-
self.assertEqual(getattr(obj, self.slug_source), new_slug_source_value)
|
|
460
|
-
self.assertEqual(obj.slug, expected_slug)
|
|
461
|
-
|
|
462
432
|
class EditObjectViewTestCase(ModelViewTestCase):
|
|
463
433
|
"""
|
|
464
434
|
Edit a single existing instance.
|
|
@@ -491,10 +461,7 @@ class ViewTestCases:
|
|
|
491
461
|
instance = self._get_queryset().first()
|
|
492
462
|
|
|
493
463
|
# Assign model-level permission
|
|
494
|
-
|
|
495
|
-
obj_perm.save()
|
|
496
|
-
obj_perm.users.add(self.user)
|
|
497
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
464
|
+
self.add_permissions(f"{self.model._meta.app_label}.change_{self.model._meta.model_name}")
|
|
498
465
|
|
|
499
466
|
# Try GET with model-level permission
|
|
500
467
|
self.assertHttpStatus(self.client.get(self._get_url("edit", instance)), 200)
|
|
@@ -615,10 +582,7 @@ class ViewTestCases:
|
|
|
615
582
|
instance_note_pk_list.append(note.pk)
|
|
616
583
|
|
|
617
584
|
# Assign model-level permission
|
|
618
|
-
|
|
619
|
-
obj_perm.save()
|
|
620
|
-
obj_perm.users.add(self.user)
|
|
621
|
-
obj_perm.object_types.add(assigned_object_type)
|
|
585
|
+
self.add_permissions(f"{self.model._meta.app_label}.delete_{self.model._meta.model_name}")
|
|
622
586
|
|
|
623
587
|
# Try GET with model-level permission
|
|
624
588
|
self.assertHttpStatus(self.client.get(self._get_url("delete", instance)), 200)
|
|
@@ -654,10 +618,7 @@ class ViewTestCases:
|
|
|
654
618
|
instance = self.get_deletable_object()
|
|
655
619
|
|
|
656
620
|
# Assign model-level permission
|
|
657
|
-
|
|
658
|
-
obj_perm.save()
|
|
659
|
-
obj_perm.users.add(self.user)
|
|
660
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
621
|
+
self.add_permissions(f"{self.model._meta.app_label}.delete_{self.model._meta.model_name}")
|
|
661
622
|
|
|
662
623
|
# Try GET with model-level permission
|
|
663
624
|
self.assertHttpStatus(self.client.get(self._get_url("delete", instance)), 200)
|
|
@@ -862,10 +823,7 @@ class ViewTestCases:
|
|
|
862
823
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
|
|
863
824
|
def test_list_objects_with_permission(self):
|
|
864
825
|
# Add model-level permission
|
|
865
|
-
|
|
866
|
-
obj_perm.save()
|
|
867
|
-
obj_perm.users.add(self.user)
|
|
868
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
826
|
+
self.add_permissions(f"{self.model._meta.app_label}.view_{self.model._meta.model_name}")
|
|
869
827
|
|
|
870
828
|
# Try GET with model-level permission
|
|
871
829
|
response = self.client.get(self._get_url("list"))
|
|
@@ -878,11 +836,17 @@ class ViewTestCases:
|
|
|
878
836
|
# Check if breadcrumb is rendered correctly
|
|
879
837
|
self.assertBodyContains(response, f'<a href="{list_url}">{title}</a>', html=True)
|
|
880
838
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
839
|
+
with self.subTest("Assert import-objects URL is absent due to user permissions"):
|
|
840
|
+
self.assertNotIn(
|
|
841
|
+
reverse("extras:job_run_by_class_path", kwargs={"class_path": "nautobot.core.jobs.ImportObjects"}),
|
|
842
|
+
response_body,
|
|
843
|
+
)
|
|
844
|
+
|
|
845
|
+
if "example_app" in settings.PLUGINS:
|
|
846
|
+
with self.subTest("Assert example-app banner is present"):
|
|
847
|
+
self.assertIn(
|
|
848
|
+
f"<div>You are viewing a table of {self.model._meta.verbose_name_plural}</div>", response_body
|
|
849
|
+
)
|
|
886
850
|
|
|
887
851
|
return response
|
|
888
852
|
|
|
@@ -989,13 +953,7 @@ class ViewTestCases:
|
|
|
989
953
|
}
|
|
990
954
|
|
|
991
955
|
# Assign non-constrained permission
|
|
992
|
-
|
|
993
|
-
name="Test permission",
|
|
994
|
-
actions=["add"],
|
|
995
|
-
)
|
|
996
|
-
obj_perm.save()
|
|
997
|
-
obj_perm.users.add(self.user)
|
|
998
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
956
|
+
self.add_permissions(f"{self.model._meta.app_label}.add_{self.model._meta.model_name}")
|
|
999
957
|
|
|
1000
958
|
# Bulk create objects
|
|
1001
959
|
response = self.client.post(**request)
|
|
@@ -1049,34 +1007,6 @@ class ViewTestCases:
|
|
|
1049
1007
|
pass
|
|
1050
1008
|
self.assertEqual(matching_count, self.bulk_create_count)
|
|
1051
1009
|
|
|
1052
|
-
class BulkImportObjectsViewTestCase(ModelViewTestCase): # 3.0 TODO: remove this test mixin, no longer relevant.
|
|
1053
|
-
"""
|
|
1054
|
-
Vestigial test case, to be removed in 3.0.
|
|
1055
|
-
|
|
1056
|
-
This is vestigial since the introduction of the ImportObjects system Job to handle bulk-import of all
|
|
1057
|
-
content-types via REST API serializers. The parsing of CSV data by the serializer is exercised by
|
|
1058
|
-
APIViewTestCases.CreateObjectViewTestCase.test_recreate_object_csv(), and the basic operation of the Job is
|
|
1059
|
-
exercised by nautobot.core.tests.test_jobs.
|
|
1060
|
-
"""
|
|
1061
|
-
|
|
1062
|
-
csv_data = ()
|
|
1063
|
-
|
|
1064
|
-
def _get_csv_data(self):
|
|
1065
|
-
return "\n".join(self.csv_data)
|
|
1066
|
-
|
|
1067
|
-
# Just in case Apps are extending any of these tests and calling super() in them.
|
|
1068
|
-
def test_bulk_import_objects_without_permission(self):
|
|
1069
|
-
pass
|
|
1070
|
-
|
|
1071
|
-
def test_bulk_import_objects_with_permission(self):
|
|
1072
|
-
pass
|
|
1073
|
-
|
|
1074
|
-
def test_bulk_import_objects_with_permission_csv_file(self):
|
|
1075
|
-
pass
|
|
1076
|
-
|
|
1077
|
-
def test_bulk_import_objects_with_constrained_permission(self):
|
|
1078
|
-
pass
|
|
1079
|
-
|
|
1080
1010
|
class BulkEditObjectsViewTestCase(ModelViewTestCase):
|
|
1081
1011
|
"""
|
|
1082
1012
|
Edit multiple instances.
|
|
@@ -1091,6 +1021,17 @@ class ViewTestCases:
|
|
|
1091
1021
|
for instance in self._get_queryset().filter(pk__in=pk_list):
|
|
1092
1022
|
self.assertInstanceEqual(instance, self.bulk_edit_data)
|
|
1093
1023
|
|
|
1024
|
+
def validate_redirect_to_job_result(self, response):
|
|
1025
|
+
# Get the last Bulk Edit Objects JobResult created
|
|
1026
|
+
job_result = JobResult.objects.filter(name="Bulk Edit Objects").first()
|
|
1027
|
+
# Assert redirect to Job Results
|
|
1028
|
+
self.assertRedirects(
|
|
1029
|
+
response,
|
|
1030
|
+
reverse("extras:jobresult", args=[job_result.pk]),
|
|
1031
|
+
status_code=302,
|
|
1032
|
+
target_status_code=200,
|
|
1033
|
+
)
|
|
1034
|
+
|
|
1094
1035
|
def test_bulk_edit_objects_without_permission(self):
|
|
1095
1036
|
pk_list = list(self._get_queryset().values_list("pk", flat=True)[:3])
|
|
1096
1037
|
data = {
|
|
@@ -1114,14 +1055,10 @@ class ViewTestCases:
|
|
|
1114
1055
|
data.update(utils.post_data(self.bulk_edit_data))
|
|
1115
1056
|
|
|
1116
1057
|
# Assign model-level permission
|
|
1117
|
-
|
|
1118
|
-
obj_perm.save()
|
|
1119
|
-
obj_perm.users.add(self.user)
|
|
1120
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
1058
|
+
self.add_permissions(f"{self.model._meta.app_label}.change_{self.model._meta.model_name}")
|
|
1121
1059
|
|
|
1122
|
-
|
|
1123
|
-
self.
|
|
1124
|
-
self.validate_object_data_after_bulk_edit(pk_list)
|
|
1060
|
+
response = self.client.post(self._get_url("bulk_edit"), data)
|
|
1061
|
+
self.validate_redirect_to_job_result(response)
|
|
1125
1062
|
|
|
1126
1063
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
1127
1064
|
def test_bulk_edit_form_contains_all_pks(self):
|
|
@@ -1132,10 +1069,7 @@ class ViewTestCases:
|
|
|
1132
1069
|
"_all": "on",
|
|
1133
1070
|
}
|
|
1134
1071
|
# Assign model-level permission
|
|
1135
|
-
|
|
1136
|
-
obj_perm.save()
|
|
1137
|
-
obj_perm.users.add(self.user)
|
|
1138
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
1072
|
+
self.add_permissions(f"{self.model._meta.app_label}.change_{self.model._meta.model_name}")
|
|
1139
1073
|
|
|
1140
1074
|
# Try POST with model-level permission
|
|
1141
1075
|
response = self.client.post(self._get_url("bulk_edit"), selected_data)
|
|
@@ -1149,7 +1083,7 @@ class ViewTestCases:
|
|
|
1149
1083
|
for pk in pk_list:
|
|
1150
1084
|
self.assertNotIn(str(pk), response_body)
|
|
1151
1085
|
self.assertInHTML(
|
|
1152
|
-
'<input type="hidden" name="_all" value="True" class="form-control"
|
|
1086
|
+
'<input type="hidden" name="_all" value="True" class="form-control" placeholder="None" id="id__all">',
|
|
1153
1087
|
response_body,
|
|
1154
1088
|
)
|
|
1155
1089
|
|
|
@@ -1185,7 +1119,7 @@ class ViewTestCases:
|
|
|
1185
1119
|
self.assertNotIn(str(third_pk), response_body)
|
|
1186
1120
|
self.assertIn("Editing 2 ", response_body)
|
|
1187
1121
|
self.assertInHTML(
|
|
1188
|
-
'<input type="hidden" name="_all" value="True" class="form-control"
|
|
1122
|
+
'<input type="hidden" name="_all" value="True" class="form-control" placeholder="None" id="id__all">',
|
|
1189
1123
|
response_body,
|
|
1190
1124
|
)
|
|
1191
1125
|
|
|
@@ -1225,21 +1159,9 @@ class ViewTestCases:
|
|
|
1225
1159
|
|
|
1226
1160
|
# Attempt to bulk edit permitted objects into a non-permitted state
|
|
1227
1161
|
response = self.client.post(self._get_url("bulk_edit"), data)
|
|
1228
|
-
#
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
for instance in self._get_queryset().filter(pk__in=pk_list):
|
|
1232
|
-
self.assertIn(field.value_from_object(instance), values)
|
|
1233
|
-
self.assertNotEqual(field.value_from_object(instance), self.bulk_edit_data[attr_name])
|
|
1234
|
-
|
|
1235
|
-
# Update permission constraints to permit all objects
|
|
1236
|
-
obj_perm.constraints = {"pk__gt": 0}
|
|
1237
|
-
obj_perm.save()
|
|
1238
|
-
|
|
1239
|
-
# Bulk edit permitted objects and expect a redirect back to the list view
|
|
1240
|
-
self.assertHttpStatus(self.client.post(self._get_url("bulk_edit"), data), 302)
|
|
1241
|
-
# Assert that the objects were all updated correctly
|
|
1242
|
-
self.validate_object_data_after_bulk_edit(pk_list)
|
|
1162
|
+
# NOTE: There is no way of testing constrained failure as bulk edit is a system Job;
|
|
1163
|
+
# and can only be tested by checking JobLogs.
|
|
1164
|
+
self.validate_redirect_to_job_result(response)
|
|
1243
1165
|
|
|
1244
1166
|
class BulkDeleteObjectsViewTestCase(ModelViewTestCase):
|
|
1245
1167
|
"""
|
|
@@ -1271,7 +1193,6 @@ class ViewTestCases:
|
|
|
1271
1193
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
|
|
1272
1194
|
def test_bulk_delete_objects_with_permission(self):
|
|
1273
1195
|
pk_list = self.get_deletable_object_pks()
|
|
1274
|
-
initial_count = self._get_queryset().count()
|
|
1275
1196
|
data = {
|
|
1276
1197
|
"pk": pk_list,
|
|
1277
1198
|
"confirm": True,
|
|
@@ -1279,14 +1200,18 @@ class ViewTestCases:
|
|
|
1279
1200
|
}
|
|
1280
1201
|
|
|
1281
1202
|
# Assign unconstrained permission
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
1203
|
+
self.add_permissions(
|
|
1204
|
+
f"{self.model._meta.app_label}.delete_{self.model._meta.model_name}", "extras.view_jobresult"
|
|
1205
|
+
)
|
|
1286
1206
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
self.
|
|
1207
|
+
response = self.client.post(self._get_url("bulk_delete"), data)
|
|
1208
|
+
job_result = JobResult.objects.filter(name="Bulk Delete Objects").first()
|
|
1209
|
+
self.assertRedirects(
|
|
1210
|
+
response,
|
|
1211
|
+
reverse("extras:jobresult", args=[job_result.pk]),
|
|
1212
|
+
status_code=302,
|
|
1213
|
+
target_status_code=200,
|
|
1214
|
+
)
|
|
1290
1215
|
|
|
1291
1216
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=[])
|
|
1292
1217
|
def test_bulk_delete_form_contains_all_objects(self):
|
|
@@ -1298,10 +1223,7 @@ class ViewTestCases:
|
|
|
1298
1223
|
}
|
|
1299
1224
|
|
|
1300
1225
|
# Assign unconstrained permission
|
|
1301
|
-
|
|
1302
|
-
obj_perm.save()
|
|
1303
|
-
obj_perm.users.add(self.user)
|
|
1304
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
1226
|
+
self.add_permissions(f"{self.model._meta.app_label}.delete_{self.model._meta.model_name}")
|
|
1305
1227
|
|
|
1306
1228
|
# Try POST with the selected data first. Emulating selecting all -> pressing Delete Selected button.
|
|
1307
1229
|
response = self.client.post(self._get_url("bulk_delete"), selected_data)
|
|
@@ -1373,9 +1295,16 @@ class ViewTestCases:
|
|
|
1373
1295
|
obj_perm.constraints = {"pk__isnull": False} # Match a non-existent pk (i.e., allow all)
|
|
1374
1296
|
obj_perm.save()
|
|
1375
1297
|
|
|
1376
|
-
#
|
|
1377
|
-
self.
|
|
1378
|
-
self.
|
|
1298
|
+
# User would be redirected to Job Result therefore user needs to have permission to view Job Result
|
|
1299
|
+
self.add_permissions("extras.view_jobresult")
|
|
1300
|
+
response = self.client.post(self._get_url("bulk_delete"), data)
|
|
1301
|
+
job_result = JobResult.objects.filter(name="Bulk Delete Objects").first()
|
|
1302
|
+
self.assertRedirects(
|
|
1303
|
+
response,
|
|
1304
|
+
reverse("extras:jobresult", args=[job_result.pk]),
|
|
1305
|
+
status_code=302,
|
|
1306
|
+
target_status_code=200,
|
|
1307
|
+
)
|
|
1379
1308
|
|
|
1380
1309
|
class BulkRenameObjectsViewTestCase(ModelViewTestCase):
|
|
1381
1310
|
"""
|
|
@@ -1415,10 +1344,7 @@ class ViewTestCases:
|
|
|
1415
1344
|
data.update(self.rename_data)
|
|
1416
1345
|
|
|
1417
1346
|
# Assign model-level permission
|
|
1418
|
-
|
|
1419
|
-
obj_perm.save()
|
|
1420
|
-
obj_perm.users.add(self.user)
|
|
1421
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
1347
|
+
self.add_permissions(f"{self.model._meta.app_label}.change_{self.model._meta.model_name}")
|
|
1422
1348
|
|
|
1423
1349
|
# Try POST with model-level permission
|
|
1424
1350
|
self.assertHttpStatus(self.client.post(self._get_url("bulk_rename"), data), 302)
|
|
@@ -1528,14 +1454,13 @@ class ViewTestCases:
|
|
|
1528
1454
|
maxDiff = None
|
|
1529
1455
|
bulk_add_data = None
|
|
1530
1456
|
"""Used for bulk-add (distinct from bulk-create) view testing; self.bulk_create_data will be used if unset."""
|
|
1457
|
+
selected_objects: list[ComponentModel]
|
|
1458
|
+
selected_objects_parent_name: str
|
|
1531
1459
|
|
|
1532
1460
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
1533
1461
|
def test_bulk_add_component(self):
|
|
1534
1462
|
"""Test bulk-adding this component to devices/virtual-machines."""
|
|
1535
|
-
|
|
1536
|
-
obj_perm.save()
|
|
1537
|
-
obj_perm.users.add(self.user)
|
|
1538
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
1463
|
+
self.add_permissions(f"{self.model._meta.app_label}.add_{self.model._meta.model_name}")
|
|
1539
1464
|
|
|
1540
1465
|
initial_count = self._get_queryset().count()
|
|
1541
1466
|
|
|
@@ -1579,10 +1504,7 @@ class ViewTestCases:
|
|
|
1579
1504
|
|
|
1580
1505
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
1581
1506
|
def test_bulk_rename(self):
|
|
1582
|
-
|
|
1583
|
-
obj_perm.save()
|
|
1584
|
-
obj_perm.users.add(self.user)
|
|
1585
|
-
obj_perm.object_types.add(ContentType.objects.get_for_model(self.model))
|
|
1507
|
+
self.add_permissions(f"{self.model._meta.app_label}.change_{self.model._meta.model_name}")
|
|
1586
1508
|
|
|
1587
1509
|
objects = self.selected_objects
|
|
1588
1510
|
pk_list = [obj.pk for obj in objects]
|
|
@@ -9,7 +9,6 @@ from example_app.models import ExampleModel
|
|
|
9
9
|
class AppHomeTestCase(SeleniumTestCase):
|
|
10
10
|
"""Integration test the Example App homepage extensions."""
|
|
11
11
|
|
|
12
|
-
fixtures = ["user-data.json"] # bob/bob
|
|
13
12
|
layout = {
|
|
14
13
|
"Organization": {
|
|
15
14
|
"Locations": {"model": Location, "permission": "dcim.view_location"},
|
|
@@ -11,8 +11,6 @@ from nautobot.extras.models import CustomField, CustomFieldChoice, Status
|
|
|
11
11
|
class ListViewFilterTestCase(SeleniumTestCase):
|
|
12
12
|
"""Integration test for the list view filter ui."""
|
|
13
13
|
|
|
14
|
-
fixtures = ["user-data.json"]
|
|
15
|
-
|
|
16
14
|
def setUp(self):
|
|
17
15
|
super().setUp()
|
|
18
16
|
self.login(self.user.username, self.password)
|
|
@@ -7,7 +7,6 @@ from nautobot.tenancy.models import Tenant
|
|
|
7
7
|
class HomeTestCase(SeleniumTestCase):
|
|
8
8
|
"""Integration tests against the home page."""
|
|
9
9
|
|
|
10
|
-
fixtures = ["user-data.json"] # bob/bob
|
|
11
10
|
layout = {
|
|
12
11
|
"Organization": {
|
|
13
12
|
"Locations": {"model": Location, "permission": "dcim.view_location"},
|
|
@@ -14,7 +14,7 @@ class AuthenticationEnforcedTestCase(TestCase):
|
|
|
14
14
|
|
|
15
15
|
def test_all_views_require_authentication(self):
|
|
16
16
|
self.client.logout()
|
|
17
|
-
url_patterns = get_url_patterns()
|
|
17
|
+
url_patterns = get_url_patterns(ignore_redirects=True)
|
|
18
18
|
|
|
19
19
|
for url_pattern in url_patterns:
|
|
20
20
|
with self.subTest(url_pattern=url_pattern):
|
|
@@ -31,6 +31,7 @@ class AuthenticationEnforcedTestCase(TestCase):
|
|
|
31
31
|
"/health/",
|
|
32
32
|
"/login/",
|
|
33
33
|
"/media-failure/",
|
|
34
|
+
"/robots.txt",
|
|
34
35
|
"/template.css",
|
|
35
36
|
]:
|
|
36
37
|
self.assertHttpStatus(response, 200, msg=url)
|