From e340a0425cd9d3c2c5890b6d871d3e892e4bcac1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Thu, 10 Feb 2022 20:19:53 +0100
Subject: [PATCH] misc: allow picking a custom view on card cell (#58878)

---
 combo/apps/wcs/forms.py  |  2 +-
 combo/apps/wcs/models.py | 25 ++++++++++++++++++++++++-
 tests/test_wcs.py        | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/combo/apps/wcs/forms.py b/combo/apps/wcs/forms.py
index 1ab27de2..72cb5bf0 100644
--- a/combo/apps/wcs/forms.py
+++ b/combo/apps/wcs/forms.py
@@ -96,7 +96,7 @@ class WcsCardInfoCellForm(forms.ModelForm):
         initial = kwargs.pop('initial', {})
         initial['with_user'] = not instance.without_user
         super().__init__(initial=initial, *args, **kwargs)
-        card_models = get_wcs_options('/api/cards/@list')
+        card_models = get_wcs_options('/api/cards/@list', include_custom_views=True)
         self.fields['carddef_reference'].widget = forms.Select(choices=card_models)
         if self.instance.custom_schema:
             self.initial['customize_display'] = True
diff --git a/combo/apps/wcs/models.py b/combo/apps/wcs/models.py
index 02b523ef..7280229c 100644
--- a/combo/apps/wcs/models.py
+++ b/combo/apps/wcs/models.py
@@ -782,6 +782,13 @@ class CardMixin:
     def card_slug(self):
         return self.carddef_reference.split(':')[1]
 
+    @property
+    def card_custom_view(self):
+        try:
+            return self.carddef_reference.split(':')[2]
+        except IndexError:
+            return None
+
     def get_additional_label(self):
         if not self.cached_title:
             return
@@ -948,7 +955,8 @@ class WcsCardInfosCell(CardMixin, CellBase):
 
         def populate_cache():
             if self.carddef_reference:
-                wcs_key, card_slug = self.carddef_reference.split(':')
+                parts = self.carddef_reference.split(':')
+                wcs_key, card_slug = parts[:2]
                 wcs_site = get_wcs_services().get(wcs_key)
                 card_schema = get_wcs_json(wcs_site, 'api/cards/%s/@schema' % card_slug, log_errors='warn')
 
@@ -996,6 +1004,17 @@ class WcsCardInfosCell(CardMixin, CellBase):
 
     def get_card_data(self, card_slug, card_id, context, synchronous=False):
         api_url = '/api/cards/%s/%s/?include-files-content=off' % (card_slug, card_id)
+        if self.card_custom_view:
+            api_url = '/api/cards/%s/%s/%s/?include-files-content=off' % (
+                card_slug,
+                self.card_custom_view,
+                card_id,
+            )
+            user = self.get_concerned_user(context)
+            if user:
+                user_name_id = user.get_name_id()
+                if user_name_id:
+                    api_url += '&filter-user-uuid=%s' % user_name_id
         if not synchronous:
             synchronous = bool(context.get('synchronous'))
         wcs_site = get_wcs_services().get(self.wcs_site)
@@ -1011,6 +1030,10 @@ class WcsCardInfosCell(CardMixin, CellBase):
             )
             response.raise_for_status()
         except RequestException:
+            if self.card_custom_view:
+                # if there's a custom view consider the error is a 404 because
+                # the card was not found in that view, and mark it so.
+                context['card_not_found'] = True
             return {}
 
         if response.status_code == 200:
diff --git a/tests/test_wcs.py b/tests/test_wcs.py
index 0404cee4..391042a3 100644
--- a/tests/test_wcs.py
+++ b/tests/test_wcs.py
@@ -417,6 +417,12 @@ def get_data_from_url(url):
             return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(2))][0]
         except IndexError:
             return {}
+    m_card = re.match(r'/api/cards/([a-z0-9_]+)/([a-z0-9_]+)/(\d+)/', url)  # model/custom-view/id
+    if m_card:
+        try:
+            return [d for d in WCS_CARDS_DATA[m_card.group(1)] if d['id'] == int(m_card.group(3))][0]
+        except IndexError:
+            return {}
     if 'api/cards/card_model_1/list/foo' in url:
         return WCS_CARDS_CUSTOM_VIEW_DATA
     m_list = re.match(r'/api/cards/([a-z0-9_]+)/list', url)
@@ -1861,6 +1867,7 @@ def test_card_cell_setup(mock_send, app, admin_user):
     form = form_class(instance=cell)
     assert form.fields['carddef_reference'].widget.choices == [
         ('default:card_model_1', 'test : Card Model 1'),
+        ('default:card_model_1:foo', 'test : Card Model 1 - bar'),
         ('default:card_model_2', 'test : Card Model 2'),
         ('default:card_model_3', 'test : Card Model 3'),
         ('default:card_a', 'test : Card A'),
@@ -1869,6 +1876,7 @@ def test_card_cell_setup(mock_send, app, admin_user):
         ('default:card_d', 'test : Card D'),
         ('default:card_e', 'test : Card E'),
         ('other:card_model_1', 'test2 : Card Model 1'),
+        ('other:card_model_1:foo', 'test2 : Card Model 1 - bar'),
         ('other:card_model_2', 'test2 : Card Model 2'),
         ('other:card_model_3', 'test2 : Card Model 3'),
         ('other:card_a', 'test2 : Card A'),
@@ -1892,6 +1900,17 @@ def test_card_cell_setup(mock_send, app, admin_user):
     assert 'customize_display' not in form.initial
     assert form.initial['custom_schema'] == {}
 
+    cell.carddef_reference = 'default:card_model_1:foo'
+    cell.save()
+    form = form_class(instance=cell)
+    assert 'customize_display' in form.fields
+    assert 'custom_schema' in form.fields
+    assert 'customize_display' not in form.initial
+    assert form.initial['custom_schema'] == {}
+
+    cell.carddef_reference = 'default:card_model_1'
+    cell.save()
+
     cell.custom_schema = {'cells': [{'varname': 'foo', 'display_mode': 'value'}]}
     cell.save()
     form = form_class(instance=cell)
@@ -2475,6 +2494,21 @@ def test_card_cell_render(mock_send, context, app):
     for i in range(0, 3):
         assert '<h2>Foo bar X%sY</h2>' % i in resp
 
+    # using custom view
+    cell.carddef_reference = 'default:card_model_1:foo'
+    cell.save()
+    result = cell.render(context)
+    assert 'Foo bar X0Y' in result
+
+    with mock.patch('combo.apps.wcs.models.requests.get') as requests_get:
+        mock_resp = Response()
+        mock_resp.status_code = 404
+        requests_get.return_value = mock_resp
+        result = cell.render(context)
+
+    # nothing, hide cell
+    assert not result.strip()
+
 
 @mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send)
 def test_card_cell_render_text_field(mock_send, context):
-- 
2.34.1

