From 08b70c131758eeda93ad8025f7727a138e046b2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Fri, 4 Dec 2020 15:29:43 +0100
Subject: [PATCH] cards: csv import & user support (#48776)

---
 tests/backoffice_pages/test_carddata.py | 63 +++++++++++++++++++++++++
 wcs/backoffice/data_management.py       | 31 +++++++++++-
 2 files changed, 93 insertions(+), 1 deletion(-)

diff --git a/tests/backoffice_pages/test_carddata.py b/tests/backoffice_pages/test_carddata.py
index 5234cc2b..676ab6a5 100644
--- a/tests/backoffice_pages/test_carddata.py
+++ b/tests/backoffice_pages/test_carddata.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 import datetime
 import os
+import uuid
 
 import pytest
 from webtest import Upload
@@ -377,6 +378,68 @@ def test_backoffice_cards_import_data_from_csv(pub, studio):
     assert card2.data['5'].tm_mday == 3
 
 
+def test_backoffice_cards_import_data_csv_user_support(pub, studio):
+    user = create_user(pub)
+    user.name_identifiers = [str(uuid.uuid4())]
+    user.store()
+
+    CardDef.wipe()
+    carddef = CardDef()
+    carddef.name = 'test'
+    carddef.fields = [
+        fields.ItemField(id='1', label='List',
+                         items=['item1', 'item2']),
+    ]
+    carddef.user_support = 'optional'
+    carddef.workflow_roles = {'_editor': user.roles[0]}
+    carddef.backoffice_submission_roles = user.roles
+    carddef.store()
+    carddef.data_class().wipe()
+
+    app = login(get_app(pub))
+    sample_resp = app.get('/backoffice/data/test/data-sample-csv')
+    assert sample_resp.text == 'User (email or UUID),List\r\nvalue,value\r\n'
+    data = [
+        b'User,List',
+        b'%s,item1' % user.email.encode('utf-8'),
+        b'%s,item2' % user.nameid.encode('utf-8'),
+        b',item1',
+        b'foobar,item2',
+        b'foobar@mail.com,item2',
+    ]
+    resp = app.get('/backoffice/data/test/import-csv')
+    resp.forms[0]['file'] = Upload('test.csv', b'\n'.join(data),
+                                   'text/csv')
+    resp = resp.forms[0].submit().follow()
+    assert carddef.data_class().count() == 5
+    cards = carddef.data_class().select(order_by='id')
+    #assert cards[0].user_id == user.id
+    #assert cards[1].user_id == user.id
+    #assert cards[2].user_id is None
+    #assert cards[3].user_id is None
+    #assert cards[4].user_id is None
+
+    # if no user support, user columns is ignored in import
+    carddef.user_support = None
+    carddef.store()
+    carddef.data_class().wipe()
+
+    data = [
+        b'User',
+        user.email.encode('utf-8'),
+        user.nameid.encode('utf-8'),
+        b'foobar',
+        b'foobar@mail.com',
+    ]
+    resp = app.get('/backoffice/data/test/import-csv')
+    resp.forms[0]['file'] = Upload('test.csv', b'\n'.join(data),
+                                   'text/csv')
+    resp = resp.forms[0].submit().follow()
+    assert carddef.data_class().count() == 4
+    cards = carddef.data_class().select(order_by='id')
+    assert [c.user_id for c in cards] == [None, None, None, None]
+
+
 def test_backoffice_cards_import_data_csv_invalid_columns(pub):
     user = create_user(pub)
 
diff --git a/wcs/backoffice/data_management.py b/wcs/backoffice/data_management.py
index 7ab2c561..22d10cb8 100644
--- a/wcs/backoffice/data_management.py
+++ b/wcs/backoffice/data_management.py
@@ -140,8 +140,21 @@ class CardPage(FormPage):
         return r
 
     def get_import_csv_fields(self):
+        class UserField:
+            key = 'user'
+            id = '_user'
+            label = _('User (email or UUID)')
+            store_display_value = None
+            store_structured_value = None
+
+            def convert_value_from_str(self, x):
+                return x
+
         # skip non-data fields
-        return [x for x in self.formdef.get_all_fields() if isinstance(x, fields.WidgetField)]
+        csv_fields = [x for x in self.formdef.get_all_fields() if isinstance(x, fields.WidgetField)]
+        if self.formdef.user_support == 'optional':
+            return [UserField()] + csv_fields
+        return csv_fields
 
     def data_sample_csv(self):
         carddef_fields = self.get_import_csv_fields()
@@ -277,6 +290,20 @@ class CardPage(FormPage):
                 error_message += ' ' + _('(line numbers %s and more)') % ', '.join(incomplete_lines[:5])
             raise ValueError(error_message)
 
+        def user_lookup(user_value):
+            if self.formdef.user_support != 'optional':
+                return
+            if not user_value:
+                return
+            users = []
+            if '@' in user_value:
+                users = get_publisher().user_class.get_users_with_email(user_value)
+            else:
+                users = get_publisher().user_class.get_users_with_name_identifier(user_value)
+            if not users:
+                return
+            return users[0]
+
         class ImportAction:
             def __init__(self, data_class, lines):
                 self.data_class = data_class
@@ -285,6 +312,8 @@ class CardPage(FormPage):
             def execute(self, job=None):
                 for item in self.lines:
                     data_instance = self.data_class()
+                    user_value = item.pop('_user', None)
+                    data_instance.user = user_lookup(user_value)
                     data_instance.data = item
                     data_instance.just_created()
                     data_instance.store()
-- 
2.28.0

