From 2071e8ab482115eed31c64c4072ebc181f19ff67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 4 Jun 2020 11:06:43 +0200
Subject: [PATCH] carddefs: check on form import if carddef exists (#42579)

---
 tests/test_admin_pages.py    |  4 ++++
 tests/test_formdef_import.py | 28 +++++++++++++++++++++++++---
 wcs/formdef.py               |  7 +++++++
 3 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/tests/test_admin_pages.py b/tests/test_admin_pages.py
index 5d21f368..7713295d 100644
--- a/tests/test_admin_pages.py
+++ b/tests/test_admin_pages.py
@@ -4630,6 +4630,9 @@ def test_settings_export_import(pub, studio):
     formdef.roles = [role.id]
     formdef.backoffice_submission_roles = [role.id]
     formdef.workflow_roles = {'_receiver': role.id}
+    formdef.fields = [fields.StringField(
+        id='1', type='string',
+        data_source={'type': 'carddef:unknown'})]
     formdef.store()
 
     resp = app.get('/backoffice/settings/export')
@@ -4666,6 +4669,7 @@ def test_settings_export_import(pub, studio):
     assert FormDef.select()[0].roles == ['012345']
     assert FormDef.select()[0].backoffice_submission_roles == ['012345']
     assert FormDef.select()[0].workflow_roles == {'_receiver': '012345'}
+    assert len(FormDef.select()[0].fields) == 1
     assert Workflow.select()[0].possible_status[0].items[0].by == ['012345']
 
     # do not export roles when managed by idp
diff --git a/tests/test_formdef_import.py b/tests/test_formdef_import.py
index aea38e15..9596b580 100644
--- a/tests/test_formdef_import.py
+++ b/tests/test_formdef_import.py
@@ -1,7 +1,6 @@
 # -*- coding: utf-8 -*-
 
 import pytest
-import sys
 import shutil
 import time
 import xml.etree.ElementTree as ET
@@ -10,6 +9,7 @@ from django.utils.six import BytesIO, StringIO
 from quixote import cleanup
 
 from wcs.categories import Category
+from wcs.carddef import CardDef
 from wcs.formdef import FormDef, fields, FormdefImportError
 from wcs.workflows import Workflow
 from wcs.roles import Role
@@ -346,15 +346,37 @@ def test_invalid_field_type():
 def test_unknown_data_source():
     formdef = FormDef()
     formdef.name = 'foo'
-    formdef.fields = [fields.StringField(id='1', type='string',
+    formdef.fields = [fields.StringField(
+        id='1', type='string',
         data_source={'type': 'json', 'value': 'http://example.net'})]
     export = ET.tostring(export_to_indented_xml(formdef))
 
     FormDef.import_from_xml(BytesIO(export))
 
-    formdef.fields = [fields.StringField(id='1', type='string',
+    formdef.fields = [fields.StringField(
+        id='1', type='string',
         data_source={'type': 'foobar'})]
     export = ET.tostring(export_to_indented_xml(formdef))
+    with pytest.raises(FormdefImportError, match='Unknown datasources'):
+        FormDef.import_from_xml(BytesIO(export))
+
+    carddef = CardDef()
+    carddef.name = 'foo'
+    carddef.fields = [
+        fields.StringField(id='1', label='Test', type='string', varname='foo'),
+    ]
+    carddef.store()
+
+    formdef.fields = [fields.StringField(
+        id='1', type='string',
+        data_source={'type': 'carddef:foo'})]
+    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:unknown'})]
+    export = ET.tostring(export_to_indented_xml(formdef))
     with pytest.raises(FormdefImportError):
         FormDef.import_from_xml(BytesIO(export))
 
diff --git a/wcs/formdef.py b/wcs/formdef.py
index 25e7275b..92b057a1 100644
--- a/wcs/formdef.py
+++ b/wcs/formdef.py
@@ -1009,6 +1009,7 @@ class FormDef(StorableObject):
     @classmethod
     def import_from_xml(cls, fd, charset=None, include_id=False,
             fix_on_error=False, check_datasources=True):
+        from wcs.carddef import CardDef
         try:
             tree = ET.parse(fd)
         except:
@@ -1039,6 +1040,12 @@ class FormDef(StorableObject):
                     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:'):
+                        # check if carddef exists
+                        try:
+                            CardDef.get_by_urlname(data_source['type'][8:])
+                        except KeyError:
+                            unknown_datasources.add(data_source.get('type'))
             if unknown_datasources:
                 raise FormdefImportError(N_('Unknown datasources'),
                         details=', '.join(sorted(unknown_datasources)))
-- 
2.20.1

