From 9ead4c07989d4beac200bc2a6f690335e8ee8427 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Thu, 11 Feb 2021 16:20:02 +0100
Subject: [PATCH] custom views: filter by current user (#50460)

---
 tests/backoffice_pages/test_all.py         |   6 +-
 tests/backoffice_pages/test_custom_view.py | 148 +++++++++++++++++++++
 wcs/backoffice/management.py               |  42 +++---
 3 files changed, 177 insertions(+), 19 deletions(-)

diff --git a/tests/backoffice_pages/test_all.py b/tests/backoffice_pages/test_all.py
index 9dfff00e..295eeed1 100644
--- a/tests/backoffice_pages/test_all.py
+++ b/tests/backoffice_pages/test_all.py
@@ -1375,13 +1375,11 @@ def test_backoffice_user_filter(pub):
 
     app = login(get_app(pub))
     resp = app.get('/backoffice/management/form-title/')
-    # check the filter is hidden
-    assert resp.pyquery.find('li[hidden] input[name=filter-user]')
 
     resp = app.get('/backoffice/management/form-title/?filter-user=on&filter-user-value=%s' % user1.id)
     assert resp.text.count('>userA<') > 0
     assert resp.text.count('>userB<') == 0
-    assert resp.pyquery.find('input[value=userA]')  # displayed in sidebar
+    assert '<option value="%s" selected="selected">userA</option>' % user1.id in resp
     # check it persits on filter changes
     resp = resp.forms['listing-settings'].submit()
     assert resp.text.count('>userA<') > 0
@@ -1397,7 +1395,7 @@ def test_backoffice_user_filter(pub):
     resp = app.get('/backoffice/management/form-title/?filter-user-uuid=0123456789')
     assert resp.text.count('>userA<') > 0
     assert resp.text.count('>userB<') == 0
-    assert resp.pyquery.find('input[value=userA]')  # displayed in sidebar
+    assert '<option value="%s" selected="selected">userA</option>' % user1.id in resp
     # check it persists on filter changes
     resp = resp.forms['listing-settings'].submit()
     assert resp.text.count('>userA<') > 0
diff --git a/tests/backoffice_pages/test_custom_view.py b/tests/backoffice_pages/test_custom_view.py
index 50a2f442..2e60ac86 100644
--- a/tests/backoffice_pages/test_custom_view.py
+++ b/tests/backoffice_pages/test_custom_view.py
@@ -138,6 +138,154 @@ def test_backoffice_custom_view(pub):
     assert 'Views must have at least one column.' in resp.text
 
 
+def test_backoffice_custom_view_user_filter(pub):
+    superuser = create_superuser(pub)
+
+    FormDef.wipe()
+    pub.custom_view_class.wipe()
+    formdef = FormDef()
+    formdef.name = 'form title'
+    formdef.fields = [
+        fields.ItemField(
+            id='1',
+            label='field',
+            type='item',
+            items=['foo', 'bar', 'baz'],
+            display_locations=['validation', 'summary', 'listings'],
+        ),
+    ]
+    formdef.workflow_roles = {'_receiver': 1}
+    formdef.store()
+
+    user1 = pub.user_class(name='userA')
+    user1.store()
+    user2 = pub.user_class(name='userB')
+    user2.store()
+
+    formdef.data_class().wipe()
+    for i in range(10):
+        formdata = formdef.data_class()()
+        formdata.data = {'1': 'foo', '1_display': 'foo'}
+        if i < 1:
+            formdata.user_id = user1.id
+        elif i < 3:
+            formdata.user_id = user2.id
+        else:
+            formdata.user_id = superuser.id
+        formdata.jump_status('new')
+        formdata.store()
+
+    app = login(get_app(pub))
+    resp = app.get('/backoffice/management/form-title/')
+    assert resp.text.count('<tr') == 10 + 1
+
+    # No value selected, no filtering
+    resp.forms['listing-settings']['filter-user'].checked = True
+    resp = resp.forms['listing-settings'].submit()
+    resp.forms['listing-settings']['filter-user-value'] = ''
+    resp = resp.forms['listing-settings'].submit()
+    assert resp.text.count('<tr') == 10 + 1
+    assert resp.text.count('"cell-user">userA<') == 1
+    assert resp.text.count('"cell-user">userB<') == 2
+    assert resp.text.count('"cell-user">admin<') == 7
+    resp.forms['save-custom-view']['title'] = 'custom test view'
+    resp = resp.forms['save-custom-view'].submit().follow()
+    assert resp.text.count('<tr') == 10 + 1
+    assert resp.text.count('"cell-user">userA<') == 1
+    assert resp.text.count('"cell-user">userB<') == 2
+    assert resp.text.count('"cell-user">admin<') == 7
+
+    # filter on current user
+    resp.forms['listing-settings']['filter-user-value'] = '__current__'
+    resp = resp.forms['listing-settings'].submit()
+    assert resp.text.count('<tr') == 7 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 7
+    resp = resp.forms['save-custom-view'].submit().follow()
+    assert resp.text.count('<tr') == 7 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 7
+
+    # filter on userA
+    resp = app.get(
+        '/backoffice/management/form-title/user-custom-test-view/?filter-user=on&filter-user-value=%s'
+        % user1.id
+    )
+    assert resp.text.count('<tr') == 1 + 1
+    assert resp.text.count('"cell-user">userA<') == 1
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 0
+    assert '<option value="%s" selected="selected">userA</option>' % user1.id in resp
+    resp = resp.forms['listing-settings'].submit()
+    resp = resp.forms['save-custom-view'].submit().follow()
+    assert resp.text.count('<tr') == 1 + 1
+    assert resp.text.count('"cell-user">userA<') == 1
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 0
+
+    # filter on unknown
+    resp = app.get(
+        '/backoffice/management/form-title/user-custom-test-view/?filter-user=on&filter-user-value=unknown'
+    )
+    assert resp.text.count('<tr') == 0 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 0
+    assert '<option value="unknown" selected="selected">Unknown</option>' in resp
+    resp = resp.forms['listing-settings'].submit()
+    resp = resp.forms['save-custom-view'].submit().follow()
+    assert resp.text.count('<tr') == 0 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 0
+
+    # filter on uuid - userB
+    user2.name_identifiers = ['0123456789']
+    user2.store()
+    resp = app.get('/backoffice/management/form-title/user-custom-test-view/?filter-user-uuid=0123456789')
+    assert resp.text.count('<tr') == 2 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 2
+    assert resp.text.count('"cell-user">admin<') == 0
+    assert '<option value="%s" selected="selected">userB</option>' % user2.id in resp
+    resp = resp.forms['listing-settings'].submit()
+    resp = resp.forms['save-custom-view'].submit().follow()
+    assert resp.text.count('<tr') == 2 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 2
+    assert resp.text.count('"cell-user">admin<') == 0
+
+    # filter on uuid - current
+    resp = app.get('/backoffice/management/form-title/user-custom-test-view/?filter-user-uuid=__current__')
+    assert resp.text.count('<tr') == 7 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 7
+    assert '<option value="__current__" selected="selected">Current user</option>' in resp
+    resp = resp.forms['listing-settings'].submit()
+    resp = resp.forms['save-custom-view'].submit().follow()
+    assert resp.text.count('<tr') == 7 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 7
+
+    # filter on uuid - unknown
+    resp = app.get('/backoffice/management/form-title/user-custom-test-view/?filter-user-uuid=unknown')
+    assert resp.text.count('<tr') == 0 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 0
+    assert '<option value="-1" selected="selected">Unknown</option>' in resp
+    resp = resp.forms['listing-settings'].submit()
+    resp = resp.forms['save-custom-view'].submit().follow()
+    assert resp.text.count('<tr') == 0 + 1
+    assert resp.text.count('"cell-user">userA<') == 0
+    assert resp.text.count('"cell-user">userB<') == 0
+    assert resp.text.count('"cell-user">admin<') == 0
+
+
 def test_backoffice_custom_view_delete(pub):
     create_superuser(pub)
 
diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py
index e1cfd458..9d4971de 100644
--- a/wcs/backoffice/management.py
+++ b/wcs/backoffice/management.py
@@ -1274,7 +1274,7 @@ class FormPage(Directory):
         fake_fields = [
             FakeField('start', 'period-date', _('Start')),
             FakeField('end', 'period-date', _('End')),
-            FakeField('user', 'user-id', _('User'), addable=False),
+            FakeField('user', 'user-id', _('User')),
             FakeField('submission-agent', 'submission-agent-id', _('Submission Agent'), addable=False),
         ]
         default_filters = self.get_default_filters(mode)
@@ -1374,18 +1374,24 @@ class FormPage(Directory):
                 ).render()
 
             elif filter_field.type == 'user-id':
-                r += HiddenWidget(filter_field_key, value=filter_field_value).render()
-                if filter_field_value:
-                    filtered_user = get_publisher().user_class.get(filter_field_value, ignore_errors=True)
-                    widget = StringWidget(
-                        '_' + filter_field_key,
-                        title=filter_field.label,
-                        value=filtered_user.display_name if filtered_user else _('Unknown'),
-                        readonly=True,
-                        render_br=False,
-                    )
-                    widget._parsed = True  # make sure value is not replaced by request query
-                    r += widget.render()
+                options = [
+                    ('', _('None'), ''),
+                    ('__current__', _('Current user'), '__current__'),
+                ]
+                if filter_field_value and filter_field_value != '__current__':
+                    try:
+                        filtered_user = get_publisher().user_class.get(filter_field_value)
+                    except KeyError:
+                        filtered_user = None
+                    filtered_user_value = filtered_user.display_name if filtered_user else _('Unknown')
+                    options += [(filter_field_value, filtered_user_value, filter_field_value)]
+                r += SingleSelectWidget(
+                    filter_field_key,
+                    title=filter_field.label,
+                    options=options,
+                    value=filter_field_value,
+                    render_br=False,
+                ).render()
 
             elif filter_field.type == 'submission-agent-id':
                 r += HiddenWidget(filter_field_key, value=filter_field_value).render()
@@ -1858,8 +1864,12 @@ class FormPage(Directory):
                         filters_dict['filter-user-value'] = str(nameid_users[0].id)
                         request_form['filter-user-value'] = filters_dict['filter-user-value']
                     else:
-                        filters_dict['filter-user-value'] = '-1'
-                        request_form['filter-user-value'] = '-1'
+                        filters_dict['filter-user-value'] = (
+                            '__current__' if name_id == '__current__' else '-1'
+                        )
+                        request_form['filter-user-value'] = (
+                            '__current__' if name_id == '__current__' else '-1'
+                        )
 
             if filter_field.type == 'submission-agent-id':
                 # convert uuid based filter into local id filter
@@ -1904,6 +1914,8 @@ class FormPage(Directory):
                     criterias.append(LessOrEqual('last_update_time', filter_date_value))
                 criterias[-1]._label = '%s: %s' % (filter_field.label, filter_field_value)
             elif filter_field.type == 'user-id':
+                if filter_field_value == '__current__' and get_request().user:
+                    filter_field_value = str(get_request().user.id)
                 criterias.append(Equal('user_id', filter_field_value))
             elif filter_field.type == 'submission-agent-id':
                 criterias.append(Equal('submission_agent_id', filter_field_value))
-- 
2.30.1

