From 61a0c9f8191edc1157af4a4c7719f675e9ed6060 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sat, 29 Oct 2022 14:54:07 +0200 Subject: [PATCH 1/2] api: apply named ds parameters on autocomplete results (#39723) --- tests/form_pages/test_all.py | 38 ++++++++++++++++++++++++++++++++---- wcs/api.py | 28 +++++++++----------------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/tests/form_pages/test_all.py b/tests/form_pages/test_all.py index 2006f3f51..750aab810 100644 --- a/tests/form_pages/test_all.py +++ b/tests/form_pages/test_all.py @@ -6660,7 +6660,7 @@ def test_item_field_autocomplete_json_source(http_requests, pub, error_email, em resp2 = app.get(select2_url + '?q=hell') assert len(rsps.calls) == 1 assert rsps.calls[-1].request.url == 'http://remote.example.net/json?q=hell' - assert resp2.json == data + assert resp2.json == dict(data, err=0) # check unauthorized access resp2 = get_app(pub).get(select2_url + '?q=hell', status=403) @@ -6680,7 +6680,7 @@ def test_item_field_autocomplete_json_source(http_requests, pub, error_email, em resp2 = app.get(select2_url + '?q=hell') assert len(rsps.calls) == 1 assert rsps.calls[-1].request.url == 'http://remote.example.net/json?q=hell' - assert resp2.json == {'data': [], 'err': '1'} + assert resp2.json == {'data': [], 'err': 1} assert emails.count() == 0 data_source.notify_on_errors = True @@ -6739,7 +6739,7 @@ def test_item_field_autocomplete_json_source(http_requests, pub, error_email, em resp2 = app.get(select2_url + '?q=hell') assert len(rsps.calls) == 1 assert rsps.calls[-1].request.url == 'http://remote.example.net/json-numeric-id?q=hell' - assert resp2.json == data + assert resp2.json == dict(data, err=0) # check unauthorized access resp2 = get_app(pub).get(select2_url + '?q=hell', status=403) @@ -6795,7 +6795,7 @@ remote.example.net = 1234 assert rsps.calls[-1].request.url.startswith( 'http://remote.example.net/json?q=hell&orig=example.net&' ) - assert resp2.json == data + assert resp2.json == dict(data, err=0) # simulate select2 mode, with qommon.forms.js adding an extra hidden widget resp.form.fields['f0_display'] = Hidden(form=resp.form, tag='input', name='f0_display', pos=10) @@ -6862,6 +6862,36 @@ remote.example.net = 1234 resp2 = app.get(select2_url + '?q=hell', status=403) assert len(rsps.calls) == 0 + # check with data, id and text attribute + data_source.data_source = {'type': 'json', 'value': 'http://remote.example.net/json'} + data_source.data_attribute = 'x.results' + data_source.id_attribute = 'key' + data_source.text_attribute = 'value' + data_source.store() + + formdef.data_class().wipe() + + app = get_app(pub) + with responses.RequestsMock() as rsps: + resp = app.get('/test/') + pq = resp.pyquery.remove_namespaces() + select2_url = pq('select').attr['data-select2-url'] + + with responses.RequestsMock() as rsps: + data = { + 'x': { + 'results': [ + {'key': '1', 'value': 'hello', 'extra': 'foo'}, + ] + } + } + normalized_data = { + 'data': [{'id': '1', 'text': 'hello', 'extra': 'foo', 'key': '1', 'value': 'hello'}] + } + rsps.get('http://remote.example.net/json', json=data) + resp2 = app.get(select2_url + '?q=hell') + assert resp2.json == dict(normalized_data, err=0) + def test_item_field_autocomplete_jsonp_source(http_requests, pub): create_user(pub) diff --git a/wcs/api.py b/wcs/api.py index 8eabd3240..dedb6f2b7 100644 --- a/wcs/api.py +++ b/wcs/api.py @@ -36,6 +36,7 @@ from wcs.conditions import Condition, ValidationError from wcs.ctl.hobo_notify import CmdHoboNotify from wcs.data_sources import NamedDataSource from wcs.data_sources import get_object as get_data_source_object +from wcs.data_sources import request_json_items from wcs.formdef import FormDef from wcs.forms.common import FormStatusPage from wcs.qommon import get_cfg @@ -48,12 +49,7 @@ from .backoffice.management import FormPage as BackofficeFormPage from .backoffice.management import ManagementDirectory from .backoffice.submission import SubmissionDirectory from .qommon import _, misc -from .qommon.errors import ( - AccessForbiddenError, - ConnectionError, - TraversalError, - UnknownNameIdAccessForbiddenError, -) +from .qommon.errors import AccessForbiddenError, TraversalError, UnknownNameIdAccessForbiddenError from .qommon.form import ComputedExpressionWidget from .qommon.storage import Contains, Equal, Intersects, NotContains, Or, StrictNotEqual from .qommon.template import Template, TemplateError @@ -1190,23 +1186,17 @@ class AutocompleteDirectory(Directory): info = token.context if 'url' in info: + named_data_source = None + if info.get('data_source'): + named_data_source = NamedDataSource.get(info['data_source']) url = info['url'] url += urllib.parse.quote(get_request().form.get('q', '')) url = sign_url_auto_orig(url) get_response().set_content_type('application/json') - try: - return misc.urlopen(url).read() - except ConnectionError as e: - if 'data_source' in info: - error_summary = 'Error loading JSON data source (%s)' % str(e) - data_source = NamedDataSource.get(info['data_source']) - get_publisher().record_error( - error_summary, - context='[DATASOURCE]', - notify=data_source.notify_on_errors, - record=data_source.record_on_errors, - ) - return json.dumps({'data': [], 'err': '1'}) + entries = request_json_items(url, named_data_source and named_data_source.extended_data_source) + if entries is not None: + return json.dumps({'err': 0, 'data': entries}) + return json.dumps({'err': 1, 'data': []}) # carddef_ref in info carddef_ref = info['carddef_ref'] -- 2.37.2