From 72f9a9a663490294f1d7a00294aabe4144fbac9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 16 Oct 2020 11:11:23 +0200
Subject: [PATCH] cards: check on form import if carddef custom view exists
 (#47780)

---
 tests/test_formdef_import.py | 24 ++++++++++++++++++++++++
 wcs/formdef.py               | 27 ++++++++++++++++++++++-----
 2 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/tests/test_formdef_import.py b/tests/test_formdef_import.py
index 7a1d355a..b10465e0 100644
--- a/tests/test_formdef_import.py
+++ b/tests/test_formdef_import.py
@@ -378,6 +378,7 @@ def test_unknown_data_source():
     with pytest.raises(FormdefImportError, match='Unknown datasources'):
         FormDef.import_from_xml(BytesIO(export))
 
+    # carddef as datasource
     carddef = CardDef()
     carddef.name = 'foo'
     carddef.fields = [
@@ -398,6 +399,29 @@ def test_unknown_data_source():
     with pytest.raises(FormdefImportError):
         FormDef.import_from_xml(BytesIO(export))
 
+    # carddef custom view as datasource
+    pub.custom_view_class.wipe()
+    custom_view = pub.custom_view_class()
+    custom_view.title = 'card view'
+    custom_view.formdef = carddef
+    custom_view.columns = {'list': [{'id': 'id'}]}
+    custom_view.filters = {}
+    custom_view.visibility = 'datasource'
+    custom_view.store()
+
+    formdef.fields = [fields.StringField(
+        id='1', type='string',
+        data_source={'type': 'carddef:foo:card-view'})]
+    export = ET.tostring(export_to_indented_xml(formdef))
+    FormDef.import_from_xml(BytesIO(export))
+
+    formdef.fields = [fields.StringField(
+        id='1', type='string',
+        data_source={'type': 'carddef:foo:unknown'})]
+    export = ET.tostring(export_to_indented_xml(formdef))
+    with pytest.raises(FormdefImportError):
+        FormDef.import_from_xml(BytesIO(export))
+
 
 def test_duplicated_field_ids():
     formdef = FormDef()
diff --git a/wcs/formdef.py b/wcs/formdef.py
index 9db0dcdb..00b42a01 100644
--- a/wcs/formdef.py
+++ b/wcs/formdef.py
@@ -33,7 +33,7 @@ from quixote import get_request, get_publisher
 from quixote.http_request import Upload
 
 from .qommon import _, N_, force_str, PICKLE_KWARGS
-from .qommon.storage import StorableObject, fix_key
+from .qommon.storage import StorableObject, fix_key, Equal
 from .qommon.cron import CronJob
 from .qommon.form import *
 from .qommon.misc import simplify, get_as_datetime, xml_node_text
@@ -1044,19 +1044,36 @@ class FormDef(StorableObject):
             for field in formdef.fields:
                 data_source = getattr(field, 'data_source', None)
                 if data_source:
+                    data_source_id = data_source.get('type')
                     if isinstance(data_sources.get_object(data_source),
                                   data_sources.StubNamedDataSource):
-                        unknown_datasources.add(data_source.get('type'))
-                    elif data_source.get('type') and data_source.get('type').startswith('carddef:'):
+                        unknown_datasources.add(data_source_id)
+                    elif data_source_id and data_source_id.startswith('carddef:'):
+                        parts = data_source_id.split(':')
                         # check if carddef exists
-                        url_name = data_source['type'][8:]
+                        url_name = parts[1]
                         if formdef.xml_root_node == 'carddef' and formdef.url_name == url_name:
                             # reference to itself, it's ok
                             continue
                         try:
                             CardDef.get_by_urlname(url_name)
                         except KeyError:
-                            unknown_datasources.add(data_source.get('type'))
+                            unknown_datasources.add(data_source_id)
+                            continue
+
+                        if len(parts) == 2:
+                            continue
+
+                        lookup_criterias = [
+                            Equal('formdef_type', 'carddef'),
+                            Equal('visibility', 'datasource'),
+                            Equal('slug', parts[2]),
+                        ]
+                        try:
+                            get_publisher().custom_view_class.select(lookup_criterias)[0]
+                        except IndexError:
+                            unknown_datasources.add(data_source_id)
+
             if unknown_datasources:
                 raise FormdefImportError(N_('Unknown datasources'),
                         details=', '.join(sorted(unknown_datasources)))
-- 
2.28.0

