From f258a4d8e5679e86a8d6f49c832a71425125ae0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Mon, 9 Nov 2020 09:03:49 +0100
Subject: [PATCH] wcs: option to get cards only for current user (#48190)

---
 combo/apps/wcs/forms.py                      |  2 +-
 combo/apps/wcs/migrations/0022_cards_user.py | 19 +++++++++++
 combo/apps/wcs/models.py                     | 15 ++++++--
 tests/test_wcs.py                            | 36 ++++++++++++++++++++
 4 files changed, 69 insertions(+), 3 deletions(-)
 create mode 100644 combo/apps/wcs/migrations/0022_cards_user.py

diff --git a/combo/apps/wcs/forms.py b/combo/apps/wcs/forms.py
index abb0d7d3..d20c9d58 100644
--- a/combo/apps/wcs/forms.py
+++ b/combo/apps/wcs/forms.py
@@ -40,7 +40,7 @@ class WcsFormCellForm(forms.ModelForm):
 class WcsCardsCellForm(forms.ModelForm):
     class Meta:
         model = WcsCardsCell
-        fields = ('carddef_reference',)
+        fields = ('carddef_reference', 'only_for_user')
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
diff --git a/combo/apps/wcs/migrations/0022_cards_user.py b/combo/apps/wcs/migrations/0022_cards_user.py
new file mode 100644
index 00000000..dbeb87c1
--- /dev/null
+++ b/combo/apps/wcs/migrations/0022_cards_user.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('wcs', '0021_card'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='wcscardscell',
+            name='only_for_user',
+            field=models.BooleanField(default=False, verbose_name='Limit to cards linked to the logged-in user'),
+        ),
+    ]
diff --git a/combo/apps/wcs/models.py b/combo/apps/wcs/models.py
index d6e68875..149a1b35 100644
--- a/combo/apps/wcs/models.py
+++ b/combo/apps/wcs/models.py
@@ -727,6 +727,7 @@ class CardMixin(object):
 class WcsCardsCell(CardMixin, WcsBlurpMixin, CellBase):
     carddef_reference = models.CharField(_('Card Model'), max_length=150)
     cached_title = models.CharField(_('Title'), max_length=150)
+    only_for_user = models.BooleanField(_('Limit to cards linked to the logged-in user'), default=False)
 
     template_name = 'combo/wcs/cards.html'
     variable_name = 'cards'
@@ -789,11 +790,21 @@ class WcsCardsCell(CardMixin, WcsBlurpMixin, CellBase):
 
         populate_cache()
 
+    def is_visible(self, **kwargs):
+        user = kwargs.get('user')
+        if self.only_for_user and (not user or user.is_anonymous):
+            return False
+        return super().is_visible(**kwargs)
+
     def get_api_url(self, context):
         parts = self.carddef_reference.split(':')
+        url = 'api/cards/%s/list' % parts[1]
         if len(parts) > 2:
-            return 'api/cards/%s/list/%s' % (parts[1], parts[2])
-        return 'api/cards/%s/list' % parts[1]
+            url = '%s/%s' % (url, parts[2])
+        user = self.get_concerned_user(context)
+        if self.only_for_user and user and user.get_name_id():
+            url = '%s?filter-user-uuid=%s' % (url, user.get_name_id())
+        return url
 
     def get_cell_extra_context(self, context):
         extra_context = super().get_cell_extra_context(context)
diff --git a/tests/test_wcs.py b/tests/test_wcs.py
index 8cf2f162..7672ffb3 100644
--- a/tests/test_wcs.py
+++ b/tests/test_wcs.py
@@ -167,6 +167,7 @@ WCS_CARD_DATA = {
 class MockUser(object):
     email = 'foo@example.net'
     is_authenticated = True
+    is_anonymous = False
 
     def get_name_id(self):
         return None
@@ -175,6 +176,7 @@ class MockUser(object):
 class MockUserWithNameId(object):
     email = 'foo@example.net'
     is_authenticated = True
+    is_anonymous = False
 
     def get_name_id(self):
         return 'xyz'
@@ -1202,6 +1204,40 @@ def test_cards_cell_render(mock_send, context):
     assert '<a href="/foo/13"><span class="card-title">cc</span></a>' not in result
 
 
+@mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send)
+def test_cards_cell_only_for_user(mock_send, context):
+    page = Page.objects.create(title='xxx', template_name='standard')
+    cell = WcsCardsCell(page=page, placeholder='content', order=0)
+    cell.carddef_reference = 'default:card_model_1'
+    cell.only_for_user = False
+    cell.save()
+
+    assert cell.is_visible(user=None) is True
+    assert cell.is_visible(user=MockUserWithNameId()) is True
+
+    cell.only_for_user = True
+    cell.save()
+    assert cell.is_visible(user=None) is False
+    assert cell.is_visible(user=MockUserWithNameId()) is True
+
+    cache.clear()
+    context['synchronous'] = True  # to get fresh content
+
+    mock_send.reset_mock()
+    cell.render(context)
+    assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
+
+    context['request'].user = MockUser()
+    mock_send.reset_mock()
+    cell.render(context)
+    assert 'filter-user-uuid' not in mock_send.call_args_list[0][0][0].url
+
+    context['request'].user = MockUserWithNameId()
+    mock_send.reset_mock()
+    cell.render(context)
+    assert 'filter-user-uuid=xyz' in mock_send.call_args_list[0][0][0].url
+
+
 @mock.patch('combo.apps.wcs.utils.requests.send', side_effect=mocked_requests_send)
 def test_card_cell_setup(mock_send):
     cell = WcsCardInfosCell()
-- 
2.28.0

