Projet

Général

Profil

0004-add-new-API-api-forms-slug-anonymized-returning-anon.patch

Benjamin Dauvergne, 06 décembre 2015 15:23

Télécharger (5,92 ko)

Voir les différences:

Subject: [PATCH 4/4] add new API /api/forms/<slug>/anonymized returning
 anonymized formdata (#9146)

Service is open to any request which bear a valid signature, no need to
authenticate as a known user. It's also open to authenticated admin users
for debugging.
 tests/test_api.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 wcs/api.py        | 18 ++++++++++++---
 2 files changed, 81 insertions(+), 3 deletions(-)
tests/test_api.py
663 663
        upload = PicklableUpload('test.txt', 'text/plain', 'ascii')
664 664
        upload.receive(['base64me'])
665 665
        formdata.data = {'0': 'FOO BAR %d' % i, '2': upload}
666
        formdata.user_id = local_user.id
666 667
        if i%4 == 0:
667 668
            formdata.data['1'] = 'foo'
668 669
            formdata.data['1_display'] = 'foo'
......
699 700
    assert 'receipt_time' in resp.json[0]
700 701
    assert 'fields' in resp.json[0]
701 702
    assert 'file' not in resp.json[0]['fields'] # no file export in full lists
703
    assert 'user' in resp.json[0]
702 704

  
703 705
    # check filtered results
704 706
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?filter-foobar3=foo', user=local_user))
......
716 718
    resp = get_app(pub).get(sign_uri('/api/forms/test/list?filter=all', user=local_user))
717 719
    assert len(resp.json) == 30
718 720

  
721
def test_api_anonymized_formdata(pub, local_user):
722
    Role.wipe()
723
    role = Role(name='test')
724
    role.store()
725

  
726
    FormDef.wipe()
727
    formdef = FormDef()
728
    formdef.name = 'test'
729
    formdef.workflow_roles = {'_receiver': role.id}
730
    formdef.fields = [
731
        fields.StringField(id='0', label='foobar', varname='foobar'),
732
        fields.ItemField(id='1', label='foobar3', varname='foobar3', type='item',
733
            items=['foo', 'bar', 'baz']),
734
        fields.FileField(id='2', label='foobar4', varname='file'),
735
        ]
736
    formdef.store()
737

  
738
    data_class = formdef.data_class()
739
    data_class.wipe()
740

  
741
    for i in range(30):
742
        formdata = data_class()
743
        date = time.strptime('2014-01-20', '%Y-%m-%d')
744
        upload = PicklableUpload('test.txt', 'text/plain', 'ascii')
745
        upload.receive(['base64me'])
746
        formdata.data = {'0': 'FOO BAR %d' % i, '2': upload}
747
        formdata.user_id = local_user.id
748
        if i%4 == 0:
749
            formdata.data['1'] = 'foo'
750
            formdata.data['1_display'] = 'foo'
751
        elif i%4 == 1:
752
            formdata.data['1'] = 'bar'
753
            formdata.data['1_display'] = 'bar'
754
        else:
755
            formdata.data['1'] = 'baz'
756
            formdata.data['1_display'] = 'baz'
757

  
758
        formdata.just_created()
759
        if i%3 == 0:
760
            formdata.jump_status('new')
761
        else:
762
            formdata.jump_status('finished')
763
        formdata.store()
764

  
765
    # check access is granted even if the user has not the appropriate role
766
    resp = get_app(pub).get(sign_uri('/api/forms/test/anonymized', user=local_user))
767
    assert len(resp.json) == 30
768
    assert 'receipt_time' in resp.json[0]
769
    assert 'fields' in resp.json[0]
770
    assert 'user' not in resp.json[0]
771
    assert 'file' not in resp.json[0]['fields'] # no file export in full lists
772
    assert 'foobar3' in resp.json[0]['fields']
773
    assert 'foobar' not in resp.json[0]['fields']
774

  
775
    # check access is granted event if there is no user
776
    resp = get_app(pub).get(sign_uri('/api/forms/test/anonymized'))
777
    assert len(resp.json) == 30
778
    assert 'receipt_time' in resp.json[0]
779
    assert 'fields' in resp.json[0]
780
    assert 'user' not in resp.json[0]
781
    assert 'file' not in resp.json[0]['fields'] # no file export in full lists
782
    assert 'foobar3' in resp.json[0]['fields']
783
    assert 'foobar' not in resp.json[0]['fields']
784

  
719 785
def test_roles(pub, local_user):
720 786
    Role.wipe()
721 787
    role = Role(name='Hello World')
wcs/api.py
156 156

  
157 157

  
158 158
class ApiFormPage(BackofficeFormPage):
159
    _q_exports = [('list', 'json')] # same as backoffice but restricted to json export
159
    _q_exports = [('list', 'json'), # same as backoffice but restricted to json export
160
                  ('anonymized', 'anonymised'),
161
    ]
160 162

  
161 163
    def __init__(self, component):
162 164
        try:
......
173 175
        if not self.formdef.is_of_concern_for_user(api_user):
174 176
            raise AccessForbiddenError('unsufficient roles')
175 177

  
178
    def anonymised(self):
179
        get_response().set_content_type('application/json')
180
        if (not (get_request().user and get_request().user.is_admin) and
181
            not is_url_signed()):
182
            raise AccessForbiddenError('user not authenticated')
183
        output = [filled.get_json_export_dict(include_files=False, anonymise=True) for filled in
184
                  self.formdef.data_class().select()]
185
        return json.dumps(output,
186
                cls=misc.JSONEncoder,
187
                encoding=get_publisher().site_charset)
188

  
176 189
    def _q_lookup(self, component):
177 190
        # check access for all paths, to block access to formdata that would
178 191
        # otherwise be accessible if the user is the submitter.
......
186 199

  
187 200
class ApiFormsDirectory(Directory):
188 201
    def _q_lookup(self, component):
189
        api_user = get_user_from_api_query_string()
190
        if not api_user:
202
        if not is_url_signed():
191 203
            # grant access to admins, to ease debug
192 204
            if not (get_request().user and get_request().user.is_admin):
193 205
                raise AccessForbiddenError('user not authenticated')
194
-