From 92e1f14d8166ab10b2485420d04514e3a13dd249 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Thu, 22 Aug 2024 11:38:02 -0700 Subject: [PATCH 1/4] 17219 fix custom validator display if function --- netbox/core/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/netbox/core/views.py b/netbox/core/views.py index d453cf00488..3a38c4a9032 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -560,6 +560,12 @@ def get(self, request): # Fall back to using the active config data if no record is found config = get_config() + # If Custom Validators is function (in configuration.py) get function name + if hasattr(config, 'CUSTOM_VALIDATORS') and config.CUSTOM_VALIDATORS: + for k, v in config.CUSTOM_VALIDATORS.items(): + if isinstance(v, tuple): + config.CUSTOM_VALIDATORS[k] = type(v[0]).__name__ + # Raw data export if 'export' in request.GET: params = [param.name for param in PARAMS] From 67e4b8c8c6863315eab4531668507c469148ec4d Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Fri, 23 Aug 2024 07:43:00 -0700 Subject: [PATCH 2/4] 17219 fix custom validator display if function --- netbox/core/views.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/netbox/core/views.py b/netbox/core/views.py index 3a38c4a9032..26e04a8d826 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -25,6 +25,7 @@ from rq.worker import Worker from rq.worker_registration import clean_worker_registry +from extras.validators import CustomValidator from netbox.config import get_config, PARAMS from netbox.views import generic from netbox.views.generic.base import BaseObjectView @@ -522,6 +523,23 @@ class SystemView(UserPassesTestMixin, View): def test_func(self): return self.request.user.is_staff + def map_validators(self, validator): + if isinstance(validator, dict): + for k, v in validator.items(): + if isinstance(v, tuple): + validator[k] = type(v[0]).__name__ + else: + validator[k] = self.map_validators(v) + + elif isinstance(validator, list): + for index, v in enumerate(validator): + validator[index] = self.map_validators(v) + + elif issubclass(type(validator), CustomValidator): + return type(validator).__name__ + + return validator + def get(self, request): # System stats @@ -562,9 +580,7 @@ def get(self, request): # If Custom Validators is function (in configuration.py) get function name if hasattr(config, 'CUSTOM_VALIDATORS') and config.CUSTOM_VALIDATORS: - for k, v in config.CUSTOM_VALIDATORS.items(): - if isinstance(v, tuple): - config.CUSTOM_VALIDATORS[k] = type(v[0]).__name__ + config.CUSTOM_VALIDATORS = self.map_validators(config.CUSTOM_VALIDATORS) # Raw data export if 'export' in request.GET: From 3c2af9782379e19f6a70f55fc0b076348bb5f9eb Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Tue, 27 Aug 2024 10:02:03 -0700 Subject: [PATCH 3/4] 17219 use custom json encoder --- netbox/core/views.py | 25 ++++------------------ netbox/templates/core/inc/config_data.html | 2 +- netbox/utilities/json.py | 13 +++++++++++ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/netbox/core/views.py b/netbox/core/views.py index 26e04a8d826..bc45089f1dc 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -32,6 +32,7 @@ from netbox.views.generic.mixins import TableMixin from utilities.forms import ConfirmationForm from utilities.htmx import htmx_partial +from utilities.json import ConfigJSONEncoder from utilities.query import count_related from utilities.views import ContentTypePermissionRequiredMixin, GetRelatedModelsMixin, register_model_view from . import filtersets, forms, tables @@ -523,23 +524,6 @@ class SystemView(UserPassesTestMixin, View): def test_func(self): return self.request.user.is_staff - def map_validators(self, validator): - if isinstance(validator, dict): - for k, v in validator.items(): - if isinstance(v, tuple): - validator[k] = type(v[0]).__name__ - else: - validator[k] = self.map_validators(v) - - elif isinstance(validator, list): - for index, v in enumerate(validator): - validator[index] = self.map_validators(v) - - elif issubclass(type(validator), CustomValidator): - return type(validator).__name__ - - return validator - def get(self, request): # System stats @@ -578,10 +562,6 @@ def get(self, request): # Fall back to using the active config data if no record is found config = get_config() - # If Custom Validators is function (in configuration.py) get function name - if hasattr(config, 'CUSTOM_VALIDATORS') and config.CUSTOM_VALIDATORS: - config.CUSTOM_VALIDATORS = self.map_validators(config.CUSTOM_VALIDATORS) - # Raw data export if 'export' in request.GET: params = [param.name for param in PARAMS] @@ -601,6 +581,9 @@ def get(self, request): plugins_table = tables.PluginTable(plugins, orderable=False) plugins_table.configure(request) + if hasattr(config, 'CUSTOM_VALIDATORS') and config.CUSTOM_VALIDATORS: + config.CUSTOM_VALIDATORS = json.dumps(config.CUSTOM_VALIDATORS, cls=ConfigJSONEncoder, indent=4) + return render(request, 'core/system.html', { 'stats': stats, 'plugins_table': plugins_table, diff --git a/netbox/templates/core/inc/config_data.html b/netbox/templates/core/inc/config_data.html index 8305b55404b..41471a10374 100644 --- a/netbox/templates/core/inc/config_data.html +++ b/netbox/templates/core/inc/config_data.html @@ -95,7 +95,7 @@ {% trans "Custom validators" %} {% if config.CUSTOM_VALIDATORS %} -
{{ config.CUSTOM_VALIDATORS|json }}
+
{{ config.CUSTOM_VALIDATORS }}
{% else %} {{ ''|placeholder }} {% endif %} diff --git a/netbox/utilities/json.py b/netbox/utilities/json.py index 5574ff36f78..926df898ee9 100644 --- a/netbox/utilities/json.py +++ b/netbox/utilities/json.py @@ -3,6 +3,7 @@ from django.core.serializers.json import DjangoJSONEncoder __all__ = ( + 'ConfigJSONEncoder', 'CustomFieldJSONEncoder', ) @@ -15,3 +16,15 @@ def default(self, o): if isinstance(o, decimal.Decimal): return float(o) return super().default(o) + + +class ConfigJSONEncoder(DjangoJSONEncoder): + """ + Override Django's built-in JSON encoder to save python functions as function names. + """ + def default(self, o): + from extras.validators import CustomValidator + + if issubclass(type(o), CustomValidator): + return type(o).__name__ + return super().default(o) From ffbc8b4b41afc63283128e98c679b54beee374ee Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 27 Aug 2024 13:56:38 -0400 Subject: [PATCH 4/4] Fix system config export --- netbox/core/views.py | 3 ++- netbox/utilities/json.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/netbox/core/views.py b/netbox/core/views.py index bc45089f1dc..230134cc362 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -574,13 +574,14 @@ def get(self, request): k: getattr(config, k) for k in sorted(params) }, } - response = HttpResponse(json.dumps(data, indent=4), content_type='text/json') + response = HttpResponse(json.dumps(data, cls=ConfigJSONEncoder, indent=4), content_type='text/json') response['Content-Disposition'] = 'attachment; filename="netbox.json"' return response plugins_table = tables.PluginTable(plugins, orderable=False) plugins_table.configure(request) + # Serialize any CustomValidator classes if hasattr(config, 'CUSTOM_VALIDATORS') and config.CUSTOM_VALIDATORS: config.CUSTOM_VALIDATORS = json.dumps(config.CUSTOM_VALIDATORS, cls=ConfigJSONEncoder, indent=4) diff --git a/netbox/utilities/json.py b/netbox/utilities/json.py index 926df898ee9..3114be1bff4 100644 --- a/netbox/utilities/json.py +++ b/netbox/utilities/json.py @@ -20,11 +20,12 @@ def default(self, o): class ConfigJSONEncoder(DjangoJSONEncoder): """ - Override Django's built-in JSON encoder to save python functions as function names. + Override Django's built-in JSON encoder to serialize CustomValidator classes as strings. """ def default(self, o): from extras.validators import CustomValidator if issubclass(type(o), CustomValidator): return type(o).__name__ + return super().default(o)