From 0f562b3e6e07889715021b941122c12f70030ec0 Mon Sep 17 00:00:00 2001 From: Romain Courteaud <romain@nexedi.com> Date: Tue, 24 Nov 2015 14:37:30 +0000 Subject: [PATCH] [erp5_hal_json_style] Add a new worklist mode. This allow to provide worklist information to a javascript application. allDocs query parameter are provided to get list of document to work on. --- .../extension.erp5.HalStyle.py | 30 +++++++- .../ERP5Document_getHateoas.xml | 47 +++++++++++++ .../WorkflowTool_listActionParameterList.xml | 28 ++++++++ .../test.erp5.testHalJsonStyle.py | 70 +++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/WorkflowTool_listActionParameterList.xml diff --git a/bt5/erp5_hal_json_style/ExtensionTemplateItem/portal_components/extension.erp5.HalStyle.py b/bt5/erp5_hal_json_style/ExtensionTemplateItem/portal_components/extension.erp5.HalStyle.py index a2a67c564c..2f6e3af06f 100644 --- a/bt5/erp5_hal_json_style/ExtensionTemplateItem/portal_components/extension.erp5.HalStyle.py +++ b/bt5/erp5_hal_json_style/ExtensionTemplateItem/portal_components/extension.erp5.HalStyle.py @@ -8,9 +8,33 @@ def Listbox_getListMethodName(self, field): return list_method_name -def Field_getSubFieldKeyDict(self, field, id, key=None): +def Field_getSubFieldKeyDict(self, field, field_id, key=None): """XXX""" - return field.generate_subfield_key(id, key=key) + return field.generate_subfield_key(field_id, key=key) def Field_getDefaultValue(self, field, key, value, REQUEST): - return field._get_default(key, value, REQUEST) \ No newline at end of file + return field._get_default(key, value, REQUEST) + +def WorkflowTool_listActionParameterList(self): + action_list = self.listActions() + info = self._getOAI(None) + + workflow_dict = {} + result_list = [] + + for action in action_list: + if (action['workflow_id'] not in workflow_dict): + workflow = self.getWorkflowById(action['workflow_id']) + workflow_dict[action['workflow_id']] = workflow.getWorklistVariableMatchDict(info, check_guard=False) + + query = workflow_dict[action['workflow_id']][action['worklist_id']] + query.pop('metadata') + result_list.append({ + 'count': action['count'], + 'name': action['name'], + 'local_roles': query.pop('local_roles'), + 'query': query + }) + + + return result_list 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 513b8bc2fa..037c59357d 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 @@ -76,6 +76,7 @@ url_template_dict = {\n "{&relative_url,view}",\n "search_template": "%(root_url)s/%(script_id)s?mode=search" + \\\n "{&query,select_list*,limit*,sort_on*,local_roles*}",\n + "worklist_template": "%(root_url)s/%(script_id)s?mode=worklist",\n "custom_search_template": "%(root_url)s/%(script_id)s?mode=search" + \\\n "&relative_url=%(relative_url)s" \\\n "&form_relative_url=%(form_relative_url)s" \\\n @@ -866,6 +867,13 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, if traversed_document_portal_type == "ERP5 Form":\n renderFormDefinition(traversed_document, result_dict)\n REQUEST.set("X-HATEOAS-CACHE", 1)\n + elif relative_url == \'portal_workflow\':\n + result_dict[\'_links\'][\'action_worklist\'] = {\n + "href": url_template_dict[\'worklist_template\'] % {\n + "root_url": site_root.absolute_url(),\n + "script_id": script.id\n + }\n + }\n \n # Define document action\n if action_dict:\n @@ -1064,6 +1072,44 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, return ""\n result_dict["result_list"] = [calculateHateoas(mode="traverse", **x) for x in json.loads(bulk_list)]\n \n + elif mode == \'worklist\':\n + #################################################\n + # Return all worklist jio urls\n + #################################################\n + if REQUEST.other[\'method\'] != "GET":\n + response.setStatus(405)\n + return ""\n + action_list = portal.portal_workflow.WorkflowTool_listActionParameterList()\n + work_list = []\n + for action in action_list:\n + query = sql_catalog.buildQuery(action[\'query\'])\\\n + .asSearchTextExpression(sql_catalog)\n +\n + if (action[\'local_roles\']):\n + # Hack to consider local_roles as a valid catalog parameter\n + role_query = sql_catalog.buildQuery({\'simulation_state\': action[\'local_roles\']})\\\n + .asSearchTextExpression(sql_catalog)\n +\n + query += \' AND %s\' % role_query.replace(\'simulation_state\', \'local_roles\')\n +\n + portal_type = action[\'query\'].get(\'portal_type\', None)\n + if (portal_type):\n + if not same_type(portal_type, \'\'):\n + portal_type = portal_type[0]\n +\n + work_list.append({\n + \'href\': url_template_dict["jio_search_template"] % {\n + "query": make_query({"query": query})\n + },\n + \'name\': action[\'name\'],\n + \'count\': action[\'count\'],\n + \'module\': default_document_uri_template % {\n + "relative_url": portal.getDefaultModuleId(portal_type)\n + }\n + })\n +\n + result_dict["worklist"] = work_list\n +\n else:\n raise NotImplementedError("Unsupported mode %s" % mode)\n \n @@ -1072,6 +1118,7 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None, response.setHeader(\'Content-Type\', mime_type)\n hateoas = calculateHateoas(is_portal=temp_is_portal, is_site_root=temp_is_site_root,\n traversed_document=temp_traversed_document,\n + relative_url=relative_url,\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 diff --git a/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/WorkflowTool_listActionParameterList.xml b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/WorkflowTool_listActionParameterList.xml new file mode 100644 index 0000000000..fde1e66c24 --- /dev/null +++ b/bt5/erp5_hal_json_style/SkinTemplateItem/portal_skins/erp5_hal_json_style/WorkflowTool_listActionParameterList.xml @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_function</string> </key> + <value> <string>WorkflowTool_listActionParameterList</string> </value> + </item> + <item> + <key> <string>_module</string> </key> + <value> <string>HalStyle</string> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>WorkflowTool_listActionParameterList</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> 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 442317ade4..8155f0398d 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 @@ -47,6 +47,16 @@ def simulate(script_id, params_string, code_string): return decorated return upperWrap +def createIndexedDocument(): + def decorator(func): + def wrapped(self, *args, **kwargs): + self._makeDocument() + self.portal.portal_caches.clearAllCache() + self.tic() + return func(self, *args, **kwargs) + return wrapped + return decorator + def do_fake_request(request_method, headers=None): __version__ = "0.1" if (headers is None): @@ -436,6 +446,24 @@ class TestERP5Document_getHateoas_mode_traverse(ERP5HALJSONStyleSkinsMixin): self.assertEqual(result_dict['title'].encode("UTF-8"), document.getTitle()) self.assertEqual(result_dict['_debug'], "traverse") + @simulate('Base_getRequestUrl', '*args, **kwargs', + 'return "http://example.org/bar"') + @simulate('Base_getRequestHeader', '*args, **kwargs', + 'return "application/hal+json"') + @changeSkin('Hal') + def test_getHateoasDocument_portal_workflow(self): + fake_request = do_fake_request("GET") + result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(REQUEST=fake_request, mode="traverse", relative_url='portal_workflow') + 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(result_dict['_links']['action_worklist']['href'], + "%s/web_site_module/hateoas/ERP5Document_getHateoas?mode=worklist" % self.portal.absolute_url()) + @simulate('Base_getRequestUrl', '*args, **kwargs', 'return "http://example.org/bar"') @simulate('Base_getRequestHeader', '*args, **kwargs', @@ -825,3 +853,45 @@ class TestERP5Document_getHateoas_mode_bulk(ERP5HALJSONStyleSkinsMixin): self.portal.absolute_url(), document.getRelativeUrl())) self.assertEqual(result_dict['result_list'][0]['_embedded']['_view']['_actions']['put']['method'], 'POST') + +class TestERP5Document_getHateoas_mode_worklist(ERP5HALJSONStyleSkinsMixin): + + @simulate('Base_getRequestHeader', '*args, **kwargs', + 'return "application/hal+json"') + @changeSkin('Hal') + def test_getHateoasWorklist_bad_method(self): + fake_request = do_fake_request("POST") + result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(REQUEST=fake_request, mode="worklist") + 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"') + @createIndexedDocument() + @changeSkin('Hal') + def test_getHateoasWorklist_default_view(self): + # self._makeDocument() + fake_request = do_fake_request("GET") + result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas( + REQUEST=fake_request, + mode="worklist" + ) + 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"}) + + work_list = [x for x in result_dict['worklist'] if x['name'].startswith('Draft To Validate (')] + self.assertEqual(len(work_list), 1) + self.assertTrue(work_list[0]['count'] > 0) + self.assertEqual(work_list[0]['name'], 'Draft To Validate (%i)' % work_list[0]['count']) + self.assertEqual(work_list[0]['module'], 'urn:jio:get:bar_module') + self.assertEqual(work_list[0]['href'], 'urn:jio:allDocs?query=portal_type%3A%28%22Bar%22%20OR%20%22Foo%22%29%20AND%20simulation_state%3A%22draft%22') + + self.assertEqual(result_dict['_debug'], "worklist") + -- 2.30.9