From 556ff4f15bf1572f0c9704d2c9f84ff730057227 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 24 Oct 2024 13:12:39 +1100 Subject: [PATCH] Settings validation enhancements (#8351) * Enforce lower case for model name checks * Enhance settings validation - Add support for "float" settings type - Improve validation code and error handling --- src/backend/InvenTree/common/models.py | 59 ++++++++++++++++++- .../js/translated/model_renderers.js | 3 + .../src/components/render/Instance.tsx | 4 +- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index 6bd224aa25..7891eeb9fe 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -826,6 +826,9 @@ class BaseInvenTreeSetting(models.Model): elif self.is_bool(): self.value = self.as_bool() + elif self.is_float(): + self.value = self.as_float() + validator = self.__class__.get_setting_validator( self.key, **self.get_filters_for_instance() ) @@ -862,6 +865,14 @@ class BaseInvenTreeSetting(models.Model): except (ValueError, TypeError): raise ValidationError({'value': _('Value must be an integer value')}) + # Floating point validator + if validator is float: + try: + # Coerce into a floating point value + value = float(value) + except (ValueError, TypeError): + raise ValidationError({'value': _('Value must be a valid number')}) + # If a list of validators is supplied, iterate through each one if type(validator) in [list, tuple]: for v in validator: @@ -873,10 +884,18 @@ class BaseInvenTreeSetting(models.Model): if self.is_bool(): value = self.as_bool() - if self.is_int(): + elif self.is_int(): value = self.as_int() - validator(value) + elif self.is_float(): + value = self.as_float() + + try: + validator(value) + except ValidationError as e: + raise e + except Exception: + raise ValidationError({'value': _('Invalid value')}) def validate_unique(self, exclude=None): """Ensure that the key:value pair is unique. In addition to the base validators, this ensures that the 'key' is unique, using a case-insensitive comparison. @@ -970,6 +989,9 @@ class BaseInvenTreeSetting(models.Model): if not model_name: return None + # Enforce lower-case model name + model_name = str(model_name).strip().lower() + try: (app, mdl) = model_name.strip().split('.') except ValueError: @@ -1069,6 +1091,39 @@ class BaseInvenTreeSetting(models.Model): return False + def is_float(self): + """Check if the setting is required to be a float value.""" + validator = self.__class__.get_setting_validator( + self.key, **self.get_filters_for_instance() + ) + + return self.__class__.validator_is_float(validator) + + @classmethod + def validator_is_float(cls, validator): + """Return if validator is for float.""" + if validator == float: + return True + + if type(validator) in [list, tuple]: + for v in validator: + if v == float: + return True + + return False + + def as_float(self): + """Return the value of this setting converted to a float value. + + If an error occurs, return the default value + """ + try: + value = float(self.value) + except (ValueError, TypeError): + value = self.default_value + + return value + def is_int(self): """Check if the setting is required to be an integer value.""" validator = self.__class__.get_setting_validator( diff --git a/src/backend/InvenTree/templates/js/translated/model_renderers.js b/src/backend/InvenTree/templates/js/translated/model_renderers.js index 67eb4186e7..0b96c9a1ec 100644 --- a/src/backend/InvenTree/templates/js/translated/model_renderers.js +++ b/src/backend/InvenTree/templates/js/translated/model_renderers.js @@ -49,6 +49,9 @@ */ function getModelRenderer(model) { + // Ensure correct formatting of provided model name + model = model.toString().toLowerCase(); + // Find a custom renderer switch (model) { case 'company': diff --git a/src/frontend/src/components/render/Instance.tsx b/src/frontend/src/components/render/Instance.tsx index 9f9c4b1c76..5e01c8ff68 100644 --- a/src/frontend/src/components/render/Instance.tsx +++ b/src/frontend/src/components/render/Instance.tsx @@ -108,7 +108,9 @@ export function RenderInstance(props: RenderInstanceProps): ReactNode { return ; } - const RenderComponent = RendererLookup[props.model]; + const model_name = props.model.toString().toLowerCase() as ModelType; + + const RenderComponent = RendererLookup[model_name]; if (!RenderComponent) { console.error(`RenderInstance: No renderer for model ${props.model}`);