From a903632c0778a3654a1c69bc10502d2732d3080a Mon Sep 17 00:00:00 2001 From: wesleybl Date: Tue, 2 Apr 2024 14:33:47 -0300 Subject: [PATCH 1/4] Returns an error message when an Invalid occurs when validating a controlpanel field --- news/1771.bugfix | 1 + .../deserializer/controlpanels/__init__.py | 5 +++-- .../restapi/tests/test_services_controlpanels.py | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 news/1771.bugfix diff --git a/news/1771.bugfix b/news/1771.bugfix new file mode 100644 index 0000000000..696a013b85 --- /dev/null +++ b/news/1771.bugfix @@ -0,0 +1 @@ +Returns an error message when an Invalid error occurs when validating a controlpanel field. @wesleybl diff --git a/src/plone/restapi/deserializer/controlpanels/__init__.py b/src/plone/restapi/deserializer/controlpanels/__init__.py index 53b9a2a07c..ef7c9699a3 100644 --- a/src/plone/restapi/deserializer/controlpanels/__init__.py +++ b/src/plone/restapi/deserializer/controlpanels/__init__.py @@ -10,6 +10,7 @@ from zope.component import getUtility from zope.component import queryMultiAdapter from zope.interface import implementer +from zope.interface.exceptions import Invalid from zope.schema import getFields from zope.schema.interfaces import ValidationError @@ -61,10 +62,10 @@ def __call__(self): field.validate(value) # Set the value. setattr(proxy, name, value) - except ValueError as e: - errors.append({"message": str(e), "field": name, "error": e}) except ValidationError as e: errors.append({"message": e.doc(), "field": name, "error": e}) + except (ValueError, Invalid) as e: + errors.append({"message": str(e), "field": name, "error": e}) else: field_data[name] = value diff --git a/src/plone/restapi/tests/test_services_controlpanels.py b/src/plone/restapi/tests/test_services_controlpanels.py index f23affcca5..54a63b13a1 100644 --- a/src/plone/restapi/tests/test_services_controlpanels.py +++ b/src/plone/restapi/tests/test_services_controlpanels.py @@ -115,6 +115,22 @@ def test_update_required(self): self.assertIn("message", response) self.assertIn("Required input is missing.", response["message"]) + def test_update_validation(self): + response = self.api_session.patch( + "/@controlpanels/socialmedia", json={"twitter_username": "@test"} + ) + response = response.json() + self.assertIn( + 'Twitter username should not include the "@" prefix character.', + response["message"], + ) + + def test_update_validation_status(self): + response = self.api_session.patch( + "/@controlpanels/socialmedia", json={"twitter_username": "@test"} + ) + self.assertEqual(response.status_code, 400) + def test_get_usergroup_control_panel(self): # This control panel does not exist in Plone 5 response = self.api_session.get("/@controlpanels/usergroup") From 687fb4ef9ac7607c73bb50ec4cf3cdbe6e2b0af3 Mon Sep 17 00:00:00 2001 From: wesleybl Date: Tue, 2 Apr 2024 14:44:35 -0300 Subject: [PATCH 2/4] Translates controlpanel validation error message --- news/1771.bugfix | 2 +- src/plone/restapi/deserializer/controlpanels/__init__.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/news/1771.bugfix b/news/1771.bugfix index 696a013b85..55046bdae0 100644 --- a/news/1771.bugfix +++ b/news/1771.bugfix @@ -1 +1 @@ -Returns an error message when an Invalid error occurs when validating a controlpanel field. @wesleybl +Returns an error message when an Invalid error occurs when validating a controlpanel field. Also translates the message. @wesleybl diff --git a/src/plone/restapi/deserializer/controlpanels/__init__.py b/src/plone/restapi/deserializer/controlpanels/__init__.py index ef7c9699a3..0afe908312 100644 --- a/src/plone/restapi/deserializer/controlpanels/__init__.py +++ b/src/plone/restapi/deserializer/controlpanels/__init__.py @@ -9,6 +9,7 @@ from zope.component import adapter from zope.component import getUtility from zope.component import queryMultiAdapter +from zope.i18n import translate from zope.interface import implementer from zope.interface.exceptions import Invalid from zope.schema import getFields @@ -77,5 +78,8 @@ def __call__(self): for error in validator.validate(field_data): errors.append({"error": error, "message": str(error)}) + for error in errors: + error["message"] = translate(error["message"], context=self.request) + if errors: raise BadRequest(errors) From 1015378bea505e5ce009e8f521b0fece970bfdf8 Mon Sep 17 00:00:00 2001 From: wesleybl Date: Wed, 3 Apr 2024 13:23:33 -0300 Subject: [PATCH 3/4] Does not return the "error" key as an object in controlpanel When deserializing the controlpanel, do not return the "error" key as an object, but rather as a string "ValidationError". On the front end, we are unable to convert an object to json. So we need to return a string. This is the same way content deserialization does. --- .../restapi/deserializer/controlpanels/__init__.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plone/restapi/deserializer/controlpanels/__init__.py b/src/plone/restapi/deserializer/controlpanels/__init__.py index 0afe908312..d61a79f1be 100644 --- a/src/plone/restapi/deserializer/controlpanels/__init__.py +++ b/src/plone/restapi/deserializer/controlpanels/__init__.py @@ -34,7 +34,7 @@ def __init__(self, controlpanel): self.context = self.controlpanel.context self.request = self.controlpanel.request - def __call__(self): + def __call__(self, mask_validation_errors=True): data = json_body(self.controlpanel.request) proxy = self.registry.forInterface(self.schema, prefix=self.schema_prefix) @@ -78,8 +78,12 @@ def __call__(self): for error in validator.validate(field_data): errors.append({"error": error, "message": str(error)}) - for error in errors: - error["message"] = translate(error["message"], context=self.request) - if errors: + if mask_validation_errors: + # Drop Python specific error classes in order to be able to better handle + # errors on front-end + for error in errors: + error["error"] = "ValidationError" + for error in errors: + error["message"] = translate(error["message"], context=self.request) raise BadRequest(errors) From 1996339dbeb2b03e8d7d7de9c3ba37a0e65e6fa7 Mon Sep 17 00:00:00 2001 From: wesleybl Date: Tue, 23 Apr 2024 18:15:55 -0300 Subject: [PATCH 4/4] Improves error handling --- src/plone/restapi/deserializer/controlpanels/__init__.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plone/restapi/deserializer/controlpanels/__init__.py b/src/plone/restapi/deserializer/controlpanels/__init__.py index d61a79f1be..f27b8fd4b8 100644 --- a/src/plone/restapi/deserializer/controlpanels/__init__.py +++ b/src/plone/restapi/deserializer/controlpanels/__init__.py @@ -79,11 +79,10 @@ def __call__(self, mask_validation_errors=True): errors.append({"error": error, "message": str(error)}) if errors: - if mask_validation_errors: - # Drop Python specific error classes in order to be able to better handle - # errors on front-end - for error in errors: - error["error"] = "ValidationError" for error in errors: + if mask_validation_errors: + # Drop Python specific error classes in order to be able to better handle + # errors on front-end + error["error"] = "ValidationError" error["message"] = translate(error["message"], context=self.request) raise BadRequest(errors)