From 79e81295d58547a240caf007fc3f2e14eb74d494 Mon Sep 17 00:00:00 2001 From: Jakob Ketterl Date: Wed, 17 Jan 2024 20:05:47 +0100 Subject: [PATCH] preserve user input in case of form validation errors --- owrx/controllers/settings/__init__.py | 27 +++++++++++++++++++++------ owrx/form/input/__init__.py | 6 ++++-- owrx/form/input/location.py | 2 -- owrx/form/section.py | 4 +++- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/owrx/controllers/settings/__init__.py b/owrx/controllers/settings/__init__.py index 8ad8a4e8..0ac3c5de 100644 --- a/owrx/controllers/settings/__init__.py +++ b/owrx/controllers/settings/__init__.py @@ -20,6 +20,7 @@ class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageControl super().__init__(handler, request, options) self.errors = {} self.globalError = None + self.formData = None @abstractmethod def getSections(self): @@ -35,8 +36,18 @@ class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageControl def getErrors(self): return self.errors + def buildRenderData(self): + # this basially builds an intermediate result to be rendered + # relevant when the form has to be displayed again due to errors + # in this specific scenario, we mix the config with the data the user already submitted + # we use a copy of the config so that whatever we apply here does not get accidentally stored + res = self.getData().__dict__() + if self.formData is not None: + self._applyConfigData(res, self.formData) + return res + def render_sections(self): - sections = "".join(section.render(self.getData(), self.getErrors()) for section in self.getSections()) + sections = "".join(section.render(self.buildRenderData(), self.getErrors()) for section in self.getSections()) buttons = self.render_buttons() return """
@@ -97,6 +108,7 @@ class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageControl self.globalError = str(e) return self.indexAction() + self.formData = data if errors: self.errors = self._mergeErrors(errors) return self.indexAction() @@ -109,14 +121,17 @@ class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageControl self.globalError = str(e) return self.indexAction() - def processData(self, data): - config = self.getData() + def _applyConfigData(self, dest, data): for k, v in data.items(): if v is None: - if k in config: - del config[k] + if k in dest: + del dest[k] else: - config[k] = v + dest[k] = v + + def processData(self, data): + config = self.getData() + self._applyConfigData(config, data) def store(self): Config.get().store() diff --git a/owrx/form/input/__init__.py b/owrx/form/input/__init__.py index 57e59b7a..42feb2ac 100644 --- a/owrx/form/input/__init__.py +++ b/owrx/form/input/__init__.py @@ -91,11 +91,13 @@ class Input(ABC): def parse(self, data): if self.id in data: value = self.converter.convert_from_form(data[self.id][0]) - if self.validator is not None: - self.validator.validate(self.id, value) return {self.id: value} return {} + def validate(self, data): + if self.id in data and self.validator is not None: + self.validator.validate(self.id, data[self.id]) + def getLabel(self): return self.label diff --git a/owrx/form/input/location.py b/owrx/form/input/location.py index 3a9fcb31..36245596 100644 --- a/owrx/form/input/location.py +++ b/owrx/form/input/location.py @@ -59,6 +59,4 @@ class LocationInput(Input): def parse(self, data): value = {k: float(data["{0}-{1}".format(self.id, k)][0]) for k in ["lat", "lon"]} - if self.validator is not None: - self.validator.validate(self.id, value) return {self.id: value} diff --git a/owrx/form/section.py b/owrx/form/section.py index 1eb9b9e6..f50c65f9 100644 --- a/owrx/form/section.py +++ b/owrx/form/section.py @@ -34,7 +34,9 @@ class Section(object): errors = [] for i in self.inputs: try: - parsed_data.update(i.parse(data)) + res = i.parse(data) + parsed_data.update(res) + i.validate(res) except FormError as e: errors.append(e) except Exception as e: