From b702b2ed1bc323b6aadd4dbdde61e36f12d0502a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 5 May 2022 11:02:00 +0200
Subject: [PATCH] listing: fix internal-id dynamic filter with lazy objects
 (#64768)

---
 tests/form_pages/test_live.py | 35 +++++++++++++++++++++++++++++++++--
 wcs/backoffice/management.py  |  6 ++++--
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/tests/form_pages/test_live.py b/tests/form_pages/test_live.py
index f8f94d92b..867f0573c 100644
--- a/tests/form_pages/test_live.py
+++ b/tests/form_pages/test_live.py
@@ -1605,6 +1605,26 @@ def test_dynamic_internal_id_from_custom_view_on_cards(pub):
         'for custom view "as-datasource", CardDef "items", field "internal-id", operator "eq"'
     )
 
+    formdef.fields[0].value_template = '{{ cards|objects:"items"|filter_by:"bool"|filter_value:True }}'
+    formdef.store()
+    pub.loggederror_class.wipe()
+    with pytest.raises(Exception):
+        """
+        File "/home/lguerin/src/wcs/wcs/sql.py", line 3225, in store
+            'session_data': bytearray(pickle.dumps(self.__dict__, protocol=2)),
+        _pickle.PicklingError: Can't pickle <class 'wcs.carddef._wcs_Items'>: it's not the same object as wcs.carddef._wcs_Items
+        """
+        resp = get_app(pub).get('/test/')  # XXX pickle error in session
+    assert resp.form['f1'].options == [('', False, '---')]
+    assert pub.loggederror_class.count() == 1
+    logged_error = pub.loggederror_class.select()[0]
+    assert logged_error.formdef_id == formdef.id
+    assert logged_error.summary.startswith('Invalid value "[')
+    assert logged_error.summary.endswith(
+        'for custom view "as-datasource", CardDef "items", field "internal-id", operator "eq"'
+    )
+    assert '<wcs.variables.LazyFormData object at ' in logged_error.summary
+
     # empty list
     formdef.fields[
         0
@@ -1612,8 +1632,6 @@ def test_dynamic_internal_id_from_custom_view_on_cards(pub):
         '{{ cards|objects:"items"|filter_by:"attr"|filter_value:"unknown"|getlist:"form_internal_id"|list }}'
     )
     formdef.store()
-    custom_view.filters['filter-internal-id-operator'] = 'eq'
-    custom_view.store()
     resp = get_app(pub).get('/test/')
     assert resp.form['f1'].options == [('', False, '---')]
     custom_view.filters['filter-internal-id-operator'] = 'ne'
@@ -1628,6 +1646,19 @@ def test_dynamic_internal_id_from_custom_view_on_cards(pub):
     formdef.store()
     resp = get_app(pub).get('/test/')
     assert {int(x[0]) for x in resp.form['f1'].options} == {1, 3, 5, 7, 9}
+    formdef.fields[
+        0
+    ].value_template = '{{ cards|objects:"items"|filter_by:"bool"|filter_value:True|getlist:"attr2" }}'
+    formdef.store()
+    pub.loggederror_class.wipe()
+    with pytest.raises(Exception):
+        """
+        File "/home/lguerin/src/wcs/wcs/sql.py", line 3225, in store
+            'session_data': bytearray(pickle.dumps(self.__dict__, protocol=2)),
+        _pickle.PicklingError: Can't pickle <class 'wcs.carddef._wcs_Items'>: it's not the same object as wcs.carddef._wcs_Items
+        """
+        resp = get_app(pub).get('/test/')
+    assert {int(x[0]) for x in resp.form['f1'].options} == {1, 3, 5, 7, 9}
 
 
 def test_item_field_from_cards_check_lazy_live(pub):
diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py
index 9092eaafc..c1e58b8f2 100644
--- a/wcs/backoffice/management.py
+++ b/wcs/backoffice/management.py
@@ -43,7 +43,7 @@ from wcs.formdef import FormDef
 from wcs.forms.backoffice import FormDefUI
 from wcs.forms.common import FormStatusPage
 from wcs.roles import logged_users_role
-from wcs.variables import LazyFieldVar, LazyList
+from wcs.variables import LazyFieldVar, LazyFormDefObjectsManager, LazyList
 from wcs.workflows import ActionsTracingEvolutionPart, WorkflowStatusItem, item_classes, template_on_formdata
 
 from ..qommon import _, errors, ezt, force_str, get_cfg, misc, ngettext, ods, template
@@ -1979,10 +1979,12 @@ class FormPage(Directory):
                             )
                         )
 
+                    if isinstance(filter_field_value, (LazyFormDefObjectsManager, LazyList)):
+                        filter_field_value = list(filter_field_value)
                     if isinstance(filter_field_value, list):
                         try:
                             [int(v) for v in filter_field_value]
-                        except ValueError:
+                        except (ValueError, TypeError):
                             record_error(filter_field_value, filter_field_operator)
                             criterias.append(Equal('status', '_none'))
                             continue
-- 
2.35.1

