Projet

Général

Profil

0001-api-add-possibility-of-ignoring-roles-to-api-forms-2.patch

Frédéric Péters, 20 novembre 2018 21:48

Télécharger (8,01 ko)

Voir les différences:

Subject: [PATCH] api: add possibility of ignoring roles to /api/forms/
 (#28201)

 tests/test_api.py            | 50 ++++++++++++++++++++++++++++++++----
 wcs/api.py                   | 31 +++++++++++++++++++---
 wcs/backoffice/management.py | 14 ++++++----
 3 files changed, 82 insertions(+), 13 deletions(-)
tests/test_api.py
1742 1742
    assert len(resp.json['features']) == 20
1743 1743

  
1744 1744
def test_api_global_listing(pub, local_user):
1745
    if not pub.is_using_postgresql():
1746
        resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user), status=404)
1747
        pytest.skip('this requires SQL')
1748
        return
1749

  
1745 1750
    Role.wipe()
1746 1751
    role = Role(name='test')
1747 1752
    role.store()
......
1772 1777
            formdata.jump_status('finished')
1773 1778
        formdata.store()
1774 1779

  
1775
    if not pub.is_using_postgresql():
1776
        resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user), status=404)
1777
        pytest.skip('this requires SQL')
1778
        return
1779

  
1780 1780
    # check empty content if user doesn't have the appropriate role
1781 1781
    resp = get_app(pub).get(sign_uri('/api/forms/', user=local_user))
1782 1782
    assert len(resp.json['data']) == 0
......
1793 1793
    resp = get_app(pub).get(sign_uri('/api/forms/?status=done', user=local_user))
1794 1794
    assert len(resp.json['data']) == 20
1795 1795

  
1796
def test_api_global_listing_ignored_roles(pub, local_user):
1797
    test_api_global_listing(pub, local_user)
1798

  
1799
    role = Role(name='test2')
1800
    role.store()
1801

  
1802
    formdef = FormDef()
1803
    formdef.name = 'test2'
1804
    formdef.workflow_roles = {'_receiver': role.id}
1805
    formdef.fields = [
1806
        fields.StringField(id='0', label='foobar', varname='foobar'),
1807
        ]
1808
    formdef.store()
1809

  
1810
    data_class = formdef.data_class()
1811
    data_class.wipe()
1812

  
1813
    for i in range(10):
1814
        formdata = data_class()
1815
        date = time.strptime('2014-01-20', '%Y-%m-%d')
1816
        formdata.data = {'0': 'FOO BAR'}
1817
        formdata.user_id = local_user.id
1818
        formdata.just_created()
1819
        formdata.jump_status('new')
1820
        formdata.store()
1821

  
1822
    # considering roles
1823
    resp = get_app(pub).get(sign_uri('/api/forms/?status=all&limit=100', user=local_user))
1824
    assert len(resp.json['data']) == 30
1825

  
1826
    # ignore roles
1827
    resp = get_app(pub).get(sign_uri('/api/forms/?status=all&limit=100&ignore-roles=on', user=local_user))
1828
    assert len(resp.json['data']) == 40
1829

  
1830
    # check sensitive forms are not exposed
1831
    formdef.skip_from_360_view = True
1832
    formdef.store()
1833
    resp = get_app(pub).get(sign_uri('/api/forms/?status=all&limit=100&ignore-roles=on', user=local_user))
1834
    assert len(resp.json['data']) == 30
1835

  
1796 1836
@pytest.fixture
1797 1837
def ics_data(local_user):
1798 1838
    Role.wipe()
wcs/api.py
195 195
            # grant access to admins, to ease debug
196 196
            if not (get_request().user and get_request().user.is_admin):
197 197
                raise AccessForbiddenError('user not authenticated')
198
            if get_request().form.get('ignore-roles') == 'on' and not get_request().user.can_go_in_backoffice():
199
                raise AccessForbiddenError('user not allowed to ignore roles')
198 200

  
199 201
    def _q_index(self):
200 202
        if not get_publisher().is_using_postgresql():
......
207 209

  
208 210
        management_directory = ManagementDirectory()
209 211
        criterias = management_directory.get_global_listing_criterias()
212
        if get_request().form.get('ignore-roles') == 'on':
213
            roles_criterias = criterias
214
            criterias = management_directory.get_global_listing_criterias(ignore_user_roles=True)
210 215

  
211 216
        limit = int(get_request().form.get('limit',
212 217
            get_publisher().get_site_option('default-page-size') or 20))
......
214 219
        order_by = get_request().form.get('order_by',
215 220
            get_publisher().get_site_option('default-sort-order') or '-receipt_time')
216 221

  
217
        output = [get_formdata_dict(x, user=get_request().user, consider_status_visibility=False)
218
                  for x in sql.AnyFormData.select(
219
                      criterias, order_by=order_by, limit=limit, offset=offset)]
222
        formdatas = sql.AnyFormData.select(criterias, order_by=order_by, limit=limit, offset=offset)
223
        if get_request().form.get('ignore-roles') == 'on':
224
            # When ignoring roles formdatas will be returned even if they are
225
            # not readable by the user, an additional attribute (readable) is
226
            # added to differentiate readable and non-readable formdatas.
227
            #
228
            # A full SQL query is run as it will benefit from cached
229
            # concerned_roles/action_roles.
230
            limited_formdatas = [(x.formdef.id, x.id) for x in sql.AnyFormData.select(
231
                    roles_criterias, order_by=order_by, limit=limit, offset=offset)]
232
            output = []
233
            for formdata in formdatas:
234
                readable = bool((formdata.formdef.id, formdata.id) in limited_formdatas)
235
                if not readable and formdata.formdef.skip_from_360_view:
236
                    continue
237
                formdata_dict = get_formdata_dict(formdata,
238
                        user=get_request().user,
239
                        consider_status_visibility=False)
240
                formdata_dict['readable'] = readable
241
                output.append(formdata_dict)
242
        else:
243
            output = [get_formdata_dict(x, user=get_request().user, consider_status_visibility=False)
244
                      for x in formdatas]
220 245

  
221 246
        get_response().set_content_type('application/json')
222 247
        return json.dumps({'data': output},
wcs/backoffice/management.py
765 765
        r += htmltext('</ul>')
766 766
        return r.getvalue()
767 767

  
768
    def get_global_listing_criterias(self):
768
    def get_global_listing_criterias(self, ignore_user_roles=False):
769 769
        parsed_values = {}
770 770
        user_roles = [logged_users_role().id]
771 771
        if get_request().user and get_request().user.roles:
......
782 782
            status = 'open'
783 783
        if status == 'waiting':
784 784
            criterias.append(Equal('is_at_endpoint', False))
785
            criterias.append(Intersects('actions_roles_array', user_roles))
785
            if not ignore_user_roles:
786
                criterias.append(Intersects('actions_roles_array', user_roles))
786 787
        elif status == 'open':
787 788
            criterias.append(Equal('is_at_endpoint', False))
788
            criterias.append(Intersects('concerned_roles_array', user_roles))
789
            if not ignore_user_roles:
790
                criterias.append(Intersects('concerned_roles_array', user_roles))
789 791
        elif status == 'done':
790 792
            criterias.append(Equal('is_at_endpoint', True))
791
            criterias.append(Intersects('concerned_roles_array', user_roles))
793
            if not ignore_user_roles:
794
                criterias.append(Intersects('concerned_roles_array', user_roles))
792 795
        elif status == 'all':
793
            criterias.append(Intersects('concerned_roles_array', user_roles))
796
            if not ignore_user_roles:
797
                criterias.append(Intersects('concerned_roles_array', user_roles))
794 798
        if get_request().form.get('submission_channel'):
795 799
            if get_request().form.get('submission_channel') == 'web':
796 800
                criterias.append(Null('submission_channel'))
797
-