From 20866ea72fff7f4b57a730268eb2b2f9b3abea6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Fri, 7 Aug 2020 15:00:02 +0200
Subject: [PATCH] fields: add spreadsheet export support for block fields
 (#45792)

---
 tests/test_backoffice_pages.py | 51 ++++++++++++++++++++++++++++++++++
 wcs/fields.py                  | 16 +++++++++++
 2 files changed, 67 insertions(+)

diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py
index 7b04ece18..10f873b3a 100644
--- a/tests/test_backoffice_pages.py
+++ b/tests/test_backoffice_pages.py
@@ -126,6 +126,7 @@ def create_environment(pub, set_receiver=True):
     Workflow.wipe()
     Category.wipe()
     FormDef.wipe()
+    BlockDef.wipe()
     CardDef.wipe()
     pub.custom_view_class.wipe()
     formdef = FormDef()
@@ -136,6 +137,9 @@ def create_environment(pub, set_receiver=True):
     datasource = {'type': 'formula',
             'value': repr([('A', 'aa'), ('B', 'bb'), ('C', 'cc')])}
 
+    formdef.fields = []
+    formdef.store()  # make sure sql columns are removed
+
     formdef.fields = [
             fields.StringField(id='1', label='1st field', type='string',
                 display_locations=['validation', 'summary', 'listings']),
@@ -1472,6 +1476,52 @@ def test_backoffice_csv_export_anonymised(pub):
     assert resp_csv.text.splitlines()[1].split(',')[-1] == 'No'
 
 
+def test_backoffice_csv_export_block(pub):
+    create_superuser(pub)
+    create_environment(pub)
+
+    block = BlockDef()
+    block.name = 'foobar'
+    block.fields = [
+        fields.StringField(id='123', required=True, label='Test', type='string', varname='foo'),
+        fields.StringField(id='234', required=True, label='Test2', type='string', varname='bar'),
+    ]
+    block.digest_template = 'X{{foobar_var_foo}}Y'
+    block.store()
+
+    formdef = FormDef.get_by_urlname('form-title')
+    formdef.fields = []
+    formdef.store()  # make sure sql columns are removed
+
+    formdef.fields = [
+        fields.BlockField(id='1', label='test', type='block:foobar', max_items=3),
+    ]
+    formdef.store()
+
+    formdef.data_class().wipe()
+    formdata = formdef.data_class()()
+    formdata.data = {}
+    formdata.data['1'] = {
+        'data': [
+            {'123': 'foo', '234': 'bar'},
+            {'123': 'foo2', '234': 'bar2'},
+        ],
+        'schema': {'123': 'string', '234': 'string'},
+    }
+    formdata.just_created()
+    formdata.jump_status('new')
+    formdata.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/management/form-title/')
+    resp_csv = resp.click('Export as CSV File')
+    resp.forms['listing-settings']['1'].checked = True
+    resp = resp.forms['listing-settings'].submit()
+    resp_csv = resp.click('Export as CSV File')
+    assert resp_csv.text.splitlines()[0].split(',')[-3:] == ['test - 1', 'test - 2', 'test - 3']
+    assert resp_csv.text.splitlines()[1].split(',')[-3:] == ['XfooY', 'Xfoo2Y', '']
+
+
 def test_backoffice_ods(pub):
     create_superuser(pub)
     create_environment(pub)
@@ -7142,6 +7192,7 @@ def test_block_card_item_link(pub, studio, blocks_feature):
     card2.data = {'1': 'plop2'}
     card2.store()
 
+    BlockDef.wipe()
     block = BlockDef()
     block.name = 'foobar'
     block.fields = [
diff --git a/wcs/fields.py b/wcs/fields.py
index 5431dd676..0a90b1f1f 100644
--- a/wcs/fields.py
+++ b/wcs/fields.py
@@ -2711,6 +2711,22 @@ class BlockField(WidgetField):
                 r += htmltext('</div>\n')
         return r.getvalue()
 
+    def get_csv_heading(self):
+        nb_items = (self.max_items or 1)
+        if nb_items == 1:
+            return [self.label]
+        headings = ['%s - %s' % (self.label, x + 1) for x in range(nb_items)]
+        return headings
+
+    def get_csv_value(self, value, **kwargs):
+        nb_items = (self.max_items or 1)
+        cells = [''] * nb_items
+        if value and value.get('data'):
+            for i, subvalue in enumerate(value.get('data')[:nb_items]):
+                if subvalue:
+                    cells[i] = self.block.get_display_value(subvalue)
+        return cells
+
 
 def get_field_class_by_type(type):
     for k in field_classes:
-- 
2.28.0

