Commit b00b9e5c authored by Romain Courteaud's avatar Romain Courteaud

[erp5_hal_json_style] Draft support for bulk method

Speed up jIO synchronization by allowing fetching multiple documents JSON with one request
parent 513d2d5f
...@@ -72,13 +72,14 @@ return context.ERP5Document_getHateoas(\n ...@@ -72,13 +72,14 @@ return context.ERP5Document_getHateoas(\n
list_method=list_method,\n list_method=list_method,\n
default_param_json=default_param_json,\n default_param_json=default_param_json,\n
form_relative_url=form_relative_url,\n form_relative_url=form_relative_url,\n
bulk_list=bulk_list,\n
restricted=1\n restricted=1\n
)\n )\n
</string> </value> </string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, form=None, relative_url=None, list_method=None, default_param_json=None, form_relative_url=None</string> </value> <value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, form=None, relative_url=None, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]"</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -88,6 +88,7 @@ url_template_dict = {\n ...@@ -88,6 +88,7 @@ url_template_dict = {\n
"&default_param_json=%(default_param_json)s" \\\n "&default_param_json=%(default_param_json)s" \\\n
"{&query,select_list*,limit*}",\n "{&query,select_list*,limit*}",\n
"new_content_action": "%(root_url)s/%(script_id)s?mode=newContent",\n "new_content_action": "%(root_url)s/%(script_id)s?mode=newContent",\n
"bulk_action": "%(root_url)s/%(script_id)s?mode=bulk",\n
# XXX View is set by default to empty\n # XXX View is set by default to empty\n
"document_hal": "%(root_url)s/%(script_id)s?mode=traverse" + \\\n "document_hal": "%(root_url)s/%(script_id)s?mode=traverse" + \\\n
"&relative_url=%(relative_url)s",\n "&relative_url=%(relative_url)s",\n
...@@ -109,18 +110,18 @@ def getFormRelativeUrl(form):\n ...@@ -109,18 +110,18 @@ def getFormRelativeUrl(form):\n
select_dict={\'relative_url\': None}\n select_dict={\'relative_url\': None}\n
)[0].relative_url\n )[0].relative_url\n
\n \n
def getFieldDefault(field, key, value=None):\n def getFieldDefault(traversed_document, field, key, value=None):\n
# REQUEST.get(field.id, field.get_value("default"))\n # REQUEST.get(field.id, field.get_value("default"))\n
return traversed_document.Field_getDefaultValue(field, key, value, REQUEST)\n return traversed_document.Field_getDefaultValue(field, key, value, REQUEST)\n
\n \n
def renderField(field, form_relative_url, value=None, meta_type=None, key=None):\n def renderField(traversed_document, field, form_relative_url, value=None, meta_type=None, key=None):\n
if meta_type is None:\n if meta_type is None:\n
meta_type = field.meta_type\n meta_type = field.meta_type\n
if key is None:\n if key is None:\n
key = field.generate_field_key()\n key = field.generate_field_key()\n
\n \n
if meta_type == "ProxyField":\n if meta_type == "ProxyField":\n
result = renderField(field, form_relative_url, value, meta_type=field.getRecursiveTemplateField().meta_type, key=key)\n result = renderField(traversed_document, field, form_relative_url, value, meta_type=field.getRecursiveTemplateField().meta_type, key=key)\n
elif meta_type == "ListField":\n elif meta_type == "ListField":\n
result = {\n result = {\n
"type": meta_type,\n "type": meta_type,\n
...@@ -134,7 +135,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -134,7 +135,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
# XXX Message can not be converted to json as is\n # XXX Message can not be converted to json as is\n
"items": field.get_value("items"),\n "items": field.get_value("items"),\n
}\n }\n
result["default"] = getFieldDefault(field, result["key"], value)\n result["default"] = getFieldDefault(traversed_document, field, result["key"], value)\n
elif meta_type == "RadioField":\n elif meta_type == "RadioField":\n
result = {\n result = {\n
"type": meta_type,\n "type": meta_type,\n
...@@ -149,7 +150,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -149,7 +150,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
"select_first_item": field.get_value("first_item"),\n "select_first_item": field.get_value("first_item"),\n
"orientation": field.get_value("orientation"),\n "orientation": field.get_value("orientation"),\n
}\n }\n
result["default"] = getFieldDefault(field, result["key"], value)\n result["default"] = getFieldDefault(traversed_document, field, result["key"], value)\n
elif meta_type in ("ParallelListField", "MultiListField"):\n elif meta_type in ("ParallelListField", "MultiListField"):\n
result = {\n result = {\n
"type": meta_type,\n "type": meta_type,\n
...@@ -163,7 +164,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -163,7 +164,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
# XXX Message can not be converted to json as is\n # XXX Message can not be converted to json as is\n
"items": field.get_value("items"),\n "items": field.get_value("items"),\n
}\n }\n
result["default"] = getFieldDefault(field, result["key"], value)\n result["default"] = getFieldDefault(traversed_document, field, result["key"], value)\n
result["sub_select_key"] = traversed_document.Field_getSubFieldKeyDict(field, \'default:list\', key=result["key"])\n result["sub_select_key"] = traversed_document.Field_getSubFieldKeyDict(field, \'default:list\', key=result["key"])\n
result["sub_input_key"] = "default_" + traversed_document.Field_getSubFieldKeyDict(field, \'default:list:int\', key=result["key"])\n result["sub_input_key"] = "default_" + traversed_document.Field_getSubFieldKeyDict(field, \'default:list:int\', key=result["key"])\n
elif meta_type in ("StringField", "FloatField", "EmailField", "TextAreaField",\n elif meta_type in ("StringField", "FloatField", "EmailField", "TextAreaField",\n
...@@ -179,7 +180,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -179,7 +180,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
"title": field.get_value("title"),\n "title": field.get_value("title"),\n
"required": field.get_value("required"),\n "required": field.get_value("required"),\n
}\n }\n
result["default"] = getFieldDefault(field, result["key"], value)\n result["default"] = getFieldDefault(traversed_document, field, result["key"], value)\n
if meta_type == "FloatField":\n if meta_type == "FloatField":\n
result["precision"] = field.get_value("precision")\n result["precision"] = field.get_value("precision")\n
if meta_type == "ImageField":\n if meta_type == "ImageField":\n
...@@ -212,7 +213,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -212,7 +213,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
"hide_day": field.get_value(\'hide_day\'),\n "hide_day": field.get_value(\'hide_day\'),\n
"hidden_day_is_last_day": field.get_value(\'hidden_day_is_last_day\'),\n "hidden_day_is_last_day": field.get_value(\'hidden_day_is_last_day\'),\n
}\n }\n
date_value = getFieldDefault(field, result["key"], value)\n date_value = getFieldDefault(traversed_document, field, result["key"], value)\n
if same_type(date_value, DateTime()):\n if same_type(date_value, DateTime()):\n
# Serialize DateTime\n # Serialize DateTime\n
date_value = date_value.rfc822()\n date_value = date_value.rfc822()\n
...@@ -258,7 +259,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -258,7 +259,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
"title": field.get_value("title"),\n "title": field.get_value("title"),\n
"required": field.get_value("required")\n "required": field.get_value("required")\n
}\n }\n
result["default"] = getFieldDefault(field, result["key"], value)\n result["default"] = getFieldDefault(traversed_document, field, result["key"], value)\n
result["relation_field_id"] = traversed_document.Field_getSubFieldKeyDict(\n result["relation_field_id"] = traversed_document.Field_getSubFieldKeyDict(\n
field,\n field,\n
"relation",\n "relation",\n
...@@ -285,7 +286,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -285,7 +286,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
"description": field.get_value("description"),\n "description": field.get_value("description"),\n
"title": field.get_value("title")\n "title": field.get_value("title")\n
}\n }\n
result["default"] = getFieldDefault(field, result["key"], value)\n result["default"] = getFieldDefault(traversed_document, field, result["key"], value)\n
elif meta_type == "GadgetField":\n elif meta_type == "GadgetField":\n
result = {\n result = {\n
"type": meta_type,\n "type": meta_type,\n
...@@ -298,7 +299,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -298,7 +299,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
"url": field.get_value("gadget_url"),\n "url": field.get_value("gadget_url"),\n
"sandbox": field.get_value("js_sandbox"),\n "sandbox": field.get_value("js_sandbox"),\n
}\n }\n
result["default"] = getFieldDefault(field, result["key"], value)\n result["default"] = getFieldDefault(traversed_document, field, result["key"], value)\n
elif meta_type == "ListBox":\n elif meta_type == "ListBox":\n
# XXX Not implemented\n # XXX Not implemented\n
column_list = field.get_value("columns")\n column_list = field.get_value("columns")\n
...@@ -398,7 +399,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None): ...@@ -398,7 +399,7 @@ def renderField(field, form_relative_url, value=None, meta_type=None, key=None):
return result\n return result\n
\n \n
\n \n
def renderForm(form, response_dict):\n def renderForm(traversed_document, form, response_dict):\n
REQUEST.set(\'here\', traversed_document)\n REQUEST.set(\'here\', traversed_document)\n
field_errors = REQUEST.get(\'field_errors\', {})\n field_errors = REQUEST.get(\'field_errors\', {})\n
\n \n
...@@ -451,7 +452,7 @@ def renderForm(form, response_dict):\n ...@@ -451,7 +452,7 @@ def renderForm(form, response_dict):\n
# field_list.append((field.id, renderRawField(field)))\n # field_list.append((field.id, renderRawField(field)))\n
if field.get_value("enabled"):\n if field.get_value("enabled"):\n
try:\n try:\n
response_dict[field.id] = renderField(field, form_relative_url)\n response_dict[field.id] = renderField(traversed_document, field, form_relative_url)\n
if field_errors.has_key(field.id):\n if field_errors.has_key(field.id):\n
response_dict[field.id]["error_text"] = field_errors[field.id].error_text\n response_dict[field.id]["error_text"] = field_errors[field.id].error_text\n
except AttributeError:\n except AttributeError:\n
...@@ -542,12 +543,6 @@ def renderFormDefinition(form, response_dict):\n ...@@ -542,12 +543,6 @@ def renderFormDefinition(form, response_dict):\n
response_dict["pt"] = form.pt\n response_dict["pt"] = form.pt\n
response_dict["action"] = form.action\n response_dict["action"] = form.action\n
\n \n
\n
\n
\n
\n
\n
context.Base_prepareCorsResponse(RESPONSE=response)\n
\n \n
mime_type = \'application/hal+json\'\n mime_type = \'application/hal+json\'\n
portal = context.getPortalObject()\n portal = context.getPortalObject()\n
...@@ -563,22 +558,38 @@ else:\n ...@@ -563,22 +558,38 @@ else:\n
site_root = portal\n site_root = portal\n
view_action_type = "object_view"\n view_action_type = "object_view"\n
\n \n
context.Base_prepareCorsResponse(RESPONSE=response)\n
\n
# Check if traversed_document is the site_root\n # Check if traversed_document is the site_root\n
if relative_url:\n if relative_url:\n
traversed_document = site_root.restrictedTraverse(relative_url, None)\n temp_traversed_document = site_root.restrictedTraverse(relative_url, None)\n
if (traversed_document is None):\n if (temp_traversed_document is None):\n
response.setStatus(404)\n response.setStatus(404)\n
return ""\n return ""\n
else:\n else:\n
traversed_document = context\n temp_traversed_document = context\n
is_site_root = (traversed_document.getPath() == site_root.getPath())\n temp_is_site_root = (temp_traversed_document.getPath() == site_root.getPath())\n
is_portal = (traversed_document.getPath() == portal.getPath())\n temp_is_portal = (temp_traversed_document.getPath() == portal.getPath())\n
\n \n
result_dict = {\n def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, REQUEST=None,\n
response=None, view=None, mode=None, query=None,\n
select_list=None, limit=None, form=None,\n
relative_url=None, restricted=None, list_method=None,\n
default_param_json=None, form_relative_url=None):\n
\n
if relative_url:\n
try:\n
traversed_document = site_root.restrictedTraverse(str(relative_url))\n
view = str(view)\n
is_site_root = False\n
except:\n
raise NotImplementedError(relative_url)\n
result_dict = {\n
\'_debug\': mode,\n \'_debug\': mode,\n
\'_links\': {\n \'_links\': {\n
"self": {\n "self": {\n
# XXX Include query parameters\n # XXX Include query parameters\n
# FIXME does not work in case of bulk queries\n
"href": traversed_document.Base_getRequestUrl()\n "href": traversed_document.Base_getRequestUrl()\n
},\n },\n
# Always inform about site root\n # Always inform about site root\n
...@@ -602,28 +613,29 @@ result_dict = {\n ...@@ -602,28 +613,29 @@ result_dict = {\n
"name": portal.getTitle(),\n "name": portal.getTitle(),\n
}\n }\n
}\n }\n
}\n }\n
\n \n
if (restricted == 1) and (portal.portal_membership.isAnonymousUser()):\n \n
if (restricted == 1) and (portal.portal_membership.isAnonymousUser()):\n
response.setStatus(401)\n response.setStatus(401)\n
\n \n
elif mime_type != traversed_document.Base_handleAcceptHeader([mime_type]):\n elif mime_type != traversed_document.Base_handleAcceptHeader([mime_type]):\n
response.setStatus(406)\n response.setStatus(406)\n
return ""\n return ""\n
\n \n
\n \n
elif (mode == \'root\') or (mode == \'traverse\'):\n elif (mode == \'root\') or (mode == \'traverse\'):\n
#################################################\n #################################################\n
# Raw document\n # Raw document\n
#################################################\n #################################################\n
if REQUEST.other[\'method\'] != "GET":\n if (REQUEST is not None) and (REQUEST.other[\'method\'] != "GET"):\n
response.setStatus(405)\n response.setStatus(405)\n
return ""\n return ""\n
# Default properties shared by all ERP5 Document and Site\n # Default properties shared by all ERP5 Document and Site\n
action_dict = {}\n action_dict = {}\n
# result_dict[\'_relative_url\'] = traversed_document.getRelativeUrl()\n # result_dict[\'_relative_url\'] = traversed_document.getRelativeUrl()\n
result_dict[\'title\'] = traversed_document.getTitle()\n result_dict[\'title\'] = traversed_document.getTitle()\n
\n \n
# Add a link to the portal type if possible\n # Add a link to the portal type if possible\n
if not is_portal:\n if not is_portal:\n
result_dict[\'_links\'][\'type\'] = {\n result_dict[\'_links\'][\'type\'] = {\n
...@@ -649,11 +661,11 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -649,11 +661,11 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
},\n },\n
"name": container.getTitle(),\n "name": container.getTitle(),\n
}\n }\n
\n \n
# XXX Loop on form rendering\n # XXX Loop on form rendering\n
erp5_action_dict = portal.Base_filterDuplicateActions(\n erp5_action_dict = portal.Base_filterDuplicateActions(\n
portal.portal_actions.listFilteredActionsFor(traversed_document))\n portal.portal_actions.listFilteredActionsFor(traversed_document))\n
\n \n
embedded_url = None\n embedded_url = None\n
# XXX See ERP5Type.getDefaultViewFor\n # XXX See ERP5Type.getDefaultViewFor\n
for erp5_action_key in erp5_action_dict.keys():\n for erp5_action_key in erp5_action_dict.keys():\n
...@@ -676,7 +688,7 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -676,7 +688,7 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
"relative_url": traversed_document.getRelativeUrl().replace("/", "%2F"),\n "relative_url": traversed_document.getRelativeUrl().replace("/", "%2F"),\n
"view": erp5_action_list[-1][\'name\']\n "view": erp5_action_list[-1][\'name\']\n
}\n }\n
\n \n
if erp5_action_list:\n if erp5_action_list:\n
if len(erp5_action_list) == 1:\n if len(erp5_action_list) == 1:\n
erp5_action_list = erp5_action_list[0]\n erp5_action_list = erp5_action_list[0]\n
...@@ -687,24 +699,24 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -687,24 +699,24 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
\n \n
# XXX Put a prefix to prevent conflict\n # XXX Put a prefix to prevent conflict\n
result_dict[\'_links\']["action_" + erp5_action_key] = erp5_action_list\n result_dict[\'_links\']["action_" + erp5_action_key] = erp5_action_list\n
\n \n
# for view_action in erp5_action_dict.get(\'object_view\', []):\n # for view_action in erp5_action_dict.get(\'object_view\', []):\n
# traversed_document.log(view_action)\n # traversed_document.log(view_action)\n
# # XXX Check the action condition\n # # XXX Check the action condition\n
# # if (view is None) or (view != view_action[\'name\']):\n # # if (view is None) or (view != view_action[\'name\']):\n
# object_view_list.append({\n # object_view_list.append({\n
# \'href\': \'%s\' % view_action[\'url\'],\n # \'href\': \'%s\' % view_action[\'url\'],\n
# \'name\': view_action[\'name\']\n # \'name\': view_action[\'name\']\n
# })\n # })\n
\n \n
\n \n
# if (renderer_form is not None):\n # if (renderer_form is not None):\n
# traversed_document_property_dict, renderer_form_json = traversed_document.Base_renderFormAsSomething(renderer_form)\n # traversed_document_property_dict, renderer_form_json = traversed_document.Base_renderFormAsSomething(renderer_form)\n
# result_dict[\'_embedded\'] = {\n # result_dict[\'_embedded\'] = {\n
# \'object_view\': renderer_form_json\n # \'object_view\': renderer_form_json\n
# }\n # }\n
# result_dict.update(traversed_document_property_dict)\n # result_dict.update(traversed_document_property_dict)\n
\n \n
# XXX XXX XXX XXX\n # XXX XXX XXX XXX\n
if (embedded_url is not None):\n if (embedded_url is not None):\n
# XXX Try to fetch the form in the traversed_document of the document\n # XXX Try to fetch the form in the traversed_document of the document\n
...@@ -715,7 +727,7 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -715,7 +727,7 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
# renderer_form = traversed_document.restrictedTraverse(form_id, None)\n # renderer_form = traversed_document.restrictedTraverse(form_id, None)\n
# XXX Proxy field are not correctly handled in traversed_document of web site\n # XXX Proxy field are not correctly handled in traversed_document of web site\n
renderer_form = getattr(traversed_document, form_id)\n renderer_form = getattr(traversed_document, form_id)\n
# traversed_document.log(form_id)\n # traversed_document.log(form_id)\n
if (renderer_form is not None):\n if (renderer_form is not None):\n
embedded_dict = {\n embedded_dict = {\n
\'_links\': {\n \'_links\': {\n
...@@ -730,24 +742,24 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -730,24 +742,24 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
for query_parameter in query_split[1].split("&"):\n for query_parameter in query_split[1].split("&"):\n
query_key, query_value = query_parameter.split("=")\n query_key, query_value = query_parameter.split("=")\n
REQUEST.set(query_key, query_value)\n REQUEST.set(query_key, query_value)\n
\n \n
renderForm(renderer_form, embedded_dict)\n renderForm(traversed_document, renderer_form, embedded_dict)\n
result_dict[\'_embedded\'] = {\n result_dict[\'_embedded\'] = {\n
\'_view\': embedded_dict\n \'_view\': embedded_dict\n
# embedded_action_key: embedded_dict\n # embedded_action_key: embedded_dict\n
}\n }\n
# result_dict[\'_links\']["_view"] = {"href": embedded_url}\n # result_dict[\'_links\']["_view"] = {"href": embedded_url}\n
\n \n
# Include properties in document JSON\n # Include properties in document JSON\n
# XXX Extract from renderer form?\n # XXX Extract from renderer form?\n
"""\n """\n
for group in renderer_form.Form_getGroupTitleAndId():\n for group in renderer_form.Form_getGroupTitleAndId():\n
for field in renderer_form.get_fields_in_group(group[\'goid\']):\n for field in renderer_form.get_fields_in_group(group[\'goid\']):\n
field_id = field.id\n field_id = field.id\n
# traversed_document.log(field_id)\n # traversed_document.log(field_id)\n
if field_id.startswith(\'my_\'):\n if field_id.startswith(\'my_\'):\n
property_name = field_id[len(\'my_\'):]\n property_name = field_id[len(\'my_\'):]\n
# traversed_document.log(property_name)\n # traversed_document.log(property_name)\n
property_value = traversed_document.getProperty(property_name, d=None)\n property_value = traversed_document.getProperty(property_name, d=None)\n
if (property_value is not None):\n if (property_value is not None):\n
if same_type(property_value, DateTime()):\n if same_type(property_value, DateTime()):\n
...@@ -755,27 +767,27 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -755,27 +767,27 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
property_value = property_value.rfc822()\n property_value = property_value.rfc822()\n
result_dict[property_name] = property_value \n result_dict[property_name] = property_value \n
"""\n """\n
\n \n
##############\n ##############\n
# XXX Custom slapos code\n # XXX Custom slapos code\n
##############\n ##############\n
if is_site_root:\n if is_site_root:\n
\n \n
result_dict[\'default_view\'] = \'view\'\n result_dict[\'default_view\'] = \'view\'\n
# XXX Hardcoded cache for 30 minutes. Should only bother developers but speed up Jio access\n # XXX Hardcoded cache for 30 minutes. Should only bother developers but speed up Jio access\n
response.setHeader("Cache-Control", "public, max-age=1800")\n response.setHeader("Cache-Control", "public, max-age=1800")\n
response.setHeader("Vary", "Cookie")\n response.setHeader("Vary", "Cookie")\n
response.setHeader("Last-Modified", DateTime().rfc822())\n response.setHeader("Last-Modified", DateTime().rfc822())\n
REQUEST.set("X-HATEOAS-CACHE", 1)\n REQUEST.set("X-HATEOAS-CACHE", 1)\n
\n \n
# Global action users for the jIO plugin\n # Global action users for the jIO plugin\n
# XXX Would be better to not hardcode them but put them as portal type\n # XXX Would be better to not hardcode them but put them as portal type\n
# "actions" (search could be on portal_catalog document, traverse on all\n # "actions" (search could be on portal_catalog document, traverse on all\n
# documents, newContent on all, etc)\n # documents, newContent on all, etc)\n
# result_dict[\'_links\'][\'object_search\'] = {\n # result_dict[\'_links\'][\'object_search\'] = {\n
# \'href\': \'%s/ERP5Site_viewSearchForm?portal_skin=Hal\' % absolute_url,\n # \'href\': \'%s/ERP5Site_viewSearchForm?portal_skin=Hal\' % absolute_url,\n
# \'name\': \'Global Search\'\n # \'name\': \'Global Search\'\n
# }\n # }\n
result_dict[\'_links\'][\'raw_search\'] = {\n result_dict[\'_links\'][\'raw_search\'] = {\n
"href": url_template_dict["search_template"] % {\n "href": url_template_dict["search_template"] % {\n
"root_url": site_root.absolute_url(),\n "root_url": site_root.absolute_url(),\n
...@@ -800,7 +812,15 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -800,7 +812,15 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
\'method\': \'POST\',\n \'method\': \'POST\',\n
\'name\': \'New Content\',\n \'name\': \'New Content\',\n
}\n }\n
\n action_dict[\'bulk\'] = {\n
"href": url_template_dict["bulk_action"] % {\n
"root_url": site_root.absolute_url(),\n
"script_id": script.id\n
},\n
\'method\': \'POST\',\n
\'name\': \'Bulk\'\n
}\n
\n
# Handle also other kind of users: instance, computer, master\n # Handle also other kind of users: instance, computer, master\n
person = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n person = portal.ERP5Site_getAuthenticatedMemberPersonValue()\n
if person is not None:\n if person is not None:\n
...@@ -810,60 +830,60 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n ...@@ -810,60 +830,60 @@ elif (mode == \'root\') or (mode == \'traverse\'):\n
"relative_url": person.getRelativeUrl(), \n "relative_url": person.getRelativeUrl(), \n
"script_id": script.id\n "script_id": script.id\n
},\n },\n
# \'_relative_url\': person.getRelativeUrl()\n # \'_relative_url\': person.getRelativeUrl()\n
}\n }\n
\n \n
else:\n else:\n
traversed_document_portal_type = traversed_document.getPortalType()\n traversed_document_portal_type = traversed_document.getPortalType()\n
if traversed_document_portal_type == "ERP5 Form":\n if traversed_document_portal_type == "ERP5 Form":\n
renderFormDefinition(traversed_document, result_dict)\n renderFormDefinition(traversed_document, result_dict)\n
REQUEST.set("X-HATEOAS-CACHE", 1)\n REQUEST.set("X-HATEOAS-CACHE", 1)\n
\n \n
# Define document action\n # Define document action\n
if action_dict:\n if action_dict:\n
result_dict[\'_actions\'] = action_dict\n result_dict[\'_actions\'] = action_dict\n
\n \n
\n \n
elif mode == \'search\':\n elif mode == \'search\':\n
#################################################\n #################################################\n
# Portal catalog search\n # Portal catalog search\n
#################################################\n #################################################\n
if REQUEST.other[\'method\'] != "GET":\n if REQUEST.other[\'method\'] != "GET":\n
response.setStatus(405)\n response.setStatus(405)\n
return ""\n return ""\n
\n \n
if query == "__root__":\n if query == "__root__":\n
# XXX Hardcoded behaviour to get root object with jIO\n # XXX Hardcoded behaviour to get root object with jIO\n
sql_list = [site_root]\n sql_list = [site_root]\n
\n \n
elif query == "__portal__":\n elif query == "__portal__":\n
# XXX Hardcoded behaviour to get portal object with jIO\n # XXX Hardcoded behaviour to get portal object with jIO\n
sql_list = [portal]\n sql_list = [portal]\n
\n \n
# document = site_root\n # document = site_root\n
# document_result = {\n # document_result = {\n
# # \'_relative_url\': site_root.getRelativeUrl(),\n # # \'_relative_url\': site_root.getRelativeUrl(),\n
# \'_links\': {\n # \'_links\': {\n
# \'self\': {\n # \'self\': {\n
# "href": default_document_uri_template % {\n # "href": default_document_uri_template % {\n
# "root_url": site_root.absolute_url(),\n # "root_url": site_root.absolute_url(),\n
# "relative_url": document.getRelativeUrl(), \n # "relative_url": document.getRelativeUrl(), \n
# "script_id": script.id\n # "script_id": script.id\n
# },\n # },\n
# },\n # },\n
# }\n # }\n
# }\n # }\n
# for select in select_list:\n # for select in select_list:\n
# document_result[select] = document.getProperty(select, d=None)\n # document_result[select] = document.getProperty(select, d=None)\n
# result_dict[\'_embedded\'] = {"contents": [document_result]}\n # result_dict[\'_embedded\'] = {"contents": [document_result]}\n
else:\n else:\n
# raise NotImplementedError("Unsupported query: %s" % query)\n # raise NotImplementedError("Unsupported query: %s" % query)\n
\n \n
\n \n
# # XXX\n # # XXX\n
# length = len(\'/%s/\' % portal.getId())\n # length = len(\'/%s/\' % portal.getId())\n
# # context.log(portal.portal_catalog(full_text=query, limit=limit, src__=1))\n # # context.log(portal.portal_catalog(full_text=query, limit=limit, src__=1))\n
# context.log(query)\n # context.log(query)\n
catalog_kw = {}\n catalog_kw = {}\n
if (default_param_json is not None):\n if (default_param_json is not None):\n
catalog_kw = json.loads(urlsafe_b64decode(default_param_json))\n catalog_kw = json.loads(urlsafe_b64decode(default_param_json))\n
...@@ -875,31 +895,31 @@ elif mode == \'search\':\n ...@@ -875,31 +895,31 @@ elif mode == \'search\':\n
sql_list = callable_list_method(full_text=query, limit=limit, **catalog_kw)\n sql_list = callable_list_method(full_text=query, limit=limit, **catalog_kw)\n
else:\n else:\n
sql_list = callable_list_method(limit=limit, **catalog_kw)\n sql_list = callable_list_method(limit=limit, **catalog_kw)\n
\n \n
result_list = []\n result_list = []\n
\n \n
# if (select_list is None):\n # if (select_list is None):\n
# # Only include links\n # # Only include links\n
# for sql_document in sql_list:\n # for sql_document in sql_list:\n
# document = sql_document.getObject()\n # document = sql_document.getObject()\n
# result_list.append({\n # result_list.append({\n
# "href": default_document_uri_template % {\n # "href": default_document_uri_template % {\n
# "root_url": site_root.absolute_url(),\n # "root_url": site_root.absolute_url(),\n
# "relative_url": document.getRelativeUrl(), \n # "relative_url": document.getRelativeUrl(), \n
# "script_id": script.id\n # "script_id": script.id\n
# },\n # },\n
# })\n # })\n
# result_dict[\'_links\'][\'contents\'] = result_list\n # result_dict[\'_links\'][\'contents\'] = result_list\n
# \n # \n
# else:\n # else:\n
\n \n
# Cast to list if only one element is provided\n # Cast to list if only one element is provided\n
editable_field_dict = {}\n editable_field_dict = {}\n
if select_list is None:\n if select_list is None:\n
select_list = []\n select_list = []\n
elif same_type(select_list, ""):\n elif same_type(select_list, ""):\n
select_list = [select_list]\n select_list = [select_list]\n
\n \n
if select_list:\n if select_list:\n
if (form_relative_url is not None):\n if (form_relative_url is not None):\n
listbox_field = portal.restrictedTraverse(form_relative_url)\n listbox_field = portal.restrictedTraverse(form_relative_url)\n
...@@ -910,7 +930,7 @@ elif mode == \'search\':\n ...@@ -910,7 +930,7 @@ elif mode == \'search\':\n
# See Listbox.py getEditableField method\n # See Listbox.py getEditableField method\n
if listbox_form.has_field("%s_%s" % (listbox_field_id, select), include_disabled=1):\n if listbox_form.has_field("%s_%s" % (listbox_field_id, select), include_disabled=1):\n
editable_field_dict[select] = listbox_form.get_field("%s_%s" % (listbox_field_id, select), include_disabled=1)\n editable_field_dict[select] = listbox_form.get_field("%s_%s" % (listbox_field_id, select), include_disabled=1)\n
\n \n
for sql_document in sql_list:\n for sql_document in sql_list:\n
try:\n try:\n
document = sql_document.getObject()\n document = sql_document.getObject()\n
...@@ -919,7 +939,7 @@ elif mode == \'search\':\n ...@@ -919,7 +939,7 @@ elif mode == \'search\':\n
document = sql_document\n document = sql_document\n
document_uid = document.getUid()\n document_uid = document.getUid()\n
document_result = {\n document_result = {\n
# \'_relative_url\': sql_document.path[length:],\n # \'_relative_url\': sql_document.path[length:],\n
\'_links\': {\n \'_links\': {\n
\'self\': {\n \'self\': {\n
"href": default_document_uri_template % {\n "href": default_document_uri_template % {\n
...@@ -939,13 +959,13 @@ elif mode == \'search\':\n ...@@ -939,13 +959,13 @@ elif mode == \'search\':\n
for select in select_list:\n for select in select_list:\n
if editable_field_dict.has_key(select):\n if editable_field_dict.has_key(select):\n
REQUEST.set(\'cell\', document)\n REQUEST.set(\'cell\', document)\n
\n \n
if (\'default\' in editable_field_dict[select].tales):\n if (\'default\' in editable_field_dict[select].tales):\n
tmp_value = None\n tmp_value = None\n
else:\n else:\n
tmp_value = document.getProperty(select, d=None)\n tmp_value = document.getProperty(select, d=None)\n
\n \n
property_value = renderField(editable_field_dict[select], form_relative_url,\n property_value = renderField(traversed_document, editable_field_dict[select], form_relative_url,\n
tmp_value,\n tmp_value,\n
key=\'field_%s_%s\' % (editable_field_dict[select].id,\n key=\'field_%s_%s\' % (editable_field_dict[select].id,\n
document_uid))\n document_uid))\n
...@@ -959,22 +979,22 @@ elif mode == \'search\':\n ...@@ -959,22 +979,22 @@ elif mode == \'search\':\n
document_result[select] = property_value\n document_result[select] = property_value\n
result_list.append(document_result)\n result_list.append(document_result)\n
result_dict[\'_embedded\'] = {"contents": result_list}\n result_dict[\'_embedded\'] = {"contents": result_list}\n
\n \n
result_dict[\'_query\'] = query\n result_dict[\'_query\'] = query\n
result_dict[\'_limit\'] = limit\n result_dict[\'_limit\'] = limit\n
result_dict[\'_select_list\'] = select_list\n result_dict[\'_select_list\'] = select_list\n
\n \n
elif mode == \'form\':\n elif mode == \'form\':\n
#################################################\n #################################################\n
# Calculate form value\n # Calculate form value\n
#################################################\n #################################################\n
if REQUEST.other[\'method\'] != "POST":\n if REQUEST.other[\'method\'] != "POST":\n
response.setStatus(405)\n response.setStatus(405)\n
return ""\n return ""\n
\n \n
renderForm(form, result_dict)\n renderForm(traversed_document, form, result_dict)\n
\n \n
elif mode == \'newContent\':\n elif mode == \'newContent\':\n
#################################################\n #################################################\n
# Create new document\n # Create new document\n
#################################################\n #################################################\n
...@@ -998,19 +1018,40 @@ elif mode == \'newContent\':\n ...@@ -998,19 +1018,40 @@ elif mode == \'newContent\':\n
"script_id": script.id\n "script_id": script.id\n
})\n })\n
return \'\'\n return \'\'\n
\n \n
else:\n elif mode == \'bulk\':\n
#################################################\n
# Return multiple documents in one request\n
#################################################\n
if REQUEST.other[\'method\'] != "POST":\n
response.setStatus(405)\n
return ""\n
result_dict["result_list"] = [calculateHateoas(mode="traverse", **x) for x in json.loads(bulk_list)]\n
\n
else:\n
raise NotImplementedError("Unsupported mode %s" % mode)\n raise NotImplementedError("Unsupported mode %s" % mode)\n
\n
return result_dict\n
\n \n
response.setHeader(\'Content-Type\', mime_type)\n response.setHeader(\'Content-Type\', mime_type)\n
return json.dumps(result_dict, indent=2)\n hateoas = calculateHateoas(is_portal=temp_is_portal, is_site_root=temp_is_site_root,\n
traversed_document=temp_traversed_document,\n
REQUEST=REQUEST, response=response, view=view, mode=mode,\n
query=query, select_list=select_list, limit=limit, form=form,\n
restricted=restricted, list_method=list_method,\n
default_param_json=default_param_json,\n
form_relative_url=form_relative_url)\n
if hateoas == "":\n
return hateoas\n
else:\n
return json.dumps(hateoas, indent=2)\n
]]></string> </value> ]]></string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, form=None, relative_url=None, restricted=0, list_method=None, default_param_json=None, form_relative_url=None</string> </value> <value> <string>REQUEST=None, response=None, view=None, mode=\'root\', query=None, select_list=None, limit=10, form=None, relative_url=None, restricted=0, list_method=None, default_param_json=None, form_relative_url=None, bulk_list="[]"</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -689,3 +689,113 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin): ...@@ -689,3 +689,113 @@ class TestERP5Document_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
self.assertEqual(result_dict['_select_list'], []) self.assertEqual(result_dict['_select_list'], [])
self.assertEqual(len(result_dict['_embedded']['contents']), 0) self.assertEqual(len(result_dict['_embedded']['contents']), 0)
class TestERP5Document_getHateoas_mode_bulk(ERP5HALJSONStyleSkinsMixin):
@simulate('Base_getRequestHeader', '*args, **kwargs',
'return "application/hal+json"')
@changeSkin('Hal')
def test_getHateoasBulk_bad_method(self):
fake_request = do_fake_request("GET")
result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(REQUEST=fake_request, mode="bulk")
self.assertEquals(fake_request.RESPONSE.status, 405)
self.assertEquals(result, "")
@simulate('Base_getRequestUrl', '*args, **kwargs',
'return "http://example.org/bar"')
@simulate('Base_getRequestHeader', '*args, **kwargs',
'return "application/hal+json"')
@changeSkin('Hal')
def test_getHateoasBulk_default_view(self):
document = self._makeDocument()
parent = document.getParentValue()
fake_request = do_fake_request("POST")
result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(
REQUEST=fake_request,
mode="bulk",
bulk_list=json.dumps([{"relative_url": document.getRelativeUrl(), "view": "view"}])
)
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['_links']['self'], {"href": "http://example.org/bar"})
self.assertEqual(len(result_dict['result_list']), 1)
self.assertEqual(result_dict['result_list'][0]['_links']['self'], {"href": "http://example.org/bar"})
self.assertEqual(result_dict['result_list'][0]['_links']['parent'],
{"href": "urn:jio:get:%s" % parent.getRelativeUrl(), "name": parent.getTitle()})
self.assertEqual(result_dict['result_list'][0]['_links']['view'][0]['href'],
"%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=traverse&relative_url=%s&view=view" % (
self.portal.absolute_url(),
urllib.quote_plus(document.getRelativeUrl())))
self.assertEqual(result_dict['result_list'][0]['_links']['view'][0]['title'], "View")
self.assertEqual(result_dict['result_list'][0]['_links']['view'][0]['name'], "view")
self.assertEqual(result_dict['result_list'][0]['_links']['action_object_view'][0]['href'],
"%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=traverse&relative_url=%s&view=view" % (
self.portal.absolute_url(),
urllib.quote_plus(document.getRelativeUrl())))
self.assertEqual(result_dict['result_list'][0]['_links']['action_object_view'][0]['title'], "View")
self.assertEqual(result_dict['result_list'][0]['_links']['action_object_view'][0]['name'], "view")
self.assertEqual(result_dict['result_list'][0]['_links']['action_workflow'][0]['href'],
"%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=traverse&relative_url=%s&view=custom_action_no_dialog" % (
self.portal.absolute_url(),
urllib.quote_plus(document.getRelativeUrl())))
self.assertEqual(result_dict['result_list'][0]['_links']['action_workflow'][0]['title'], "Custom Action No Dialog")
self.assertEqual(result_dict['result_list'][0]['_links']['action_workflow'][0]['name'], "custom_action_no_dialog")
self.assertEqual(result_dict['result_list'][0]['_links']['portal']['href'], 'urn:jio:get:%s' % document.getPortalObject().getId())
self.assertEqual(result_dict['result_list'][0]['_links']['portal']['name'], document.getPortalObject().getTitle())
self.assertEqual(result_dict['result_list'][0]['_links']['site_root']['href'], 'urn:jio:get:web_site_module/hateoas')
self.assertEqual(result_dict['result_list'][0]['_links']['site_root']['name'], self.portal.web_site_module.hateoas.getTitle())
self.assertEqual(result_dict['result_list'][0]['_links']['action_object_new_content_action']['href'],
"%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=traverse&relative_url=%s&view=create_a_document" % (
self.portal.absolute_url(),
urllib.quote_plus(document.getRelativeUrl())))
self.assertEqual(result_dict['result_list'][0]['_links']['action_object_new_content_action']['title'], "Create a Document")
self.assertEqual(result_dict['result_list'][0]['_links']['action_object_new_content_action']['name'], "create_a_document")
self.assertEqual(result_dict['result_list'][0]['_links']['type']['href'], 'urn:jio:get:portal_types/%s' % document.getPortalType())
self.assertEqual(result_dict['result_list'][0]['_links']['type']['name'], document.getPortalType())
self.assertEqual(result_dict['result_list'][0]['title'].encode("UTF-8"), document.getTitle())
self.assertEqual(result_dict['result_list'][0]['_debug'], "traverse")
# Check embedded form rendering
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['form_id']['default'], 'Foo_view')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['form_id']['editable'], 0)
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['form_id']['hidden'], 1)
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['form_id']['key'], 'form_id')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['form_id']['required'], 1)
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['form_id']['type'], 'StringField')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_id']['default'], document.getId())
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_id']['editable'], 1)
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_id']['hidden'], 0)
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_id']['key'], 'field_my_id')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_id']['required'], 1)
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_id']['type'], 'StringField')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['my_id']['title'], 'ID')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_links']['traversed_document']['href'], 'urn:jio:get:%s' % document.getRelativeUrl())
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_links']['traversed_document']['name'], document.getRelativeUrl())
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_links']['traversed_document']['title'], document.getTitle().decode("UTF-8"))
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_links']['self']['href'], "%s/%s/Foo_view" % (
self.portal.absolute_url(),
document.getRelativeUrl()))
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_links']['form_definition']['href'], 'urn:jio:get:portal_skins/erp5_ui_test/Foo_view')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_links']['form_definition']['name'], 'Foo_view')
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_actions']['put']['href'], '%s/web_site_module/hateoas/%s/Base_edit' % (
self.portal.absolute_url(),
document.getRelativeUrl()))
self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_actions']['put']['method'], 'POST')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment