From 0f44f7eb20ebf10dd0418d42c57c6511986a262b Mon Sep 17 00:00:00 2001 From: Devon Mar Date: Sun, 14 May 2023 01:08:25 -0700 Subject: [PATCH 01/74] Use .font-monospace instead of .text-monospace --- netbox/templates/dcim/interface.html | 4 ++-- netbox/templates/virtualization/vminterface.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/netbox/templates/dcim/interface.html b/netbox/templates/dcim/interface.html index db0fd7dfd..11f262eeb 100644 --- a/netbox/templates/dcim/interface.html +++ b/netbox/templates/dcim/interface.html @@ -123,11 +123,11 @@ - + - + diff --git a/netbox/templates/virtualization/vminterface.html b/netbox/templates/virtualization/vminterface.html index a7d4d92ba..82071bdaa 100644 --- a/netbox/templates/virtualization/vminterface.html +++ b/netbox/templates/virtualization/vminterface.html @@ -59,7 +59,7 @@ - + From c65b2a080f693d858078faabfbdfb3b1967cfa2a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 15 May 2023 09:13:11 -0400 Subject: [PATCH 02/74] Changelog for #11017, #12468 --- docs/release-notes/version-3.5.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 39e159268..b101a7912 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -5,6 +5,7 @@ ### Enhancements * [#7671](https://github.com/netbox-community/netbox/issues/7671) - Introduce `REMOTE_AUTH_AUTO_CREATE_GROUPS` config parameter to enable the automatic creation of new groups when remote authentication is in use +* [#11017](https://github.com/netbox-community/netbox/issues/11017) - Increase the maximum values for allocated and maximum power draws * [#11233](https://github.com/netbox-community/netbox/issues/11233) - Intercept and cleanly report errors upon attempted database writes when maintenance mode is enabled * [#11599](https://github.com/netbox-community/netbox/issues/11599) - Move contacts panels to separate tabs under object views * [#11670](https://github.com/netbox-community/netbox/issues/11670) - Enable setting device type & module type weight via bulk import @@ -20,6 +21,7 @@ ### Bug Fixes * [#10686](https://github.com/netbox-community/netbox/issues/10686) - Enable specifying termination object by virtual chassis master when importing cables +* [#12468](https://github.com/netbox-community/netbox/issues/12468) - Custom field names should not permit double underscores * [#12550](https://github.com/netbox-community/netbox/issues/12550) - Fix rear port selection widget under front port creation form * [#12570](https://github.com/netbox-community/netbox/issues/12570) - Disable ordering of synchronized object tables by the "synced" attribute From 0ad88e24312c256ef0a3189c71009d5b8d97cdf5 Mon Sep 17 00:00:00 2001 From: kkthxbye <400797+kkthxbye-code@users.noreply.github.com> Date: Tue, 16 May 2023 08:19:57 +0200 Subject: [PATCH 03/74] Changed docs to reflect the new URL for the dynamic API documentation --- docs/integrations/rest-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/integrations/rest-api.md b/docs/integrations/rest-api.md index af2f86e4c..cf3d11126 100644 --- a/docs/integrations/rest-api.md +++ b/docs/integrations/rest-api.md @@ -63,7 +63,7 @@ Each attribute of the IP address is expressed as an attribute of the JSON object ## Interactive Documentation -Comprehensive, interactive documentation of all REST API endpoints is available on a running NetBox instance at `/api/docs/`. This interface provides a convenient sandbox for researching and experimenting with specific endpoints and request types. The API itself can also be explored using a web browser by navigating to its root at `/api/`. +Comprehensive, interactive documentation of all REST API endpoints is available on a running NetBox instance at `/api/schema/swagger-ui/`. This interface provides a convenient sandbox for researching and experimenting with specific endpoints and request types. The API itself can also be explored using a web browser by navigating to its root at `/api/`. ## Endpoint Hierarchy From d5be59ef67c4a48698543ee9fe0c3d53254578bd Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 16 May 2023 08:39:05 -0400 Subject: [PATCH 04/74] Update README --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 480f0f856..81217797f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@
+ The :ballot_box_with_check: 2023 NetBox Community Survey is now open! +

Please take a few minutes to tell us about your NetBox deployment.

+ NetBox logo - - The premiere source of truth powering network automation +

The premiere source of truth powering network automation

+ CI status +

-![Master branch build status](https://github.com/netbox-community/netbox/workflows/CI/badge.svg?branch=master) - NetBox is the leading solution for modeling and documenting modern networks. By combining the traditional disciplines of IP address management (IPAM) and datacenter infrastructure management (DCIM) with powerful APIs and extensions, From eeb15ab5d1531b6502734c5592755f498d2bcf7c Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 15 May 2023 14:22:45 -0700 Subject: [PATCH 05/74] 12594 add config context to object count / list widget --- netbox/extras/dashboard/widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py index 69d1cc36d..dc68e1388 100644 --- a/netbox/extras/dashboard/widgets.py +++ b/netbox/extras/dashboard/widgets.py @@ -35,7 +35,8 @@ def get_content_type_labels(): return [ (content_type_identifier(ct), content_type_name(ct)) for ct in ContentType.objects.filter( - FeatureQuery('export_templates').get_query() | Q(app_label='extras', model='objectchange') + FeatureQuery('export_templates').get_query() | Q(app_label='extras', model='objectchange') | + Q(app_label='extras', model='configcontext') ).order_by('app_label', 'model') ] From 0df6a5793aefd64172d4e62f02e9d592dc715330 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Tue, 16 May 2023 08:35:21 -0700 Subject: [PATCH 06/74] Adds maintenance exempt paths (#12592) * adds maintenance exempt paths #11233 * adds maintenance exempt paths #11233 * Rename method & remove login/logout from exempt paths --------- Co-authored-by: jeremystretch --- netbox/netbox/middleware.py | 14 +++++++++----- netbox/netbox/settings.py | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/netbox/netbox/middleware.py b/netbox/netbox/middleware.py index 461c018b9..76b3e42a8 100644 --- a/netbox/netbox/middleware.py +++ b/netbox/netbox/middleware.py @@ -181,19 +181,23 @@ class MaintenanceModeMiddleware: def __call__(self, request): if get_config().MAINTENANCE_MODE: - self._prevent_db_write_operations() + self._set_session_type( + allow_write=request.path_info.startswith(settings.MAINTENANCE_EXEMPT_PATHS) + ) return self.get_response(request) @staticmethod - def _prevent_db_write_operations(): + def _set_session_type(allow_write): """ Prevent any write-related database operations. + + Args: + allow_write (bool): If True, write operations will be permitted. """ with connection.cursor() as cursor: - cursor.execute( - 'SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY;' - ) + mode = 'READ WRITE' if allow_write else 'READ ONLY' + cursor.execute(f'SET SESSION CHARACTERISTICS AS TRANSACTION {mode};') def process_exception(self, request, exception): """ diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 575755d2b..4d2dd8a81 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -478,6 +478,11 @@ AUTH_EXEMPT_PATHS = ( f'/{BASE_PATH}metrics', ) +# All URLs starting with a string listed here are exempt from maintenance mode enforcement +MAINTENANCE_EXEMPT_PATHS = ( + f'/{BASE_PATH}admin/', +) + SERIALIZATION_MODULES = { 'json': 'utilities.serializers.json', } From 2204735e9fbe93b1c77ba047a85845b9fdaffc41 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Tue, 16 May 2023 11:10:44 -0700 Subject: [PATCH 07/74] Adds rq retry options (#12588) * adds rq retry options #12327 * Clean up docs; disable retries of failed jobs by default * Pass a Retry object only if RQ_RETRY_MAX is non-zero --------- Co-authored-by: jeremystretch --- docs/configuration/miscellaneous.md | 22 ++++++++++++++++++++++ netbox/core/models/jobs.py | 5 +++-- netbox/extras/webhooks.py | 4 +++- netbox/netbox/settings.py | 2 ++ netbox/utilities/rqworker.py | 14 +++++++++++++- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index e3728acab..fd410a9d4 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -204,3 +204,25 @@ This parameter defines the URL of the repository that will be checked for new Ne Default: `300` The maximum execution time of a background task (such as running a custom script), in seconds. + +--- + +## RQ_RETRY_INTERVAL + +!!! note + This parameter was added in NetBox v3.5. + +Default: `60` + +This parameter controls how frequently a failed job is retried, up to the maximum number of times specified by `RQ_RETRY_MAX`. This must be either an integer specifying the number of seconds to wait between successive attempts, or a list of such values. For example, `[60, 300, 3600]` will retry the task after 1 minute, 5 minutes, and 1 hour. + +--- + +## RQ_RETRY_MAX + +!!! note + This parameter was added in NetBox v3.5. + +Default: `0` (retries disabled) + +The maximum number of times a background task will be retried before being marked as failed. diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 1d0eecd21..a91e75e61 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -16,7 +16,7 @@ from extras.utils import FeatureQuery from netbox.config import get_config from netbox.constants import RQ_QUEUE_DEFAULT from utilities.querysets import RestrictedQuerySet -from utilities.rqworker import get_queue_for_model +from utilities.rqworker import get_queue_for_model, get_rq_retry __all__ = ( 'Job', @@ -219,5 +219,6 @@ class Job(models.Model): event=event, data=self.data, timestamp=str(timezone.now()), - username=self.user.username + username=self.user.username, + retry=get_rq_retry() ) diff --git a/netbox/extras/webhooks.py b/netbox/extras/webhooks.py index 23702949a..1fc869ee8 100644 --- a/netbox/extras/webhooks.py +++ b/netbox/extras/webhooks.py @@ -9,6 +9,7 @@ from netbox.config import get_config from netbox.constants import RQ_QUEUE_DEFAULT from netbox.registry import registry from utilities.api import get_serializer_for_model +from utilities.rqworker import get_rq_retry from utilities.utils import serialize_object from .choices import * from .models import Webhook @@ -116,5 +117,6 @@ def flush_webhooks(queue): snapshots=data['snapshots'], timestamp=str(timezone.now()), username=data['username'], - request_id=data['request_id'] + request_id=data['request_id'], + retry=get_rq_retry() ) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 4d2dd8a81..d6d5c84ca 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -140,6 +140,8 @@ REMOTE_AUTH_STAFF_USERS = getattr(configuration, 'REMOTE_AUTH_STAFF_USERS', []) REMOTE_AUTH_GROUP_SEPARATOR = getattr(configuration, 'REMOTE_AUTH_GROUP_SEPARATOR', '|') REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/') RQ_DEFAULT_TIMEOUT = getattr(configuration, 'RQ_DEFAULT_TIMEOUT', 300) +RQ_RETRY_INTERVAL = getattr(configuration, 'RQ_RETRY_INTERVAL', 60) +RQ_RETRY_MAX = getattr(configuration, 'RQ_RETRY_MAX', 0) SCRIPTS_ROOT = getattr(configuration, 'SCRIPTS_ROOT', os.path.join(BASE_DIR, 'scripts')).rstrip('/') SEARCH_BACKEND = getattr(configuration, 'SEARCH_BACKEND', 'netbox.search.backends.CachedValueSearchBackend') SECURE_SSL_REDIRECT = getattr(configuration, 'SECURE_SSL_REDIRECT', False) diff --git a/netbox/utilities/rqworker.py b/netbox/utilities/rqworker.py index 5866dfee0..61f594767 100644 --- a/netbox/utilities/rqworker.py +++ b/netbox/utilities/rqworker.py @@ -1,11 +1,12 @@ from django_rq.queues import get_connection -from rq import Worker +from rq import Retry, Worker from netbox.config import get_config from netbox.constants import RQ_QUEUE_DEFAULT __all__ = ( 'get_queue_for_model', + 'get_rq_retry', 'get_workers_for_queue', ) @@ -22,3 +23,14 @@ def get_workers_for_queue(queue_name): Returns True if a worker process is currently servicing the specified queue. """ return Worker.count(get_connection(queue_name)) + + +def get_rq_retry(): + """ + If RQ_RETRY_MAX is defined and greater than zero, instantiate and return a Retry object to be + used when queuing a job. Otherwise, return None. + """ + retry_max = get_config().RQ_RETRY_MAX + retry_interval = get_config().RQ_RETRY_INTERVAL + if retry_max: + return Retry(max=retry_max, interval=retry_interval) From 92c49669f96d8f6427f7ec4e4ea83712362f5680 Mon Sep 17 00:00:00 2001 From: Arthur Date: Thu, 18 May 2023 10:40:41 -0700 Subject: [PATCH 08/74] 12548 add prefetch_related for l2vpn and vdcs to interface api --- netbox/dcim/api/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 0d9fcdc5f..a62315b57 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -493,7 +493,8 @@ class PowerOutletViewSet(PathEndpointMixin, NetBoxModelViewSet): class InterfaceViewSet(PathEndpointMixin, NetBoxModelViewSet): queryset = Interface.objects.prefetch_related( 'device', 'module__module_bay', 'parent', 'bridge', 'lag', '_path', 'cable__terminations', 'wireless_lans', - 'untagged_vlan', 'tagged_vlans', 'vrf', 'ip_addresses', 'fhrp_group_assignments', 'tags' + 'untagged_vlan', 'tagged_vlans', 'vrf', 'ip_addresses', 'fhrp_group_assignments', 'tags', 'l2vpn_terminations', + 'vdcs', ) serializer_class = serializers.InterfaceSerializer filterset_class = filtersets.InterfaceFilterSet From 23b21246f078989b6cc8a51eaac54efde001700a Mon Sep 17 00:00:00 2001 From: neope <58367950+apellini@users.noreply.github.com> Date: Thu, 18 May 2023 20:21:32 +0200 Subject: [PATCH 09/74] Adding CDFP and CFP8 400GE connectors (#12646) * Adding CDFP and CFP8 400GE connectors * Update choices.py typo on CFP8 --- netbox/dcim/choices.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index d32f5aaee..4586f2111 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -814,6 +814,8 @@ class InterfaceTypeChoices(ChoiceSet): TYPE_200GE_QSFP56 = '200gbase-x-qsfp56' TYPE_400GE_QSFP_DD = '400gbase-x-qsfpdd' TYPE_400GE_OSFP = '400gbase-x-osfp' + TYPE_400GE_CDFP = '400gbase-x-cdfp' + TYPE_400GE_CFP8 = '400gbase-x-cfp8' TYPE_800GE_QSFP_DD = '800gbase-x-qsfpdd' TYPE_800GE_OSFP = '800gbase-x-osfp' @@ -959,6 +961,8 @@ class InterfaceTypeChoices(ChoiceSet): (TYPE_200GE_QSFP56, 'QSFP56 (200GE)'), (TYPE_400GE_QSFP_DD, 'QSFP-DD (400GE)'), (TYPE_400GE_OSFP, 'OSFP (400GE)'), + (TYPE_400GE_CDFP, 'CDFP (400GE)'), + (TYPE_400GE_CFP8, 'CPF8 (400GE)'), (TYPE_800GE_QSFP_DD, 'QSFP-DD (800GE)'), (TYPE_800GE_OSFP, 'OSFP (800GE)'), ) From 311dce0b5f2adaf124f5a8d4a3fb2ccdf0b46f9d Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank Date: Mon, 15 May 2023 10:20:35 -0500 Subject: [PATCH 10/74] Closes #12605: Add LX.5 port type --- netbox/dcim/choices.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index 4586f2111..c256761c7 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -1227,6 +1227,10 @@ class PortTypeChoices(ChoiceSet): TYPE_LSH_PC = 'lsh-pc' TYPE_LSH_UPC = 'lsh-upc' TYPE_LSH_APC = 'lsh-apc' + TYPE_LX5 = 'lx5' + TYPE_LX5_PC = 'lx5-pc' + TYPE_LX5_UPC = 'lx5-upc' + TYPE_LX5_APC = 'lx5-apc' TYPE_SPLICE = 'splice' TYPE_CS = 'cs' TYPE_SN = 'sn' @@ -1273,6 +1277,10 @@ class PortTypeChoices(ChoiceSet): (TYPE_LSH_PC, 'LSH/PC'), (TYPE_LSH_UPC, 'LSH/UPC'), (TYPE_LSH_APC, 'LSH/APC'), + (TYPE_LX5, 'LX.5'), + (TYPE_LX5_PC, 'LX.5/PC'), + (TYPE_LX5_UPC, 'LX.5/UPC'), + (TYPE_LX5_APC, 'LX.5/APC'), (TYPE_MPO, 'MPO'), (TYPE_MTRJ, 'MTRJ'), (TYPE_SC, 'SC'), From c8d9a3b4eb58221b3806113718e50b29dcfe947c Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 18 May 2023 14:34:13 -0400 Subject: [PATCH 11/74] Changelog for #12327, #12548, #12594, #12605, #12629 --- docs/release-notes/version-3.5.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index b101a7912..4a77934b5 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -15,8 +15,12 @@ * [#12233](https://github.com/netbox-community/netbox/issues/12233) - Move related IP addresses table to a separate tab * [#12286](https://github.com/netbox-community/netbox/issues/12286) - Show height and total weight under device view * [#12323](https://github.com/netbox-community/netbox/issues/12323) - Add 100GE CXP interface type +* [#12327](https://github.com/netbox-community/netbox/issues/12327) - Introduce the ability to automatically retry failed background jobs * [#12498](https://github.com/netbox-community/netbox/issues/12498) - Hide map button if `MAPS_URL` is empty +* [#12548](https://github.com/netbox-community/netbox/issues/12548) - Optimize REST API performance when retrieving interfaces with L2VPN assignments * [#12554](https://github.com/netbox-community/netbox/issues/12554) - Allow customization or disabling of the maintenance mode banner +* [#12605](https://github.com/netbox-community/netbox/issues/12605) - Add LX.5 port types +* [#12629](https://github.com/netbox-community/netbox/issues/12629) - Add 400GE CDFP and CFP8 interface types ### Bug Fixes @@ -24,6 +28,7 @@ * [#12468](https://github.com/netbox-community/netbox/issues/12468) - Custom field names should not permit double underscores * [#12550](https://github.com/netbox-community/netbox/issues/12550) - Fix rear port selection widget under front port creation form * [#12570](https://github.com/netbox-community/netbox/issues/12570) - Disable ordering of synchronized object tables by the "synced" attribute +* [#12594](https://github.com/netbox-community/netbox/issues/12594) - Enable selecting config context as object type in object counts dashboard widget --- From fa3bedb947f6cb166bf8f1a6b6d0e57a875006c1 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 22 May 2023 13:07:40 -0400 Subject: [PATCH 12/74] Fixes #12642: Fix bulk tenant assignment via cluster import form --- docs/release-notes/version-3.5.md | 1 + netbox/virtualization/forms/bulk_import.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 4a77934b5..79d9d12b7 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -29,6 +29,7 @@ * [#12550](https://github.com/netbox-community/netbox/issues/12550) - Fix rear port selection widget under front port creation form * [#12570](https://github.com/netbox-community/netbox/issues/12570) - Disable ordering of synchronized object tables by the "synced" attribute * [#12594](https://github.com/netbox-community/netbox/issues/12594) - Enable selecting config context as object type in object counts dashboard widget +* [#12642](https://github.com/netbox-community/netbox/issues/12642) - Fix bulk tenant assignment via cluster import form --- diff --git a/netbox/virtualization/forms/bulk_import.py b/netbox/virtualization/forms/bulk_import.py index a229bd935..15651f2ae 100644 --- a/netbox/virtualization/forms/bulk_import.py +++ b/netbox/virtualization/forms/bulk_import.py @@ -65,7 +65,7 @@ class ClusterImportForm(NetBoxModelImportForm): class Meta: model = Cluster - fields = ('name', 'type', 'group', 'status', 'site', 'description', 'comments', 'tags') + fields = ('name', 'type', 'group', 'status', 'site', 'tenant', 'description', 'comments', 'tags') class VirtualMachineImportForm(NetBoxModelImportForm): From 80fc8db514486448f406e1f695b18ac255f54997 Mon Sep 17 00:00:00 2001 From: "Daniel W. Anner" Date: Mon, 22 May 2023 14:22:33 +0000 Subject: [PATCH 13/74] Adding interface type `200gbase-x-qsfpdd` --- netbox/dcim/choices.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netbox/dcim/choices.py b/netbox/dcim/choices.py index c256761c7..cc388b750 100644 --- a/netbox/dcim/choices.py +++ b/netbox/dcim/choices.py @@ -812,6 +812,7 @@ class InterfaceTypeChoices(ChoiceSet): TYPE_100GE_QSFP28 = '100gbase-x-qsfp28' TYPE_200GE_CFP2 = '200gbase-x-cfp2' TYPE_200GE_QSFP56 = '200gbase-x-qsfp56' + TYPE_200GE_QSFP_DD = '200gbase-x-qsfpdd' TYPE_400GE_QSFP_DD = '400gbase-x-qsfpdd' TYPE_400GE_OSFP = '400gbase-x-osfp' TYPE_400GE_CDFP = '400gbase-x-cdfp' @@ -959,6 +960,7 @@ class InterfaceTypeChoices(ChoiceSet): (TYPE_100GE_CPAK, 'Cisco CPAK (100GE)'), (TYPE_100GE_QSFP28, 'QSFP28 (100GE)'), (TYPE_200GE_QSFP56, 'QSFP56 (200GE)'), + (TYPE_200GE_QSFP_DD, 'QSFP-DD (200GE)'), (TYPE_400GE_QSFP_DD, 'QSFP-DD (400GE)'), (TYPE_400GE_OSFP, 'OSFP (400GE)'), (TYPE_400GE_CDFP, 'CDFP (400GE)'), From 078893e0341f433ec975eb595acedfaf1c537955 Mon Sep 17 00:00:00 2001 From: Dillon Henschen Date: Mon, 22 May 2023 15:37:31 -0400 Subject: [PATCH 14/74] Closes #11619: Include VLANs with a null site in query during bulk interface edit for Devices > DEVICE COMPONENTS > Interfaces (#12659) * Closes #11619: Allow VLANs without a site during multi-port edits This commit allows users to be able to select VLANs without a site assignment during bulk interfaces edits under Devices > DEVICE COMPONENTS > Interfaces. Prior to this commit, only VLANs that were assigned the same site as the device were available for selection. * Replace 'null' with FILTERS_NULL_CHOICE_VALUE constant --------- Co-authored-by: jeremystretch --- netbox/dcim/forms/bulk_edit.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index 6ed483c79..bc9693afb 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -1,4 +1,5 @@ from django import forms +from django.conf import settings from django.contrib.auth.models import User from django.utils.translation import gettext as _ from timezone_field import TimeZoneFormField @@ -1292,8 +1293,13 @@ class InterfaceBulkEditForm( break if site is not None: - self.fields['untagged_vlan'].widget.add_query_param('site_id', site.pk) - self.fields['tagged_vlans'].widget.add_query_param('site_id', site.pk) + # Query for VLANs assigned to the same site and VLANs with no site assigned (null). + self.fields['untagged_vlan'].widget.add_query_param( + 'site_id', [site.pk, settings.FILTERS_NULL_CHOICE_VALUE] + ) + self.fields['tagged_vlans'].widget.add_query_param( + 'site_id', [site.pk, settings.FILTERS_NULL_CHOICE_VALUE] + ) self.fields['parent'].choices = () self.fields['parent'].widget.attrs['disabled'] = True From 005e3fd6926aa12ebd8e5c22ce6c1538bea19ad0 Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank <94914780+decoupca@users.noreply.github.com> Date: Mon, 22 May 2023 15:16:17 -0500 Subject: [PATCH 15/74] Closes #9068: validate addresses assigned to interfaces (#12618) * Begin logic * Closes #9068: Disallow assigning bcast/networks to interfaces * Allow net IDs in /31, /32, /127, /128 * linting error * Implement requested changes * Condensed the "if" logic a bit --------- Co-authored-by: Austin de Coup-Crank Co-authored-by: jeremystretch --- netbox/ipam/forms/model_forms.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index cf8117bf7..ac75e2cc3 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -351,6 +351,18 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): 'primary_for_parent', "Only IP addresses assigned to an interface can be designated as primary IPs." ) + # Do not allow assigning a network ID or broadcast address to an interface. + if interface and (address := self.cleaned_data.get('address')): + if address.ip == address.network: + msg = f"{address} is a network ID, which may not be assigned to an interface." + if address.version == 4 and address.prefixlen not in (31, 32): + raise ValidationError(msg) + if address.version == 6 and address.prefixlen not in (127, 128): + raise ValidationError(msg) + if address.ip == address.broadcast: + msg = f"{address} is a broadcast address, which may not be assigned to an interface." + raise ValidationError(msg) + def save(self, *args, **kwargs): ipaddress = super().save(*args, **kwargs) From fbc7811f56040aee5d7dd0f6be568665172d5ba2 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 22 May 2023 16:24:30 -0400 Subject: [PATCH 16/74] Release v3.5.2 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- docs/release-notes/version-3.5.md | 5 ++++- netbox/netbox/settings.py | 2 +- requirements.txt | 14 +++++++------- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index be2aacff5..1a0e68929 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.5.1 + placeholder: v3.5.2 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index fcb3516b4..526057454 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.5.1 + placeholder: v3.5.2 validations: required: true - type: dropdown diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 79d9d12b7..24d1ce2dc 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -1,10 +1,11 @@ # NetBox v3.5 -## v3.5.2 (FUTURE) +## v3.5.2 (2023-05-22) ### Enhancements * [#7671](https://github.com/netbox-community/netbox/issues/7671) - Introduce `REMOTE_AUTH_AUTO_CREATE_GROUPS` config parameter to enable the automatic creation of new groups when remote authentication is in use +* [#9068](https://github.com/netbox-community/netbox/issues/9068) - Disallow the assignment of network/broadcast IP addresses to interfaces * [#11017](https://github.com/netbox-community/netbox/issues/11017) - Increase the maximum values for allocated and maximum power draws * [#11233](https://github.com/netbox-community/netbox/issues/11233) - Intercept and cleanly report errors upon attempted database writes when maintenance mode is enabled * [#11599](https://github.com/netbox-community/netbox/issues/11599) - Move contacts panels to separate tabs under object views @@ -21,10 +22,12 @@ * [#12554](https://github.com/netbox-community/netbox/issues/12554) - Allow customization or disabling of the maintenance mode banner * [#12605](https://github.com/netbox-community/netbox/issues/12605) - Add LX.5 port types * [#12629](https://github.com/netbox-community/netbox/issues/12629) - Add 400GE CDFP and CFP8 interface types +* [#12678](https://github.com/netbox-community/netbox/issues/12678) - Add 200GE QSFP-DD interface type ### Bug Fixes * [#10686](https://github.com/netbox-community/netbox/issues/10686) - Enable specifying termination object by virtual chassis master when importing cables +* [#11619](https://github.com/netbox-community/netbox/issues/11619) - Enable assigning VLANs without a site to interfaces during bulk edit * [#12468](https://github.com/netbox-community/netbox/issues/12468) - Custom field names should not permit double underscores * [#12550](https://github.com/netbox-community/netbox/issues/12550) - Fix rear port selection widget under front port creation form * [#12570](https://github.com/netbox-community/netbox/issues/12570) - Disable ordering of synchronized object tables by the "synced" attribute diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index d6d5c84ca..a5923c9f0 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW # Environment setup # -VERSION = '3.5.2-dev' +VERSION = '3.5.2' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index c3d9c8c38..6757f3260 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ bleach==6.0.0 -boto3==1.26.127 +boto3==1.26.138 Django==4.1.9 -django-cors-headers==3.14.0 -django-debug-toolbar==4.0.0 +django-cors-headers==4.0.0 +django-debug-toolbar==4.1.0 django-filter==23.2 django-graphiql-debug-toolbar==0.2.0 django-mptt==0.14 @@ -10,7 +10,7 @@ django-pglocks==1.0.4 django-prometheus==2.3.1 django-redis==5.2.0 django-rich==1.5.0 -django-rq==2.8.0 +django-rq==2.8.1 django-tables2==2.5.3 django-taggit==4.0.0 django-timezone-field==5.0 @@ -19,17 +19,17 @@ drf-spectacular==0.26.2 drf-spectacular-sidecar==2023.5.1 dulwich==0.21.5 feedparser==6.0.10 -graphene-django==3.0.0 +graphene-django==3.0.2 gunicorn==20.1.0 Jinja2==3.1.2 Markdown==3.3.7 -mkdocs-material==9.1.9 +mkdocs-material==9.1.14 mkdocstrings[python-legacy]==0.21.2 netaddr==0.8.0 Pillow==9.5.0 psycopg2-binary==2.9.6 PyYAML==6.0 -sentry-sdk==1.22.1 +sentry-sdk==1.23.1 social-auth-app-django==5.2.0 social-auth-core[openidconnect]==4.4.2 svgwrite==1.4.3 From 6160e034263e44334d55055a1a0a4286b25008cf Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 22 May 2023 17:00:29 -0400 Subject: [PATCH 17/74] PRVB --- docs/release-notes/version-3.5.md | 4 ++++ netbox/netbox/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 24d1ce2dc..e36a1f3b4 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -1,5 +1,9 @@ # NetBox v3.5 +## v3.5.3 (FUTURE) + +--- + ## v3.5.2 (2023-05-22) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index a5923c9f0..354e6e3a9 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW # Environment setup # -VERSION = '3.5.2' +VERSION = '3.5.3-dev' # Hostname HOSTNAME = platform.node() From b31b086a4d6518d143f2f1837391379ea9b94fc9 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 23 May 2023 15:34:03 -0400 Subject: [PATCH 18/74] Link to the plugin ideas board --- .github/ISSUE_TEMPLATE/config.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 1f8fdebd4..e6a5e76c2 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,10 +3,13 @@ blank_issues_enabled: false contact_links: - name: 📖 Contributing Policy url: https://github.com/netbox-community/netbox/blob/develop/CONTRIBUTING.md - about: "Please read through our contributing policy before opening an issue or pull request" + about: "Please read through our contributing policy before opening an issue or pull request." - name: ❓ Discussion url: https://github.com/netbox-community/netbox/discussions - about: "If you're just looking for help, try starting a discussion instead" + about: "If you're just looking for help, try starting a discussion instead." + - name: 💡 Plugin Idea + url: https://plugin-ideas.netbox.dev + about: "Have an idea for a plugin? Head over to the ideas board!" - name: 💬 Community Slack - url: https://netdev.chat/ - about: "Join #netbox on the NetDev Community Slack for assistance with installation issues and other problems" + url: https://netdev.chat + about: "Join #netbox on the NetDev Community Slack for assistance with installation issues and other problems." From bf1c191b2e9a52ecb122d3e4c456b9be3bcfa032 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 24 May 2023 15:45:24 -0400 Subject: [PATCH 19/74] Fixes #12694: Strip leading & trailing whitespace from custom link URL & text --- docs/release-notes/version-3.5.md | 4 ++++ netbox/extras/models/models.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index e36a1f3b4..1154d4fcd 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -2,6 +2,10 @@ ## v3.5.3 (FUTURE) +### Bug Fixes + +* [#12694](https://github.com/netbox-community/netbox/issues/12694) - Strip leading & trailing whitespace from custom link URL & text + --- ## v3.5.2 (2023-05-22) diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 16e4fb577..9433ab6b0 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -274,10 +274,10 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): :param context: The context passed to Jinja2 """ - text = render_jinja2(self.link_text, context) + text = render_jinja2(self.link_text, context).strip() if not text: return {} - link = render_jinja2(self.link_url, context) + link = render_jinja2(self.link_url, context).strip() link_target = ' target="_blank"' if self.new_window else '' # Sanitize link text From 24a51dd86e213cedf561bfb84853a4bb484ec211 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 25 May 2023 15:20:08 -0400 Subject: [PATCH 20/74] Fixes #11539: Use BooleanFilter for 'empty' lookups (#11784) * Use BooleanFilter for 'empty' lookups * Always use BooleanFilter for 'empty' lookups * Restore Empty lookup logic --- netbox/extras/lookups.py | 12 +++++++----- netbox/netbox/filtersets.py | 11 ++++++++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/netbox/extras/lookups.py b/netbox/extras/lookups.py index 77fe2301e..a8d89c943 100644 --- a/netbox/extras/lookups.py +++ b/netbox/extras/lookups.py @@ -7,12 +7,14 @@ class Empty(Lookup): Filter on whether a string is empty. """ lookup_name = 'empty' + prepare_rhs = False - def as_sql(self, qn, connection): - lhs, lhs_params = self.process_lhs(qn, connection) - rhs, rhs_params = self.process_rhs(qn, connection) - params = lhs_params + rhs_params - return 'CAST(LENGTH(%s) AS BOOLEAN) != %s' % (lhs, rhs), params + def as_sql(self, compiler, connection): + sql, params = compiler.compile(self.lhs) + if self.rhs: + return f"CAST(LENGTH({sql}) AS BOOLEAN) IS NOT TRUE", params + else: + return f"CAST(LENGTH({sql}) AS BOOLEAN) IS TRUE", params class NetContainsOrEquals(Lookup): diff --git a/netbox/netbox/filtersets.py b/netbox/netbox/filtersets.py index a0c1edee8..9a2385c45 100644 --- a/netbox/netbox/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -177,7 +177,8 @@ class BaseFilterSet(django_filters.FilterSet): # create the new filter with the same type because there is no guarantee the defined type # is the same as the default type for the field resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid - new_filter = type(existing_filter)( + filter_cls = django_filters.BooleanFilter if lookup_expr == 'empty' else type(existing_filter) + new_filter = filter_cls( field_name=field_name, lookup_expr=lookup_expr, label=existing_filter.label, @@ -224,6 +225,14 @@ class BaseFilterSet(django_filters.FilterSet): return filters + @classmethod + def filter_for_lookup(cls, field, lookup_type): + + if lookup_type == 'empty': + return django_filters.BooleanFilter, {} + + return super().filter_for_lookup(field, lookup_type) + class ChangeLoggedModelFilterSet(BaseFilterSet): """ From b64b19a3f4011be1fc3889d2668b26e3135cadf2 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 25 May 2023 16:42:24 -0400 Subject: [PATCH 21/74] Fixes #11934: Prevent reassignment of an IP address designated as primary for its parent object --- docs/release-notes/version-3.5.md | 1 + netbox/ipam/forms/model_forms.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 1154d4fcd..816fe124c 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -4,6 +4,7 @@ ### Bug Fixes +* [#11934](https://github.com/netbox-community/netbox/issues/11934) - Prevent reassignment of an IP address designated as primary for its parent object * [#12694](https://github.com/netbox-community/netbox/issues/12694) - Strip leading & trailing whitespace from custom link URL & text --- diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index ac75e2cc3..eb6dbe598 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -328,6 +328,12 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): ): self.initial['primary_for_parent'] = True + # Disable object assignment fields if the IP address is designated as primary + if self.initial.get('primary_for_parent'): + self.fields['interface'].disabled = True + self.fields['vminterface'].disabled = True + self.fields['fhrpgroup'].disabled = True + def clean(self): super().clean() @@ -340,7 +346,12 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): selected_objects[1]: "An IP address can only be assigned to a single object." }) elif selected_objects: - self.instance.assigned_object = self.cleaned_data[selected_objects[0]] + assigned_object = self.cleaned_data[selected_objects[0]] + if self.cleaned_data['primary_for_parent'] and assigned_object != self.instance.assigned_object: + raise ValidationError( + "Cannot reassign IP address while it is designated as the primary IP for the parent object" + ) + self.instance.assigned_object = assigned_object else: self.instance.assigned_object = None From e2f9a3c07a3c3c586ed43e6dbcedded002bb271c Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Fri, 26 May 2023 13:21:42 +0530 Subject: [PATCH 22/74] fixes contact assignments filter to include parent content type #12730 --- netbox/tenancy/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 5f8a7e314..c2ef4b487 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -29,7 +29,10 @@ class ObjectContactsView(generic.ObjectChildrenView): def get_children(self, request, parent): return Contact.objects.annotate( assignment_count=count_related(ContactAssignment, 'contact') - ).restrict(request.user, 'view').filter(assignments__object_id=parent.pk) + ).restrict(request.user, 'view').filter( + assignments__content_type=ContentType.objects.get_for_model(parent), + assignments__object_id=parent.pk + ) def get_extra_context(self, request, instance): return { From 5869894a48ba8b3384d44f564d47adad5df141c3 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Fri, 26 May 2023 18:16:49 +0530 Subject: [PATCH 23/74] Adds ip to failed logs (#12725) * adds ip to failed logs #12562 * added additional logging when client ip cannot be determined --- netbox/users/signals.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/netbox/users/signals.py b/netbox/users/signals.py index 8915af1dc..98036d5d1 100644 --- a/netbox/users/signals.py +++ b/netbox/users/signals.py @@ -1,10 +1,18 @@ import logging from django.dispatch import receiver from django.contrib.auth.signals import user_login_failed +from utilities.request import get_client_ip @receiver(user_login_failed) def log_user_login_failed(sender, credentials, request, **kwargs): logger = logging.getLogger('netbox.auth.login') username = credentials.get("username") - logger.info(f"Failed login attempt for username: {username}") + if client_ip := get_client_ip(request): + logger.info(f"Failed login attempt for username: {username} from {client_ip}") + else: + logger.warning( + "Client IP address could not be determined for validation. Check that the HTTP server is properly " + "configured to pass the required header(s)." + ) + logger.info(f"Failed login attempt for username: {username}") From 5a5fcf7d377d61e114a738c59edb9e015f465efe Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Fri, 26 May 2023 19:02:58 +0530 Subject: [PATCH 24/74] Changes render config card with accordian (#12724) * changes render config card with accordian #12470 * fixed indentation #12470 * Use -flush CSS class to reduce whitespace --------- Co-authored-by: jeremystretch --- .../templates/dcim/device/render_config.html | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/netbox/templates/dcim/device/render_config.html b/netbox/templates/dcim/device/render_config.html index b6e16701f..dfda7cdf6 100644 --- a/netbox/templates/dcim/device/render_config.html +++ b/netbox/templates/dcim/device/render_config.html @@ -28,8 +28,22 @@
-
Context Data
-
{{ context_data|pprint }}
+
+
+
+

+ +

+
+
+
{{ context_data|pprint }}
+
+
+
+
+
From 1f71d3570a7e4c66563223a8044d8e6b62c4323a Mon Sep 17 00:00:00 2001 From: kkthxbye-code Date: Tue, 30 May 2023 08:12:51 +0200 Subject: [PATCH 25/74] Escape text passed as display values to slim-select --- netbox/project-static/dist/netbox.js | Bin 438912 -> 530549 bytes netbox/project-static/dist/netbox.js.map | Bin 402467 -> 450821 bytes netbox/project-static/package.json | 1 + .../src/select/api/apiSelect.ts | 5 +++-- netbox/project-static/yarn.lock | 5 +++++ 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 8caaaa9a06b98ae6307412f09c4e3e29af0efc04..bb83314f5fbec1fb8100db2cbf9db944ef6e25a8 100644 GIT binary patch literal 530549 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 z z!LC*-@vwx{;KS@|W_%z;SNqWC*-Fq!TX#Z3hIs*UenM~;^Vdh@Jc_PLYo} z)d5WayCm)|R7F`dT34Xm$pSUp4wtXsSW7!%vXSpNZjyH)8_xDzF)S6~f5&0B05au75eUR0)PQ z7?3eP^Wniw1m}i^Js`wi^+m^V(9>J;DRp;GG1u|%G9AGGV0Q@~KT9cK(T{kc$O~xE zzxbbY0s7~DA0yO)aZRas#aV5$ zx%XZ*E))GFm(!hqf?tbFdp(0dFogW#*QOS~pfqWAoO=44`3QT!s0s$1 z*~vKTy-V+88ra(wo`YdPcSg4(0zt1szkz5cGC{u#(oFjj4i~aDIxb@jPwBWpS5t~E z5Wpz9KpcI7z6(a9U4@ASib2>D5WnD!DrCnQl@1C(AZa35BIY+Tgkgl<;r#hi(dNV= znRO2>3U4ajL;HFnH^#cOMh;0NSwOA0B|UP~zcUK?x)+r8%^_bv^Nl zK*SW0&)mMf>w(WXWpw5@R{R!=#CzJRUb1_?UxukA~AgWg52OA(7a zK`g5gHcGxT^+aJLHN@Q8joC7mNrVZe!T&3Beb%ludjTFxjD)f~2$K5N4WB z^yEgBE~IV|0eliMrUIjl(LEbBlE{=po0%8D9GVun+G=Q6k;{o$ytmbmCBb9w;&%eI z%%rsiO~~8T{d5ds)=ujZ{af{bN4?}KohTQDT-LV^oTQ_a?D_6h)7QyN9d3a zys@>qyx?IMpcEYzOkiF@r$pM#>XKhbrY-0?zZ}Kx=<}SHVT7A5)HmdxSS5tm%Mu(d zo`LHdQrn`Oe$-=#NDikn`$8@m!p=(k3C&<7Fv@NOtHs3Vk+ z0Qm|Sq1rWmSZ6vIG!*3rz>b~!2kkiX0ITQ4FSN0H|gSarjZ>s z;nPPB(kBFZrV@u-3KQOtk2c0|y+Ft!GXh`>iBOj)t5qe&C}XNHI^enF2GFow_=3`o zY#)&C$z0dZ+*Y4rVN+h=tL2%Qnf*|=9o>Oec-R5ikBkO-`wV;!IwiYUlWjpU9dvpN zin#$rGs0E`+eh?HVJAiMk0AGw54siDfv=j+C9wZEh9bm$qY47ay0uYT-`LwH7TvhH!sQJ(sD$mcIvcM`&jq545Z z#ekCGF|GOGCai!m2SZ29`{FlNLJb56hzVWUy>T(V>1#c>I1}8&76v!x*w~j^$gIZq ztl)0}(e6QPI4ga=(#O>X0K*@WH-U=<{voATxJc+FIlKV@lGF7CNToBx$+}0TU{k74 zd&GrcE7Mb4=wFY<3n{WYQaEzch1P<_hlOFbfKs_?XK=QVo7*n|EIx<`Ff85DAaLma zTS1cw`iY;YZc{_C~laO8DtP3^BK0L%T!luuxo?i{{F@jG@J?27`!#kvT!em z04xT~Kf_9z*$c2iw--oS9J3CzW#RMCF32DdznN>YN<
74aRfO~d*+TuT2pJF6Y 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

+vA|xtplm<)(;jhAfCa*`HYTCRE_?F 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 z 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 literal 438912 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 z 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 diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 0201e7bf85d9b6fba1d1c66fbdf7087f428c36e4..9b2017e3f91382cc1a9f2a3ab813d65c83e641cf 100644 GIT binary patch delta 48484 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 delta 112 zcmZoYB)#~A#D*u5&HJUc@0VgcmfT)y#RSC6K+Lke)QXi~kgeQFC)n9-`!sLX!!?Yi z+oMjf3h;8eJ39L7ggQDWO|QJl>I~rqI=bd;KXsM$B@d@zg;SNYj=!VP_C1eS{n#1J Lw{yQ@{q+q10M;mP diff --git a/netbox/project-static/package.json b/netbox/project-static/package.json index f10b5b7ac..98e1a5c60 100644 --- a/netbox/project-static/package.json +++ b/netbox/project-static/package.json @@ -30,6 +30,7 @@ "dayjs": "^1.11.5", "flatpickr": "4.6.13", "gridstack": "^7.2.3", + "html-entities": "^2.3.3", "htmx.org": "^1.8.0", "just-debounce-it": "^3.1.1", "query-string": "^7.1.1", diff --git a/netbox/project-static/src/select/api/apiSelect.ts b/netbox/project-static/src/select/api/apiSelect.ts index f5b605d58..53996910e 100644 --- a/netbox/project-static/src/select/api/apiSelect.ts +++ b/netbox/project-static/src/select/api/apiSelect.ts @@ -1,5 +1,6 @@ import { readableColor } from 'color2k'; import debounce from 'just-debounce-it'; +import { encode } from 'html-entities'; import queryString from 'query-string'; import SlimSelect from 'slim-select'; import { createToast } from '../../bs'; @@ -446,7 +447,7 @@ export class APISelect { // Build SlimSelect options from all already-selected options. const preSelectedOptions = preSelected.map(option => ({ value: option.value, - text: option.innerText, + text: encode(option.innerText), selected: true, disabled: false, })) as Option[]; @@ -454,7 +455,7 @@ export class APISelect { let options = [] as Option[]; for (const result of data.results) { - let text = result.display; + let text = encode(result.display); if (typeof result._depth === 'number' && result._depth > 0) { // If the object has a `_depth` property, indent its display text. diff --git a/netbox/project-static/yarn.lock b/netbox/project-static/yarn.lock index c4bee7557..2adc50001 100644 --- a/netbox/project-static/yarn.lock +++ b/netbox/project-static/yarn.lock @@ -1818,6 +1818,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +html-entities@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== + htmx.org@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/htmx.org/-/htmx.org-1.8.0.tgz#f3a2f681f3e2b6357b5a29bba24a2572a8e48fd3" From 9b9a559e0cc49c0a7f8b5171fbf2e082775e46b2 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Tue, 30 May 2023 19:11:32 +0530 Subject: [PATCH 26/74] Adds image preview back on the table (#12739) * adds image preview on image attachment #12627 * adds bootstrap initialization for hx-trigger=load #12627 --------- Co-authored-by: jeremystretch --- netbox/extras/tables/tables.py | 11 +++++++++++ netbox/project-static/dist/netbox.js | Bin 530549 -> 530632 bytes netbox/project-static/dist/netbox.js.map | Bin 450821 -> 450874 bytes netbox/project-static/src/htmx.ts | 7 ++++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index 8d046b85d..9e4924532 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -22,6 +22,14 @@ __all__ = ( 'WebhookTable', ) +IMAGEATTACHMENT_IMAGE = ''' +{% if record.image %} + {{ record }} +{% else %} + — +{% endif %} +''' + class CustomFieldTable(NetBoxTable): name = tables.Column( @@ -96,6 +104,9 @@ class ImageAttachmentTable(NetBoxTable): parent = tables.Column( linkify=True ) + image = tables.TemplateColumn( + template_code=IMAGEATTACHMENT_IMAGE, + ) size = tables.Column( orderable=False, verbose_name='Size (bytes)' diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index bb83314f5fbec1fb8100db2cbf9db944ef6e25a8..9642d15851c5238db66f5a46ac81880ce2f10e1f 100644 GIT binary patch delta 30650 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%0A2lVM5+?54CIk>0n9ACql(gqFsvvq1t)! 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 delta 30574 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 BA)^2Q delta 50 zcmdmWNV@fqbVCbc3sVbo3rh>@7Ph8)jE2*j@3CpJdOA8AJ5S$!kFB1?+u5UFd**$% Gi;Mu@GZLx* diff --git a/netbox/project-static/src/htmx.ts b/netbox/project-static/src/htmx.ts index 09d423cbd..2410a5fd9 100644 --- a/netbox/project-static/src/htmx.ts +++ b/netbox/project-static/src/htmx.ts @@ -2,9 +2,10 @@ import { getElements, isTruthy } from './util'; import { initButtons } from './buttons'; import { initSelect } from './select'; import { initObjectSelector } from './objectSelector'; +import { initBootstrap } from './bs'; function initDepedencies(): void { - for (const init of [initButtons, initSelect, initObjectSelector]) { + for (const init of [initButtons, initSelect, initObjectSelector, initBootstrap]) { init(); } } @@ -22,4 +23,8 @@ export function initHtmx(): void { } } } + + for (const element of getElements('[hx-trigger=load]')) { + element.addEventListener('htmx:afterSettle', initDepedencies); + } } From d7ca453f2608e7d8caa432cd42d4daf6a5ca3167 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Tue, 30 May 2023 19:12:37 +0530 Subject: [PATCH 27/74] Adds hide-if-unset to custom field (#12723) * adds hide-if-unset to custom field #12597 * moved hide logic from template to python * fix indentation * Update logic for omit_hidden under get_custom_fields() * Update docs * Account for False values --------- Co-authored-by: jeremystretch --- docs/models/extras/customfield.md | 11 ++++++----- netbox/extras/choices.py | 2 ++ netbox/netbox/models/features.py | 14 ++++++++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/models/extras/customfield.md b/docs/models/extras/customfield.md index 0d92ec656..df0408f7c 100644 --- a/docs/models/extras/customfield.md +++ b/docs/models/extras/customfield.md @@ -68,11 +68,12 @@ Defines how filters are evaluated against custom field values. Controls how and whether the custom field is displayed within the NetBox user interface. -| Option | Description | -|------------|--------------------------------------| -| Read/write | Display and permit editing (default) | -| Read-only | Display field but disallow editing | -| Hidden | Do not display field in the UI | +| Option | Description | +|-------------------|--------------------------------------------------| +| Read/write | Display and permit editing (default) | +| Read-only | Display field but disallow editing | +| Hidden | Do not display field in the UI | +| Hidden (if unset) | Display in the UI only when a value has been set | ### Default diff --git a/netbox/extras/choices.py b/netbox/extras/choices.py index e10516c4c..6fc14b965 100644 --- a/netbox/extras/choices.py +++ b/netbox/extras/choices.py @@ -56,11 +56,13 @@ class CustomFieldVisibilityChoices(ChoiceSet): VISIBILITY_READ_WRITE = 'read-write' VISIBILITY_READ_ONLY = 'read-only' VISIBILITY_HIDDEN = 'hidden' + VISIBILITY_HIDDEN_IFUNSET = 'hidden-ifunset' CHOICES = ( (VISIBILITY_READ_WRITE, 'Read/Write'), (VISIBILITY_READ_ONLY, 'Read-only'), (VISIBILITY_HIDDEN, 'Hidden'), + (VISIBILITY_HIDDEN_IFUNSET, 'Hidden (if unset)'), ) diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index 6d82e2a2b..8bacba534 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -197,11 +197,15 @@ class CustomFieldsMixin(models.Model): data = {} for field in CustomField.objects.get_for_model(self): - # Skip fields that are hidden if 'omit_hidden' is set - if omit_hidden and field.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_HIDDEN: - continue - value = self.custom_field_data.get(field.name) + + # Skip fields that are hidden if 'omit_hidden' is set + if omit_hidden: + if field.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_HIDDEN: + continue + if field.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_HIDDEN_IFUNSET and not value: + continue + data[field] = field.deserialize(value) return data @@ -227,6 +231,8 @@ class CustomFieldsMixin(models.Model): for cf in visible_custom_fields: value = self.custom_field_data.get(cf.name) + if value in (None, []) and cf.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_HIDDEN_IFUNSET: + continue value = cf.deserialize(value) groups[cf.group_name][cf] = value From 18c863e393c32731e0cbf13ff56e854a79249c4f Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 30 May 2023 09:52:14 -0400 Subject: [PATCH 28/74] Changelog for #11539, #12370, #12470, #12562, #12597, #12627, #12745 --- docs/release-notes/version-3.5.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 816fe124c..ad5828e8e 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -2,10 +2,20 @@ ## v3.5.3 (FUTURE) +### Enhancements + +* [#12470](https://github.com/netbox-community/netbox/issues/12470) - Collapse context data by default when viewing a rendered device configuration +* [#12562](https://github.com/netbox-community/netbox/issues/12562) - Record client IP address when logging authentication failures +* [#12597](https://github.com/netbox-community/netbox/issues/12597) - Add an option to hide custom fields only if unset + ### Bug Fixes +* [#11539](https://github.com/netbox-community/netbox/issues/11539) - Fix exception when applying "empty" filter lookup with invalid value * [#11934](https://github.com/netbox-community/netbox/issues/11934) - Prevent reassignment of an IP address designated as primary for its parent object +* [#12370](https://github.com/netbox-community/netbox/issues/12370) - Fix extraneous contacts listed in object contact assignments view +* [#12627](https://github.com/netbox-community/netbox/issues/12627) - Restore hover preview for embedded image attachment tables * [#12694](https://github.com/netbox-community/netbox/issues/12694) - Strip leading & trailing whitespace from custom link URL & text +* [#12745](https://github.com/netbox-community/netbox/issues/12745) - Escape display text in API-backed selection widgets --- From b3bd03a1e9441742d056fe28f1114230c75dad24 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 30 May 2023 14:51:16 -0400 Subject: [PATCH 29/74] Fixes #12715: Use contact assignments table to display the contacts assigned to an object --- docs/release-notes/version-3.5.md | 3 ++- netbox/tenancy/views.py | 25 ++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index ad5828e8e..32f4ded32 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -12,9 +12,10 @@ * [#11539](https://github.com/netbox-community/netbox/issues/11539) - Fix exception when applying "empty" filter lookup with invalid value * [#11934](https://github.com/netbox-community/netbox/issues/11934) - Prevent reassignment of an IP address designated as primary for its parent object -* [#12370](https://github.com/netbox-community/netbox/issues/12370) - Fix extraneous contacts listed in object contact assignments view +* [#12730](https://github.com/netbox-community/netbox/issues/12730) - Fix extraneous contacts listed in object contact assignments view * [#12627](https://github.com/netbox-community/netbox/issues/12627) - Restore hover preview for embedded image attachment tables * [#12694](https://github.com/netbox-community/netbox/issues/12694) - Strip leading & trailing whitespace from custom link URL & text +* [#12715](https://github.com/netbox-community/netbox/issues/12715) - Use contact assignments table to display the contacts assigned to an object * [#12745](https://github.com/netbox-community/netbox/issues/12745) - Escape display text in API-backed selection widgets --- diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index c2ef4b487..bbe901bde 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -15,25 +15,32 @@ from .models import * class ObjectContactsView(generic.ObjectChildrenView): - child_model = Contact - table = tables.ContactTable - filterset = filtersets.ContactFilterSet + child_model = ContactAssignment + table = tables.ContactAssignmentTable + filterset = filtersets.ContactAssignmentFilterSet template_name = 'tenancy/object_contacts.html' tab = ViewTab( label=_('Contacts'), badge=lambda obj: obj.contacts.count(), - permission='tenancy.view_contact', + permission='tenancy.view_contactassignment', weight=5000 ) def get_children(self, request, parent): - return Contact.objects.annotate( - assignment_count=count_related(ContactAssignment, 'contact') - ).restrict(request.user, 'view').filter( - assignments__content_type=ContentType.objects.get_for_model(parent), - assignments__object_id=parent.pk + return ContactAssignment.objects.restrict(request.user, 'view').filter( + content_type=ContentType.objects.get_for_model(parent), + object_id=parent.pk ) + def get_table(self, *args, **kwargs): + table = super().get_table(*args, **kwargs) + + # Hide object columns + table.columns.hide('content_type') + table.columns.hide('object') + + return table + def get_extra_context(self, request, instance): return { 'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html', From 9b8ab1c1f7b364e3694bead05173e746a1f4571f Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 30 May 2023 15:44:43 -0400 Subject: [PATCH 30/74] Fixes #12742: Object counts dashboard widget should support URL-compatible query filters --- docs/release-notes/version-3.5.md | 1 + netbox/extras/dashboard/widgets.py | 19 +++++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 32f4ded32..6656aa1bb 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -16,6 +16,7 @@ * [#12627](https://github.com/netbox-community/netbox/issues/12627) - Restore hover preview for embedded image attachment tables * [#12694](https://github.com/netbox-community/netbox/issues/12694) - Strip leading & trailing whitespace from custom link URL & text * [#12715](https://github.com/netbox-community/netbox/issues/12715) - Use contact assignments table to display the contacts assigned to an object +* [#12742](https://github.com/netbox-community/netbox/issues/12742) - Object counts dashboard widget should support URL-compatible query filters * [#12745](https://github.com/netbox-community/netbox/issues/12745) - Escape display text in API-backed selection widgets --- diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py index dc68e1388..ed50a8451 100644 --- a/netbox/extras/dashboard/widgets.py +++ b/netbox/extras/dashboard/widgets.py @@ -10,8 +10,9 @@ from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.core.cache import cache from django.db.models import Q +from django.http import QueryDict from django.template.loader import render_to_string -from django.urls import NoReverseMatch, reverse +from django.urls import NoReverseMatch, resolve, reverse from django.utils.translation import gettext as _ from extras.utils import FeatureQuery @@ -149,7 +150,7 @@ class ObjectCountsWidget(DashboardWidget): filters = forms.JSONField( required=False, label='Object filters', - help_text=_("Only objects matching the specified filters will be counted") + help_text=_("Filters to apply when counting the number of objects") ) def clean_filters(self): @@ -158,13 +159,6 @@ class ObjectCountsWidget(DashboardWidget): dict(data) except TypeError: raise forms.ValidationError("Invalid format. Object filters must be passed as a dictionary.") - for model in get_models_from_content_types(self.cleaned_data.get('models')): - try: - # Validate the filters by creating a QuerySet - model.objects.filter(**data).none() - except Exception: - model_name = model._meta.verbose_name_plural - raise forms.ValidationError(f"Invalid filter specification for {model_name}.") return data def render(self, request): @@ -172,9 +166,14 @@ class ObjectCountsWidget(DashboardWidget): for model in get_models_from_content_types(self.config['models']): permission = get_permission_for_model(model, 'view') if request.user.has_perm(permission): + url = reverse(get_viewname(model, 'list')) qs = model.objects.restrict(request.user, 'view') + # Apply any specified filters if filters := self.config.get('filters'): - qs = qs.filter(**filters) + params = QueryDict(mutable=True) + params.update(filters) + filterset = getattr(resolve(url).func.view_class, 'filterset', None) + qs = filterset(params, qs).qs object_count = qs.count counts.append((model, object_count)) else: From bca9d0fa8ae243459191355edaf625748b1fde42 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Tue, 30 May 2023 16:31:34 -0400 Subject: [PATCH 31/74] Closes #12599: Apply filter parameters to links in object count dashboard widgets --- docs/release-notes/version-3.5.md | 1 + netbox/extras/dashboard/widgets.py | 5 +++-- netbox/templates/extras/dashboard/widgets/objectcounts.html | 6 ++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 6656aa1bb..ac02f0f79 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -7,6 +7,7 @@ * [#12470](https://github.com/netbox-community/netbox/issues/12470) - Collapse context data by default when viewing a rendered device configuration * [#12562](https://github.com/netbox-community/netbox/issues/12562) - Record client IP address when logging authentication failures * [#12597](https://github.com/netbox-community/netbox/issues/12597) - Add an option to hide custom fields only if unset +* [#12599](https://github.com/netbox-community/netbox/issues/12599) - Apply filter parameters to links in object count dashboard widgets ### Bug Fixes diff --git a/netbox/extras/dashboard/widgets.py b/netbox/extras/dashboard/widgets.py index ed50a8451..b3a4d090c 100644 --- a/netbox/extras/dashboard/widgets.py +++ b/netbox/extras/dashboard/widgets.py @@ -174,10 +174,11 @@ class ObjectCountsWidget(DashboardWidget): params.update(filters) filterset = getattr(resolve(url).func.view_class, 'filterset', None) qs = filterset(params, qs).qs + url = f'{url}?{params.urlencode()}' object_count = qs.count - counts.append((model, object_count)) + counts.append((model, object_count, url)) else: - counts.append((model, None)) + counts.append((model, None, None)) return render_to_string(self.template_name, { 'counts': counts, diff --git a/netbox/templates/extras/dashboard/widgets/objectcounts.html b/netbox/templates/extras/dashboard/widgets/objectcounts.html index d0e604c9a..8b68dc166 100644 --- a/netbox/templates/extras/dashboard/widgets/objectcounts.html +++ b/netbox/templates/extras/dashboard/widgets/objectcounts.html @@ -1,10 +1,8 @@ -{% load helpers %} - {% if counts %}

- {% for model, count in counts %} + {% for model, count, url in counts %} {% if count != None %} - +
{{ model|meta:"verbose_name_plural"|bettertitle }}
{{ count }}
From 8b051ea2f3cf17da3fd3440b12a0bbb7d0119487 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Wed, 31 May 2023 06:06:09 -0700 Subject: [PATCH 32/74] 7503 do device validate-create in serial (#12222) * 7503 do device validate-create in serial * 7503 fix single instance * 7503 atomic transaction * 7503 fix return data for bulk operations * 7503 add test * Move sequential creation logic to a mixin --------- Co-authored-by: jeremystretch --- netbox/dcim/api/views.py | 13 +++++++---- netbox/dcim/tests/test_api.py | 35 +++++++++++++++++++++++++++- netbox/netbox/api/viewsets/mixins.py | 27 ++++++++++++++++++++- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index a62315b57..5b87c4e5d 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -1,12 +1,12 @@ from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404 -from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiParameter from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import extend_schema, OpenApiParameter from rest_framework.decorators import action from rest_framework.renderers import JSONRenderer from rest_framework.response import Response -from rest_framework.status import HTTP_400_BAD_REQUEST from rest_framework.routers import APIRootView +from rest_framework.status import HTTP_400_BAD_REQUEST from rest_framework.viewsets import ViewSet from circuits.models import Circuit @@ -14,7 +14,6 @@ from dcim import filtersets from dcim.constants import CABLE_TRACE_SVG_DEFAULT_WIDTH from dcim.models import * from dcim.svg import CableTraceSVG -from extras.api.nested_serializers import NestedConfigTemplateSerializer from extras.api.mixins import ConfigContextQuerySetMixin, ConfigTemplateRenderMixin from ipam.models import Prefix, VLAN from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired @@ -22,6 +21,7 @@ from netbox.api.metadata import ContentTypeMetadata from netbox.api.pagination import StripCountAnnotationsPaginator from netbox.api.renderers import TextRenderer from netbox.api.viewsets import NetBoxModelViewSet +from netbox.api.viewsets.mixins import SequentialBulkCreatesMixin from netbox.constants import NESTED_SERIALIZER_PREFIX from utilities.api import get_serializer_for_model from utilities.utils import count_related @@ -386,7 +386,12 @@ class PlatformViewSet(NetBoxModelViewSet): # Devices/modules # -class DeviceViewSet(ConfigContextQuerySetMixin, ConfigTemplateRenderMixin, NetBoxModelViewSet): +class DeviceViewSet( + SequentialBulkCreatesMixin, + ConfigContextQuerySetMixin, + ConfigTemplateRenderMixin, + NetBoxModelViewSet +): queryset = Device.objects.prefetch_related( 'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'site', 'location', 'rack', 'parent_bay', 'virtual_chassis__master', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'config_template', 'tags', diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index 3445b7e75..af15e1343 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -1115,7 +1115,7 @@ class DeviceTest(APIViewTestCases.APIViewTestCase): device_types = ( DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), - DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2', u_height=2), ) DeviceType.objects.bulk_create(device_types) @@ -1229,6 +1229,39 @@ class DeviceTest(APIViewTestCases.APIViewTestCase): self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) + def test_rack_fit(self): + """ + Check that creating multiple devices with overlapping position fails. + """ + device = Device.objects.first() + device_type = DeviceType.objects.all()[1] + data = [ + { + 'device_type': device_type.pk, + 'device_role': device.device_role.pk, + 'site': device.site.pk, + 'name': 'Test Device 7', + 'rack': device.rack.pk, + 'face': 'front', + 'position': 1 + }, + { + 'device_type': device_type.pk, + 'device_role': device.device_role.pk, + 'site': device.site.pk, + 'name': 'Test Device 8', + 'rack': device.rack.pk, + 'face': 'front', + 'position': 2 + } + ] + + self.add_permissions('dcim.add_device') + url = reverse('dcim-api:device-list') + response = self.client.post(url, data, format='json', **self.header) + + self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) + class ModuleTest(APIViewTestCases.APIViewTestCase): model = Module diff --git a/netbox/netbox/api/viewsets/mixins.py b/netbox/netbox/api/viewsets/mixins.py index 8b629bbc6..fde486fe9 100644 --- a/netbox/netbox/api/viewsets/mixins.py +++ b/netbox/netbox/api/viewsets/mixins.py @@ -15,11 +15,12 @@ from utilities.api import get_serializer_for_model __all__ = ( 'BriefModeMixin', + 'BulkDestroyModelMixin', 'BulkUpdateModelMixin', 'CustomFieldsMixin', 'ExportTemplatesMixin', - 'BulkDestroyModelMixin', 'ObjectValidationMixin', + 'SequentialBulkCreatesMixin', ) @@ -94,6 +95,30 @@ class ExportTemplatesMixin: return super().list(request, *args, **kwargs) +class SequentialBulkCreatesMixin: + """ + Perform bulk creation of new objects sequentially, rather than all at once. This ensures that any validation + which depends on the evaluation of existing objects (such as checking for free space within a rack) functions + appropriately. + """ + @transaction.atomic + def create(self, request, *args, **kwargs): + if not isinstance(request.data, list): + # Creating a single object + return super().create(request, *args, **kwargs) + + return_data = [] + for data in request.data: + serializer = self.get_serializer(data=data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + return_data.append(serializer.data) + + headers = self.get_success_headers(serializer.data) + + return Response(return_data, status=status.HTTP_201_CREATED, headers=headers) + + class BulkUpdateModelMixin: """ Support bulk modification of objects using the list endpoint for a model. Accepts a PATCH action with a list of one From a9b0b49ef94d6c52862c3e0f63169e39f9824d42 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Wed, 31 May 2023 08:49:23 -0500 Subject: [PATCH 33/74] Fixes #12702 - Adds widget to FrontPortTemplateCreateForm --- netbox/dcim/forms/object_create.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index d4c9e6ec3..9589ab533 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -101,6 +101,7 @@ class FrontPortTemplateCreateForm(ComponentCreateForm, model_forms.FrontPortTemp choices=[], label=_('Rear ports'), help_text=_('Select one rear port assignment for each front port being created.'), + widget=forms.SelectMultiple(attrs={'size': 6}) ) # Override fieldsets from FrontPortTemplateForm to omit rear_port_position From bd88ee7063c65d3634b2d6e6c548e1c4b2b14259 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 31 May 2023 19:29:22 +0530 Subject: [PATCH 34/74] Adds device type and role to device component filter (#12504) * adds device type and role to device component filter #12015 * changes as per review * Add filterset tests for device type & role filters --------- Co-authored-by: jeremystretch --- netbox/dcim/filtersets.py | 22 ++ netbox/dcim/forms/filtersets.py | 45 +++-- netbox/dcim/tests/test_filtersets.py | 289 +++++++++++++++++++++------ 3 files changed, 278 insertions(+), 78 deletions(-) diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index fccaa72f0..e784be8e8 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -1219,6 +1219,28 @@ class DeviceComponentFilterSet(django_filters.FilterSet): to_field_name='name', label=_('Device (name)'), ) + device_type_id = django_filters.ModelMultipleChoiceFilter( + field_name='device__device_type', + queryset=DeviceType.objects.all(), + label=_('Device type (ID)'), + ) + device_type = django_filters.ModelMultipleChoiceFilter( + field_name='device__device_type__model', + queryset=DeviceType.objects.all(), + to_field_name='model', + label=_('Device type (model)'), + ) + device_role_id = django_filters.ModelMultipleChoiceFilter( + field_name='device__device_role', + queryset=DeviceRole.objects.all(), + label=_('Device role (ID)'), + ) + device_role = django_filters.ModelMultipleChoiceFilter( + field_name='device__device_role__slug', + queryset=DeviceRole.objects.all(), + to_field_name='slug', + label=_('Device role (slug)'), + ) virtual_chassis_id = django_filters.ModelMultipleChoiceFilter( field_name='device__virtual_chassis', queryset=VirtualChassis.objects.all(), diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index d31bba030..4edee6014 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -102,13 +102,25 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm): required=False, label=_('Virtual Chassis') ) + device_type_id = DynamicModelMultipleChoiceField( + queryset=DeviceType.objects.all(), + required=False, + label=_('Device type') + ) + device_role_id = DynamicModelMultipleChoiceField( + queryset=DeviceRole.objects.all(), + required=False, + label=_('Device role') + ) device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), required=False, query_params={ 'site_id': '$site_id', 'location_id': '$location_id', - 'virtual_chassis_id': '$virtual_chassis_id' + 'virtual_chassis_id': '$virtual_chassis_id', + 'device_type_id': '$device_type_id', + 'role_id': '$device_role_id' }, label=_('Device') ) @@ -1070,7 +1082,8 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'speed')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1089,7 +1102,8 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'speed')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1108,7 +1122,8 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1123,7 +1138,8 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1141,8 +1157,8 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): ('Addressing', ('vrf_id', 'l2vpn_id', 'mac_address', 'wwn')), ('PoE', ('poe_mode', 'poe_type')), ('Wireless', ('rf_role', 'rf_channel', 'rf_channel_width', 'tx_power')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', - 'device_id', 'vdc_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id', 'vdc_id')), ('Connection', ('cabled', 'connected', 'occupied')), ) vdc_id = DynamicModelMultipleChoiceField( @@ -1242,7 +1258,8 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'color')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ('Cable', ('cabled', 'occupied')), ) model = FrontPort @@ -1261,7 +1278,8 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'type', 'color')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ('Cable', ('cabled', 'occupied')), ) type = forms.MultipleChoiceField( @@ -1279,7 +1297,8 @@ class ModuleBayFilterForm(DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'position')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ) tag = TagFilterField(model) position = forms.CharField( @@ -1292,7 +1311,8 @@ class DeviceBayFilterForm(DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ) tag = TagFilterField(model) @@ -1302,7 +1322,8 @@ class InventoryItemFilterForm(DeviceComponentFilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), ('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')), - ('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')), + ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')), + ('Device', ('device_type_id', 'device_role_id', 'device_id', 'virtual_chassis_id')), ) role_id = DynamicModelMultipleChoiceField( queryset=InventoryItemRole.objects.all(), diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index 346b35005..3f9712f2a 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -12,6 +12,23 @@ from virtualization.models import Cluster, ClusterType from wireless.choices import WirelessChannelChoices, WirelessRoleChoices +class DeviceComponentFilterSetTests: + + def test_device_type(self): + device_types = DeviceType.objects.all()[:2] + params = {'device_type_id': [device_types[0].pk, device_types[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'device_type': [device_types[0].model, device_types[1].model]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + def test_device_role(self): + device_role = DeviceRole.objects.all()[:2] + params = {'device_role_id': [device_role[0].pk, device_role[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + params = {'device_role': [device_role[0].slug, device_role[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + class RegionTestCase(TestCase, ChangeLoggedFilterSetTests): queryset = Region.objects.all() filterset = RegionFilterSet @@ -1998,7 +2015,7 @@ class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) -class ConsolePortTestCase(TestCase, ChangeLoggedFilterSetTests): +class ConsolePortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = ConsolePort.objects.all() filterset = ConsolePortFilterSet @@ -2027,10 +2044,23 @@ class ConsolePortTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -2048,10 +2078,10 @@ class ConsolePortTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), - Device(name=None, device_type=device_type, device_role=device_role, site=sites[3]), # For cable connections + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device(name=None, device_type=device_types[0], device_role=device_roles[0], site=sites[3]), # For cable connections ) Device.objects.bulk_create(devices) @@ -2165,7 +2195,7 @@ class ConsolePortTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) -class ConsoleServerPortTestCase(TestCase, ChangeLoggedFilterSetTests): +class ConsoleServerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = ConsoleServerPort.objects.all() filterset = ConsoleServerPortFilterSet @@ -2194,10 +2224,23 @@ class ConsoleServerPortTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -2215,10 +2258,10 @@ class ConsoleServerPortTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), - Device(name=None, device_type=device_type, device_role=device_role, site=sites[3]), # For cable connections + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device(name=None, device_type=device_types[2], device_role=device_roles[2], site=sites[3]), # For cable connections ) Device.objects.bulk_create(devices) @@ -2332,7 +2375,7 @@ class ConsoleServerPortTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) -class PowerPortTestCase(TestCase, ChangeLoggedFilterSetTests): +class PowerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = PowerPort.objects.all() filterset = PowerPortFilterSet @@ -2361,10 +2404,23 @@ class PowerPortTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -2382,10 +2438,10 @@ class PowerPortTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), - Device(name=None, device_type=device_type, device_role=device_role, site=sites[3]), # For cable connections + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device(name=None, device_type=device_types[2], device_role=device_roles[2], site=sites[3]), # For cable connections ) Device.objects.bulk_create(devices) @@ -2507,7 +2563,7 @@ class PowerPortTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) -class PowerOutletTestCase(TestCase, ChangeLoggedFilterSetTests): +class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = PowerOutlet.objects.all() filterset = PowerOutletFilterSet @@ -2536,10 +2592,23 @@ class PowerOutletTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -2557,10 +2626,10 @@ class PowerOutletTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), - Device(name=None, device_type=device_type, device_role=device_role, site=sites[3]), # For cable connections + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device(name=None, device_type=device_types[2], device_role=device_roles[2], site=sites[3]), # For cable connections ) Device.objects.bulk_create(devices) @@ -2678,7 +2747,7 @@ class PowerOutletTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) -class InterfaceTestCase(TestCase, ChangeLoggedFilterSetTests): +class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = Interface.objects.all() filterset = InterfaceFilterSet @@ -2707,10 +2776,23 @@ class InterfaceTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -2728,10 +2810,10 @@ class InterfaceTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), - Device(name=None, device_type=device_type, device_role=device_role, site=sites[3]), # For cable connections + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device(name=None, device_type=device_types[2], device_role=device_roles[2], site=sites[3]), # For cable connections ) Device.objects.bulk_create(devices) @@ -3101,7 +3183,7 @@ class InterfaceTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) -class FrontPortTestCase(TestCase, ChangeLoggedFilterSetTests): +class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = FrontPort.objects.all() filterset = FrontPortFilterSet @@ -3130,10 +3212,23 @@ class FrontPortTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3151,10 +3246,10 @@ class FrontPortTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), - Device(name=None, device_type=device_type, device_role=device_role, site=sites[3]), # For cable connections + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device(name=None, device_type=device_types[2], device_role=device_roles[2], site=sites[3]), # For cable connections ) Device.objects.bulk_create(devices) @@ -3277,7 +3372,7 @@ class FrontPortTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) -class RearPortTestCase(TestCase, ChangeLoggedFilterSetTests): +class RearPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = RearPort.objects.all() filterset = RearPortFilterSet @@ -3306,10 +3401,23 @@ class RearPortTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + module_type = ModuleType.objects.create(manufacturer=manufacturer, model='Module Type 1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3327,10 +3435,10 @@ class RearPortTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), - Device(name=None, device_type=device_type, device_role=device_role, site=sites[3]), # For cable connections + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), + Device(name=None, device_type=device_types[2], device_role=device_roles[2], site=sites[3]), # For cable connections ) Device.objects.bulk_create(devices) @@ -3447,7 +3555,7 @@ class RearPortTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) -class ModuleBayTestCase(TestCase, ChangeLoggedFilterSetTests): +class ModuleBayTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = ModuleBay.objects.all() filterset = ModuleBayFilterSet @@ -3476,9 +3584,21 @@ class ModuleBayTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Model 1', slug='model-1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3496,9 +3616,9 @@ class ModuleBayTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), ) Device.objects.bulk_create(devices) @@ -3564,7 +3684,7 @@ class ModuleBayTestCase(TestCase, ChangeLoggedFilterSetTests): self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) -class DeviceBayTestCase(TestCase, ChangeLoggedFilterSetTests): +class DeviceBayTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests): queryset = DeviceBay.objects.all() filterset = DeviceBayFilterSet @@ -3593,9 +3713,21 @@ class DeviceBayTestCase(TestCase, ChangeLoggedFilterSetTests): Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]), Site(name='Site X', slug='site-x'), )) + manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1') - device_type = DeviceType.objects.create(manufacturer=manufacturer, model='Model 1', slug='model-1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + device_types = ( + DeviceType(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturer, model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturer, model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) locations = ( Location(name='Location 1', slug='location-1', site=sites[0]), @@ -3613,9 +3745,9 @@ class DeviceBayTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), ) Device.objects.bulk_create(devices) @@ -3694,8 +3826,19 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests): ) Manufacturer.objects.bulk_create(manufacturers) - device_type = DeviceType.objects.create(manufacturer=manufacturers[0], model='Model 1', slug='model-1') - device_role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1') + device_types = ( + DeviceType(manufacturer=manufacturers[0], model='Device Type 1', slug='device-type-1'), + DeviceType(manufacturer=manufacturers[0], model='Device Type 2', slug='device-type-2'), + DeviceType(manufacturer=manufacturers[0], model='Device Type 3', slug='device-type-3'), + ) + DeviceType.objects.bulk_create(device_types) + + device_roles = ( + DeviceRole(name='Device Role 1', slug='device-role-1'), + DeviceRole(name='Device Role 2', slug='device-role-2'), + DeviceRole(name='Device Role 3', slug='device-role-3'), + ) + DeviceRole.objects.bulk_create(device_roles) regions = ( Region(name='Region 1', slug='region-1'), @@ -3736,9 +3879,9 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests): Rack.objects.bulk_create(racks) devices = ( - Device(name='Device 1', device_type=device_type, device_role=device_role, site=sites[0], location=locations[0], rack=racks[0]), - Device(name='Device 2', device_type=device_type, device_role=device_role, site=sites[1], location=locations[1], rack=racks[1]), - Device(name='Device 3', device_type=device_type, device_role=device_role, site=sites[2], location=locations[2], rack=racks[2]), + Device(name='Device 1', device_type=device_types[0], device_role=device_roles[0], site=sites[0], location=locations[0], rack=racks[0]), + Device(name='Device 2', device_type=device_types[1], device_role=device_roles[1], site=sites[1], location=locations[1], rack=racks[1]), + Device(name='Device 3', device_type=device_types[2], device_role=device_roles[2], site=sites[2], location=locations[2], rack=racks[2]), ) Device.objects.bulk_create(devices) @@ -3829,6 +3972,20 @@ class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'rack': [racks[0].name, racks[1].name]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + def test_device_type(self): + device_types = DeviceType.objects.all()[:2] + params = {'device_type_id': [device_types[0].pk, device_types[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + params = {'device_type': [device_types[0].model, device_types[1].model]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + + def test_device_role(self): + device_role = DeviceRole.objects.all()[:2] + params = {'device_role_id': [device_role[0].pk, device_role[1].pk]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + params = {'device_role': [device_role[0].slug, device_role[1].slug]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) + def test_device(self): devices = Device.objects.all()[:2] params = {'device_id': [devices[0].pk, devices[1].pk]} From 3e77daff012b9a0e127330c42d713362cf10a74b Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 31 May 2023 08:08:32 -0700 Subject: [PATCH 35/74] 12767 pin graphene-django version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 6757f3260..29f5bbc7b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ drf-spectacular==0.26.2 drf-spectacular-sidecar==2023.5.1 dulwich==0.21.5 feedparser==6.0.10 -graphene-django==3.0.2 +graphene-django==3.0.0 gunicorn==20.1.0 Jinja2==3.1.2 Markdown==3.3.7 From dbd3c6de24afd318d6204f96c12b64e86082475f Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Thu, 1 Jun 2023 00:52:37 +0530 Subject: [PATCH 36/74] Fixes return_url for image attachment (#12721) * fixes return_url for image attachment #12538 * simplified conditions * handle nonetype error * fixed request check * Introduce htmx_table template tag for embedding HTMX-backed object tables --------- Co-authored-by: jeremystretch --- netbox/netbox/tables/columns.py | 8 ++++++-- .../inc/panels/image_attachments.html | 8 ++------ .../templates/builtins/htmx_table.html | 4 ++++ .../utilities/templatetags/builtins/tags.py | 20 +++++++++++++++++++ 4 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 netbox/utilities/templates/builtins/htmx_table.html diff --git a/netbox/netbox/tables/columns.py b/netbox/netbox/tables/columns.py index 66ee787a8..9ef327026 100644 --- a/netbox/netbox/tables/columns.py +++ b/netbox/netbox/tables/columns.py @@ -234,8 +234,12 @@ class ActionsColumn(tables.Column): return '' model = table.Meta.model - request = getattr(table, 'context', {}).get('request') - url_appendix = f'?return_url={quote(request.get_full_path())}' if request else '' + if request := getattr(table, 'context', {}).get('request'): + return_url = request.GET.get('return_url', request.get_full_path()) + url_appendix = f'?return_url={quote(return_url)}' + else: + url_appendix = '' + html = '' # Compile actions menu diff --git a/netbox/templates/inc/panels/image_attachments.html b/netbox/templates/inc/panels/image_attachments.html index 0c1d212d9..a09fe78d5 100644 --- a/netbox/templates/inc/panels/image_attachments.html +++ b/netbox/templates/inc/panels/image_attachments.html @@ -1,12 +1,8 @@ {% load helpers %}
-
- Images -
-
+
Images
+ {% htmx_table 'extras:imageattachment_list' content_type_id=object|content_type_id object_id=object.pk %} {% if perms.extras.add_imageattachment %}
+ + + + + + + +
MAC Address{{ object.mac_address|placeholder }}{{ object.mac_address|placeholder }}
WWN{{ object.wwn|placeholder }}{{ object.wwn|placeholder }}
VRF
MAC Address{{ object.mac_address|placeholder }}{{ object.mac_address|placeholder }}
802.1Q Mode
GPS Coordinates + {% if object.latitude and object.longitude %} + {% if config.MAPS_URL %} + + {% endif %} + {{ object.latitude }}, {{ object.longitude }} + {% else %} + {{ ''|placeholder }} + {% endif %} +
Tenant diff --git a/netbox/templates/dcim/device_edit.html b/netbox/templates/dcim/device_edit.html index 17780b513..2dbe1e3c5 100644 --- a/netbox/templates/dcim/device_edit.html +++ b/netbox/templates/dcim/device_edit.html @@ -53,6 +53,8 @@ {% else %} {% render_field form.face %} {% render_field form.position %} + {% render_field form.latitude %} + {% render_field form.longitude %} {% endif %} From b4a315604610e9016fd0a5046782e4e81c1d0ba5 Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 31 May 2023 13:47:22 -0700 Subject: [PATCH 57/74] 9077 audit alters_data=True --- netbox/core/models/data.py | 1 + netbox/dcim/models/cables.py | 2 ++ netbox/dcim/models/device_component_templates.py | 9 +++++++++ netbox/extras/models/configs.py | 2 ++ netbox/extras/models/models.py | 2 ++ netbox/extras/models/staging.py | 1 + netbox/netbox/models/features.py | 4 ++++ 7 files changed, 21 insertions(+) diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py index a8ac4e8f1..2af697f60 100644 --- a/netbox/core/models/data.py +++ b/netbox/core/models/data.py @@ -200,6 +200,7 @@ class DataSource(JobsMixin, PrimaryModel): # Emit the post_sync signal post_sync.send(sender=self.__class__, instance=self) + sync.alters_data = True def _walk(self, root): """ diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index af69c440e..b2786719c 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -359,6 +359,7 @@ class CableTermination(ChangeLoggedModel): # Circuit terminations elif getattr(self.termination, 'site', None): self._site = self.termination.site + cache_related_objects.alters_data = True def to_objectchange(self, action): objectchange = super().to_objectchange(action) @@ -637,6 +638,7 @@ class CablePath(models.Model): self.save() else: self.delete() + retrace.alters_data = True def _get_path(self): """ diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 6a89655b2..0355d7028 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -213,6 +213,7 @@ class ConsoleServerPortTemplate(ModularComponentTemplateModel): type=self.type, **kwargs ) + instantiate.do_not_call_in_templates = True def to_yaml(self): return { @@ -256,6 +257,7 @@ class PowerPortTemplate(ModularComponentTemplateModel): allocated_draw=self.allocated_draw, **kwargs ) + instantiate.do_not_call_in_templates = True def clean(self): super().clean() @@ -330,6 +332,7 @@ class PowerOutletTemplate(ModularComponentTemplateModel): feed_leg=self.feed_leg, **kwargs ) + instantiate.do_not_call_in_templates = True def to_yaml(self): return { @@ -413,6 +416,7 @@ class InterfaceTemplate(ModularComponentTemplateModel): poe_type=self.poe_type, **kwargs ) + instantiate.do_not_call_in_templates = True def to_yaml(self): return { @@ -507,6 +511,7 @@ class FrontPortTemplate(ModularComponentTemplateModel): rear_port_position=self.rear_port_position, **kwargs ) + instantiate.do_not_call_in_templates = True def to_yaml(self): return { @@ -550,6 +555,7 @@ class RearPortTemplate(ModularComponentTemplateModel): positions=self.positions, **kwargs ) + instantiate.do_not_call_in_templates = True def to_yaml(self): return { @@ -581,6 +587,7 @@ class ModuleBayTemplate(ComponentTemplateModel): label=self.label, position=self.position ) + instantiate.do_not_call_in_templates = True def to_yaml(self): return { @@ -603,6 +610,7 @@ class DeviceBayTemplate(ComponentTemplateModel): name=self.name, label=self.label ) + instantiate.do_not_call_in_templates = True def clean(self): if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT: @@ -696,3 +704,4 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel): part_id=self.part_id, **kwargs ) + instantiate.do_not_call_in_templates = True diff --git a/netbox/extras/models/configs.py b/netbox/extras/models/configs.py index 632323af0..ee9f7cfda 100644 --- a/netbox/extras/models/configs.py +++ b/netbox/extras/models/configs.py @@ -146,6 +146,7 @@ class ConfigContext(SyncedDataMixin, CloningMixin, ChangeLoggedModel): Synchronize context data from the designated DataFile (if any). """ self.data = self.data_file.get_data() + sync_data.alters_data = True class ConfigContextModel(models.Model): @@ -236,6 +237,7 @@ class ConfigTemplate(SyncedDataMixin, ExportTemplatesMixin, TagsMixin, ChangeLog Synchronize template content from the designated DataFile (if any). """ self.template_code = self.data_file.data_as_string + sync_data.alters_data = True def render(self, context=None): """ diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 9433ab6b0..969fd22e0 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -362,6 +362,7 @@ class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, Change Synchronize template content from the designated DataFile (if any). """ self.template_code = self.data_file.data_as_string + sync_data.alters_data = True def render(self, queryset): """ @@ -625,6 +626,7 @@ class ConfigRevision(models.Model): """ cache.set('config', self.data, None) cache.set('config_version', self.pk, None) + activate.alters_data = True @admin.display(boolean=True) def is_active(self): diff --git a/netbox/extras/models/staging.py b/netbox/extras/models/staging.py index b46d6a7bc..3d1c149bc 100644 --- a/netbox/extras/models/staging.py +++ b/netbox/extras/models/staging.py @@ -112,3 +112,4 @@ class StagedChange(ChangeLoggedModel): instance = self.model.objects.get(pk=self.object_id) logger.info(f'Deleting {self.model._meta.verbose_name} {instance}') instance.delete() + apply.alters_data = True diff --git a/netbox/netbox/models/features.py b/netbox/netbox/models/features.py index 8bacba534..8d79dd6bc 100644 --- a/netbox/netbox/models/features.py +++ b/netbox/netbox/models/features.py @@ -71,6 +71,7 @@ class ChangeLoggingMixin(models.Model): `_prechange_snapshot` on the instance. """ self._prechange_snapshot = self.serialize_object() + snapshot.alters_data = True def to_objectchange(self, action): """ @@ -244,6 +245,7 @@ class CustomFieldsMixin(models.Model): """ for cf in self.custom_fields: self.custom_field_data[cf.name] = cf.default + populate_custom_field_defaults.alters_data = True def clean(self): super().clean() @@ -419,6 +421,7 @@ class SyncedDataMixin(models.Model): self.data_synced = None super().clean() + clean.alters_data = True def save(self, *args, **kwargs): from core.models import AutoSyncRecord @@ -466,6 +469,7 @@ class SyncedDataMixin(models.Model): self.data_synced = timezone.now() if save: self.save() + sync.alters_data = True def sync_data(self): """ From 93175888f088aa99c58b05e8deef806f0b640c24 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Wed, 14 Jun 2023 13:36:30 +0530 Subject: [PATCH 58/74] add color to ChangeActionChoices #12828 --- netbox/extras/choices.py | 6 +++--- netbox/extras/models/staging.py | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/netbox/extras/choices.py b/netbox/extras/choices.py index 6fc14b965..63bdbf7db 100644 --- a/netbox/extras/choices.py +++ b/netbox/extras/choices.py @@ -210,7 +210,7 @@ class ChangeActionChoices(ChoiceSet): ACTION_DELETE = 'delete' CHOICES = ( - (ACTION_CREATE, 'Create'), - (ACTION_UPDATE, 'Update'), - (ACTION_DELETE, 'Delete'), + (ACTION_CREATE, 'Create', 'green'), + (ACTION_UPDATE, 'Update', 'blue'), + (ACTION_DELETE, 'Delete', 'red'), ) diff --git a/netbox/extras/models/staging.py b/netbox/extras/models/staging.py index b46d6a7bc..6d86e0dfe 100644 --- a/netbox/extras/models/staging.py +++ b/netbox/extras/models/staging.py @@ -112,3 +112,6 @@ class StagedChange(ChangeLoggedModel): instance = self.model.objects.get(pk=self.object_id) logger.info(f'Deleting {self.model._meta.verbose_name} {instance}') instance.delete() + + def get_action_color(self): + return ChangeActionChoices.colors.get(self.action) From 0b2162569ff3801d9e51aa69348baffd6d8dc464 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 16 May 2023 10:49:01 -0700 Subject: [PATCH 59/74] 12474 update cable terminations when moving location between sites --- netbox/dcim/signals.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/dcim/signals.py b/netbox/dcim/signals.py index 7ef08d2cc..a51872719 100644 --- a/netbox/dcim/signals.py +++ b/netbox/dcim/signals.py @@ -27,6 +27,7 @@ def handle_location_site_change(instance, created, **kwargs): Rack.objects.filter(location__in=locations).update(site=instance.site) Device.objects.filter(location__in=locations).update(site=instance.site) PowerPanel.objects.filter(location__in=locations).update(site=instance.site) + CableTermination.objects.filter(_location__in=locations).update(_site=instance.site) @receiver(post_save, sender=Rack) From 8aeb31751ab6b36d92ffd485aab5879473e63eca Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 14 Jun 2023 15:29:48 -0400 Subject: [PATCH 60/74] Fixes #12845: Fix pagination of related IP addresses table --- .../ipam/ipaddress/ip_addresses.html | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/netbox/templates/ipam/ipaddress/ip_addresses.html b/netbox/templates/ipam/ipaddress/ip_addresses.html index 7034329aa..b82ec2375 100644 --- a/netbox/templates/ipam/ipaddress/ip_addresses.html +++ b/netbox/templates/ipam/ipaddress/ip_addresses.html @@ -2,18 +2,18 @@ {% load helpers %} {% block content %} - {% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %} - - {% csrf_token %} -
-
- {% include 'htmx/table.html' %} -
-
- -{% endblock content %} + {% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %} +
+ {% csrf_token %} +
+
+ {% include 'htmx/table.html' %} +
+
+
+{% endblock %} {% block modals %} - {{ block.super }} - {% table_config_form table %} + {{ block.super }} + {% table_config_form table %} {% endblock modals %} From 7fc69f3945a123aff522f3a2fe110a1f96245ebc Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 15 Jun 2023 09:17:03 -0400 Subject: [PATCH 61/74] Fixes #12914: Clear stored ordering from user config when cleared by request --- netbox/netbox/tables/tables.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/netbox/netbox/tables/tables.py b/netbox/netbox/tables/tables.py index 839d85996..20eab822d 100644 --- a/netbox/netbox/tables/tables.py +++ b/netbox/netbox/tables/tables.py @@ -140,10 +140,14 @@ class BaseTable(tables.Table): if request.user.is_authenticated: table_name = self.__class__.__name__ if self.prefixed_order_by_field in request.GET: - # If an ordering has been specified as a query parameter, save it as the - # user's preferred ordering for this table. - ordering = request.GET.getlist(self.prefixed_order_by_field) - request.user.config.set(f'tables.{table_name}.ordering', ordering, commit=True) + if request.GET[self.prefixed_order_by_field]: + # If an ordering has been specified as a query parameter, save it as the + # user's preferred ordering for this table. + ordering = request.GET.getlist(self.prefixed_order_by_field) + request.user.config.set(f'tables.{table_name}.ordering', ordering, commit=True) + else: + # If the ordering has been set to none (empty), clear any existing preference. + request.user.config.clear(f'tables.{table_name}.ordering', commit=True) elif ordering := request.user.config.get(f'tables.{table_name}.ordering'): # If no ordering has been specified, set the preferred ordering (if any). self.order_by = ordering From 6ef333ea6870f2b62bf62053f05cc93fdbb83bc3 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 15 Jun 2023 15:00:45 -0400 Subject: [PATCH 62/74] Fixes #12885: Permit mounting of devices in U100 (#12901) * Fixes #12885: Permit mounting of devices in U100 * Define a RACK_U_HEIGHT_MAX constant --- netbox/dcim/constants.py | 1 + netbox/dcim/migrations/0154_half_height_rack_units.py | 2 +- netbox/dcim/models/devices.py | 2 +- netbox/dcim/models/racks.py | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/netbox/dcim/constants.py b/netbox/dcim/constants.py index 80d7558c9..b3c065b5a 100644 --- a/netbox/dcim/constants.py +++ b/netbox/dcim/constants.py @@ -11,6 +11,7 @@ DEVICETYPE_IMAGE_FORMATS = 'image/bmp,image/gif,image/jpeg,image/png,image/tiff, # RACK_U_HEIGHT_DEFAULT = 42 +RACK_U_HEIGHT_MAX = 100 RACK_ELEVATION_BORDER_WIDTH = 2 RACK_ELEVATION_DEFAULT_LEGEND_WIDTH = 30 diff --git a/netbox/dcim/migrations/0154_half_height_rack_units.py b/netbox/dcim/migrations/0154_half_height_rack_units.py index dd21fddcf..f212aa21a 100644 --- a/netbox/dcim/migrations/0154_half_height_rack_units.py +++ b/netbox/dcim/migrations/0154_half_height_rack_units.py @@ -18,6 +18,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='device', name='position', - field=models.DecimalField(blank=True, decimal_places=1, max_digits=4, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(99.5)]), + field=models.DecimalField(blank=True, decimal_places=1, max_digits=4, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100.5)]), ), ] diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 85a5d6870..4cf330ffd 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -568,7 +568,7 @@ class Device(PrimaryModel, ConfigContextModel): decimal_places=1, blank=True, null=True, - validators=[MinValueValidator(1), MaxValueValidator(99.5)], + validators=[MinValueValidator(1), MaxValueValidator(RACK_U_HEIGHT_MAX + 0.5)], verbose_name='Position (U)', help_text=_('The lowest-numbered unit occupied by the device') ) diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 54de5c434..d73c8e27b 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -126,7 +126,7 @@ class Rack(PrimaryModel, WeightMixin): u_height = models.PositiveSmallIntegerField( default=RACK_U_HEIGHT_DEFAULT, verbose_name='Height (U)', - validators=[MinValueValidator(1), MaxValueValidator(100)], + validators=[MinValueValidator(1), MaxValueValidator(RACK_U_HEIGHT_MAX)], help_text=_('Height in rack units') ) desc_units = models.BooleanField( From e11991c7a4caceb33f55412d8dffa1051223abcd Mon Sep 17 00:00:00 2001 From: Luke Anderson Date: Fri, 16 Jun 2023 04:34:08 +0930 Subject: [PATCH 63/74] Fix #12865 - Include Add Nav Buttons for Report and Script Objects (#12909) --- netbox/netbox/navigation/menu.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index d139546d9..e009f62f1 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -301,12 +301,14 @@ CUSTOMIZATION_MENU = Menu( MenuItem( link='extras:report_list', link_text=_('Reports'), - permissions=['extras.view_report'] + permissions=['extras.view_report'], + buttons=get_model_buttons('extras', "reportmodule", actions=['add']) ), MenuItem( link='extras:script_list', link_text=_('Scripts'), - permissions=['extras.view_script'] + permissions=['extras.view_script'], + buttons=get_model_buttons('extras', "scriptmodule", actions=['add']) ), ), ), From cdce500d909ffc91d24107fa60191da9d00828ec Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 15 Jun 2023 16:15:15 -0400 Subject: [PATCH 64/74] Changelog for #12474, #12828, #12845, #12865, #12885, #12914 --- docs/release-notes/version-3.5.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index f2a3de0e8..29c9b5d50 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -4,18 +4,24 @@ ### Enhancements +* [#12828](https://github.com/netbox-community/netbox/issues/12828) - Define colors for staged change action choices * [#12847](https://github.com/netbox-community/netbox/issues/12847) - Include "add" button on all device & virtual machine component list views * [#12862](https://github.com/netbox-community/netbox/issues/12862) - Add menu navigation button to add wireless links directly +* [#12865](https://github.com/netbox-community/netbox/issues/12865) - Add "add" buttons for reports & scripts to navigation menu ### Bug Fixes +* [#12474](https://github.com/netbox-community/netbox/issues/12474) - Update cable terminations when assigning a location to a new site * [#12622](https://github.com/netbox-community/netbox/issues/12622) - Permit the assignment of non-site VLANs to prefixes assigned to a site * [#12682](https://github.com/netbox-community/netbox/issues/12682) - Correct OpenAPI schema for connected device API endpoint * [#12687](https://github.com/netbox-community/netbox/issues/12687) - Allow the assignment of all /31 IP addresses to interfaces * [#12818](https://github.com/netbox-community/netbox/issues/12818) - Fix permissions evaluation when queuing a data sync job * [#12822](https://github.com/netbox-community/netbox/issues/12822) - Fix encoding of whitespace in custom link URLs * [#12838](https://github.com/netbox-community/netbox/issues/12838) - Correct rounding of rack power utilization values +* [#12845](https://github.com/netbox-community/netbox/issues/12845) - Fix pagination of objects for related IP addresses table * [#12850](https://github.com/netbox-community/netbox/issues/12850) - Fix table configuration modal for the contact assignments list +* [#12885](https://github.com/netbox-community/netbox/issues/12885) - Permit mounting of devices in rack unit 100 +* [#12914](https://github.com/netbox-community/netbox/issues/12914) - Clear stored ordering from user config when cleared by request --- From 54622b5f9263dfe2bea9edb2b2e9559096762697 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 20 Jun 2023 13:56:09 -0400 Subject: [PATCH 65/74] Release v3.5.4 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- docs/release-notes/version-3.5.md | 2 +- netbox/netbox/settings.py | 2 +- requirements.txt | 16 ++++++++-------- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 5e456d0df..b3dd583ca 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.5.3 + placeholder: v3.5.4 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index e317dd64c..bd93001e7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.5.3 + placeholder: v3.5.4 validations: required: true - type: dropdown diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 29c9b5d50..49d2e6347 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -1,6 +1,6 @@ # NetBox v3.5 -## v3.5.4 (FUTURE) +## v3.5.4 (2023-06-20) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index e77ac43c0..22193dbac 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW # Environment setup # -VERSION = '3.5.4-dev' +VERSION = '3.5.4' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index ee6a79635..e6e56ce56 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,19 +1,19 @@ bleach==6.0.0 -boto3==1.26.145 +boto3==1.26.156 Django==4.1.9 -django-cors-headers==4.0.0 +django-cors-headers==4.1.0 django-debug-toolbar==4.1.0 django-filter==23.2 django-graphiql-debug-toolbar==0.2.0 django-mptt==0.14 django-pglocks==1.0.4 django-prometheus==2.3.1 -django-redis==5.2.0 -django-rich==1.5.0 +django-redis==5.3.0 +django-rich==1.6.0 django-rq==2.8.1 django-tables2==2.5.3 django-taggit==4.0.0 -django-timezone-field==5.0 +django-timezone-field==5.1 djangorestframework==3.14.0 drf-spectacular==0.26.2 drf-spectacular-sidecar==2023.6.1 @@ -23,15 +23,15 @@ graphene-django==3.0.0 gunicorn==20.1.0 Jinja2==3.1.2 Markdown==3.3.7 -mkdocs-material==9.1.15 +mkdocs-material==9.1.16 mkdocstrings[python-legacy]==0.22.0 netaddr==0.8.0 Pillow==9.5.0 psycopg2-binary==2.9.6 PyYAML==6.0 -sentry-sdk==1.25.0 +sentry-sdk==1.25.1 social-auth-app-django==5.2.0 social-auth-core[openidconnect]==4.4.2 svgwrite==1.4.3 -tablib==3.4.0 +tablib==3.5.0 tzdata==2023.3 From 70c2b358ad6c778344b2ee0639dab6b76f751fdc Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 20 Jun 2023 14:27:18 -0400 Subject: [PATCH 66/74] PRVB --- docs/release-notes/version-3.5.md | 4 ++++ netbox/netbox/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.5.md b/docs/release-notes/version-3.5.md index 49d2e6347..7ad333e47 100644 --- a/docs/release-notes/version-3.5.md +++ b/docs/release-notes/version-3.5.md @@ -1,5 +1,9 @@ # NetBox v3.5 +## v3.5.5 (FUTURE) + +--- + ## v3.5.4 (2023-06-20) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 22193dbac..31363144f 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW # Environment setup # -VERSION = '3.5.4' +VERSION = '3.5.5-dev' # Hostname HOSTNAME = platform.node() From bace24b68e4f38456f275802e64a6b595c69e263 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 20 Jun 2023 15:04:10 -0400 Subject: [PATCH 67/74] 12180 available objects api (#12935) * Introduce AvailableObjectsView and refactor 'available objects' API views * Restore advisory PostgreSQL locks * Move get_next_available_prefix() * Apply OpenAPI decorators for get() and post() --- netbox/ipam/api/serializers.py | 2 + netbox/ipam/api/views.py | 447 +++++++++++++++------------------ netbox/ipam/utils.py | 22 +- 3 files changed, 226 insertions(+), 245 deletions(-) diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index 064452667..f59850aa2 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -58,6 +58,7 @@ class AvailableASNSerializer(serializers.Serializer): Representation of an ASN which does not exist in the database. """ asn = serializers.IntegerField(read_only=True) + description = serializers.CharField(required=False) def to_representation(self, asn): rir = NestedRIRSerializer(self.context['range'].rir, context={ @@ -432,6 +433,7 @@ class AvailableIPSerializer(serializers.Serializer): family = serializers.IntegerField(read_only=True) address = serializers.CharField(read_only=True) vrf = NestedVRFSerializer(read_only=True) + description = serializers.CharField(required=False) def to_representation(self, instance): if self.context.get('vrf'): diff --git a/netbox/ipam/api/views.py b/netbox/ipam/api/views.py index f432e0e6b..c895a706b 100644 --- a/netbox/ipam/api/views.py +++ b/netbox/ipam/api/views.py @@ -3,7 +3,9 @@ from django.db import transaction from django.shortcuts import get_object_or_404 from django_pglocks import advisory_lock from drf_spectacular.utils import extend_schema +from netaddr import IPSet from rest_framework import status +from rest_framework.exceptions import ValidationError from rest_framework.response import Response from rest_framework.routers import APIRootView from rest_framework.views import APIView @@ -12,10 +14,12 @@ from circuits.models import Provider from dcim.models import Site from ipam import filtersets from ipam.models import * +from ipam.utils import get_next_available_prefix from netbox.api.viewsets import NetBoxModelViewSet from netbox.api.viewsets.mixins import ObjectValidationMixin from netbox.config import get_config from netbox.constants import ADVISORY_LOCK_KEYS +from utilities.api import get_serializer_for_model from utilities.utils import count_related from . import serializers from ipam.models import L2VPN, L2VPNTermination @@ -207,237 +211,233 @@ def get_results_limit(request): return limit -class AvailableASNsView(ObjectValidationMixin, APIView): - queryset = ASN.objects.all() +class AvailableObjectsView(ObjectValidationMixin, APIView): + """ + Return a list of dicts representing child objects that have not yet been created for a parent object. + """ + read_serializer_class = None + write_serializer_class = None + advisory_lock_key = None + + def get_parent(self, request, pk): + """ + Return the parent object. + """ + raise NotImplemented() + + def get_available_objects(self, parent, limit=None): + """ + Return all available objects for the parent. + """ + raise NotImplemented() + + def get_extra_context(self, parent): + """ + Return any extra context data for the serializer. + """ + return {} + + def check_sufficient_available(self, requested_objects, available_objects): + """ + Check if there exist a sufficient number of available objects to satisfy the request. + """ + return len(requested_objects) <= len(available_objects) + + def prep_object_data(self, requested_objects, available_objects, parent): + """ + Prepare data by setting any programmatically determined object attributes (e.g. next available VLAN ID) + on the request data. + """ + return requested_objects - @extend_schema(methods=["get"], responses={200: serializers.AvailableASNSerializer(many=True)}) def get(self, request, pk): - asnrange = get_object_or_404(ASNRange.objects.restrict(request.user), pk=pk) + parent = self.get_parent(request, pk) limit = get_results_limit(request) + available_objects = self.get_available_objects(parent, limit) - available_asns = asnrange.get_available_asns()[:limit] - - serializer = serializers.AvailableASNSerializer(available_asns, many=True, context={ + serializer = self.read_serializer_class(available_objects, many=True, context={ 'request': request, - 'range': asnrange, + **self.get_extra_context(parent), }) return Response(serializer.data) - @extend_schema(methods=["post"], responses={201: serializers.ASNSerializer(many=True)}) - @advisory_lock(ADVISORY_LOCK_KEYS['available-asns']) def post(self, request, pk): self.queryset = self.queryset.restrict(request.user, 'add') - asnrange = get_object_or_404(ASNRange.objects.restrict(request.user), pk=pk) + parent = self.get_parent(request, pk) - # Normalize to a list of objects - requested_asns = request.data if isinstance(request.data, list) else [request.data] + # Normalize request data to a list of objects + requested_objects = request.data if isinstance(request.data, list) else [request.data] - # Determine if the requested number of IPs is available - available_asns = asnrange.get_available_asns() - if len(available_asns) < len(requested_asns): - return Response( - { - "detail": f"An insufficient number of ASNs are available within {asnrange} " - f"({len(requested_asns)} requested, {len(available_asns)} available)" - }, - status=status.HTTP_409_CONFLICT - ) - - # Assign ASNs from the list of available IPs and copy VRF assignment from the parent - for i, requested_asn in enumerate(requested_asns): - requested_asn.update({ - 'rir': asnrange.rir.pk, - 'range': asnrange.pk, - 'asn': available_asns[i], - }) - - # Initialize the serializer with a list or a single object depending on what was requested - context = {'request': request} - if isinstance(request.data, list): - serializer = serializers.ASNSerializer(data=requested_asns, many=True, context=context) - else: - serializer = serializers.ASNSerializer(data=requested_asns[0], context=context) - - # Create the new IP address(es) - if serializer.is_valid(): - try: - with transaction.atomic(): - created = serializer.save() - self._validate_objects(created) - except ObjectDoesNotExist: - raise PermissionDenied() - return Response(serializer.data, status=status.HTTP_201_CREATED) - - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - def get_serializer_class(self): - if self.request.method == "GET": - return serializers.AvailableASNSerializer - - return serializers.ASNSerializer - - -class AvailablePrefixesView(ObjectValidationMixin, APIView): - queryset = Prefix.objects.all() - - @extend_schema(methods=["get"], responses={200: serializers.AvailablePrefixSerializer(many=True)}) - def get(self, request, pk): - prefix = get_object_or_404(Prefix.objects.restrict(request.user), pk=pk) - available_prefixes = prefix.get_available_prefixes() - - serializer = serializers.AvailablePrefixSerializer(available_prefixes.iter_cidrs(), many=True, context={ + # Serialize and validate the request data + serializer = self.write_serializer_class(data=requested_objects, many=True, context={ 'request': request, - 'vrf': prefix.vrf, + **self.get_extra_context(parent), }) - - return Response(serializer.data) - - @extend_schema(methods=["post"], responses={201: serializers.PrefixSerializer(many=True)}) - @advisory_lock(ADVISORY_LOCK_KEYS['available-prefixes']) - def post(self, request, pk): - self.queryset = self.queryset.restrict(request.user, 'add') - prefix = get_object_or_404(Prefix.objects.restrict(request.user), pk=pk) - available_prefixes = prefix.get_available_prefixes() - - # Validate Requested Prefixes' length - serializer = serializers.PrefixLengthSerializer( - data=request.data if isinstance(request.data, list) else [request.data], - many=True, - context={ - 'request': request, - 'prefix': prefix, - } - ) if not serializer.is_valid(): return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST ) - requested_prefixes = serializer.validated_data - # Allocate prefixes to the requested objects based on availability within the parent - for i, requested_prefix in enumerate(requested_prefixes): + with advisory_lock(ADVISORY_LOCK_KEYS[self.advisory_lock_key]): + available_objects = self.get_available_objects(parent) - # Find the first available prefix equal to or larger than the requested size - for available_prefix in available_prefixes.iter_cidrs(): - if requested_prefix['prefix_length'] >= available_prefix.prefixlen: - allocated_prefix = '{}/{}'.format(available_prefix.network, requested_prefix['prefix_length']) - requested_prefix['prefix'] = allocated_prefix - requested_prefix['vrf'] = prefix.vrf.pk if prefix.vrf else None - break - else: + # Determine if the requested number of objects is available + if not self.check_sufficient_available(serializer.validated_data, available_objects): return Response( - { - "detail": "Insufficient space is available to accommodate the requested prefix size(s)" - }, + {"detail": f"Insufficient resources are available to satisfy the request"}, status=status.HTTP_409_CONFLICT ) - # Remove the allocated prefix from the list of available prefixes - available_prefixes.remove(allocated_prefix) + # Prepare object data for deserialization + requested_objects = self.prep_object_data(serializer.validated_data, available_objects, parent) - # Initialize the serializer with a list or a single object depending on what was requested - context = {'request': request} - if isinstance(request.data, list): - serializer = serializers.PrefixSerializer(data=requested_prefixes, many=True, context=context) - else: - serializer = serializers.PrefixSerializer(data=requested_prefixes[0], context=context) + # Initialize the serializer with a list or a single object depending on what was requested + serializer_class = get_serializer_for_model(self.queryset.model) + context = {'request': request} + if isinstance(request.data, list): + serializer = serializer_class(data=requested_objects, many=True, context=context) + else: + serializer = serializer_class(data=requested_objects[0], context=context) - # Create the new Prefix(es) - if serializer.is_valid(): + if not serializer.is_valid(): + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + # Create the new IP address(es) try: with transaction.atomic(): created = serializer.save() self._validate_objects(created) except ObjectDoesNotExist: raise PermissionDenied() - return Response(serializer.data, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - def get_serializer_class(self): - if self.request.method == "GET": - return serializers.AvailablePrefixSerializer - - return serializers.PrefixLengthSerializer + return Response(serializer.data, status=status.HTTP_201_CREATED) -class AvailableIPAddressesView(ObjectValidationMixin, APIView): - queryset = IPAddress.objects.all() +class AvailableASNsView(AvailableObjectsView): + queryset = ASN.objects.all() + read_serializer_class = serializers.AvailableASNSerializer + write_serializer_class = serializers.AvailableASNSerializer + advisory_lock_key = 'available-asns' def get_parent(self, request, pk): - raise NotImplemented() + return get_object_or_404(ASNRange.objects.restrict(request.user), pk=pk) - @extend_schema(methods=["get"], responses={200: serializers.AvailableIPSerializer(many=True)}) + def get_available_objects(self, parent, limit=None): + return parent.get_available_asns()[:limit] + + def get_extra_context(self, parent): + return { + 'range': parent, + } + + def prep_object_data(self, requested_objects, available_objects, parent): + for i, request_data in enumerate(requested_objects): + request_data.update({ + 'rir': parent.rir.pk, + 'range': parent.pk, + 'asn': available_objects[i], + }) + + return requested_objects + + @extend_schema(methods=["get"], responses={200: serializers.AvailableASNSerializer(many=True)}) def get(self, request, pk): - parent = self.get_parent(request, pk) - limit = get_results_limit(request) + return super().get(request, pk) + @extend_schema(methods=["post"], responses={201: serializers.AvailableASNSerializer(many=True)}) + def post(self, request, pk): + return super().post(request, pk) + + +class AvailablePrefixesView(AvailableObjectsView): + queryset = Prefix.objects.all() + read_serializer_class = serializers.AvailablePrefixSerializer + write_serializer_class = serializers.PrefixLengthSerializer + advisory_lock_key = 'available-prefixes' + + def get_parent(self, request, pk): + return get_object_or_404(Prefix.objects.restrict(request.user), pk=pk) + + def get_available_objects(self, parent, limit=None): + return parent.get_available_prefixes().iter_cidrs() + + def check_sufficient_available(self, requested_objects, available_objects): + available_prefixes = IPSet(available_objects) + for requested_object in requested_objects: + if not get_next_available_prefix(available_prefixes, requested_object['prefix_length']): + return False + return True + + def get_extra_context(self, parent): + return { + 'prefix': parent, + 'vrf': parent.vrf, + } + + def prep_object_data(self, requested_objects, available_objects, parent): + available_prefixes = IPSet(available_objects) + for i, request_data in enumerate(requested_objects): + + # Find the first available prefix equal to or larger than the requested size + if allocated_prefix := get_next_available_prefix(available_prefixes, request_data['prefix_length']): + request_data.update({ + 'prefix': allocated_prefix, + 'vrf': parent.vrf.pk if parent.vrf else None, + }) + else: + raise ValidationError("Insufficient space is available to accommodate the requested prefix size(s)") + + return requested_objects + + @extend_schema(methods=["get"], responses={200: serializers.AvailablePrefixSerializer(many=True)}) + def get(self, request, pk): + return super().get(request, pk) + + @extend_schema(methods=["post"], responses={201: serializers.PrefixSerializer(many=True)}) + def post(self, request, pk): + return super().post(request, pk) + + +class AvailableIPAddressesView(AvailableObjectsView): + queryset = IPAddress.objects.all() + read_serializer_class = serializers.AvailableIPSerializer + write_serializer_class = serializers.AvailableIPSerializer + advisory_lock_key = 'available-ips' + + def get_available_objects(self, parent, limit=None): # Calculate available IPs within the parent ip_list = [] for index, ip in enumerate(parent.get_available_ips(), start=1): ip_list.append(ip) if index == limit: break - serializer = serializers.AvailableIPSerializer(ip_list, many=True, context={ - 'request': request, + return ip_list + + def get_extra_context(self, parent): + return { 'parent': parent, 'vrf': parent.vrf, - }) + } - return Response(serializer.data) + def prep_object_data(self, requested_objects, available_objects, parent): + available_ips = iter(available_objects) + for i, request_data in enumerate(requested_objects): + request_data.update({ + 'address': f'{next(available_ips)}/{parent.mask_length}', + 'vrf': parent.vrf.pk if parent.vrf else None, + }) + + return requested_objects + + @extend_schema(methods=["get"], responses={200: serializers.AvailableIPSerializer(many=True)}) + def get(self, request, pk): + return super().get(request, pk) @extend_schema(methods=["post"], responses={201: serializers.IPAddressSerializer(many=True)}) - @advisory_lock(ADVISORY_LOCK_KEYS['available-ips']) def post(self, request, pk): - self.queryset = self.queryset.restrict(request.user, 'add') - parent = self.get_parent(request, pk) - - # Normalize to a list of objects - requested_ips = request.data if isinstance(request.data, list) else [request.data] - - # Determine if the requested number of IPs is available - available_ips = parent.get_available_ips() - if available_ips.size < len(requested_ips): - return Response( - { - "detail": f"An insufficient number of IP addresses are available within {parent} " - f"({len(requested_ips)} requested, {len(available_ips)} available)" - }, - status=status.HTTP_409_CONFLICT - ) - - # Assign addresses from the list of available IPs and copy VRF assignment from the parent - available_ips = iter(available_ips) - for requested_ip in requested_ips: - requested_ip['address'] = f'{next(available_ips)}/{parent.mask_length}' - requested_ip['vrf'] = parent.vrf.pk if parent.vrf else None - - # Initialize the serializer with a list or a single object depending on what was requested - context = {'request': request} - if isinstance(request.data, list): - serializer = serializers.IPAddressSerializer(data=requested_ips, many=True, context=context) - else: - serializer = serializers.IPAddressSerializer(data=requested_ips[0], context=context) - - # Create the new IP address(es) - if serializer.is_valid(): - try: - with transaction.atomic(): - created = serializer.save() - self._validate_objects(created) - except ObjectDoesNotExist: - raise PermissionDenied() - return Response(serializer.data, status=status.HTTP_201_CREATED) - - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - def get_serializer_class(self): - if self.request.method == "GET": - return serializers.AvailableIPSerializer - - return serializers.IPAddressSerializer + return super().post(request, pk) class PrefixAvailableIPAddressesView(AvailableIPAddressesView): @@ -452,77 +452,36 @@ class IPRangeAvailableIPAddressesView(AvailableIPAddressesView): return get_object_or_404(IPRange.objects.restrict(request.user), pk=pk) -class AvailableVLANsView(ObjectValidationMixin, APIView): +class AvailableVLANsView(AvailableObjectsView): queryset = VLAN.objects.all() + read_serializer_class = serializers.AvailableVLANSerializer + write_serializer_class = serializers.CreateAvailableVLANSerializer + advisory_lock_key = 'available-vlans' + + def get_parent(self, request, pk): + return get_object_or_404(VLANGroup.objects.restrict(request.user), pk=pk) + + def get_available_objects(self, parent, limit=None): + return parent.get_available_vids()[:limit] + + def get_extra_context(self, parent): + return { + 'group': parent, + } + + def prep_object_data(self, requested_objects, available_objects, parent): + for i, request_data in enumerate(requested_objects): + request_data.update({ + 'vid': available_objects.pop(0), + 'group': parent.pk, + }) + + return requested_objects @extend_schema(methods=["get"], responses={200: serializers.AvailableVLANSerializer(many=True)}) def get(self, request, pk): - vlangroup = get_object_or_404(VLANGroup.objects.restrict(request.user), pk=pk) - limit = get_results_limit(request) - - available_vlans = vlangroup.get_available_vids()[:limit] - serializer = serializers.AvailableVLANSerializer(available_vlans, many=True, context={ - 'request': request, - 'group': vlangroup, - }) - - return Response(serializer.data) + return super().get(request, pk) @extend_schema(methods=["post"], responses={201: serializers.VLANSerializer(many=True)}) - @advisory_lock(ADVISORY_LOCK_KEYS['available-vlans']) def post(self, request, pk): - self.queryset = self.queryset.restrict(request.user, 'add') - vlangroup = get_object_or_404(VLANGroup.objects.restrict(request.user), pk=pk) - available_vlans = vlangroup.get_available_vids() - many = isinstance(request.data, list) - - # Validate requested VLANs - serializer = serializers.CreateAvailableVLANSerializer( - data=request.data if many else [request.data], - many=True, - context={ - 'request': request, - 'group': vlangroup, - } - ) - if not serializer.is_valid(): - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST - ) - - requested_vlans = serializer.validated_data - - for i, requested_vlan in enumerate(requested_vlans): - try: - requested_vlan['vid'] = available_vlans.pop(0) - requested_vlan['group'] = vlangroup.pk - except IndexError: - return Response({ - "detail": "The requested number of VLANs is not available" - }, status=status.HTTP_409_CONFLICT) - - # Initialize the serializer with a list or a single object depending on what was requested - context = {'request': request} - if many: - serializer = serializers.VLANSerializer(data=requested_vlans, many=True, context=context) - else: - serializer = serializers.VLANSerializer(data=requested_vlans[0], context=context) - - # Create the new VLAN(s) - if serializer.is_valid(): - try: - with transaction.atomic(): - created = serializer.save() - self._validate_objects(created) - except ObjectDoesNotExist: - raise PermissionDenied() - return Response(serializer.data, status=status.HTTP_201_CREATED) - - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - def get_serializer_class(self): - if self.request.method == "GET": - return serializers.AvailableVLANSerializer - - return serializers.VLANSerializer + return super().post(request, pk) diff --git a/netbox/ipam/utils.py b/netbox/ipam/utils.py index 93a40e5a0..f54c7d41d 100644 --- a/netbox/ipam/utils.py +++ b/netbox/ipam/utils.py @@ -1,7 +1,15 @@ import netaddr from .constants import * -from .models import ASN, Prefix, VLAN +from .models import Prefix, VLAN + +__all__ = ( + 'add_available_ipaddresses', + 'add_available_vlans', + 'add_requested_prefixes', + 'get_next_available_prefix', + 'rebuild_prefixes', +) def add_requested_prefixes(parent, prefix_list, show_available=True, show_assigned=True): @@ -184,3 +192,15 @@ def rebuild_prefixes(vrf): # Final flush of any remaining Prefixes Prefix.objects.bulk_update(update_queue, ['_depth', '_children']) + + +def get_next_available_prefix(ipset, prefix_size): + """ + Given a prefix length, allocate the next available prefix from an IPSet. + """ + for available_prefix in ipset.iter_cidrs(): + if prefix_size >= available_prefix.prefixlen: + allocated_prefix = f"{available_prefix.network}/{prefix_size}" + ipset.remove(allocated_prefix) + return allocated_prefix + return None From 518fd8cca62db9c558dfc72a440c94c052448e82 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Thu, 22 Jun 2023 05:26:50 -0700 Subject: [PATCH 68/74] 12794 change User ref to get_user_model (#12905) * 12794 change User ref to get_user_model * 12794 call get_user_model once in tests * 12794 call get_user_model once in tests * 12794 use settings.AUTH_USER_MODEL for FK reference --- netbox/core/forms/filtersets.py | 4 ++-- netbox/core/management/commands/nbshell.py | 4 ++-- netbox/core/models/jobs.py | 4 ++-- netbox/dcim/filtersets.py | 6 +++--- netbox/dcim/forms/bulk_edit.py | 4 ++-- netbox/dcim/forms/filtersets.py | 4 ++-- netbox/dcim/forms/model_forms.py | 4 ++-- netbox/dcim/models/racks.py | 4 ++-- netbox/dcim/tests/test_api.py | 5 ++++- netbox/dcim/tests/test_filtersets.py | 5 ++++- netbox/dcim/tests/test_views.py | 5 ++++- netbox/extras/api/serializers.py | 4 ++-- netbox/extras/filtersets.py | 14 +++++++------- netbox/extras/forms/filtersets.py | 6 +++--- netbox/extras/management/commands/runscript.py | 4 +++- netbox/extras/models/change_logging.py | 4 ++-- netbox/extras/models/models.py | 6 +++--- netbox/extras/tests/test_api.py | 5 ++++- netbox/extras/tests/test_filtersets.py | 5 ++++- netbox/extras/tests/test_views.py | 5 ++++- netbox/netbox/tests/test_authentication.py | 6 +++++- netbox/users/api/nested_serializers.py | 5 +++-- netbox/users/api/serializers.py | 7 ++++--- netbox/users/api/views.py | 5 +++-- netbox/users/filtersets.py | 13 +++++++------ netbox/users/graphql/schema.py | 5 +++-- netbox/users/graphql/types.py | 7 ++++--- netbox/users/tests/test_api.py | 6 +++++- netbox/users/tests/test_filtersets.py | 6 +++++- netbox/users/tests/test_models.py | 5 ++++- netbox/users/tests/test_preferences.py | 5 ++++- netbox/utilities/testing/api.py | 5 ++++- netbox/utilities/testing/base.py | 4 ++-- netbox/utilities/testing/utils.py | 5 +++-- 34 files changed, 117 insertions(+), 69 deletions(-) diff --git a/netbox/core/forms/filtersets.py b/netbox/core/forms/filtersets.py index 7c3f2ab09..d8624f6b6 100644 --- a/netbox/core/forms/filtersets.py +++ b/netbox/core/forms/filtersets.py @@ -1,5 +1,5 @@ from django import forms -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext as _ @@ -105,7 +105,7 @@ class JobFilterForm(SavedFiltersMixin, FilterForm): widget=DateTimePicker() ) user = DynamicModelMultipleChoiceField( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), required=False, label=_('User'), widget=APISelectMultiple( diff --git a/netbox/core/management/commands/nbshell.py b/netbox/core/management/commands/nbshell.py index 04a67eb49..674a878c7 100644 --- a/netbox/core/management/commands/nbshell.py +++ b/netbox/core/management/commands/nbshell.py @@ -5,7 +5,7 @@ import sys from django import get_version from django.apps import apps from django.conf import settings -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.core.management.base import BaseCommand @@ -60,7 +60,7 @@ class Command(BaseCommand): # Additional objects to include namespace['ContentType'] = ContentType - namespace['User'] = User + namespace['User'] = get_user_model() # Load convenience commands namespace.update({ diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index a91e75e61..9be06bd6d 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -1,7 +1,7 @@ import uuid import django_rq -from django.contrib.auth.models import User +from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.core.validators import MinValueValidator @@ -69,7 +69,7 @@ class Job(models.Model): blank=True ) user = models.ForeignKey( - to=User, + to=settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name='+', blank=True, diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index e87a37847..e53ea8079 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -1,5 +1,5 @@ import django_filters -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.utils.translation import gettext as _ from extras.filtersets import LocalConfigContextFilterSet @@ -395,12 +395,12 @@ class RackReservationFilterSet(NetBoxModelFilterSet, TenancyFilterSet): label=_('Location (slug)'), ) user_id = django_filters.ModelMultipleChoiceFilter( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), to_field_name='username', label=_('User (name)'), ) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index 11cfd685d..309370bfd 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -1,6 +1,6 @@ from django import forms from django.conf import settings -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.utils.translation import gettext as _ from timezone_field import TimeZoneFormField @@ -322,7 +322,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): class RackReservationBulkEditForm(NetBoxModelBulkEditForm): user = forms.ModelChoiceField( - queryset=User.objects.order_by( + queryset=get_user_model().objects.order_by( 'username' ), required=False diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index 4edee6014..0a4a22a70 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -1,5 +1,5 @@ from django import forms -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.utils.translation import gettext as _ from dcim.choices import * @@ -376,7 +376,7 @@ class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): label=_('Rack') ) user_id = DynamicModelMultipleChoiceField( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), required=False, label=_('User'), widget=APISelectMultiple( diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 56542d70c..eda302736 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -1,5 +1,5 @@ from django import forms -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext as _ from timezone_field import TimeZoneFormField @@ -236,7 +236,7 @@ class RackReservationForm(TenancyForm, NetBoxModelForm): help_text=_("Comma-separated list of numeric unit IDs. A range may be specified using a hyphen.") ) user = forms.ModelChoiceField( - queryset=User.objects.order_by( + queryset=get_user_model().objects.order_by( 'username' ) ) diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index d73c8e27b..5ac223c45 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -1,7 +1,7 @@ import decimal from functools import cached_property -from django.contrib.auth.models import User +from django.conf import settings from django.contrib.contenttypes.fields import GenericRelation from django.contrib.postgres.fields import ArrayField from django.core.exceptions import ValidationError @@ -505,7 +505,7 @@ class RackReservation(PrimaryModel): null=True ) user = models.ForeignKey( - to=User, + to=settings.AUTH_USER_MODEL, on_delete=models.PROTECT ) description = models.CharField( diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index af15e1343..ecaf32a06 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -1,4 +1,4 @@ -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.test import override_settings from django.urls import reverse from rest_framework import status @@ -14,6 +14,9 @@ from wireless.choices import WirelessChannelChoices from wireless.models import WirelessLAN +User = get_user_model() + + class AppTest(APITestCase): def test_root(self): diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index aa6860a16..a1e684cb9 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -1,4 +1,4 @@ -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.test import TestCase from dcim.choices import * @@ -12,6 +12,9 @@ from virtualization.models import Cluster, ClusterType from wireless.choices import WirelessChannelChoices, WirelessRoleChoices +User = get_user_model() + + class DeviceComponentFilterSetTests: def test_device_type(self): diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index a327d6400..23683ddce 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -6,7 +6,7 @@ except ImportError: from backports.zoneinfo import ZoneInfo import yaml -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.test import override_settings from django.urls import reverse @@ -22,6 +22,9 @@ from utilities.testing import ViewTestCases, create_tags, create_test_device, po from wireless.models import WirelessLAN +User = get_user_model() + + class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase): model = Region diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index cbe4ed56d..a02e933ba 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -1,4 +1,4 @@ -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from rest_framework import serializers @@ -256,7 +256,7 @@ class JournalEntrySerializer(NetBoxModelSerializer): assigned_object = serializers.SerializerMethodField(read_only=True) created_by = serializers.PrimaryKeyRelatedField( allow_null=True, - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), required=False, default=serializers.CurrentUserDefault() ) diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index 5253ae7b0..2cbaca5f7 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -1,5 +1,5 @@ import django_filters -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.db.models import Q from django.utils.translation import gettext as _ @@ -159,12 +159,12 @@ class SavedFilterFilterSet(BaseFilterSet): ) content_types = ContentTypeFilter() user_id = django_filters.ModelMultipleChoiceFilter( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), to_field_name='username', label=_('User (name)'), ) @@ -223,12 +223,12 @@ class JournalEntryFilterSet(NetBoxModelFilterSet): queryset=ContentType.objects.all() ) created_by_id = django_filters.ModelMultipleChoiceFilter( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), label=_('User (ID)'), ) created_by = django_filters.ModelMultipleChoiceFilter( field_name='created_by__username', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), to_field_name='username', label=_('User (name)'), ) @@ -510,12 +510,12 @@ class ObjectChangeFilterSet(BaseFilterSet): queryset=ContentType.objects.all() ) user_id = django_filters.ModelMultipleChoiceFilter( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), to_field_name='username', label=_('User name'), ) diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index fae15d041..53de81ba2 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -1,5 +1,5 @@ from django import forms -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext as _ @@ -385,7 +385,7 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm): widget=DateTimePicker() ) created_by_id = DynamicModelMultipleChoiceField( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), required=False, label=_('User'), widget=APISelectMultiple( @@ -429,7 +429,7 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm): required=False ) user_id = DynamicModelMultipleChoiceField( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), required=False, label=_('User'), widget=APISelectMultiple( diff --git a/netbox/extras/management/commands/runscript.py b/netbox/extras/management/commands/runscript.py index b42e9b47d..d9a9f41ae 100644 --- a/netbox/extras/management/commands/runscript.py +++ b/netbox/extras/management/commands/runscript.py @@ -4,7 +4,7 @@ import sys import traceback import uuid -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand, CommandError from django.db import transaction @@ -63,6 +63,8 @@ class Command(BaseCommand): logger.info(f"Script completed in {job.duration}") + User = get_user_model() + # Params script = options['script'] loglevel = options['loglevel'] diff --git a/netbox/extras/models/change_logging.py b/netbox/extras/models/change_logging.py index e2b118b84..54d72cdd8 100644 --- a/netbox/extras/models/change_logging.py +++ b/netbox/extras/models/change_logging.py @@ -1,4 +1,4 @@ -from django.contrib.auth.models import User +from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db import models @@ -24,7 +24,7 @@ class ObjectChange(models.Model): db_index=True ) user = models.ForeignKey( - to=User, + to=settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name='changes', blank=True, diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index e95c0aff3..6c7aac08d 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -3,7 +3,7 @@ import urllib.parse from django.conf import settings from django.contrib import admin -from django.contrib.auth.models import User +from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.core.cache import cache @@ -419,7 +419,7 @@ class SavedFilter(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): blank=True ) user = models.ForeignKey( - to=User, + to=settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, blank=True, null=True @@ -560,7 +560,7 @@ class JournalEntry(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ExportTemplat fk_field='assigned_object_id' ) created_by = models.ForeignKey( - to=User, + to=settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, blank=True, null=True diff --git a/netbox/extras/tests/test_api.py b/netbox/extras/tests/test_api.py index b59481a36..4c48aa73e 100644 --- a/netbox/extras/tests/test_api.py +++ b/netbox/extras/tests/test_api.py @@ -1,6 +1,6 @@ import datetime -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.urls import reverse from django.utils.timezone import make_aware @@ -15,6 +15,9 @@ from extras.scripts import BooleanVar, IntegerVar, Script, StringVar from utilities.testing import APITestCase, APIViewTestCases +User = get_user_model() + + class AppTest(APITestCase): def test_root(self): diff --git a/netbox/extras/tests/test_filtersets.py b/netbox/extras/tests/test_filtersets.py index e77afd20e..992643530 100644 --- a/netbox/extras/tests/test_filtersets.py +++ b/netbox/extras/tests/test_filtersets.py @@ -1,7 +1,7 @@ import uuid from datetime import datetime, timezone -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.test import TestCase @@ -18,6 +18,9 @@ from utilities.testing import BaseFilterSetTests, ChangeLoggedFilterSetTests, cr from virtualization.models import Cluster, ClusterGroup, ClusterType +User = get_user_model() + + class CustomFieldTestCase(TestCase, BaseFilterSetTests): queryset = CustomField.objects.all() filterset = CustomFieldFilterSet diff --git a/netbox/extras/tests/test_views.py b/netbox/extras/tests/test_views.py index ef8e87489..3dcb90875 100644 --- a/netbox/extras/tests/test_views.py +++ b/netbox/extras/tests/test_views.py @@ -1,7 +1,7 @@ import urllib.parse import uuid -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.urls import reverse @@ -11,6 +11,9 @@ from extras.models import * from utilities.testing import ViewTestCases, TestCase +User = get_user_model() + + class CustomFieldTestCase(ViewTestCases.PrimaryObjectViewTestCase): model = CustomField diff --git a/netbox/netbox/tests/test_authentication.py b/netbox/netbox/tests/test_authentication.py index 4e46996b5..1804087d1 100644 --- a/netbox/netbox/tests/test_authentication.py +++ b/netbox/netbox/tests/test_authentication.py @@ -1,7 +1,8 @@ import datetime from django.conf import settings -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from django.test import Client from django.test.utils import override_settings @@ -16,6 +17,9 @@ from utilities.testing import TestCase from utilities.testing.api import APITestCase +User = get_user_model() + + class TokenAuthenticationTestCase(APITestCase): @override_settings(LOGIN_REQUIRED=True, EXEMPT_VIEW_PERMISSIONS=['*']) diff --git a/netbox/users/api/nested_serializers.py b/netbox/users/api/nested_serializers.py index 3510184ae..5e15fa41a 100644 --- a/netbox/users/api/nested_serializers.py +++ b/netbox/users/api/nested_serializers.py @@ -1,4 +1,5 @@ -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from drf_spectacular.utils import extend_schema_field from drf_spectacular.types import OpenApiTypes @@ -28,7 +29,7 @@ class NestedUserSerializer(WritableNestedSerializer): url = serializers.HyperlinkedIdentityField(view_name='users-api:user-detail') class Meta: - model = User + model = get_user_model() fields = ['id', 'url', 'display', 'username'] @extend_schema_field(OpenApiTypes.STR) diff --git a/netbox/users/api/serializers.py b/netbox/users/api/serializers.py index 1b975791f..1f4bf4ea0 100644 --- a/netbox/users/api/serializers.py +++ b/netbox/users/api/serializers.py @@ -1,5 +1,6 @@ from django.conf import settings -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from drf_spectacular.utils import extend_schema_field from drf_spectacular.types import OpenApiTypes @@ -30,7 +31,7 @@ class UserSerializer(ValidatedModelSerializer): ) class Meta: - model = User + model = get_user_model() fields = ( 'id', 'url', 'display', 'username', 'password', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'date_joined', 'groups', @@ -124,7 +125,7 @@ class ObjectPermissionSerializer(ValidatedModelSerializer): many=True ) users = SerializedPKRelatedField( - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), serializer=NestedUserSerializer, required=False, many=True diff --git a/netbox/users/api/views.py b/netbox/users/api/views.py index 04b3ae336..4a8e1b154 100644 --- a/netbox/users/api/views.py +++ b/netbox/users/api/views.py @@ -1,5 +1,6 @@ from django.contrib.auth import authenticate -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from django.db.models import Count from drf_spectacular.utils import extend_schema from drf_spectacular.types import OpenApiTypes @@ -32,7 +33,7 @@ class UsersRootView(APIRootView): # class UserViewSet(NetBoxModelViewSet): - queryset = RestrictedQuerySet(model=User).prefetch_related('groups').order_by('username') + queryset = RestrictedQuerySet(model=get_user_model()).prefetch_related('groups').order_by('username') serializer_class = serializers.UserSerializer filterset_class = filtersets.UserFilterSet diff --git a/netbox/users/filtersets.py b/netbox/users/filtersets.py index 4ae9df89a..44ad98cc2 100644 --- a/netbox/users/filtersets.py +++ b/netbox/users/filtersets.py @@ -1,5 +1,6 @@ import django_filters -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from django.db.models import Q from django.utils.translation import gettext as _ @@ -47,7 +48,7 @@ class UserFilterSet(BaseFilterSet): ) class Meta: - model = User + model = get_user_model() fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_staff', 'is_active'] def search(self, queryset, name, value): @@ -68,12 +69,12 @@ class TokenFilterSet(BaseFilterSet): ) user_id = django_filters.ModelMultipleChoiceFilter( field_name='user', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), label=_('User'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), to_field_name='username', label=_('User (name)'), ) @@ -116,12 +117,12 @@ class ObjectPermissionFilterSet(BaseFilterSet): ) user_id = django_filters.ModelMultipleChoiceFilter( field_name='users', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), label=_('User'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='users__username', - queryset=User.objects.all(), + queryset=get_user_model().objects.all(), to_field_name='username', label=_('User (name)'), ) diff --git a/netbox/users/graphql/schema.py b/netbox/users/graphql/schema.py index 3b04d8418..f033a535a 100644 --- a/netbox/users/graphql/schema.py +++ b/netbox/users/graphql/schema.py @@ -1,6 +1,7 @@ import graphene -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from netbox.graphql.fields import ObjectField, ObjectListField from .types import * from utilities.graphql_optimizer import gql_query_optimizer @@ -17,4 +18,4 @@ class UsersQuery(graphene.ObjectType): user_list = ObjectListField(UserType) def resolve_user_list(root, info, **kwargs): - return gql_query_optimizer(User.objects.all(), info) + return gql_query_optimizer(get_user_model().objects.all(), info) diff --git a/netbox/users/graphql/types.py b/netbox/users/graphql/types.py index d948686c6..4254f1791 100644 --- a/netbox/users/graphql/types.py +++ b/netbox/users/graphql/types.py @@ -1,4 +1,5 @@ -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from graphene_django import DjangoObjectType from users import filtersets @@ -25,7 +26,7 @@ class GroupType(DjangoObjectType): class UserType(DjangoObjectType): class Meta: - model = User + model = get_user_model() fields = ( 'id', 'username', 'password', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'date_joined', 'groups', @@ -34,4 +35,4 @@ class UserType(DjangoObjectType): @classmethod def get_queryset(cls, queryset, info): - return RestrictedQuerySet(model=User).restrict(info.context.user, 'view') + return RestrictedQuerySet(model=get_user_model()).restrict(info.context.user, 'view') diff --git a/netbox/users/tests/test_api.py b/netbox/users/tests/test_api.py index 281f656d2..2de243775 100644 --- a/netbox/users/tests/test_api.py +++ b/netbox/users/tests/test_api.py @@ -1,4 +1,5 @@ -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from django.urls import reverse @@ -7,6 +8,9 @@ from utilities.testing import APIViewTestCases, APITestCase from utilities.utils import deepmerge +User = get_user_model() + + class AppTest(APITestCase): def test_root(self): diff --git a/netbox/users/tests/test_filtersets.py b/netbox/users/tests/test_filtersets.py index 33ed7e7ba..d632687ef 100644 --- a/netbox/users/tests/test_filtersets.py +++ b/netbox/users/tests/test_filtersets.py @@ -1,6 +1,7 @@ import datetime -from django.contrib.auth.models import Group, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from django.test import TestCase from django.utils.timezone import make_aware @@ -10,6 +11,9 @@ from users.models import ObjectPermission, Token from utilities.testing import BaseFilterSetTests +User = get_user_model() + + class UserTestCase(TestCase, BaseFilterSetTests): queryset = User.objects.all() filterset = filtersets.UserFilterSet diff --git a/netbox/users/tests/test_models.py b/netbox/users/tests/test_models.py index 7a2337f33..791ea8fb4 100644 --- a/netbox/users/tests/test_models.py +++ b/netbox/users/tests/test_models.py @@ -1,7 +1,10 @@ -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.test import TestCase +User = get_user_model() + + class UserConfigTest(TestCase): @classmethod diff --git a/netbox/users/tests/test_preferences.py b/netbox/users/tests/test_preferences.py index f1e947d67..203a67bdd 100644 --- a/netbox/users/tests/test_preferences.py +++ b/netbox/users/tests/test_preferences.py @@ -1,4 +1,4 @@ -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.test import override_settings from django.test.client import RequestFactory from django.urls import reverse @@ -16,6 +16,9 @@ DEFAULT_USER_PREFERENCES = { } +User = get_user_model() + + class UserPreferencesTest(TestCase): user_permissions = ['dcim.view_site'] diff --git a/netbox/utilities/testing/api.py b/netbox/utilities/testing/api.py index 7f24c86b8..8cfe1cdd7 100644 --- a/netbox/utilities/testing/api.py +++ b/netbox/utilities/testing/api.py @@ -2,7 +2,7 @@ import inspect import json from django.conf import settings -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.urls import reverse from django.test import override_settings @@ -26,6 +26,9 @@ __all__ = ( ) +User = get_user_model() + + # # REST/GraphQL API Tests # diff --git a/netbox/utilities/testing/base.py b/netbox/utilities/testing/base.py index 04ceca1e2..76a9fac06 100644 --- a/netbox/utilities/testing/base.py +++ b/netbox/utilities/testing/base.py @@ -1,6 +1,6 @@ import json -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.fields import ArrayField from django.core.exceptions import FieldDoesNotExist @@ -27,7 +27,7 @@ class TestCase(_TestCase): def setUp(self): # Create the test user and assign permissions - self.user = User.objects.create_user(username='testuser') + self.user = get_user_model().objects.create_user(username='testuser') self.add_permissions(*self.user_permissions) # Initialize the test client diff --git a/netbox/utilities/testing/utils.py b/netbox/utilities/testing/utils.py index 52ccd002d..87fc3319c 100644 --- a/netbox/utilities/testing/utils.py +++ b/netbox/utilities/testing/utils.py @@ -2,7 +2,8 @@ import logging import re from contextlib import contextmanager -from django.contrib.auth.models import Permission, User +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Permission from django.utils.text import slugify from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site @@ -63,7 +64,7 @@ def create_test_user(username='testuser', permissions=None): """ Create a User with the given permissions. """ - user = User.objects.create_user(username=username) + user = get_user_model().objects.create_user(username=username) if permissions is None: permissions = () for perm_name in permissions: From eff4a3741c05b5d3fa6dc216f19c329291bbe23e Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Thu, 22 Jun 2023 06:09:01 -0700 Subject: [PATCH 69/74] 12175 rack with starting unit > 1 (#12778) * 12175 add rack starting unit * 12175 rack starting unit to svg * verify devices can still fit if change rack starting_unit * 12175 fix migration * 12175 fix typo and test * 12175 fix test * 12175 fix max height calc display * Misc cleanup & fixes --------- Co-authored-by: Jeremy Stretch --- netbox/dcim/constants.py | 2 ++ netbox/dcim/forms/model_forms.py | 4 +-- .../migrations/0174_rack_starting_unit.py | 17 +++++++++ netbox/dcim/models/racks.py | 35 ++++++++++++------- netbox/dcim/svg/racks.py | 6 ++-- netbox/dcim/tests/test_views.py | 1 + netbox/templates/dcim/rack.html | 6 ++++ netbox/templates/dcim/rack_edit.html | 1 + 8 files changed, 55 insertions(+), 17 deletions(-) create mode 100644 netbox/dcim/migrations/0174_rack_starting_unit.py diff --git a/netbox/dcim/constants.py b/netbox/dcim/constants.py index b3c065b5a..303fc2344 100644 --- a/netbox/dcim/constants.py +++ b/netbox/dcim/constants.py @@ -17,6 +17,8 @@ RACK_ELEVATION_BORDER_WIDTH = 2 RACK_ELEVATION_DEFAULT_LEGEND_WIDTH = 30 RACK_ELEVATION_DEFAULT_MARGIN_WIDTH = 15 +RACK_STARTING_UNIT_DEFAULT = 1 + # # RearPorts diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index eda302736..04f976d94 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -221,8 +221,8 @@ class RackForm(TenancyForm, NetBoxModelForm): model = Rack fields = [ 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', - 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', - 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', + 'asset_tag', 'type', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_depth', + 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', ] diff --git a/netbox/dcim/migrations/0174_rack_starting_unit.py b/netbox/dcim/migrations/0174_rack_starting_unit.py new file mode 100644 index 000000000..e32738660 --- /dev/null +++ b/netbox/dcim/migrations/0174_rack_starting_unit.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.9 on 2023-05-31 15:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ('dcim', '0174_device_latitude_device_longitude'), + ] + + operations = [ + migrations.AddField( + model_name='rack', + name='starting_unit', + field=models.PositiveSmallIntegerField(default=1), + ), + ] diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index 5ac223c45..6d3c15eee 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -129,6 +129,11 @@ class Rack(PrimaryModel, WeightMixin): validators=[MinValueValidator(1), MaxValueValidator(RACK_U_HEIGHT_MAX)], help_text=_('Height in rack units') ) + starting_unit = models.PositiveSmallIntegerField( + default=RACK_STARTING_UNIT_DEFAULT, + verbose_name='Starting unit', + help_text=_('Starting unit for rack') + ) desc_units = models.BooleanField( default=False, verbose_name='Descending units', @@ -228,20 +233,24 @@ class Rack(PrimaryModel, WeightMixin): raise ValidationError("Must specify a unit when setting a maximum weight") if self.pk: - # Validate that Rack is tall enough to house the installed Devices - top_device = Device.objects.filter( - rack=self - ).exclude( - position__isnull=True - ).order_by('-position').first() - if top_device: - min_height = top_device.position + top_device.device_type.u_height - 1 + mounted_devices = Device.objects.filter(rack=self).exclude(position__isnull=True).order_by('position') + + # Validate that Rack is tall enough to house the highest mounted Device + if top_device := mounted_devices.last(): + min_height = top_device.position + top_device.device_type.u_height - self.starting_unit if self.u_height < min_height: raise ValidationError({ - 'u_height': "Rack must be at least {}U tall to house currently installed devices.".format( - min_height - ) + 'u_height': f"Rack must be at least {min_height}U tall to house currently installed devices." }) + + # Validate that the Rack's starting unit is less than or equal to the position of the lowest mounted Device + if last_device := mounted_devices.first(): + if self.starting_unit > last_device.position: + raise ValidationError({ + 'starting_unit': f"Rack unit numbering must begin at {last_device.position} or less to house " + f"currently installed devices." + }) + # Validate that Rack was assigned a Location of its same site, if applicable if self.location: if self.location.site != self.site: @@ -269,8 +278,8 @@ class Rack(PrimaryModel, WeightMixin): Return a list of unit numbers, top to bottom. """ if self.desc_units: - return drange(decimal.Decimal(1.0), self.u_height + 1, 0.5) - return drange(self.u_height + decimal.Decimal(0.5), 0.5, -0.5) + return drange(decimal.Decimal(self.starting_unit), self.u_height + self.starting_unit, 0.5) + return drange(self.u_height + decimal.Decimal(0.5) + self.starting_unit - 1, 0.5 + self.starting_unit - 1, -0.5) def get_status_color(self): return RackStatusChoices.colors.get(self.status) diff --git a/netbox/dcim/svg/racks.py b/netbox/dcim/svg/racks.py index 9c317ea16..6333abcf1 100644 --- a/netbox/dcim/svg/racks.py +++ b/netbox/dcim/svg/racks.py @@ -150,9 +150,9 @@ class RackElevationSVG: x = self.legend_width + RACK_ELEVATION_BORDER_WIDTH y = RACK_ELEVATION_BORDER_WIDTH if self.rack.desc_units: - y += int((position - 1) * self.unit_height) + y += int((position - self.rack.starting_unit) * self.unit_height) else: - y += int((self.rack.u_height - position + 1) * self.unit_height) - int(height * self.unit_height) + y += int((self.rack.u_height - position + self.rack.starting_unit) * self.unit_height) - int(height * self.unit_height) return x, y @@ -237,6 +237,7 @@ class RackElevationSVG: start_y = ru * self.unit_height + RACK_ELEVATION_BORDER_WIDTH position_coordinates = (self.legend_width / 2, start_y + self.unit_height / 2 + RACK_ELEVATION_BORDER_WIDTH) unit = ru + 1 if self.rack.desc_units else self.rack.u_height - ru + unit = unit + self.rack.starting_unit - 1 self.drawing.add( Text(str(unit), position_coordinates, class_='unit') ) @@ -278,6 +279,7 @@ class RackElevationSVG: for ru in range(0, self.rack.u_height): unit = ru + 1 if self.rack.desc_units else self.rack.u_height - ru + unit = unit + self.rack.starting_unit - 1 y_offset = RACK_ELEVATION_BORDER_WIDTH + ru * self.unit_height text_coords = ( x_offset + self.unit_width / 2, diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 23683ddce..cca6b3f02 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -392,6 +392,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase): 'outer_width': 500, 'outer_depth': 500, 'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER, + 'starting_unit': 1, 'weight': 100, 'max_weight': 2000, 'weight_unit': WeightUnitChoices.UNIT_POUND, diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index 52b5d4bfe..01aeacff1 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -101,6 +101,12 @@
Height {{ object.u_height }}U ({% if object.desc_units %}descending{% else %}ascending{% endif %})
Starting Unit + {{ object.starting_unit }} +
Outer Width diff --git a/netbox/templates/dcim/rack_edit.html b/netbox/templates/dcim/rack_edit.html index 4bbd72405..a1ebb7531 100644 --- a/netbox/templates/dcim/rack_edit.html +++ b/netbox/templates/dcim/rack_edit.html @@ -71,6 +71,7 @@ {% render_field form.mounting_depth %} {% render_field form.desc_units %} + {% render_field form.starting_unit %} {% if form.custom_fields %} From 9fa1411d746e018c68c93a6b463c06886a90d0f9 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 22 Jun 2023 10:55:12 -0400 Subject: [PATCH 70/74] Changelog for #9077, #11305, #12175, #12180, #12794 --- docs/release-notes/version-3.6.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/release-notes/version-3.6.md b/docs/release-notes/version-3.6.md index c4e6847d3..1ef23aa47 100644 --- a/docs/release-notes/version-3.6.md +++ b/docs/release-notes/version-3.6.md @@ -6,7 +6,15 @@ * The `napalm_driver` and `napalm_args` fields (which were deprecated in v3.5) have been removed from the platform model. +### Enhancements + +* [#11305](https://github.com/netbox-community/netbox/issues/11305) - Add GPS coordinate fields to the device model +* [#12175](https://github.com/netbox-community/netbox/issues/12175) - Permit racks to start numbering at values greater than one + ### Other Changes +* [#9077](https://github.com/netbox-community/netbox/issues/9077) - Prevent the errant execution of dangerous instance methods in Django templates * [#11766](https://github.com/netbox-community/netbox/issues/11766) - Remove obsolete custom `ChoiceField` and `MultipleChoiceField` classes +* [#12180](https://github.com/netbox-community/netbox/issues/12180) - All API endpoints for available objects (e.g. IP addresses) now inherit from a common parent view +* [#12794](https://github.com/netbox-community/netbox/issues/12794) - Avoid direct imports of Django's stock user model * [#12320](https://github.com/netbox-community/netbox/issues/12320) - Remove obsolete fields `napalm_driver` and `napalm_args` from Platform From 48b2ab3587896889e914d446cdd422be50c25c78 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 22 Jun 2023 12:27:21 -0400 Subject: [PATCH 71/74] Closes #12964: Raise minimum PostgreSQL version from 11 to 12 --- docs/configuration/required-parameters.md | 2 +- docs/installation/1-postgresql.md | 6 +++--- docs/installation/index.md | 2 +- docs/installation/upgrading.md | 4 ++-- docs/introduction.md | 2 +- docs/release-notes/version-3.6.md | 2 ++ 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/configuration/required-parameters.md b/docs/configuration/required-parameters.md index 1eba265bf..012d85762 100644 --- a/docs/configuration/required-parameters.md +++ b/docs/configuration/required-parameters.md @@ -25,7 +25,7 @@ ALLOWED_HOSTS = ['*'] ## DATABASE -NetBox requires access to a PostgreSQL 11 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary: +NetBox requires access to a PostgreSQL 12 or later database service to store data. This service can run locally on the NetBox server or on a remote system. The following parameters must be defined within the `DATABASE` dictionary: * `NAME` - Database name * `USER` - PostgreSQL username diff --git a/docs/installation/1-postgresql.md b/docs/installation/1-postgresql.md index 1fccd0270..bc1bbf22c 100644 --- a/docs/installation/1-postgresql.md +++ b/docs/installation/1-postgresql.md @@ -2,8 +2,8 @@ This section entails the installation and configuration of a local PostgreSQL database. If you already have a PostgreSQL database service in place, skip to [the next section](2-redis.md). -!!! warning "PostgreSQL 11 or later required" - NetBox requires PostgreSQL 11 or later. Please note that MySQL and other relational databases are **not** supported. +!!! warning "PostgreSQL 12 or later required" + NetBox requires PostgreSQL 12 or later. Please note that MySQL and other relational databases are **not** supported. ## Installation @@ -35,7 +35,7 @@ This section entails the installation and configuration of a local PostgreSQL da sudo systemctl enable postgresql ``` -Before continuing, verify that you have installed PostgreSQL 11 or later: +Before continuing, verify that you have installed PostgreSQL 12 or later: ```no-highlight psql -V diff --git a/docs/installation/index.md b/docs/installation/index.md index 375c0a2b5..da50fa5fa 100644 --- a/docs/installation/index.md +++ b/docs/installation/index.md @@ -18,7 +18,7 @@ The following sections detail how to set up a new instance of NetBox: | Dependency | Minimum Version | |------------|-----------------| | Python | 3.8 | -| PostgreSQL | 11 | +| PostgreSQL | 12 | | Redis | 4.0 | Below is a simplified overview of the NetBox application stack for reference: diff --git a/docs/installation/upgrading.md b/docs/installation/upgrading.md index 27401c3cf..a81d8c954 100644 --- a/docs/installation/upgrading.md +++ b/docs/installation/upgrading.md @@ -15,12 +15,12 @@ Prior to upgrading your NetBox instance, be sure to carefully review all [releas ## 2. Update Dependencies to Required Versions -NetBox v3.0 and later require the following: +NetBox requires the following dependencies: | Dependency | Minimum Version | |------------|-----------------| | Python | 3.8 | -| PostgreSQL | 11 | +| PostgreSQL | 12 | | Redis | 4.0 | ## 3. Install the Latest Release diff --git a/docs/introduction.md b/docs/introduction.md index 640147395..8f62d842a 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -75,5 +75,5 @@ NetBox is built on the [Django](https://djangoproject.com/) Python framework and | HTTP service | nginx or Apache | | WSGI service | gunicorn or uWSGI | | Application | Django/Python | -| Database | PostgreSQL 11+ | +| Database | PostgreSQL 12+ | | Task queuing | Redis/django-rq | diff --git a/docs/release-notes/version-3.6.md b/docs/release-notes/version-3.6.md index 1ef23aa47..dc5280670 100644 --- a/docs/release-notes/version-3.6.md +++ b/docs/release-notes/version-3.6.md @@ -4,6 +4,7 @@ ### Breaking Changes +* PostgreSQL 11 is no longer supported (due to adopting Django 4.2). NetBox v3.6 requires PostgreSQL 12 or later. * The `napalm_driver` and `napalm_args` fields (which were deprecated in v3.5) have been removed from the platform model. ### Enhancements @@ -18,3 +19,4 @@ * [#12180](https://github.com/netbox-community/netbox/issues/12180) - All API endpoints for available objects (e.g. IP addresses) now inherit from a common parent view * [#12794](https://github.com/netbox-community/netbox/issues/12794) - Avoid direct imports of Django's stock user model * [#12320](https://github.com/netbox-community/netbox/issues/12320) - Remove obsolete fields `napalm_driver` and `napalm_args` from Platform +* [#12964](https://github.com/netbox-community/netbox/issues/12964) - Drop support for PostgreSQL From 148278a74afd0ccb292558774015aa42ad922374 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Thu, 22 Jun 2023 11:04:24 -0700 Subject: [PATCH 72/74] 12591 config params admin (#12904) * 12591 initial commit * 12591 detail view * 12591 add/edit view * 12591 edit button * 12591 base views and forms * 12591 form cleanup * 12591 form cleanup * 12591 form cleanup * 12591 review changes * 12591 move check for restrictedqueryset * 12591 restore view * 12591 restore page styling * 12591 remove admin * Remove edit view for ConfigRevision instances * Order ConfigRevisions by creation time * Correct permission name * Use RestrictedQuerySet for ConfigRevision * Fix redirect URL --------- Co-authored-by: Jeremy Stretch --- netbox/extras/admin.py | 129 +---------- netbox/extras/filtersets.py | 25 +++ netbox/extras/forms/__init__.py | 1 - netbox/extras/forms/config.py | 82 ------- netbox/extras/forms/filtersets.py | 7 + netbox/extras/forms/model_forms.py | 102 ++++++++- .../0093_configrevision_ordering.py | 17 ++ netbox/extras/models/models.py | 8 + netbox/extras/tables/tables.py | 24 +++ netbox/extras/urls.py | 9 +- netbox/extras/views.py | 69 ++++++ netbox/netbox/navigation/menu.py | 17 ++ .../admin/extras/configrevision/restore.html | 37 ---- netbox/templates/extras/configrevision.html | 200 ++++++++++++++++++ .../extras/configrevision_restore.html | 88 ++++++++ netbox/templates/generic/object.html | 4 +- 16 files changed, 567 insertions(+), 252 deletions(-) delete mode 100644 netbox/extras/forms/config.py create mode 100644 netbox/extras/migrations/0093_configrevision_ordering.py delete mode 100644 netbox/templates/admin/extras/configrevision/restore.html create mode 100644 netbox/templates/extras/configrevision.html create mode 100644 netbox/templates/extras/configrevision_restore.html diff --git a/netbox/extras/admin.py b/netbox/extras/admin.py index 6d1b14370..6e82ffc75 100644 --- a/netbox/extras/admin.py +++ b/netbox/extras/admin.py @@ -1,129 +1,2 @@ -from django.contrib import admin -from django.shortcuts import get_object_or_404, redirect -from django.template.response import TemplateResponse -from django.urls import path, reverse -from django.utils.html import format_html - -from netbox.config import get_config, PARAMS +# TODO: Removing this import triggers an import loop due to how form mixins are currently organized from .forms import ConfigRevisionForm -from .models import ConfigRevision - - -@admin.register(ConfigRevision) -class ConfigRevisionAdmin(admin.ModelAdmin): - fieldsets = [ - ('Rack Elevations', { - 'fields': ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH'), - }), - ('Power', { - 'fields': ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION') - }), - ('IPAM', { - 'fields': ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4'), - }), - ('Security', { - 'fields': ('ALLOWED_URL_SCHEMES',), - }), - ('Banners', { - 'fields': ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM'), - 'classes': ('monospace',), - }), - ('Pagination', { - 'fields': ('PAGINATE_COUNT', 'MAX_PAGE_SIZE'), - }), - ('Validation', { - 'fields': ('CUSTOM_VALIDATORS',), - 'classes': ('monospace',), - }), - ('User Preferences', { - 'fields': ('DEFAULT_USER_PREFERENCES',), - }), - ('Miscellaneous', { - 'fields': ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL'), - }), - ('Config Revision', { - 'fields': ('comment',), - }) - ] - form = ConfigRevisionForm - list_display = ('id', 'is_active', 'created', 'comment', 'restore_link') - ordering = ('-id',) - readonly_fields = ('data',) - - def get_changeform_initial_data(self, request): - """ - Populate initial form data from the most recent ConfigRevision. - """ - latest_revision = ConfigRevision.objects.last() - initial = latest_revision.data if latest_revision else {} - initial.update(super().get_changeform_initial_data(request)) - - return initial - - # Permissions - - def has_add_permission(self, request): - # Only superusers may modify the configuration. - return request.user.is_superuser - - def has_change_permission(self, request, obj=None): - # ConfigRevisions cannot be modified once created. - return False - - def has_delete_permission(self, request, obj=None): - # Only inactive ConfigRevisions may be deleted (must be superuser). - return request.user.is_superuser and ( - obj is None or not obj.is_active() - ) - - # List display methods - - def restore_link(self, obj): - if obj.is_active(): - return '' - return format_html( - 'Restore', - url=reverse('admin:extras_configrevision_restore', args=(obj.pk,)) - ) - restore_link.short_description = "Actions" - - # URLs - - def get_urls(self): - urls = [ - path('/restore/', self.admin_site.admin_view(self.restore), name='extras_configrevision_restore'), - ] - - return urls + super().get_urls() - - # Views - - def restore(self, request, pk): - # Get the ConfigRevision being restored - candidate_config = get_object_or_404(ConfigRevision, pk=pk) - - if request.method == 'POST': - candidate_config.activate() - self.message_user(request, f"Restored configuration revision #{pk}") - - return redirect(reverse('admin:extras_configrevision_changelist')) - - # Get the current ConfigRevision - config_version = get_config().version - current_config = ConfigRevision.objects.filter(pk=config_version).first() - - params = [] - for param in PARAMS: - params.append(( - param.name, - current_config.data.get(param.name, None), - candidate_config.data.get(param.name, None) - )) - - context = self.admin_site.each_context(request) - context.update({ - 'object': candidate_config, - 'params': params, - }) - - return TemplateResponse(request, 'admin/extras/configrevision/restore.html', context) diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index 2cbaca5f7..6120e2a51 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -16,6 +16,7 @@ from .models import * __all__ = ( 'ConfigContextFilterSet', + 'ConfigRevisionFilterSet', 'ConfigTemplateFilterSet', 'ContentTypeFilterSet', 'CustomFieldFilterSet', @@ -557,3 +558,27 @@ class ContentTypeFilterSet(django_filters.FilterSet): Q(app_label__icontains=value) | Q(model__icontains=value) ) + + +# +# ConfigRevisions +# + +class ConfigRevisionFilterSet(BaseFilterSet): + q = django_filters.CharFilter( + method='search', + label=_('Search'), + ) + + class Meta: + model = ConfigRevision + fields = [ + 'id', + ] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(comment__icontains=value) + ) diff --git a/netbox/extras/forms/__init__.py b/netbox/extras/forms/__init__.py index 0825c9ca7..e203bee46 100644 --- a/netbox/extras/forms/__init__.py +++ b/netbox/extras/forms/__init__.py @@ -4,5 +4,4 @@ from .bulk_edit import * from .bulk_import import * from .misc import * from .mixins import * -from .config import * from .scripts import * diff --git a/netbox/extras/forms/config.py b/netbox/extras/forms/config.py deleted file mode 100644 index 4a7dba614..000000000 --- a/netbox/extras/forms/config.py +++ /dev/null @@ -1,82 +0,0 @@ -from django import forms -from django.conf import settings - -from netbox.config import get_config, PARAMS - -__all__ = ( - 'ConfigRevisionForm', -) - - -EMPTY_VALUES = ('', None, [], ()) - - -class FormMetaclass(forms.models.ModelFormMetaclass): - - def __new__(mcs, name, bases, attrs): - - # Emulate a declared field for each supported configuration parameter - param_fields = {} - for param in PARAMS: - field_kwargs = { - 'required': False, - 'label': param.label, - 'help_text': param.description, - } - field_kwargs.update(**param.field_kwargs) - param_fields[param.name] = param.field(**field_kwargs) - attrs.update(param_fields) - - return super().__new__(mcs, name, bases, attrs) - - -class ConfigRevisionForm(forms.BaseModelForm, metaclass=FormMetaclass): - """ - Form for creating a new ConfigRevision. - """ - class Meta: - widgets = { - 'comment': forms.Textarea(), - } - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Append current parameter values to form field help texts and check for static configurations - config = get_config() - for param in PARAMS: - value = getattr(config, param.name) - is_static = hasattr(settings, param.name) - if value: - help_text = self.fields[param.name].help_text - if help_text: - help_text += '
' # Line break - help_text += f'Current value: {value}' - if is_static: - help_text += ' (defined statically)' - elif value == param.default: - help_text += ' (default)' - self.fields[param.name].help_text = help_text - if is_static: - self.fields[param.name].disabled = True - - def save(self, commit=True): - instance = super().save(commit=False) - - # Populate JSON data on the instance - instance.data = self.render_json() - - if commit: - instance.save() - - return instance - - def render_json(self): - json = {} - - # Iterate through each field and populate non-empty values - for field_name in self.declared_fields: - if field_name in self.cleaned_data and self.cleaned_data[field_name] not in EMPTY_VALUES: - json[field_name] = self.cleaned_data[field_name] - - return json diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index 53de81ba2..bcf2e7863 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -18,6 +18,7 @@ from .mixins import SavedFiltersMixin __all__ = ( 'ConfigContextFilterForm', + 'ConfigRevisionFilterForm', 'ConfigTemplateFilterForm', 'CustomFieldFilterForm', 'CustomLinkFilterForm', @@ -444,3 +445,9 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm): api_url='/api/extras/content-types/', ) ) + + +class ConfigRevisionFilterForm(SavedFiltersMixin, FilterForm): + fieldsets = ( + (None, ('q', 'filter_id')), + ) diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 2f617b682..621052c96 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -1,6 +1,7 @@ import json from django import forms +from django.conf import settings from django.db.models import Q from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext as _ @@ -10,17 +11,20 @@ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site from extras.choices import * from extras.models import * from extras.utils import FeatureQuery +from netbox.config import get_config, PARAMS from netbox.forms import NetBoxModelForm from tenancy.models import Tenant, TenantGroup -from utilities.forms import BootstrapMixin, add_blank_choice +from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, BootstrapMixin, add_blank_choice from utilities.forms.fields import ( CommentField, ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, JSONField, SlugField, ) from virtualization.models import Cluster, ClusterGroup, ClusterType + __all__ = ( 'ConfigContextForm', + 'ConfigRevisionForm', 'ConfigTemplateForm', 'CustomFieldForm', 'CustomLinkForm', @@ -374,3 +378,99 @@ class JournalEntryForm(NetBoxModelForm): 'assigned_object_type': forms.HiddenInput, 'assigned_object_id': forms.HiddenInput, } + + +EMPTY_VALUES = ('', None, [], ()) + + +class ConfigFormMetaclass(forms.models.ModelFormMetaclass): + + def __new__(mcs, name, bases, attrs): + + # Emulate a declared field for each supported configuration parameter + param_fields = {} + for param in PARAMS: + field_kwargs = { + 'required': False, + 'label': param.label, + 'help_text': param.description, + } + field_kwargs.update(**param.field_kwargs) + param_fields[param.name] = param.field(**field_kwargs) + attrs.update(param_fields) + + return super().__new__(mcs, name, bases, attrs) + + +class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMetaclass): + """ + Form for creating a new ConfigRevision. + """ + + fieldsets = ( + ('Rack Elevations', ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH')), + ('Power', ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')), + ('IPAM', ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4')), + ('Security', ('ALLOWED_URL_SCHEMES',)), + ('Banners', ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM')), + ('Pagination', ('PAGINATE_COUNT', 'MAX_PAGE_SIZE')), + ('Validation', ('CUSTOM_VALIDATORS',)), + ('User Preferences', ('DEFAULT_USER_PREFERENCES',)), + ('Miscellaneous', ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL')), + ('Config Revision', ('comment',)) + ) + + class Meta: + model = ConfigRevision + fields = '__all__' + widgets = { + 'BANNER_LOGIN': forms.Textarea(attrs={'class': 'font-monospace'}), + 'BANNER_MAINTENANCE': forms.Textarea(attrs={'class': 'font-monospace'}), + 'BANNER_TOP': forms.Textarea(attrs={'class': 'font-monospace'}), + 'BANNER_BOTTOM': forms.Textarea(attrs={'class': 'font-monospace'}), + 'CUSTOM_VALIDATORS': forms.Textarea(attrs={'class': 'font-monospace'}), + 'comment': forms.Textarea(), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Append current parameter values to form field help texts and check for static configurations + config = get_config() + for param in PARAMS: + value = getattr(config, param.name) + is_static = hasattr(settings, param.name) + if value: + help_text = self.fields[param.name].help_text + if help_text: + help_text += '
' # Line break + help_text += f'Current value: {value}' + if is_static: + help_text += ' (defined statically)' + elif value == param.default: + help_text += ' (default)' + self.fields[param.name].help_text = help_text + self.fields[param.name].initial = value + if is_static: + self.fields[param.name].disabled = True + + def save(self, commit=True): + instance = super().save(commit=False) + + # Populate JSON data on the instance + instance.data = self.render_json() + + if commit: + instance.save() + + return instance + + def render_json(self): + json = {} + + # Iterate through each field and populate non-empty values + for field_name in self.declared_fields: + if field_name in self.cleaned_data and self.cleaned_data[field_name] not in EMPTY_VALUES: + json[field_name] = self.cleaned_data[field_name] + + return json diff --git a/netbox/extras/migrations/0093_configrevision_ordering.py b/netbox/extras/migrations/0093_configrevision_ordering.py new file mode 100644 index 000000000..a4e875e6d --- /dev/null +++ b/netbox/extras/migrations/0093_configrevision_ordering.py @@ -0,0 +1,17 @@ +# Generated by Django 4.1.9 on 2023-06-22 14:14 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0092_delete_jobresult'), + ] + + operations = [ + migrations.AlterModelOptions( + name='configrevision', + options={'ordering': ['-created']}, + ), + ] diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 6c7aac08d..0cbc7a1de 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -612,6 +612,11 @@ class ConfigRevision(models.Model): verbose_name='Configuration data' ) + objects = RestrictedQuerySet.as_manager() + + class Meta: + ordering = ['-created'] + def __str__(self): return f'Config revision #{self.pk} ({self.created})' @@ -620,6 +625,9 @@ class ConfigRevision(models.Model): return self.data[item] return super().__getattribute__(item) + def get_absolute_url(self): + return reverse('extras:configrevision', args=[self.pk]) + def activate(self): """ Cache the configuration data. diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index 9e4924532..e41bc9126 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -9,6 +9,7 @@ from .template_code import * __all__ = ( 'ConfigContextTable', + 'ConfigRevisionTable', 'ConfigTemplateTable', 'CustomFieldTable', 'CustomLinkTable', @@ -30,6 +31,29 @@ IMAGEATTACHMENT_IMAGE = ''' {% endif %} ''' +REVISION_BUTTONS = """ +{% if not record.is_active %} + + + +{% endif %} +""" + + +class ConfigRevisionTable(NetBoxTable): + is_active = columns.BooleanColumn() + actions = columns.ActionsColumn( + actions=('delete',), + extra_buttons=REVISION_BUTTONS + ) + + class Meta(NetBoxTable.Meta): + model = ConfigRevision + fields = ( + 'pk', 'id', 'is_active', 'created', 'comment', + ) + default_columns = ('pk', 'id', 'is_active', 'created', 'comment') + class CustomFieldTable(NetBoxTable): name = tables.Column( diff --git a/netbox/extras/urls.py b/netbox/extras/urls.py index c4fc3d938..b3909391a 100644 --- a/netbox/extras/urls.py +++ b/netbox/extras/urls.py @@ -85,6 +85,13 @@ urlpatterns = [ path('journal-entries/import/', views.JournalEntryBulkImportView.as_view(), name='journalentry_import'), path('journal-entries//', include(get_model_urls('extras', 'journalentry'))), + # Config revisions + path('config-revisions/', views.ConfigRevisionListView.as_view(), name='configrevision_list'), + path('config-revisions/add/', views.ConfigRevisionEditView.as_view(), name='configrevision_add'), + path('config-revisions/delete/', views.ConfigRevisionBulkDeleteView.as_view(), name='configrevision_bulk_delete'), + path('config-revisions//restore/', views.ConfigRevisionRestoreView.as_view(), name='configrevision_restore'), + path('config-revisions//', include(get_model_urls('extras', 'configrevision'))), + # Change logging path('changelog/', views.ObjectChangeListView.as_view(), name='objectchange_list'), path('changelog//', include(get_model_urls('extras', 'objectchange'))), @@ -114,5 +121,5 @@ urlpatterns = [ path('scripts///jobs/', views.ScriptJobsView.as_view(), name='script_jobs'), # Markdown - path('render/markdown/', views.RenderMarkdownView.as_view(), name="render_markdown") + path('render/markdown/', views.RenderMarkdownView.as_view(), name="render_markdown"), ] diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 6cbadf09d..9e02b5019 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -14,6 +14,7 @@ from core.models import Job from core.tables import JobTable from extras.dashboard.forms import DashboardWidgetAddForm, DashboardWidgetForm from extras.dashboard.utils import get_widget_class +from netbox.config import get_config, PARAMS from netbox.views import generic from utilities.forms import ConfirmationForm, get_field_value from utilities.htmx import is_htmx @@ -1176,6 +1177,74 @@ class ScriptResultView(ContentTypePermissionRequiredMixin, View): }) +# +# Config Revisions +# + +class ConfigRevisionListView(generic.ObjectListView): + queryset = ConfigRevision.objects.all() + filterset = filtersets.ConfigRevisionFilterSet + filterset_form = forms.ConfigRevisionFilterForm + table = tables.ConfigRevisionTable + + +@register_model_view(ConfigRevision) +class ConfigRevisionView(generic.ObjectView): + queryset = ConfigRevision.objects.all() + + +class ConfigRevisionEditView(generic.ObjectEditView): + queryset = ConfigRevision.objects.all() + form = forms.ConfigRevisionForm + + +@register_model_view(ConfigRevision, 'delete') +class ConfigRevisionDeleteView(generic.ObjectDeleteView): + queryset = ConfigRevision.objects.all() + + +class ConfigRevisionBulkDeleteView(generic.BulkDeleteView): + queryset = ConfigRevision.objects.all() + filterset = filtersets.ConfigRevisionFilterSet + table = tables.ConfigRevisionTable + + +class ConfigRevisionRestoreView(ContentTypePermissionRequiredMixin, View): + + def get_required_permission(self): + return 'extras.configrevision_edit' + + def get(self, request, pk): + candidate_config = get_object_or_404(ConfigRevision, pk=pk) + + # Get the current ConfigRevision + config_version = get_config().version + current_config = ConfigRevision.objects.filter(pk=config_version).first() + + params = [] + for param in PARAMS: + params.append(( + param.name, + current_config.data.get(param.name, None), + candidate_config.data.get(param.name, None) + )) + + return render(request, 'extras/configrevision_restore.html', { + 'object': candidate_config, + 'params': params, + }) + + def post(self, request, pk): + if not request.user.has_perm('extras.configrevision_edit'): + return HttpResponseForbidden() + + candidate_config = get_object_or_404(ConfigRevision, pk=pk) + candidate_config.activate() + messages.success(request, f"Restored configuration revision #{pk}") + + return redirect(candidate_config.get_absolute_url()) + + # # Markdown # diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index e009f62f1..100de16da 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -346,6 +346,22 @@ OPERATIONS_MENU = Menu( ), ) +ADMIN_MENU = Menu( + label=_('Admin'), + icon_class='mdi mdi-account-multiple', + groups=( + MenuGroup( + label=_('Configuration'), + items=( + MenuItem( + link='extras:configrevision_list', + link_text=_('Config Revisions'), + permissions=['extras.view_configrevision'] + ), + ), + ), + ), +) MENUS = [ ORGANIZATION_MENU, @@ -360,6 +376,7 @@ MENUS = [ PROVISIONING_MENU, CUSTOMIZATION_MENU, OPERATIONS_MENU, + ADMIN_MENU, ] # diff --git a/netbox/templates/admin/extras/configrevision/restore.html b/netbox/templates/admin/extras/configrevision/restore.html deleted file mode 100644 index 4a0eb81a6..000000000 --- a/netbox/templates/admin/extras/configrevision/restore.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "admin/base_site.html" %} -{% load static %} - -{% block content %} -

Restore configuration #{{ object.pk }} from {{ object.created }}?

- - - - - - - - - - - - {% for param, current, new in params %} - - - - - - - {% endfor %} - -
ParameterCurrent ValueNew Value
{{ param }}{{ current }}{{ new }}{% if current != new %}*{% endif %}
- -
- {% csrf_token %} -
- - Cancel -
-
-{% endblock content %} - - diff --git a/netbox/templates/extras/configrevision.html b/netbox/templates/extras/configrevision.html new file mode 100644 index 000000000..1c7eeb2dd --- /dev/null +++ b/netbox/templates/extras/configrevision.html @@ -0,0 +1,200 @@ +{% extends 'generic/object.html' %} +{% load buttons %} +{% load custom_links %} +{% load helpers %} +{% load perms %} +{% load plugins %} +{% load static %} + +{% block breadcrumbs %} +{% endblock %} + +{% block controls %} +
+
+ {% plugin_buttons object %} +
+
+ {% custom_links object %} +
+
+{% endblock controls %} + +{% block content %} +
+
+
+
Rack Elevation
+
+ + + + + + + + + +
Rack elevation default unit height:{{ object.data.RACK_ELEVATION_DEFAULT_UNIT_HEIGHT }}
Rack elevation default unit width:{{ object.data.RACK_ELEVATION_DEFAULT_UNIT_WIDTH }}
+
+
+ +
+
Power
+
+ + + + + + + + + + + + + +
Powerfeed default voltage:{{ object.data.POWERFEED_DEFAULT_VOLTAGE }}
Powerfeed default amperage:{{ object.data.POWERFEED_DEFAULT_AMPERAGE }}
Powerfeed default max utilization:{{ object.data.POWERFEED_DEFAULT_MAX_UTILIZATION }}
+
+
+ +
+
IPAM
+
+ + + + + + + + + +
IPAM enforce global unique:{{ object.data.ENFORCE_GLOBAL_UNIQUE }}
IPAM prefer IPV4:{{ object.data.PREFER_IPV4 }}
+
+
+ +
+
Security
+
+ + + + + +
Allowed URL schemes:{{ object.data.ALLOWED_URL_SCHEMES }}
+
+
+ +
+
Banners
+
+ + + + + + + + + + + + + + + + + +
Login banner:{{ object.data.BANNER_LOGIN }}
Maintenance banner:{{ object.data.BANNER_MAINTENANCE }}
Top banner:{{ object.data.BANNER_TOP }}
Bottom banner:{{ object.data.BANNER_BOTTOM }}
+
+
+ + +
+
+ +
+
Pagination
+
+ + + + + + + + + +
Paginate count:{{ object.data.PAGINATE_COUNT }}
Max page size:{{ object.data.MAX_PAGE_SIZE }}
+
+
+ +
+
Validation
+
+ + + + + +
Custom validators:{{ object.data.CUSTOM_VALIDATORS }}
+
+
+ +
+
User Preferences
+
+ + + + + +
Default user preferences:{{ object.data.DEFAULT_USER_PREFERENCES }}
+
+
+ +
+
Miscellaneous
+
+ + + + + + + + + + + + + + + + + + + + + +
Maintenance mode:{{ object.data.MAINTENANCE_MODE }}
GraphQL enabled:{{ object.data.GRAPHQL_ENABLED }}
Changelog retention:{{ object.data.CHANGELOG_RETENTION }}
Job retention:{{ object.data.JOB_RETENTION }}
Maps URL:{{ object.data.MAPS_URL }}
+
+
+ +
+
Config Revision
+
+ + + + + +
Comment:{{ object.comment }}
+
+
+ +
+
+{% endblock %} diff --git a/netbox/templates/extras/configrevision_restore.html b/netbox/templates/extras/configrevision_restore.html new file mode 100644 index 000000000..ac22f8cbd --- /dev/null +++ b/netbox/templates/extras/configrevision_restore.html @@ -0,0 +1,88 @@ +{% extends 'base/layout.html' %} +{% load helpers %} +{% load buttons %} +{% load perms %} +{% load static %} + +{% block title %}Restore: {{ object }}{% endblock %} + +{% block subtitle %} +
+ Created {{ object.created|annotated_date }} +
+{% endblock %} + +{% block header %} +
+ +
+ {{ block.super }} +{% endblock header %} + +{% block controls %} +
+
+ {% if request.user|can_delete:job %} + {% delete_button job %} + {% endif %} +
+
+{% endblock controls %} + +{% block tabs %} + +{% endblock %} + +{% block content %} +
+
+ + + + + + + + + + + {% for param, current, new in params %} + + + + + + + {% endfor %} + +
ParameterCurrent ValueNew Value
{{ param }}{{ current }}{{ new }}{% if current != new %}*{% endif %}
+
+
+ +
+ {% csrf_token %} +
+
+
+ + Cancel +
+
+
+
+ +{% endblock content %} + +{% block modals %} +{% endblock modals %} diff --git a/netbox/templates/generic/object.html b/netbox/templates/generic/object.html index d3a617455..ebbeb2dfc 100644 --- a/netbox/templates/generic/object.html +++ b/netbox/templates/generic/object.html @@ -38,7 +38,7 @@ Context: {{ block.super }} -{% endblock %} +{% endblock header %} {% block title %}{{ object }}{% endblock %} @@ -48,7 +48,7 @@ Context: · Updated {{ object.last_updated|timesince }} ago -{% endblock %} +{% endblock subtitle %} {% block controls %} {# Clone/Edit/Delete Buttons #} From 69b818ed33e0779e147af3824db49f0d8c9b7440 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Fri, 23 Jun 2023 07:38:08 -0700 Subject: [PATCH 73/74] 12237 update to Django 4.2 / psycopg3 (#12916) * 12237 upgrade django and psycopg * 12237 add migration * 12237 rename migration * 12237 update requirements * 12237 fix migration * Update base requirements --------- Co-authored-by: Jeremy Stretch --- base_requirements.txt | 6 +++--- netbox/core/models/data.py | 4 +++- .../migrations/0093_tagged_item_indexes.py | 17 +++++++++++++++++ netbox/extras/models/tags.py | 4 +--- requirements.txt | 4 ++-- 5 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 netbox/extras/migrations/0093_tagged_item_indexes.py diff --git a/base_requirements.txt b/base_requirements.txt index 40e0224e2..2d8055049 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -8,7 +8,7 @@ boto3 # The Python web framework on which NetBox is built # https://docs.djangoproject.com/en/stable/releases/ -Django<4.2 +Django<5.0 # Django middleware which permits cross-domain API requests # https://github.com/adamchainz/django-cors-headers/blob/main/CHANGELOG.rst @@ -121,8 +121,8 @@ netaddr Pillow # PostgreSQL database adapter for Python -# https://www.psycopg.org/docs/news.html -psycopg2-binary +# https://github.com/psycopg/psycopg/blob/master/docs/news.rst +psycopg[binary,pool] # YAML rendering library # https://github.com/yaml/pyyaml/blob/master/CHANGES diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py index 2af697f60..a2a20f858 100644 --- a/netbox/core/models/data.py +++ b/netbox/core/models/data.py @@ -290,8 +290,10 @@ class DataFile(models.Model): @property def data_as_string(self): + if not self.data: + return None try: - return self.data.tobytes().decode('utf-8') + return bytes(self.data, 'utf-8') except UnicodeDecodeError: return None diff --git a/netbox/extras/migrations/0093_tagged_item_indexes.py b/netbox/extras/migrations/0093_tagged_item_indexes.py new file mode 100644 index 000000000..6e24e362b --- /dev/null +++ b/netbox/extras/migrations/0093_tagged_item_indexes.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.2 on 2023-06-14 23:26 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ('extras', '0093_configrevision_ordering'), + ] + + operations = [ + migrations.RenameIndex( + model_name='taggeditem', + new_name='extras_tagg_content_717743_idx', + old_fields=('content_type', 'object_id'), + ), + ] diff --git a/netbox/extras/models/tags.py b/netbox/extras/models/tags.py index 066c0fd78..31128ad54 100644 --- a/netbox/extras/models/tags.py +++ b/netbox/extras/models/tags.py @@ -61,6 +61,4 @@ class TaggedItem(GenericTaggedItemBase): ) class Meta: - index_together = ( - ("content_type", "object_id") - ) + indexes = [models.Index(fields=["content_type", "object_id"])] diff --git a/requirements.txt b/requirements.txt index e6e56ce56..2ffcd852b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ bleach==6.0.0 boto3==1.26.156 -Django==4.1.9 +Django==4.2.2 django-cors-headers==4.1.0 django-debug-toolbar==4.1.0 django-filter==23.2 @@ -27,7 +27,7 @@ mkdocs-material==9.1.16 mkdocstrings[python-legacy]==0.22.0 netaddr==0.8.0 Pillow==9.5.0 -psycopg2-binary==2.9.6 +psycopg[binary,pool]==3.1.9 PyYAML==6.0 sentry-sdk==1.25.1 social-auth-app-django==5.2.0 From 1056e513b13968238610e39310cc3d4a7fb967f5 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 23 Jun 2023 14:08:14 -0400 Subject: [PATCH 74/74] Closes #11541: Support for limiting tag assignments by object type (#12982) * Initial work on #11541 * Merge migrations * Limit tags by object type during assignment * Add tests for object type validation * Fix form field parameters --- docs/models/extras/tag.md | 8 +++++++ netbox/extras/api/serializers.py | 8 ++++++- netbox/extras/filtersets.py | 10 +++++++- netbox/extras/forms/filtersets.py | 5 ++++ netbox/extras/forms/model_forms.py | 9 ++++++-- .../migrations/0093_tagged_item_indexes.py | 17 -------------- .../migrations/0094_tag_object_types.py | 23 +++++++++++++++++++ netbox/extras/models/tags.py | 13 ++++++++++- netbox/extras/signals.py | 21 ++++++++++++++++- netbox/extras/tables/tables.py | 6 ++++- netbox/extras/tests/test_filtersets.py | 18 +++++++++++++++ netbox/extras/tests/test_models.py | 18 +++++++++++++++ netbox/netbox/forms/base.py | 7 ++++++ netbox/templates/extras/tag.html | 20 +++++++++++++--- 14 files changed, 156 insertions(+), 27 deletions(-) delete mode 100644 netbox/extras/migrations/0093_tagged_item_indexes.py create mode 100644 netbox/extras/migrations/0094_tag_object_types.py diff --git a/docs/models/extras/tag.md b/docs/models/extras/tag.md index 97ebd9d72..684be582e 100644 --- a/docs/models/extras/tag.md +++ b/docs/models/extras/tag.md @@ -15,3 +15,11 @@ A unique URL-friendly identifier. (This value will be used for filtering.) This ### Color The color to use when displaying the tag in the NetBox UI. + +### Object Types + +!!! info "This feature was introduced in NetBox v3.6." + +The assignment of a tag may be limited to a prescribed set of objects. For example, it may be desirable to limit the application of a specific tag to only devices and virtual machines. + +If no object types are specified, the tag will be assignable to any type of object. diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index a02e933ba..c71e840d5 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -196,12 +196,18 @@ class SavedFilterSerializer(ValidatedModelSerializer): class TagSerializer(ValidatedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='extras-api:tag-detail') + object_types = ContentTypeField( + queryset=ContentType.objects.filter(FeatureQuery('custom_fields').get_query()), + many=True, + required=False + ) tagged_items = serializers.IntegerField(read_only=True) class Meta: model = Tag fields = [ - 'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tagged_items', 'created', 'last_updated', + 'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'object_types', 'tagged_items', 'created', + 'last_updated', ] diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index 6120e2a51..acb0aa359 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -258,10 +258,13 @@ class TagFilterSet(ChangeLoggedModelFilterSet): content_type_id = MultiValueNumberFilter( method='_content_type_id' ) + for_object_type_id = MultiValueNumberFilter( + method='_for_object_type' + ) class Meta: model = Tag - fields = ['id', 'name', 'slug', 'color', 'description'] + fields = ['id', 'name', 'slug', 'color', 'description', 'object_types'] def search(self, queryset, name, value): if not value.strip(): @@ -298,6 +301,11 @@ class TagFilterSet(ChangeLoggedModelFilterSet): return queryset.filter(extras_taggeditem_items__content_type__in=content_types).distinct() + def _for_object_type(self, queryset, name, values): + return queryset.filter( + Q(object_types__id__in=values) | Q(object_types__isnull=True) + ) + class ConfigContextFilterSet(ChangeLoggedModelFilterSet): q = django_filters.CharFilter( diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index bcf2e7863..56e9c8dfb 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -245,6 +245,11 @@ class TagFilterForm(SavedFiltersMixin, FilterForm): required=False, label=_('Tagged object type') ) + for_object_type_id = ContentTypeChoiceField( + queryset=ContentType.objects.filter(FeatureQuery('tags').get_query()), + required=False, + label=_('Allowed object type') + ) class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 621052c96..f8aa982bc 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -204,15 +204,20 @@ class WebhookForm(BootstrapMixin, forms.ModelForm): class TagForm(BootstrapMixin, forms.ModelForm): slug = SlugField() + object_types = ContentTypeMultipleChoiceField( + queryset=ContentType.objects.all(), + limit_choices_to=FeatureQuery('tags'), + required=False + ) fieldsets = ( - ('Tag', ('name', 'slug', 'color', 'description')), + ('Tag', ('name', 'slug', 'color', 'description', 'object_types')), ) class Meta: model = Tag fields = [ - 'name', 'slug', 'color', 'description' + 'name', 'slug', 'color', 'description', 'object_types', ] diff --git a/netbox/extras/migrations/0093_tagged_item_indexes.py b/netbox/extras/migrations/0093_tagged_item_indexes.py deleted file mode 100644 index 6e24e362b..000000000 --- a/netbox/extras/migrations/0093_tagged_item_indexes.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.2 on 2023-06-14 23:26 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ('extras', '0093_configrevision_ordering'), - ] - - operations = [ - migrations.RenameIndex( - model_name='taggeditem', - new_name='extras_tagg_content_717743_idx', - old_fields=('content_type', 'object_id'), - ), - ] diff --git a/netbox/extras/migrations/0094_tag_object_types.py b/netbox/extras/migrations/0094_tag_object_types.py new file mode 100644 index 000000000..944ef64b2 --- /dev/null +++ b/netbox/extras/migrations/0094_tag_object_types.py @@ -0,0 +1,23 @@ +from django.db import migrations, models +import extras.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('extras', '0093_configrevision_ordering'), + ] + + operations = [ + migrations.AddField( + model_name='tag', + name='object_types', + field=models.ManyToManyField(blank=True, limit_choices_to=extras.utils.FeatureQuery('tags'), related_name='+', to='contenttypes.contenttype'), + ), + migrations.RenameIndex( + model_name='taggeditem', + new_name='extras_tagg_content_717743_idx', + old_fields=('content_type', 'object_id'), + ), + ] diff --git a/netbox/extras/models/tags.py b/netbox/extras/models/tags.py index 31128ad54..f54b3d0fe 100644 --- a/netbox/extras/models/tags.py +++ b/netbox/extras/models/tags.py @@ -1,9 +1,13 @@ from django.conf import settings +from django.contrib.contenttypes.models import ContentType +from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse from django.utils.text import slugify +from django.utils.translation import gettext as _ from taggit.models import TagBase, GenericTaggedItemBase +from extras.utils import FeatureQuery from netbox.models import ChangeLoggedModel from netbox.models.features import CloningMixin, ExportTemplatesMixin from utilities.choices import ColorChoices @@ -30,9 +34,16 @@ class Tag(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, TagBase): max_length=200, blank=True, ) + object_types = models.ManyToManyField( + to=ContentType, + related_name='+', + limit_choices_to=FeatureQuery('tags'), + blank=True, + help_text=_("The object type(s) to which this this tag can be applied.") + ) clone_fields = ( - 'color', 'description', + 'color', 'description', 'object_types', ) class Meta: diff --git a/netbox/extras/signals.py b/netbox/extras/signals.py index 4972d9e85..d6550309f 100644 --- a/netbox/extras/signals.py +++ b/netbox/extras/signals.py @@ -10,8 +10,9 @@ from extras.validators import CustomValidator from netbox.config import get_config from netbox.context import current_request, webhooks_queue from netbox.signals import post_clean +from utilities.exceptions import AbortRequest from .choices import ObjectChangeActionChoices -from .models import ConfigRevision, CustomField, ObjectChange +from .models import ConfigRevision, CustomField, ObjectChange, TaggedItem from .webhooks import enqueue_object, get_snapshots, serialize_for_webhook # @@ -207,3 +208,21 @@ def update_config(sender, instance, **kwargs): Update the cached NetBox configuration when a new ConfigRevision is created. """ instance.activate() + + +# +# Tags +# + +@receiver(m2m_changed, sender=TaggedItem) +def validate_assigned_tags(sender, instance, action, model, pk_set, **kwargs): + """ + Validate that any Tags being assigned to the instance are not restricted to non-applicable object types. + """ + if action != 'pre_add': + return + ct = ContentType.objects.get_for_model(instance) + # Retrieve any applied Tags that are restricted to certain object_types + for tag in model.objects.filter(pk__in=pk_set, object_types__isnull=False).prefetch_related('object_types'): + if ct not in tag.object_types.all(): + raise AbortRequest(f"Tag {tag} cannot be assigned to {ct.model} objects.") diff --git a/netbox/extras/tables/tables.py b/netbox/extras/tables/tables.py index e41bc9126..35d53d1a6 100644 --- a/netbox/extras/tables/tables.py +++ b/netbox/extras/tables/tables.py @@ -210,10 +210,14 @@ class TagTable(NetBoxTable): linkify=True ) color = columns.ColorColumn() + object_types = columns.ContentTypesColumn() class Meta(NetBoxTable.Meta): model = Tag - fields = ('pk', 'id', 'name', 'items', 'slug', 'color', 'description', 'created', 'last_updated', 'actions') + fields = ( + 'pk', 'id', 'name', 'items', 'slug', 'color', 'description', 'object_types', 'created', 'last_updated', + 'actions', + ) default_columns = ('pk', 'name', 'items', 'slug', 'color', 'description') diff --git a/netbox/extras/tests/test_filtersets.py b/netbox/extras/tests/test_filtersets.py index 992643530..7dff14cc0 100644 --- a/netbox/extras/tests/test_filtersets.py +++ b/netbox/extras/tests/test_filtersets.py @@ -821,6 +821,10 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): @classmethod def setUpTestData(cls): + content_types = { + 'site': ContentType.objects.get_by_natural_key('dcim', 'site'), + 'provider': ContentType.objects.get_by_natural_key('circuits', 'provider'), + } tags = ( Tag(name='Tag 1', slug='tag-1', color='ff0000', description='foobar1'), @@ -828,6 +832,8 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): Tag(name='Tag 3', slug='tag-3', color='0000ff'), ) Tag.objects.bulk_create(tags) + tags[0].object_types.add(content_types['site']) + tags[1].object_types.add(content_types['provider']) # Apply some tags so we can filter by content type site = Site.objects.create(name='Site 1', slug='site-1') @@ -860,6 +866,18 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests): params = {'content_type_id': [site_ct, provider_ct]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_object_types(self): + params = {'for_object_type_id': [ContentType.objects.get_by_natural_key('dcim', 'site').pk]} + self.assertEqual( + list(self.filterset(params, self.queryset).qs.values_list('name', flat=True)), + ['Tag 1', 'Tag 3'] + ) + params = {'for_object_type_id': [ContentType.objects.get_by_natural_key('circuits', 'provider').pk]} + self.assertEqual( + list(self.filterset(params, self.queryset).qs.values_list('name', flat=True)), + ['Tag 2', 'Tag 3'] + ) + class ObjectChangeTestCase(TestCase, BaseFilterSetTests): queryset = ObjectChange.objects.all() diff --git a/netbox/extras/tests/test_models.py b/netbox/extras/tests/test_models.py index 0ac63c086..0d1dc0e51 100644 --- a/netbox/extras/tests/test_models.py +++ b/netbox/extras/tests/test_models.py @@ -1,8 +1,10 @@ +from django.contrib.contenttypes.models import ContentType from django.test import TestCase from dcim.models import Device, DeviceRole, DeviceType, Location, Manufacturer, Platform, Region, Site, SiteGroup from extras.models import ConfigContext, Tag from tenancy.models import Tenant, TenantGroup +from utilities.exceptions import AbortRequest from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine @@ -14,6 +16,22 @@ class TagTest(TestCase): self.assertEqual(tag.slug, 'testing-unicode-台灣') + def test_object_type_validation(self): + region = Region.objects.create(name='Region 1', slug='region-1') + sitegroup = SiteGroup.objects.create(name='Site Group 1', slug='site-group-1') + + # Create a Tag that can only be applied to Regions + tag = Tag.objects.create(name='Tag 1', slug='tag-1') + tag.object_types.add(ContentType.objects.get_by_natural_key('dcim', 'region')) + + # Apply the Tag to a Region + region.tags.add(tag) + self.assertIn(tag, region.tags.all()) + + # Apply the Tag to a SiteGroup + with self.assertRaises(AbortRequest): + sitegroup.tags.add(tag) + class ConfigContextTest(TestCase): """ diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index 83c238e0f..88cec405f 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -31,6 +31,13 @@ class NetBoxModelForm(BootstrapMixin, CustomFieldsMixin, forms.ModelForm): required=False ) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Limit tags to those applicable to the object type + if (ct := self._get_content_type()) and hasattr(self.fields['tags'].widget, 'add_query_param'): + self.fields['tags'].widget.add_query_param('for_object_type_id', ct.pk) + def _get_content_type(self): return ContentType.objects.get_for_model(self._meta.model) diff --git a/netbox/templates/extras/tag.html b/netbox/templates/extras/tag.html index 6e4c5aee9..e5aa5cc75 100644 --- a/netbox/templates/extras/tag.html +++ b/netbox/templates/extras/tag.html @@ -43,9 +43,23 @@
-
- Tagged Item Types -
+
Allowed Object Types
+
+ + {% for ct in object.object_types.all %} + + + + {% empty %} + + + + {% endfor %} +
{{ ct }}
Any
+
+
+
+
Tagged Item Types
{% for object_type in object_types %}