From 711c04bb6ccc9cae6375357186620d614b320e2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Fri, 5 Jun 2020 17:57:12 +0900
Subject: [PATCH] hal_json_style: support disabling URL columns with None

This is something we can do in TALES, it was supported in the old UI, so
we keep compatibility in HAL JSON API.
---
 .../ERP5Document_getHateoas.py                | 36 +++++++++----------
 .../test.erp5.testHalJsonStyle.py             | 35 ++++++++++++++++++
 2 files changed, 53 insertions(+), 18 deletions(-)

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 6cf6800e51..03fe8307d1 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
@@ -1978,25 +1978,25 @@ def calculateHateoas(is_portal=None, is_site_root=None, traversed_document=None,
           url_parameter_dict = None
           if select in url_column_dict:
             # Check if we get URL parameters using listbox field `url_columns`
-            try:
-              # XXX call on aq_base?
-              url_column_method = getattr(brain, url_column_dict[select])
-              # Result of `url_column_method` must be a dictionary in the format
-              # {'command': <command_name, ex: 'raw', 'push_history'>,
-              #  'options': {'url': <Absolute URL>, 'jio_key': <Relative URL of object>, 'view': <id of the view>}}
-              url_parameter_dict = url_column_method(url_dict=True,
-                                                     brain=brain,
-                                                     selection=catalog_kw['selection'],
-                                                     selection_name=catalog_kw['selection_name'],
-                                                     column_id=select)
-            except AttributeError:
-              # In case the URL method is invalid or empty, we expect to have no link
-              # for the column to maintain compatibility with old UI, hence we create
-              # an empty url_parameter_dict for these cases.
-              url_parameter_dict = {}
-              if url_column_dict[select]:
+            url_parameter_dict = {}
+            url_column_method_id = url_column_dict[select]
+            if url_column_method_id:
+              try:
+                url_column_method = getattr(brain, url_column_method_id)
+              except AttributeError:
+                # In case the URL method is invalid or empty, we expect to have no link
+                # for the column to maintain compatibility with old UI, hence we create
+                # an empty url_parameter_dict for these cases.
                 log("Invalid URL method {!s} on column {}".format(url_column_dict[select], select), level=800)
-
+              else:
+                # Result of `url_column_method` must be a dictionary in the format
+                # {'command': <command_name, ex: 'raw', 'push_history'>,
+                #  'options': {'url': <Absolute URL>, 'jio_key': <Relative URL of object>, 'view': <id of the view>}}
+                url_parameter_dict = url_column_method(url_dict=True,
+                                                      brain=brain,
+                                                      selection=catalog_kw['selection'],
+                                                      selection_name=catalog_kw['selection_name'],
+                                                      column_id=select)
           else:
             if not is_getListItemUrlDict_calculated:
               # XXX If only available on brains, maybe better to call on aq_self
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 0bb3f3928d..4ac0a392f7 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
@@ -1839,6 +1839,41 @@ return url
     self.portal.foo_module.FooModule_viewFooList.listbox.ListBox_setPropertyList(
       field_url_columns = '')
 
+  @simulate('Base_getRequestUrl', '*args, **kwargs',
+      'return "http://example.org/bar"')
+  @simulate('Base_getRequestHeader', '*args, **kwargs',
+            'return "application/hal+json"')
+  @changeSkin('Hal')
+  def test_getHateoasDocument_listbox_check_url_column_no_url_None(self):
+    # variation of test_getHateoasDocument_listbox_check_url_column_no_url here the
+    # "no url" is done by setting `None` in TALES expression, instead of '' that get
+    # set by formulator `key | value` syntax.
+    self._makeDocument()
+    self.portal.foo_module.FooModule_viewFooList.listbox.manage_tales_xmlrpc(
+        dict(url_columns='python: [("title", None), ]'))
+
+    fake_request = do_fake_request("GET")
+    result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(
+                  REQUEST=fake_request,
+                  mode="search",
+                  list_method='contentValues',
+                  relative_url='foo_module',
+                  select_list=['id', 'title', 'creation_date', 'modification_date'],
+                  form_relative_url='portal_skins/erp5_ui_test/FooModule_viewFooList/listbox')
+    result_dict = json.loads(result)
+
+    # Test the listbox_uid parameter
+    self.assertEqual(result_dict['_embedded']['contents'][0]['listbox_uid:list']['key'], 'listbox_uid:list')
+
+    # Test the URL value
+    self.assertEqual(result_dict['_embedded']['contents'][0]['title']['url_value'], {})
+
+    # Test if the value of the column is with right key
+    self.assertTrue(result_dict['_embedded']['contents'][0]['title']['default'])
+
+    # Reset the url_columns of the listbox
+    self.portal.foo_module.FooModule_viewFooList.listbox.manage_tales_xmlrpc(dict(url_columns=''))
+
   @simulate('Base_getRequestUrl', '*args, **kwargs',
       'return "http://example.org/bar"')
   @simulate('Base_getRequestHeader', '*args, **kwargs',
-- 
2.30.9