nautobot 2.2.0__py3-none-any.whl → 2.2.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (362) hide show
  1. nautobot/apps/api.py +2 -1
  2. nautobot/apps/utils.py +0 -4
  3. nautobot/apps/views.py +0 -2
  4. nautobot/circuits/api/urls.py +2 -1
  5. nautobot/circuits/api/views.py +12 -0
  6. nautobot/circuits/tests/test_filters.py +1 -1
  7. nautobot/core/api/routers.py +3 -25
  8. nautobot/core/api/utils.py +0 -4
  9. nautobot/core/api/views.py +15 -21
  10. nautobot/core/filters.py +1 -7
  11. nautobot/core/management/commands/generate_test_data.py +4 -4
  12. nautobot/core/settings.py +0 -1
  13. nautobot/core/tables.py +1 -2
  14. nautobot/core/templates/admin/base.html +94 -23
  15. nautobot/core/templates/graphene/graphiql.html +47 -18
  16. nautobot/core/templates/inc/footer.html +5 -5
  17. nautobot/core/templates/inc/nav_menu.html +7 -0
  18. nautobot/core/templates/rest_framework/api.html +5 -12
  19. nautobot/core/templatetags/helpers.py +2 -2
  20. nautobot/core/testing/views.py +0 -30
  21. nautobot/core/tests/test_api.py +6 -13
  22. nautobot/core/tests/test_csv.py +4 -5
  23. nautobot/core/tests/test_filters.py +1 -2
  24. nautobot/core/tests/test_graphql.py +14 -4
  25. nautobot/core/tests/test_navigations.py +0 -3
  26. nautobot/core/tests/test_views.py +16 -22
  27. nautobot/core/utils/lookup.py +0 -124
  28. nautobot/core/views/__init__.py +7 -3
  29. nautobot/core/views/generic.py +3 -19
  30. nautobot/core/views/mixins.py +0 -7
  31. nautobot/core/views/renderers.py +1 -4
  32. nautobot/dcim/api/serializers.py +4 -4
  33. nautobot/dcim/api/urls.py +3 -2
  34. nautobot/dcim/api/views.py +18 -7
  35. nautobot/dcim/factory.py +7 -7
  36. nautobot/dcim/filters/__init__.py +17 -16
  37. nautobot/dcim/forms.py +45 -61
  38. nautobot/dcim/homepage.py +3 -11
  39. nautobot/dcim/migrations/0057_controller_models.py +70 -11
  40. nautobot/dcim/models/__init__.py +2 -2
  41. nautobot/dcim/models/devices.py +16 -14
  42. nautobot/dcim/models/racks.py +3 -1
  43. nautobot/dcim/navigation.py +31 -23
  44. nautobot/dcim/signals.py +6 -6
  45. nautobot/dcim/tables/__init__.py +2 -2
  46. nautobot/dcim/tables/devices.py +15 -12
  47. nautobot/dcim/tables/template_code.py +1 -1
  48. nautobot/dcim/templates/dcim/controller_retrieve.html +18 -35
  49. nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +43 -0
  50. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +43 -67
  51. nautobot/dcim/templates/dcim/device.html +2 -10
  52. nautobot/dcim/templates/dcim/device_edit.html +1 -1
  53. nautobot/dcim/tests/test_api.py +6 -11
  54. nautobot/dcim/tests/test_filters.py +81 -92
  55. nautobot/dcim/tests/test_graphql.py +1 -11
  56. nautobot/dcim/tests/test_models.py +15 -15
  57. nautobot/dcim/tests/test_signals.py +0 -2
  58. nautobot/dcim/tests/test_views.py +12 -24
  59. nautobot/dcim/urls.py +1 -1
  60. nautobot/dcim/views.py +15 -19
  61. nautobot/extras/api/urls.py +2 -1
  62. nautobot/extras/api/views.py +10 -0
  63. nautobot/extras/filters/__init__.py +2 -53
  64. nautobot/extras/forms/contacts.py +0 -7
  65. nautobot/extras/managers.py +0 -14
  66. nautobot/extras/navigation.py +65 -71
  67. nautobot/extras/plugins/views.py +11 -7
  68. nautobot/extras/tests/test_api.py +0 -2
  69. nautobot/extras/tests/test_dynamicgroups.py +0 -2
  70. nautobot/extras/tests/test_filters.py +4 -89
  71. nautobot/extras/tests/test_models.py +0 -9
  72. nautobot/extras/tests/test_relationships.py +1 -10
  73. nautobot/extras/tests/test_views.py +1 -112
  74. nautobot/extras/views.py +10 -10
  75. nautobot/ipam/api/urls.py +2 -1
  76. nautobot/ipam/api/views.py +11 -0
  77. nautobot/ipam/tables.py +22 -2
  78. nautobot/ipam/tests/test_graphql.py +3 -2
  79. nautobot/ipam/tests/test_views.py +0 -1
  80. nautobot/ipam/views.py +9 -9
  81. nautobot/project-static/css/base.css +0 -1
  82. nautobot/project-static/docs/404.html +3 -24
  83. nautobot/project-static/docs/apps/index.html +3 -24
  84. nautobot/project-static/docs/apps/nautobot-apps.html +3 -24
  85. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +3 -24
  86. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +3 -24
  87. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +5 -26
  88. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +3 -24
  89. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +3 -24
  90. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +3 -24
  91. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +3 -24
  92. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +3 -24
  93. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +3 -24
  94. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +3 -24
  95. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +3 -24
  96. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +3 -24
  97. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +3 -24
  98. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +3 -24
  99. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +3 -24
  100. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +3 -24
  101. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +3 -24
  102. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +3 -24
  103. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +3 -24
  104. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +3 -24
  105. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +3 -24
  106. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +3 -242
  107. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +5 -69
  108. nautobot/project-static/docs/development/apps/api/configuration-view.html +3 -24
  109. nautobot/project-static/docs/development/apps/api/database-backend-config.html +3 -24
  110. nautobot/project-static/docs/development/apps/api/models/django-admin.html +3 -24
  111. nautobot/project-static/docs/development/apps/api/models/global-search.html +3 -24
  112. nautobot/project-static/docs/development/apps/api/models/graphql.html +3 -24
  113. nautobot/project-static/docs/development/apps/api/models/index.html +3 -24
  114. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +3 -24
  115. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +3 -24
  116. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +3 -24
  117. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +3 -24
  118. nautobot/project-static/docs/development/apps/api/platform-features/index.html +3 -24
  119. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +3 -24
  120. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +3 -24
  121. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +3 -24
  122. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +3 -24
  123. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +3 -24
  124. nautobot/project-static/docs/development/apps/api/prometheus.html +3 -24
  125. nautobot/project-static/docs/development/apps/api/setup.html +3 -24
  126. nautobot/project-static/docs/development/apps/api/testing.html +3 -24
  127. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +3 -24
  128. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +3 -24
  129. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +3 -24
  130. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +3 -24
  131. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +3 -24
  132. nautobot/project-static/docs/development/apps/api/views/base-template.html +3 -24
  133. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +12 -38
  134. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +15 -41
  135. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +3 -24
  136. nautobot/project-static/docs/development/apps/api/views/index.html +3 -24
  137. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +3 -24
  138. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +3 -24
  139. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +3 -24
  140. nautobot/project-static/docs/development/apps/api/views/notes.html +3 -24
  141. nautobot/project-static/docs/development/apps/api/views/rest-api.html +3 -24
  142. nautobot/project-static/docs/development/apps/api/views/urls.html +3 -24
  143. nautobot/project-static/docs/development/apps/index.html +3 -24
  144. nautobot/project-static/docs/development/apps/migration/code-updates.html +3 -24
  145. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +3 -24
  146. nautobot/project-static/docs/development/apps/migration/from-v1.html +3 -24
  147. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +3 -24
  148. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +3 -24
  149. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +3 -24
  150. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +3 -24
  151. nautobot/project-static/docs/development/apps/porting-from-netbox.html +3 -24
  152. nautobot/project-static/docs/development/core/application-registry.html +3 -24
  153. nautobot/project-static/docs/development/core/best-practices.html +3 -24
  154. nautobot/project-static/docs/development/core/bootstrap-ui.html +3 -24
  155. nautobot/project-static/docs/development/core/caching.html +3 -24
  156. nautobot/project-static/docs/development/core/controllers.html +204 -35
  157. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +3 -24
  158. nautobot/project-static/docs/development/core/extending-models.html +3 -24
  159. nautobot/project-static/docs/development/core/generic-views.html +3 -24
  160. nautobot/project-static/docs/development/core/getting-started.html +13 -43
  161. nautobot/project-static/docs/development/core/homepage.html +3 -24
  162. nautobot/project-static/docs/development/core/index.html +3 -24
  163. nautobot/project-static/docs/development/core/model-features.html +3 -24
  164. nautobot/project-static/docs/development/core/natural-keys.html +3 -24
  165. nautobot/project-static/docs/development/core/navigation-menu.html +3 -24
  166. nautobot/project-static/docs/development/core/release-checklist.html +3 -24
  167. nautobot/project-static/docs/development/core/role-internals.html +3 -24
  168. nautobot/project-static/docs/development/core/settings.html +3 -24
  169. nautobot/project-static/docs/development/core/style-guide.html +3 -24
  170. nautobot/project-static/docs/development/core/templates.html +3 -24
  171. nautobot/project-static/docs/development/core/testing.html +3 -24
  172. nautobot/project-static/docs/development/core/user-preferences.html +3 -24
  173. nautobot/project-static/docs/development/index.html +3 -24
  174. nautobot/project-static/docs/development/jobs/index.html +3 -24
  175. nautobot/project-static/docs/development/jobs/migration/from-v1.html +3 -24
  176. nautobot/project-static/docs/index.html +3 -24
  177. nautobot/project-static/docs/models/dcim/{controllermanageddevicegroup.html → controllerdevicegroup.html} +3 -3
  178. nautobot/project-static/docs/objects.inv +0 -0
  179. nautobot/project-static/docs/release-notes/index.html +3 -24
  180. nautobot/project-static/docs/release-notes/version-1.0.html +3 -24
  181. nautobot/project-static/docs/release-notes/version-1.1.html +3 -24
  182. nautobot/project-static/docs/release-notes/version-1.2.html +3 -24
  183. nautobot/project-static/docs/release-notes/version-1.3.html +3 -24
  184. nautobot/project-static/docs/release-notes/version-1.4.html +3 -24
  185. nautobot/project-static/docs/release-notes/version-1.5.html +3 -24
  186. nautobot/project-static/docs/release-notes/version-1.6.html +3 -24
  187. nautobot/project-static/docs/release-notes/version-2.0.html +3 -24
  188. nautobot/project-static/docs/release-notes/version-2.1.html +162 -411
  189. nautobot/project-static/docs/release-notes/version-2.2.html +30 -212
  190. nautobot/project-static/docs/search/search_index.json +1 -1
  191. nautobot/project-static/docs/sitemap.xml +255 -260
  192. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  193. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +3 -24
  194. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +3 -24
  195. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +3 -24
  196. nautobot/project-static/docs/user-guide/administration/configuration/index.html +3 -24
  197. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +3 -24
  198. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +3 -24
  199. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +3 -24
  200. nautobot/project-static/docs/user-guide/administration/guides/caching.html +3 -24
  201. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +3 -24
  202. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +3 -24
  203. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +3 -24
  204. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +3 -24
  205. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +3 -24
  206. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +3 -24
  207. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +3 -24
  208. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +3 -24
  209. nautobot/project-static/docs/user-guide/administration/installation/docker.html +6 -31
  210. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +3 -24
  211. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +3 -24
  212. nautobot/project-static/docs/user-guide/administration/installation/index.html +3 -24
  213. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +3 -24
  214. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +3 -24
  215. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +6 -27
  216. nautobot/project-static/docs/user-guide/administration/installation/services.html +3 -24
  217. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +3 -24
  218. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +3 -24
  219. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +3 -24
  220. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +3 -24
  221. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +3 -24
  222. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +3 -24
  223. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +3 -24
  224. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +3 -24
  225. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +3 -24
  226. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +3 -24
  227. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +3 -24
  228. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +3 -24
  229. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +3 -24
  230. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +3 -24
  231. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +3 -24
  232. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +3 -24
  233. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +3 -24
  234. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +3 -24
  235. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +3 -24
  236. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +3 -24
  237. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +3 -24
  238. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +3 -24
  239. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +3 -24
  240. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +11 -259
  241. nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllermanageddevicegroup.html → controllerdevicegroup.html} +17 -107
  242. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +3 -24
  243. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +3 -24
  244. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +3 -24
  245. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +3 -24
  246. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +3 -24
  247. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +3 -24
  248. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +3 -24
  249. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +3 -24
  250. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +3 -24
  251. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +3 -24
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +3 -24
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +3 -24
  254. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +3 -24
  255. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +3 -24
  256. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +3 -24
  257. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +3 -24
  258. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +3 -24
  259. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +3 -24
  260. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +3 -24
  261. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +3 -24
  262. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +3 -24
  263. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +3 -24
  264. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +3 -24
  265. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +3 -24
  266. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +3 -24
  267. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +3 -24
  268. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +3 -24
  269. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +3 -24
  270. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +3 -24
  271. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +3 -24
  272. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +6 -27
  273. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +3 -24
  274. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +3 -24
  275. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +3 -24
  276. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +3 -24
  277. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +3 -24
  278. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +3 -24
  279. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +3 -24
  280. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +3 -24
  281. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +3 -24
  282. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +3 -24
  283. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +3 -24
  284. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +3 -24
  285. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +3 -24
  286. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +3 -24
  287. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +3 -24
  288. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +3 -24
  289. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +3 -24
  290. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +3 -24
  291. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +3 -24
  292. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +3 -24
  293. nautobot/project-static/docs/user-guide/feature-guides/{contacts-and-teams.html → contact-and-team.html} +4 -25
  294. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +5 -26
  295. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +3 -24
  296. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +3 -24
  297. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +3 -24
  298. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +3 -24
  299. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +3 -24
  300. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +3 -24
  301. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +5 -26
  302. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +3 -24
  303. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +3 -24
  304. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +3 -24
  305. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +3 -24
  306. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +3 -24
  307. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +3 -24
  308. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +3 -24
  309. nautobot/project-static/docs/user-guide/index.html +3 -24
  310. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +3 -24
  311. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +3 -24
  312. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +3 -24
  313. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +3 -24
  314. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +3 -24
  315. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +3 -24
  316. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +3 -24
  317. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +3 -24
  318. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +3 -24
  319. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +3 -24
  320. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +3 -24
  321. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +3 -24
  322. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +3 -24
  323. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +3 -24
  324. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +3 -24
  325. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +3 -24
  326. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +3 -24
  327. nautobot/project-static/docs/user-guide/platform-functionality/note.html +3 -24
  328. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +3 -24
  329. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +3 -24
  330. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +3 -24
  331. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +3 -24
  332. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +3 -24
  333. nautobot/project-static/docs/user-guide/platform-functionality/role.html +3 -24
  334. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +3 -24
  335. nautobot/project-static/docs/user-guide/platform-functionality/status.html +3 -24
  336. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +3 -24
  337. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +3 -24
  338. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +3 -24
  339. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +3 -24
  340. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +3 -24
  341. nautobot/tenancy/api/urls.py +2 -1
  342. nautobot/tenancy/api/views.py +12 -0
  343. nautobot/tenancy/tables.py +1 -1
  344. nautobot/tenancy/tests/test_views.py +0 -1
  345. nautobot/users/api/urls.py +2 -1
  346. nautobot/users/api/views.py +65 -2
  347. nautobot/users/views.py +8 -8
  348. nautobot/virtualization/api/urls.py +2 -1
  349. nautobot/virtualization/api/views.py +12 -0
  350. {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/METADATA +3 -3
  351. {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/RECORD +356 -361
  352. nautobot/core/tests/integration/test_view_authentication.py +0 -67
  353. nautobot/dcim/management/commands/migrate_location_contacts.py +0 -218
  354. nautobot/dcim/templates/dcim/controller_create.html +0 -70
  355. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +0 -88
  356. nautobot/ipam/tests/test_tables.py +0 -42
  357. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +0 -8581
  358. /nautobot/dcim/templates/dcim/{controllermanageddevicegroup_retrieve.html → controllerdevicegroup_retrieve.html} +0 -0
  359. {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/LICENSE.txt +0 -0
  360. {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/NOTICE +0 -0
  361. {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/WHEEL +0 -0
  362. {nautobot-2.2.0.dist-info → nautobot-2.2.0b1.dist-info}/entry_points.txt +0 -0
@@ -61,7 +61,6 @@ from nautobot.extras.models import (
61
61
  ComputedField,
62
62
  ConfigContext,
63
63
  Contact,
64
- ContactAssociation,
65
64
  CustomField,
66
65
  CustomFieldChoice,
67
66
  CustomLink,
@@ -458,91 +457,7 @@ class ContentTypeFilterSetTestCase(FilterTestCases.FilterTestCase):
458
457
  )
459
458
 
460
459
 
461
- class ContactAndTeamFilterSetTestCaseMixin:
462
- """Mixin class to test common filters to both Contact and Team filter sets."""
463
-
464
- def test_similar_to_location_data(self):
465
- """Complex test to test the complex `similar_to_location_data` method filter."""
466
- ContactAssociation.objects.all().delete()
467
- self.queryset.delete()
468
- location_type = LocationType.objects.filter(parent__isnull=True).first()
469
- location_status = Status.objects.get_for_model(Location).first()
470
- test_locations = (
471
- Location.objects.create(
472
- location_type=location_type,
473
- name="Filter Test Location 0",
474
- status=location_status,
475
- contact_name="match 0",
476
- ),
477
- Location.objects.create(
478
- location_type=location_type,
479
- name="Filter Test Location 1",
480
- status=location_status,
481
- contact_email="Test email for location 1 and 2",
482
- ),
483
- Location.objects.create(
484
- location_type=location_type,
485
- name="Filter Test Location 2",
486
- status=location_status,
487
- contact_email="TEST EMAIL FOR LOCATION 1 AND 2",
488
- contact_phone="Test phone for location 2 and 3",
489
- ),
490
- Location.objects.create(
491
- location_type=location_type,
492
- name="Filter Test Location 3",
493
- status=location_status,
494
- contact_phone="Test phone for location 2 and 3",
495
- ),
496
- Location.objects.create(
497
- location_type=location_type,
498
- name="Filter Test Location 4",
499
- status=location_status,
500
- contact_name="Hopefully this doesn't match any random factory data",
501
- contact_email="Hopefully this doesn't match any random factory data",
502
- contact_phone="Hopefully this doesn't match any random factory data",
503
- physical_address="Hopefully this doesn't match any random factory data",
504
- shipping_address="Hopefully this doesn't match any random factory data",
505
- ),
506
- )
507
-
508
- self.queryset.create(name="match 0")
509
- self.queryset.create(name="match 1 and 2", email="Test email for location 1 and 2")
510
- self.queryset.create(name="match 2 and 3", phone="Test phone for location 2 and 3")
511
-
512
- # These subtests are confusing because we're trying to test the NaturalKeyOrPKMultipleChoiceFilter
513
- # behavior while also testing the `similar_to_location_data` method filter behavior.
514
- with self.subTest("Test name match"):
515
- params = {"similar_to_location_data": [test_locations[0].pk]}
516
- self.assertQuerysetEqualAndNotEmpty(
517
- self.filterset(params, self.queryset).qs,
518
- self.queryset.filter(name__in=["match 0"]),
519
- )
520
- with self.subTest("Test email match"):
521
- params = {"similar_to_location_data": [test_locations[1].pk]}
522
- self.assertQuerysetEqualAndNotEmpty(
523
- self.filterset(params, self.queryset).qs,
524
- self.queryset.filter(name__in=["match 1 and 2"]),
525
- )
526
- with self.subTest("Test phone match"):
527
- params = {"similar_to_location_data": [test_locations[2].pk]}
528
- self.assertQuerysetEqualAndNotEmpty(
529
- self.filterset(params, self.queryset).qs,
530
- self.queryset.filter(name__in=["match 1 and 2", "match 2 and 3"]),
531
- )
532
- with self.subTest("Test email and phone match"):
533
- params = {"similar_to_location_data": [test_locations[1].pk, test_locations[3].name]}
534
- self.assertQuerysetEqualAndNotEmpty(
535
- self.filterset(params, self.queryset).qs,
536
- self.queryset.filter(name__in=["match 1 and 2", "match 2 and 3"]),
537
- )
538
- with self.subTest("Test no match"):
539
- params = {"similar_to_location_data": [test_locations[4].pk]}
540
- self.assertFalse(self.filterset(params, self.queryset).qs.exists())
541
- params = {"similar_to_location_data": [test_locations[4].name]}
542
- self.assertFalse(self.filterset(params, self.queryset).qs.exists())
543
-
544
-
545
- class ContactFilterSetTestCase(ContactAndTeamFilterSetTestCaseMixin, FilterTestCases.FilterTestCase):
460
+ class ContactFilterSetTestCase(FilterTestCases.FilterTestCase):
546
461
  queryset = Contact.objects.all()
547
462
  filterset = ContactFilterSet
548
463
 
@@ -1841,7 +1756,7 @@ class TagTestCase(FilterTestCases.NameOnlyFilterTestCase):
1841
1756
  self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
1842
1757
 
1843
1758
 
1844
- class TeamFilterSetTestCase(ContactAndTeamFilterSetTestCaseMixin, FilterTestCases.FilterTestCase):
1759
+ class TeamFilterSetTestCase(FilterTestCases.FilterTestCase):
1845
1760
  queryset = Team.objects.all()
1846
1761
  filterset = TeamFilterSet
1847
1762
 
@@ -1923,8 +1838,8 @@ class RoleTestCase(FilterTestCases.NameOnlyFilterTestCase):
1923
1838
  def test_content_types(self):
1924
1839
  device_ct = ContentType.objects.get_for_model(Device)
1925
1840
  rack_ct = ContentType.objects.get_for_model(Rack)
1926
- device_roles = self.queryset.filter(content_types__in=[device_ct, rack_ct]).distinct()
1927
- params = {"content_types": ["dcim.device", "dcim.rack"]}
1841
+ device_roles = self.queryset.filter(content_types=device_ct)
1842
+ params = {"content_types": ["dcim.device"]}
1928
1843
  self.assertQuerysetEqualAndNotEmpty(self.filterset(params, self.queryset).qs, device_roles)
1929
1844
 
1930
1845
  rack_roles = self.queryset.filter(content_types=rack_ct)
@@ -1810,15 +1810,6 @@ class JobResultTestCase(TestCase):
1810
1810
  JobResult.objects.create(name="ExampleJob2", user=None, result=lambda: 1)
1811
1811
  self.assertEqual(str(err.exception), "Object of type function is not JSON serializable")
1812
1812
 
1813
- def test_get_task(self):
1814
- """Assert bug fix for `Cannot resolve keyword 'task_id' into field` #5440"""
1815
- data = {
1816
- "output": "valid data",
1817
- }
1818
- job_result = JobResult.objects.create(name="ExampleJob1", user=None, result=data)
1819
-
1820
- self.assertEqual(JobResult.objects.get_task(job_result.pk), job_result)
1821
-
1822
1813
 
1823
1814
  class WebhookTest(ModelTestCases.BaseModelTestCase):
1824
1815
  model = Webhook
@@ -15,15 +15,7 @@ from nautobot.core.tables import RelationshipColumn
15
15
  from nautobot.core.testing import TestCase
16
16
  from nautobot.core.testing.models import ModelTestCases
17
17
  from nautobot.core.utils.lookup import get_route_for_model
18
- from nautobot.dcim.models import (
19
- Controller,
20
- Device,
21
- DeviceTypeToSoftwareImageFile,
22
- Location,
23
- LocationType,
24
- Platform,
25
- Rack,
26
- )
18
+ from nautobot.dcim.models import Device, DeviceTypeToSoftwareImageFile, Location, LocationType, Platform, Rack
27
19
  from nautobot.dcim.tables import LocationTable
28
20
  from nautobot.dcim.tests.test_views import create_test_device
29
21
  from nautobot.extras.choices import RelationshipRequiredSideChoices, RelationshipSideChoices, RelationshipTypeChoices
@@ -1173,7 +1165,6 @@ class RequiredRelationshipTestMixin:
1173
1165
  # Protected FK to SoftwareImageFile prevents deletion
1174
1166
  DeviceTypeToSoftwareImageFile.objects.all().delete()
1175
1167
  # Protected FK to SoftwareVersion prevents deletion
1176
- Controller.objects.all().delete()
1177
1168
  Device.objects.all().update(software_version=None)
1178
1169
 
1179
1170
  # Create required relationships:
@@ -17,21 +17,11 @@ from nautobot.core.choices import ColorChoices
17
17
  from nautobot.core.models.fields import slugify_dashes_to_underscores
18
18
  from nautobot.core.testing import extract_form_failures, extract_page_body, TestCase, ViewTestCases
19
19
  from nautobot.core.testing.utils import disable_warnings, post_data
20
- from nautobot.dcim.models import (
21
- ConsolePort,
22
- Controller,
23
- Device,
24
- DeviceType,
25
- Interface,
26
- Location,
27
- LocationType,
28
- Manufacturer,
29
- )
20
+ from nautobot.dcim.models import ConsolePort, Device, DeviceType, Interface, Location, LocationType, Manufacturer
30
21
  from nautobot.dcim.tests import test_views
31
22
  from nautobot.extras.choices import (
32
23
  CustomFieldTypeChoices,
33
24
  JobExecutionType,
34
- LogLevelChoices,
35
25
  ObjectChangeActionChoices,
36
26
  SecretsGroupAccessTypeChoices,
37
27
  SecretsGroupSecretTypeChoices,
@@ -53,7 +43,6 @@ from nautobot.extras.models import (
53
43
  GraphQLQuery,
54
44
  Job,
55
45
  JobButton,
56
- JobLogEntry,
57
46
  JobResult,
58
47
  Note,
59
48
  ObjectChange,
@@ -792,49 +781,6 @@ class DynamicGroupTestCase(
792
781
  "dynamic_group_memberships-MAX_NUM_FORMS": "1000",
793
782
  }
794
783
 
795
- def test_get_object_dynamic_groups_anonymous(self):
796
- url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
797
- self.client.logout()
798
- response = self.client.get(url, follow=True)
799
- self.assertHttpStatus(response, 200)
800
- self.assertRedirects(response, f"/login/?next={url}")
801
-
802
- def test_get_object_dynamic_groups_without_permission(self):
803
- url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
804
- response = self.client.get(url)
805
- self.assertHttpStatus(response, [403, 404])
806
-
807
- def test_get_object_dynamic_groups_with_permission(self):
808
- url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
809
- self.add_permissions("dcim.view_device", "extras.view_dynamicgroup")
810
- response = self.client.get(url)
811
- self.assertHttpStatus(response, 200)
812
- response_body = response.content.decode(response.charset)
813
- self.assertIn("DG 1", response_body, msg=response_body)
814
- self.assertIn("DG 2", response_body, msg=response_body)
815
- self.assertIn("DG 3", response_body, msg=response_body)
816
-
817
- def test_get_object_dynamic_groups_with_constrained_permission(self):
818
- self.add_permissions("extras.view_dynamicgroup")
819
- obj_perm = ObjectPermission(
820
- name="View a device",
821
- constraints={"pk": Device.objects.first().pk},
822
- actions=["view"],
823
- )
824
- obj_perm.save()
825
- obj_perm.users.add(self.user)
826
- obj_perm.object_types.add(ContentType.objects.get_for_model(Device))
827
-
828
- url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
829
- response = self.client.get(url)
830
- self.assertHttpStatus(response, 200)
831
- response_body = response.content.decode(response.charset)
832
- self.assertIn("DG 1", response_body, msg=response_body)
833
-
834
- url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.last().pk})
835
- response = self.client.get(url)
836
- self.assertHttpStatus(response, 404)
837
-
838
784
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
839
785
  def test_edit_saved_filter(self):
840
786
  """Test that editing a filter works using the edit view."""
@@ -990,34 +936,6 @@ class GitRepositoryTestCase(
990
936
  self.form_data = form_data
991
937
  super().test_edit_object_with_constrained_permission()
992
938
 
993
- def test_post_sync_repo_anonymous(self):
994
- self.client.logout()
995
- url = reverse("extras:gitrepository_sync", kwargs={"pk": self._get_queryset().first().pk})
996
- response = self.client.post(url, follow=True)
997
- self.assertHttpStatus(response, 200)
998
- self.assertRedirects(response, f"/login/?next={url}")
999
-
1000
- def test_post_sync_repo_without_permission(self):
1001
- url = reverse("extras:gitrepository_sync", kwargs={"pk": self._get_queryset().first().pk})
1002
- response = self.client.post(url)
1003
- self.assertHttpStatus(response, [403, 404])
1004
-
1005
- # TODO: mock/stub out `enqueue_pull_git_repository_and_refresh_data` and test successful POST with permissions
1006
-
1007
- def test_post_dryrun_repo_anonymous(self):
1008
- self.client.logout()
1009
- url = reverse("extras:gitrepository_dryrun", kwargs={"pk": self._get_queryset().first().pk})
1010
- response = self.client.post(url, follow=True)
1011
- self.assertHttpStatus(response, 200)
1012
- self.assertRedirects(response, f"/login/?next={url}")
1013
-
1014
- def test_post_dryrun_repo_without_permission(self):
1015
- url = reverse("extras:gitrepository_dryrun", kwargs={"pk": self._get_queryset().first().pk})
1016
- response = self.client.post(url)
1017
- self.assertHttpStatus(response, [403, 404])
1018
-
1019
- # TODO: mock/stub out `enqueue_git_repository_diff_origin_and_local` and test successful POST with permissions
1020
-
1021
939
 
1022
940
  class NoteTestCase(
1023
941
  ViewTestCases.CreateObjectViewTestCase,
@@ -1718,34 +1636,6 @@ class JobResultTestCase(
1718
1636
  def setUpTestData(cls):
1719
1637
  JobResult.objects.create(name="pass.TestPass")
1720
1638
  JobResult.objects.create(name="fail.TestFail")
1721
- JobLogEntry.objects.create(
1722
- log_level=LogLevelChoices.LOG_INFO,
1723
- job_result=JobResult.objects.first(),
1724
- grouping="run",
1725
- message="This is a test",
1726
- )
1727
-
1728
- def test_get_joblogentrytable_anonymous(self):
1729
- url = reverse("extras:jobresult_log-table", kwargs={"pk": JobResult.objects.first().pk})
1730
- self.client.logout()
1731
- response = self.client.get(url, follow=True)
1732
- self.assertHttpStatus(response, 200)
1733
- self.assertRedirects(response, f"/login/?next={url}")
1734
-
1735
- def test_get_joblogentrytable_without_permission(self):
1736
- url = reverse("extras:jobresult_log-table", kwargs={"pk": JobResult.objects.first().pk})
1737
- response = self.client.get(url)
1738
- self.assertHttpStatus(response, [403, 404])
1739
-
1740
- def test_get_joblogentrytable_with_permission(self):
1741
- url = reverse("extras:jobresult_log-table", kwargs={"pk": JobResult.objects.first().pk})
1742
- self.add_permissions("extras.view_jobresult", "extras.view_joblogentry")
1743
- response = self.client.get(url)
1744
- self.assertHttpStatus(response, 200)
1745
- response_body = response.content.decode(response.charset)
1746
- self.assertIn("This is a test", response_body)
1747
-
1748
- # TODO test with constrained permissions on both JobResult and JobLogEntry records
1749
1639
 
1750
1640
 
1751
1641
  class JobTestCase(
@@ -2598,7 +2488,6 @@ class RelationshipTestCase(
2598
2488
  )
2599
2489
 
2600
2490
  # Try deleting all devices and then editing the 6 VLANs (fails):
2601
- Controller.objects.filter(controller_device__isnull=False).delete()
2602
2491
  Device.objects.all().delete()
2603
2492
  response = self.client.post(
2604
2493
  reverse("ipam:vlan_bulk_edit"), data={"pk": [str(vlan.id) for vlan in vlans], "_apply": [""]}
nautobot/extras/views.py CHANGED
@@ -917,7 +917,7 @@ class DynamicGroupBulkDeleteView(generic.BulkDeleteView):
917
917
  filterset = filters.DynamicGroupFilterSet
918
918
 
919
919
 
920
- class ObjectDynamicGroupsView(generic.GenericView):
920
+ class ObjectDynamicGroupsView(View):
921
921
  """
922
922
  Present a list of dynamic groups associated to a particular object.
923
923
  base_template: The name of the template to extend. If not provided, "<app>/<model>.html" will be used.
@@ -1116,18 +1116,18 @@ def check_and_call_git_repository_function(request, pk, func):
1116
1116
  messages.error(request, "Unable to run job: Celery worker process not running.")
1117
1117
  return redirect(request.get_full_path(), permanent=False)
1118
1118
  else:
1119
- repository = get_object_or_404(GitRepository.objects.restrict(request.user, "change"), pk=pk)
1119
+ repository = get_object_or_404(GitRepository, pk=pk)
1120
1120
  job_result = func(repository, request.user)
1121
1121
 
1122
1122
  return redirect(job_result.get_absolute_url())
1123
1123
 
1124
1124
 
1125
- class GitRepositorySyncView(generic.GenericView):
1125
+ class GitRepositorySyncView(View):
1126
1126
  def post(self, request, pk):
1127
1127
  return check_and_call_git_repository_function(request, pk, enqueue_pull_git_repository_and_refresh_data)
1128
1128
 
1129
1129
 
1130
- class GitRepositoryDryRunView(generic.GenericView):
1130
+ class GitRepositoryDryRunView(View):
1131
1131
  def post(self, request, pk):
1132
1132
  return check_and_call_git_repository_function(request, pk, enqueue_git_repository_diff_origin_and_local)
1133
1133
 
@@ -1806,7 +1806,7 @@ class JobResultView(generic.ObjectView):
1806
1806
  }
1807
1807
 
1808
1808
 
1809
- class JobLogEntryTableView(generic.GenericView):
1809
+ class JobLogEntryTableView(View):
1810
1810
  """
1811
1811
  Display a table of `JobLogEntry` objects for a given `JobResult` instance.
1812
1812
  """
@@ -1814,7 +1814,7 @@ class JobLogEntryTableView(generic.GenericView):
1814
1814
  queryset = JobResult.objects.all()
1815
1815
 
1816
1816
  def get(self, request, pk=None):
1817
- instance = get_object_or_404(self.queryset.restrict(request.user, "view"), pk=pk)
1817
+ instance = self.queryset.get(pk=pk)
1818
1818
  filter_q = request.GET.get("q")
1819
1819
  if filter_q:
1820
1820
  queryset = instance.job_log_entries.filter(
@@ -1893,7 +1893,7 @@ class ObjectChangeView(generic.ObjectView):
1893
1893
  }
1894
1894
 
1895
1895
 
1896
- class ObjectChangeLogView(generic.GenericView):
1896
+ class ObjectChangeLogView(View):
1897
1897
  """
1898
1898
  Present a history of changes made to a particular object.
1899
1899
  base_template: The name of the template to extend. If not provided, "<app>/<model>.html" will be used.
@@ -1979,7 +1979,7 @@ class NoteDeleteView(generic.ObjectDeleteView):
1979
1979
  queryset = Note.objects.all()
1980
1980
 
1981
1981
 
1982
- class ObjectNotesView(generic.GenericView):
1982
+ class ObjectNotesView(View):
1983
1983
  """
1984
1984
  Present a list of notes associated to a particular object.
1985
1985
  base_template: The name of the template to extend. If not provided, "<app>/<model>.html" will be used.
@@ -2000,7 +2000,7 @@ class ObjectNotesView(generic.GenericView):
2000
2000
  "assigned_object_id": obj.pk,
2001
2001
  }
2002
2002
  )
2003
- notes_table = tables.NoteTable(obj.notes.restrict(request.user, "view"))
2003
+ notes_table = tables.NoteTable(obj.notes)
2004
2004
 
2005
2005
  # Apply the request context
2006
2006
  paginate = {
@@ -2241,7 +2241,7 @@ class SecretView(generic.ObjectView):
2241
2241
  }
2242
2242
 
2243
2243
 
2244
- class SecretProviderParametersFormView(generic.GenericView):
2244
+ class SecretProviderParametersFormView(View):
2245
2245
  """
2246
2246
  Helper view to SecretView; retrieve the HTML form appropriate for entering parameters for a given SecretsProvider.
2247
2247
  """
nautobot/ipam/api/urls.py CHANGED
@@ -2,7 +2,8 @@ from nautobot.core.api.routers import OrderedDefaultRouter
2
2
 
3
3
  from . import views
4
4
 
5
- router = OrderedDefaultRouter(view_name="IPAM")
5
+ router = OrderedDefaultRouter()
6
+ router.APIRootView = views.IPAMRootView
6
7
 
7
8
  # Namespaces
8
9
  router.register("namespaces", views.NamespaceViewSet)
@@ -6,6 +6,7 @@ from rest_framework import status
6
6
  from rest_framework.decorators import action
7
7
  from rest_framework.exceptions import APIException
8
8
  from rest_framework.response import Response
9
+ from rest_framework.routers import APIRootView
9
10
 
10
11
  from nautobot.core.models.querysets import count_related
11
12
  from nautobot.core.utils.config import get_settings_or_config
@@ -31,6 +32,16 @@ from nautobot.ipam.models import (
31
32
 
32
33
  from . import serializers
33
34
 
35
+
36
+ class IPAMRootView(APIRootView):
37
+ """
38
+ IPAM API root view
39
+ """
40
+
41
+ def get_view_name(self):
42
+ return "IPAM"
43
+
44
+
34
45
  #
35
46
  # Namespace
36
47
  #
nautobot/ipam/tables.py CHANGED
@@ -42,10 +42,28 @@ UTILIZATION_GRAPH = """
42
42
  {% if record.present_in_database %}{% utilization_graph record.get_utilization %}{% else %}&mdash;{% endif %}
43
43
  """
44
44
 
45
+ PREFIX_LINK = """
46
+ {% load helpers %}
47
+ {% for i in record.ancestors.count|as_range %}
48
+ <i class="mdi mdi-circle-small"></i>
49
+ {% endfor %}
50
+ <a href="\
51
+ {% if record.present_in_database %}\
52
+ {% url 'ipam:prefix' pk=record.pk %}\
53
+ {% else %}\
54
+ {% url 'ipam:prefix_add' %}\
55
+ ?prefix={{ record }}&namespace={{ object.namespace.pk }}\
56
+ {% for loc in object.locations.all %}&locations={{ loc.pk }}{% endfor %}\
57
+ {% if object.tenant %}&tenant_group={{ object.tenant.tenant_group.pk }}&tenant={{ object.tenant.pk }}{% endif %}\
58
+ {% endif %}\
59
+ ">{{ record.prefix }}</a>
60
+ """
45
61
 
46
62
  PREFIX_COPY_LINK = """
47
63
  {% load helpers %}
48
- {% tree_hierarchy_ui_representation record.ancestors.count|as_range table.hide_hierarchy_ui%}
64
+ {% for i in record.ancestors.count|as_range %}
65
+ <i class="mdi mdi-circle-small"></i>
66
+ {% endfor %}
49
67
  <span class="hover_copy">
50
68
  <a href="\
51
69
  {% if record.present_in_database %}\
@@ -161,6 +179,7 @@ VLAN_LINK = """
161
179
  {% url 'ipam:vlan_add' %}\
162
180
  ?vid={{ record.vid }}&vlan_group={{ vlan_group.pk }}\
163
181
  {% if vlan_group.location %}&location={{ vlan_group.location.pk }}{% endif %}\
182
+ {% if vlan_group.location %}&location={{ vlan_group.location.pk }}{% endif %}\
164
183
  " class="btn btn-xs btn-success">{{ record.available }} VLAN{{ record.available|pluralize }} available</a>\
165
184
  {% else %}
166
185
  {{ record.available }} VLAN{{ record.available|pluralize }} available
@@ -350,7 +369,7 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
350
369
  namespace = tables.Column(linkify=True)
351
370
  vlan = tables.Column(linkify=True, verbose_name="VLAN")
352
371
  rir = tables.Column(linkify=True)
353
- children = tables.Column(accessor="descendants_count", orderable=False)
372
+ children = tables.Column(accessor="descendants_count")
354
373
  date_allocated = tables.DateTimeColumn()
355
374
  location_count = LinkedCountColumn(
356
375
  viewname="dcim:location_list", url_params={"prefixes": "pk"}, verbose_name="Locations"
@@ -358,6 +377,7 @@ class PrefixTable(StatusTableMixin, RoleTableMixin, BaseTable):
358
377
 
359
378
  class Meta(BaseTable.Meta):
360
379
  model = Prefix
380
+ orderable = False
361
381
  fields = (
362
382
  "pk",
363
383
  "prefix",
@@ -1,3 +1,4 @@
1
+ from django.test import override_settings
1
2
  from django.urls import reverse
2
3
  from rest_framework import status
3
4
 
@@ -8,8 +9,8 @@ class TestPrefix(APITestCase):
8
9
  def setUp(self):
9
10
  super().setUp()
10
11
  self.api_url = reverse("graphql-api")
11
- self.add_permissions("ipam.view_prefix")
12
12
 
13
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
13
14
  def test_prefix_ip_version(self):
14
15
  """Test ip_version is available for a Prefix via GraphQL."""
15
16
  get_prefixes_query = """
@@ -22,7 +23,7 @@ class TestPrefix(APITestCase):
22
23
  }
23
24
  """
24
25
  payload = {"query": get_prefixes_query}
25
- response = self.client.post(self.api_url, payload, format="json", **self.header)
26
+ response = self.client.post(self.api_url, payload, format="json")
26
27
  self.assertEqual(response.status_code, status.HTTP_200_OK)
27
28
  prefixes = response.data["data"]["prefixes"]
28
29
  self.assertIsInstance(prefixes, list)
@@ -126,7 +126,6 @@ class RIRTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
126
126
 
127
127
  class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.ListObjectsViewTestCase):
128
128
  model = Prefix
129
- filter_on_field = "prefix_length"
130
129
 
131
130
  @classmethod
132
131
  def setUpTestData(cls):
nautobot/ipam/views.py CHANGED
@@ -793,7 +793,7 @@ class IPAddressEditView(generic.ObjectEditView):
793
793
  _, error_msg = retrieve_interface_or_vminterface_from_request(request)
794
794
  if error_msg:
795
795
  messages.warning(request, error_msg)
796
- return redirect(self.get_return_url(request, default_return_url="ipam:ipaddress_add"))
796
+ return redirect(self.get_return_url(request), default_return_url="ipam:ipaddress_add")
797
797
 
798
798
  return super().dispatch(request, *args, **kwargs)
799
799
 
@@ -876,17 +876,17 @@ class IPAddressAssignView(view_mixins.GetReturnURLMixin, generic.ObjectView):
876
876
  """
877
877
 
878
878
  queryset = IPAddress.objects.all()
879
+ default_return_url = "ipam:ipaddress_add"
879
880
 
880
881
  def dispatch(self, request, *args, **kwargs):
881
- if request.user.is_authenticated:
882
- # Redirect user if an interface has not been provided
883
- if "interface" not in request.GET and "vminterface" not in request.GET:
884
- return redirect(self.get_return_url(request, default_return_url="ipam:ipaddress_add"))
882
+ # Redirect user if an interface has not been provided
883
+ if "interface" not in request.GET and "vminterface" not in request.GET:
884
+ return redirect(self.get_return_url(request))
885
885
 
886
- _, error_msg = retrieve_interface_or_vminterface_from_request(request)
887
- if error_msg:
888
- messages.warning(request, error_msg)
889
- return redirect(self.get_return_url(request, default_return_url="ipam:ipaddress_add"))
886
+ _, error_msg = retrieve_interface_or_vminterface_from_request(request)
887
+ if error_msg:
888
+ messages.warning(request, error_msg)
889
+ return redirect(self.get_return_url(request))
890
890
 
891
891
  return super().dispatch(request, *args, **kwargs)
892
892
 
@@ -27,7 +27,6 @@ body {
27
27
  transition-duration: var(--navbar-transition-duration);
28
28
  transition-timing-function: ease-in-out;
29
29
  transition-property: margin-left, width;
30
- min-height: calc(100vh - 20px);
31
30
  }
32
31
  #main-content > .form {
33
32
  margin-top: 20px;
@@ -673,27 +673,6 @@
673
673
 
674
674
 
675
675
 
676
- <li class="md-nav__item">
677
- <a href="/projects/core/en/stable/user-guide/administration/installation/health-checks.html" class="md-nav__link">
678
-
679
-
680
- <span class="md-ellipsis">
681
- Health Checks
682
- </span>
683
-
684
-
685
- </a>
686
- </li>
687
-
688
-
689
-
690
-
691
-
692
-
693
-
694
-
695
-
696
-
697
676
  <li class="md-nav__item">
698
677
  <a href="/projects/core/en/stable/user-guide/administration/installation/selinux-troubleshooting.html" class="md-nav__link">
699
678
 
@@ -1899,7 +1878,7 @@
1899
1878
 
1900
1879
 
1901
1880
  <li class="md-nav__item">
1902
- <a href="/projects/core/en/stable/user-guide/feature-guides/contacts-and-teams.html" class="md-nav__link">
1881
+ <a href="/projects/core/en/stable/user-guide/feature-guides/contact-and-team.html" class="md-nav__link">
1903
1882
 
1904
1883
 
1905
1884
  <span class="md-ellipsis">
@@ -3164,11 +3143,11 @@
3164
3143
 
3165
3144
 
3166
3145
  <li class="md-nav__item">
3167
- <a href="/projects/core/en/stable/user-guide/core-data-model/dcim/controllermanageddevicegroup.html" class="md-nav__link">
3146
+ <a href="/projects/core/en/stable/user-guide/core-data-model/dcim/controllerdevicegroup.html" class="md-nav__link">
3168
3147
 
3169
3148
 
3170
3149
  <span class="md-ellipsis">
3171
- Controller Managed Device Group
3150
+ Controller Device Group
3172
3151
  </span>
3173
3152
 
3174
3153
 
@@ -686,27 +686,6 @@
686
686
 
687
687
 
688
688
 
689
- <li class="md-nav__item">
690
- <a href="../user-guide/administration/installation/health-checks.html" class="md-nav__link">
691
-
692
-
693
- <span class="md-ellipsis">
694
- Health Checks
695
- </span>
696
-
697
-
698
- </a>
699
- </li>
700
-
701
-
702
-
703
-
704
-
705
-
706
-
707
-
708
-
709
-
710
689
  <li class="md-nav__item">
711
690
  <a href="../user-guide/administration/installation/selinux-troubleshooting.html" class="md-nav__link">
712
691
 
@@ -1912,7 +1891,7 @@
1912
1891
 
1913
1892
 
1914
1893
  <li class="md-nav__item">
1915
- <a href="../user-guide/feature-guides/contacts-and-teams.html" class="md-nav__link">
1894
+ <a href="../user-guide/feature-guides/contact-and-team.html" class="md-nav__link">
1916
1895
 
1917
1896
 
1918
1897
  <span class="md-ellipsis">
@@ -3177,11 +3156,11 @@
3177
3156
 
3178
3157
 
3179
3158
  <li class="md-nav__item">
3180
- <a href="../user-guide/core-data-model/dcim/controllermanageddevicegroup.html" class="md-nav__link">
3159
+ <a href="../user-guide/core-data-model/dcim/controllerdevicegroup.html" class="md-nav__link">
3181
3160
 
3182
3161
 
3183
3162
  <span class="md-ellipsis">
3184
- Controller Managed Device Group
3163
+ Controller Device Group
3185
3164
  </span>
3186
3165
 
3187
3166