diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.py b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.py index d786e6456623110b38d9126b6e7e46aa08388d31..948d68fe29b8aedfa85ab687da8c7b56d6bf55fe 100644 --- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.py +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.py @@ -24,6 +24,8 @@ return context.ERP5Document_getHateoas( sort_on=sort_on, local_roles=local_roles, selection_domain=selection_domain, + restricted=1, extra_param_json=extra_param_json, - restricted=1 + portal_status_message=portal_status_message, + portal_status_level=portal_status_level ) diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.xml b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.xml index 8419ac85974e8dbfa49cefeac594749ca4c41f8b..82ce578fca12dc20d6481e30d0487adefd5b5456 100644 --- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.xml +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_restricted_style/ERP5Document_getHateoas.xml @@ -50,7 +50,7 @@ </item> <item> <key> <string>_params</string> </key> - <value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, relative_url=None, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", sort_on=None, selection_domain=None, extra_param_json=None</string> </value> + <value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, relative_url=None, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", sort_on=None, selection_domain=None, extra_param_json=None, portal_status_message=\'\', portal_status_level=None</string> </value> </item> <item> <key> <string>id</string> </key> diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.py b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.py index f8c82a00b4d90e35e605f80a1991da00e335d89a..0ed9e08378cec97b4f688e2b09a6ed63b22fc4c5 100644 --- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.py +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.py @@ -1,2 +1,24 @@ +"""Render form while keeping its values back to user. + +This script differs from Base_redirect that it keeps the form values in place. + +:param message: {str} message to be displayed at the user +:param level: {str|int} severity of the message using ERP5Type.Log levels or their names like 'info', 'warn', 'error' +:param keep_items: {dict} items to be available in the next call. They will be either added as hidden fields to the + rendered form or in case of "portal_status_message" just displayed to the user +:param REQUEST: request +:param **kwargs: should contain parameters to ERP5Document_getHateoas such as 'query' to replace Selections +""" + +keep_items = keep_items or {} + form = getattr(context, form_id) -return context.ERP5Document_getHateoas(form=form, mode='form') + +if not message and "portal_status_message" in keep_items: + message = keep_items.pop("portal_status_message") + +if not level and "portal_status_level" in keep_items: + level = keep_items.pop("portal_status_level") + +return context.ERP5Document_getHateoas(form=form, mode='form', REQUEST=REQUEST, extra_param_json=keep_items, + portal_status_message=message, portal_status_level=level, **kwargs) diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.xml b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.xml index e1e14e9bd773c3bb32819968f3519efd1e8a1135..a1ff8d1688fb0aee531c8ca728f8a384018a4e4a 100644 --- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.xml +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/Base_renderForm.xml @@ -50,7 +50,7 @@ </item> <item> <key> <string>_params</string> </key> - <value> <string>form_id</string> </value> + <value> <string>form_id, message=\'\', level=None, keep_items=None, REQUEST=None, **kwargs</string> </value> </item> <item> <key> <string>id</string> </key> diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py index ff8fd787c9844c82858c2e7f9b366812628ffd5a..4d676e1d26829850bf4bbc8562b60696ddb1fa32 100644 --- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.py @@ -41,10 +41,10 @@ import time from email.Utils import formatdate import re from zExceptions import Unauthorized -from Products.ERP5Type.Utils import UpperCase +from Products.ERP5Type.Log import log, DEBUG, INFO, WARNING, ERROR from Products.ERP5Type.Message import Message +from Products.ERP5Type.Utils import UpperCase from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery -from Products.ERP5Type.Log import log from collections import OrderedDict from urlparse import urlparse @@ -1190,33 +1190,22 @@ def renderFormDefinition(form, response_dict): response_dict["action"] = form.action response_dict["update_action"] = form.update_action -mime_type = 'application/hal+json' -portal = context.getPortalObject() -sql_catalog = portal.portal_catalog.getSQLCatalog() - -# Calculate the site root to prevent unexpected browsing -is_web_mode = (context.REQUEST.get('current_web_section', None) is not None) or (hasattr(context, 'isWebMode') and context.isWebMode()) -# is_web_mode = traversed_document.isWebMode() -if is_web_mode: - site_root = context.getWebSectionValue() - view_action_type = site_root.getLayoutProperty("configuration_view_action_category", default='object_view') -else: - site_root = portal - view_action_type = "object_view" - -context.Base_prepareCorsResponse(RESPONSE=response) - -# Check if traversed_document is the site_root -if relative_url: - temp_traversed_document = site_root.restrictedTraverse(relative_url, None) - if (temp_traversed_document is None): - response.setStatus(404) - return "" -else: - temp_traversed_document = context +def statusLevelToString(level): + """Transform any level format to lowercase string representation""" + if isinstance(level, (str, unicode)): + if level.lower() == "error": + return "error" + elif level.lower().startswith("warn"): + return "error" # we might want to add another level for warning + else: + return "success" + if level == ERROR: + return "error" + elif level == WARNING: + return "error" + else: + return "success" -temp_is_site_root = (temp_traversed_document.getPath() == site_root.getPath()) -temp_is_portal = (temp_traversed_document.getPath() == portal.getPath()) def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, REQUEST=None, response=None, view=None, mode=None, query=None, @@ -1260,9 +1249,18 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, "name": portal.getTitle(), } } + # possible other attributes + # _notification {dict} form of {'message': "", 'status': ""} + # _embedded {dict} form of {"_view": <erp5_document_properties>} } - - + + # Inject notification into response no matter the kind of request + if portal_status_message: + result_dict['_notification'] = { + 'message': str(portal_status_message), + 'status': statusLevelToString(portal_status_level) + } + if (restricted == 1) and (portal.portal_membership.isAnonymousUser()): login_relative_url = site_root.getLayoutProperty("configuration_login", default="") if (login_relative_url): @@ -2101,6 +2099,35 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, return result_dict + +mime_type = 'application/hal+json' +portal = context.getPortalObject() +sql_catalog = portal.portal_catalog.getSQLCatalog() + +# Calculate the site root to prevent unexpected browsing +is_web_mode = (context.REQUEST.get('current_web_section', None) is not None) or (hasattr(context, 'isWebMode') and context.isWebMode()) +# is_web_mode = traversed_document.isWebMode() +if is_web_mode: + site_root = context.getWebSectionValue() + view_action_type = site_root.getLayoutProperty("configuration_view_action_category", default='object_view') +else: + site_root = portal + view_action_type = "object_view" + +context.Base_prepareCorsResponse(RESPONSE=response) + +# Check if traversed_document is the site_root +if relative_url: + temp_traversed_document = site_root.restrictedTraverse(relative_url, None) + if (temp_traversed_document is None): + response.setStatus(404) + return "" +else: + temp_traversed_document = context + +temp_is_site_root = (temp_traversed_document.getPath() == site_root.getPath()) +temp_is_portal = (temp_traversed_document.getPath() == portal.getPath()) + response.setHeader('Content-Type', mime_type) hateoas = calculateHateoas(is_portal=temp_is_portal, is_site_root=temp_is_site_root, traversed_document=temp_traversed_document, diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.xml b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.xml index cd553162857da696e20964c0e0d78adfa362ed82..c0b0e3cff4ff6c4393c7aaeef60ad20b8471e905 100644 --- a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.xml +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/ERP5Document_getHateoas.xml @@ -56,7 +56,7 @@ </item> <item> <key> <string>_params</string> </key> - <value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, relative_url=None, restricted=0, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", sort_on=None, selection_domain=None, extra_param_json=None</string> </value> + <value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, local_roles=None, form=None, relative_url=None, restricted=0, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]", sort_on=None, selection_domain=None, extra_param_json=None, portal_status_message=\'\', portal_status_level=None</string> </value> </item> <item> <key> <string>id</string> </key> diff --git a/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py b/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py index ace84ff175e52136d4bf1711610155cd5bf72fca..1057d4fda5868100d31672853f1bcac11ccf71e4 100644 --- a/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py +++ b/bt5/erp5_hal_json_style/TestTemplateItem/portal_components/test.erp5.testHalJsonStyle.py @@ -1615,6 +1615,28 @@ return portal.portal_simulation.getInventoryList(section_uid=context.getUid()) self.assertEqual(result_dict['_embedded'].get('count', None), None) +class TestERP5Document_getHateoas_mode_form(ERP5HALJSONStyleSkinsMixin): + + @simulate('Base_getRequestHeader', '*args, **kwargs', + 'return "application/hal+json"') + @createIndexedDocument() + @changeSkin('Hal') + def test_getHateoasForm_message(self, document): + fake_request = do_fake_request("POST") + + result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas( + REQUEST=fake_request, mode="form", relative_url=document.getRelativeUrl(), + form=getattr(document, 'Foo_view'), portal_status_message="Couscous", portal_status_level='error') + + self.assertEquals(fake_request.RESPONSE.status, 200) + self.assertEquals(fake_request.RESPONSE.getHeader('Content-Type'), + "application/hal+json" + ) + result_dict = json.loads(result) + self.assertEqual(result_dict["_notification"]["status"], "error") + self.assertEqual(result_dict["_notification"]["message"], "Couscous") + + class TestERP5Document_getHateoas_mode_bulk(ERP5HALJSONStyleSkinsMixin): @simulate('Base_getRequestHeader', '*args, **kwargs', diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.py b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.py index 0c2a28ee71c244e1429d82149e4a71e43a7725cd..285831f432424d058c6b8008faff422d35852b69 100644 --- a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.py +++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.py @@ -1 +1,26 @@ +"""Render form while keeping its values back to user. + +This script differs from Base_redirect that it keeps the form values in place. + +:param message: {str} message to be displayed at the user +:param level: {str|int} is ignored in XHTML style - no support for message level distinction +:param keep_items: {dict} items to be available in the next call. They will be either added as hidden fields to the + rendered form or in case of "portal_status_message" just displayed to the user +:param REQUEST: request +:param **kwargs: is used to pass necessary parameters to overcome backend-held state (aka Selections) +""" + +keep_items = keep_items or {} + +if message and "portal_status_message" not in keep_items: + keep_items["portal_status_message"] = message + +keep_items.pop("portal_status_level", None) + +if REQUEST is None: + REQUEST = context.REQUEST + +for key, value in keep_items.items(): + REQUEST.set(key, value) + return getattr(context, form_id)() diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.xml b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.xml index e1e14e9bd773c3bb32819968f3519efd1e8a1135..a1ff8d1688fb0aee531c8ca728f8a384018a4e4a 100644 --- a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.xml +++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/Base_renderForm.xml @@ -50,7 +50,7 @@ </item> <item> <key> <string>_params</string> </key> - <value> <string>form_id</string> </value> + <value> <string>form_id, message=\'\', level=None, keep_items=None, REQUEST=None, **kwargs</string> </value> </item> <item> <key> <string>id</string> </key>