From 76e45249f5d1e3bd0a658c9489fb603f1752e142 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Mon, 13 Jan 2020 19:36:55 +0100
Subject: [PATCH] backoffice: display card selected in item field as link
 (#38924)

---
 tests/test_backoffice_pages.py | 50 ++++++++++++++++++++++++++++++++++
 wcs/fields.py                  | 20 +++++++++++++-
 wcs/forms/common.py            | 16 +++++++----
 3 files changed, 79 insertions(+), 7 deletions(-)

diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py
index 7a6b8d7bf..f9e55011e 100644
--- a/tests/test_backoffice_pages.py
+++ b/tests/test_backoffice_pages.py
@@ -5323,6 +5323,7 @@ def test_workflow_comment_required(pub):
     assert 'HELLO WORLD 2' in resp.text
 
 def test_carddata_management(pub, studio):
+    CardDef.wipe()
     user = create_user(pub)
     app = login(get_app(pub))
     resp = app.get('/backoffice/')
@@ -5333,6 +5334,7 @@ def test_carddata_management(pub, studio):
         fields.StringField(id='1', label='Test', type='string', varname='foo'),
     ]
     carddef.store()
+    carddef.data_class().wipe()
 
     resp = app.get('/backoffice/')
     assert not 'Cards' in resp.text
@@ -5370,3 +5372,51 @@ def test_carddata_management(pub, studio):
     resp = app.get('/backoffice/data/')
     resp = resp.click('foo')
     assert resp.text.count('<tr') == 2  # header + row of data
+
+def test_studio_card_item_link(pub, studio):
+    user = create_user(pub)
+    CardDef.wipe()
+    carddef = CardDef()
+    carddef.name = 'foo'
+    carddef.fields = [
+        fields.StringField(id='1', label='Test', type='string', varname='foo'),
+    ]
+    carddef.backoffice_submission_roles = user.roles
+    carddef.workflow_roles = {'_editor': user.roles[0]}
+    carddef.digest_template = 'card {{form_var_foo}}'
+    carddef.store()
+    carddef.data_class().wipe()
+
+    card = carddef.data_class()()
+    card.data = {'1': 'plop'}
+    card.store()
+
+    carddef2 = CardDef()
+    carddef2.name = 'bar'
+    carddef2.fields = [
+        fields.ItemField(id='1', label='Test', type='item',
+            data_source={'type': 'carddef:foo', 'value': ''}),
+    ]
+    carddef2.backoffice_submission_roles = user.roles
+    carddef2.workflow_roles = {'_editor': user.roles[0]}
+    carddef2.store()
+    carddef2.data_class().wipe()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/data/')
+    resp = resp.click('bar')
+    resp = resp.click('Add')
+    resp.form['f1'] = card.id
+    resp = resp.form.submit('submit')
+    assert resp.location.endswith('/backoffice/data/bar/1/')
+    resp = resp.follow()
+    resp = resp.click('card plop')
+    assert '<div class="value">plop</div>' in resp
+
+    # look without access rights
+    carddef.backoffice_submission_roles = None
+    carddef.workflow_roles = {'_editor': None}
+    carddef.store()
+    resp = app.get('/backoffice/data/bar/1/')
+    with pytest.raises(IndexError):
+        resp.click('card plop')
diff --git a/wcs/fields.py b/wcs/fields.py
index 9416fd78d..782d493ad 100644
--- a/wcs/fields.py
+++ b/wcs/fields.py
@@ -1363,6 +1363,24 @@ class ItemField(WidgetField):
 
         return data_source.get_display_value(value)
 
+    def get_view_value(self, value, value_id=None):
+        value = super(ItemField, self).get_view_value(value)
+        if not (value_id and
+                get_request() and
+                get_request().is_in_backoffice() and
+                self.data_source and
+                self.data_source.get('type', '').startswith('carddef:')):
+            return value
+        from wcs.carddef import CardDef
+        try:
+            carddef = CardDef.get_by_urlname(self.data_source['type'][8:])
+            carddata = carddef.data_class().get(value_id)
+        except KeyError:
+            return value
+        if not carddef.is_user_allowed_read(get_request().user, carddata):
+            return value
+        return htmltext('<a href="%s">' % carddata.get_url(backoffice=True)) + htmltext('%s</a>') % value
+
     def add_to_view_form(self, form, value = None):
         real_value = value
         label_value = ''
@@ -1575,7 +1593,7 @@ class ItemsField(WidgetField):
     def convert_value_to_str(self, value):
         return value
 
-    def get_view_value(self, value):
+    def get_view_value(self, value, **kwargs):
         if type(value) is str: # == display_value
             return value
         if value:
diff --git a/wcs/forms/common.py b/wcs/forms/common.py
index ea1ca2c62..429f56574 100644
--- a/wcs/forms/common.py
+++ b/wcs/forms/common.py
@@ -394,18 +394,22 @@ class FormStatusPage(Directory, FormTemplateMixin):
         pages = []
         current_page_fields = []
 
-        def get_value(f):
+        def get_value_info(f):
+            # return the selected value and an optional dictionary that will be
+            # passed to get_view_value() to provide additional details.
+            value_details = {}
             if f.id not in self.filled.data:
                 value = None
             else:
                 if f.store_display_value and ('%s_display' % f.id) in self.filled.data:
                     value = self.filled.data['%s_display' % f.id]
+                    value_details['value_id'] = self.filled.data[f.id]
                 else:
                     value = self.filled.data[f.id]
 
                 if value is None or value == '':
                     value = None
-            return value
+            return (value, value_details)
 
         for i, f in enumerate(fields):
             if f.type == 'page':
@@ -429,11 +433,11 @@ class FormStatusPage(Directory, FormTemplateMixin):
             if not f.include_in_summary_page:
                 continue
 
-            value = get_value(f)
+            value, value_details = get_value_info(f)
             if value is None and not (f.required and include_unset_required_fields):
                 continue
 
-            current_page_fields.append({'field': f, 'value': value})
+            current_page_fields.append({'field': f, 'value': value, 'value_details': value_details})
 
         if not pages:
             fields = [x['field'] for x in current_page_fields]
@@ -477,12 +481,12 @@ class FormStatusPage(Directory, FormTemplateMixin):
                 css_classes.append(f.extra_css_class)
             r += htmltext('<div class="%s">' % ' '.join(css_classes))
             r += htmltext('<span class="label">%s</span> ') % f.label
-            value = get_value(f)
+            value, value_details = get_value_info(f)
             if value is None:
                 r += htmltext('<div class="value"><i>%s</i></div>') % _('Not set')
             else:
                 r += htmltext('<div class="value">')
-                s = f.get_view_value(value)
+                s = f.get_view_value(value, **value_details)
                 s = s.replace(str('[download]'), str('%sdownload' % form_url))
                 r += s
                 r += htmltext('</div>')
-- 
2.25.0

