From ba00789dfefaa0ddb9e51bf7660111dfde16305b Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 5 Apr 2019 12:34:04 +0200 Subject: [PATCH] api: export structured items of item and items fields (#32014) It's only exported if the call is signed, it's exported in a new field 'structured_items' to keep signature of 'items'. --- tests/test_api.py | 53 ++++++++++++++++++++++++++++++++++++++++++++--- wcs/api.py | 2 +- wcs/fields.py | 23 +++++++++++++++++++- wcs/formdef.py | 4 ++-- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 0fe8aae7..2c15e93b 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -500,12 +500,32 @@ def test_formdef_schema(pub): FormDef.wipe() formdef = FormDef() formdef.name = 'test' - formdef.fields = [fields.StringField(id='0', label='foobar')] + formdef.fields = [ + fields.StringField(id='0', label='foobar'), + fields.ItemField(id='1', label='foobar1', varname='foobar1', + data_source={ + 'type': 'json', + 'value': 'http://datasource.com', + }), + fields.ItemsField(id='2', label='foobar2', varname='foobar2', + data_source={ + 'type': 'formula', + 'value': '[dict(id=i, text=\'label %s\' % i, foo=i) for i in range(10)]', + }), + ] + formdef.workflow_id = workflow.id formdef.store() - resp = get_app(pub).get('/api/formdefs/test/schema') - resp2 = get_app(pub).get('/test/schema') + with mock.patch('qommon.misc.urlopen') as urlopen: + urlopen.side_effect = lambda *args: StringIO('''\ +{"data": [{"id": 0, "text": "zéro", "foo": "bar"}, \ +{"id": 1, "text": "uné", "foo": "bar1"}, \ +{"id": 2, "text": "deux", "foo": "bar2"}]}''') + resp = get_app(pub).get('/api/formdefs/test/schema') + resp2 = get_app(pub).get('/test/schema') + resp3 = get_app(pub).get(sign_url('/api/formdefs/test/schema?orig=coucou', '1234')) + resp4 = get_app(pub).get(sign_url('/api/formdefs/test/schema?orig=coucou', '1234')) # check schema assert resp.json == resp2.json @@ -522,6 +542,33 @@ def test_formdef_schema(pub): assert resp.json['fields'][0]['label'] == 'foobar' assert resp.json['fields'][0]['type'] == 'string' + assert resp.json['fields'][1]['label'] == 'foobar1' + assert resp.json['fields'][1]['type'] == 'item' + + # check structured items are only exported for authenticated callers + assert resp.json['fields'][1]['items'] == [] + assert resp.json['fields'][2]['items'] == [] + assert 'structured_items' not in resp.json['fields'][1] + assert 'structured_items' not in resp.json['fields'][2] + + assert len(resp3.json['fields'][1]['structured_items']) == 3 + assert resp3.json['fields'][1]['structured_items'][0]['id'] == 0 + assert resp3.json['fields'][1]['structured_items'][0]['text'] == u'zéro' + assert resp3.json['fields'][1]['structured_items'][0]['foo'] == 'bar' + assert resp3.json['fields'][1]['items'][0] == u'zéro' + + assert resp3.json['fields'][2]['label'] == 'foobar2' + assert resp3.json['fields'][2]['type'] == 'items' + assert len(resp3.json['fields'][2]['structured_items']) == 10 + assert resp3.json['fields'][2]['structured_items'][0]['id'] == 0 + assert resp3.json['fields'][2]['structured_items'][0]['text'] == 'label 0' + assert resp3.json['fields'][2]['structured_items'][0]['foo'] == 0 + assert resp3.json['fields'][2]['items'][0] == 'label 0' + + # if structured_items fails no values + assert 'structured_items' not in resp4.json['fields'][1] + assert resp4.json['fields'][1]['items'] == [] + # workflow checks assert len(resp.json['workflow']['statuses']) == 2 assert len(resp.json['workflow']['fields']) == 1 diff --git a/wcs/api.py b/wcs/api.py index bd058309..47d2fdf0 100644 --- a/wcs/api.py +++ b/wcs/api.py @@ -275,7 +275,7 @@ class ApiFormdefDirectory(Directory): def schema(self): get_response().set_content_type('application/json') - return self.formdef.export_to_json() + return self.formdef.export_to_json(anonymise=not is_url_signed()) def submit(self): # expects json as input diff --git a/wcs/fields.py b/wcs/fields.py index 749d65f8..b057acb3 100644 --- a/wcs/fields.py +++ b/wcs/fields.py @@ -186,7 +186,7 @@ class Field(object): def get_admin_attributes(self): return ['label', 'type', 'condition'] - def export_to_json(self, include_id=False): + def export_to_json(self, include_id=False, anonymise=True): field = {} if include_id: extra_fields = ['id'] @@ -1386,6 +1386,17 @@ class ItemField(WidgetField): values.append(display_value) return values + def export_to_json(self, include_id=False, anonymise=True): + field = super(ItemField, self).export_to_json(include_id=include_id, anonymise=anonymise) + if self.data_source and not anonymise: + structured_items = data_sources.get_structured_items(self.data_source) + if structured_items: + field['structured_items'] = structured_items + if not field['items']: + field['items'] = [item['text'] for item in structured_items] + return field + + register_field_class(ItemField) @@ -1548,6 +1559,16 @@ class ItemsField(WidgetField): structured_value.append(structured_option) return structured_value + def export_to_json(self, include_id=False, anonymise=True): + field = super(ItemsField, self).export_to_json(include_id=include_id, anonymise=True) + if self.data_source and not anonymise: + structured_items = data_sources.get_structured_items(self.data_source) + if structured_items: + field['structured_items'] = structured_items + if not field['items']: + field['items'] = [item['text'] for item in structured_items] + return field + register_field_class(ItemsField) diff --git a/wcs/formdef.py b/wcs/formdef.py index a34b033c..10370df8 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -657,7 +657,7 @@ class FormDef(StorableObject): d.update(self.get_field_data(field, widget)) return d - def export_to_json(self, include_id=False, indent=None): + def export_to_json(self, include_id=False, indent=None, anonymise=True): charset = get_publisher().site_charset root = {} root['name'] = unicode(self.name, charset) @@ -691,7 +691,7 @@ class FormDef(StorableObject): root['fields'] = [] if self.fields: for field in self.fields: - root['fields'].append(field.export_to_json(include_id=include_id)) + root['fields'].append(field.export_to_json(include_id=include_id, anonymise=anonymise)) if self.geolocations: root['geolocations'] = self.geolocations.copy() -- 2.20.1