From 9e0915e2530fd7b9c37faaf898a41a23dc46ca07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Mon, 26 Jun 2017 10:16:37 +0200 Subject: [PATCH] json cell: add possibility to retrieve data from multiple URLs (#17185) ex: "metro": { "url": "https://.../stops?identifier=[identifier]", "additional-data": [ {"key": "schedule", "url": "https://.../schedule?stop_identifier=[identifier]" } ] } --- combo/data/models.py | 69 ++++++++++++++++++++++++++++++++++++---------------- tests/test_cells.py | 30 +++++++++++++++++++++++ 2 files changed, 78 insertions(+), 21 deletions(-) diff --git a/combo/data/models.py b/combo/data/models.py index 98a2d01..b738564 100644 --- a/combo/data/models.py +++ b/combo/data/models.py @@ -832,6 +832,14 @@ class JsonCellBase(CellBase): varnames = None force_async = False actions = {} + additional_data = None + # [ + # {'key': ..., + # 'url': ..., + # 'cache_duration': ... (optional) + # }, + # ... + # ] _json_content = None @@ -848,28 +856,43 @@ class JsonCellBase(CellBase): if varname in context['request'].GET and varname not in context: context[varname] = context['request'].GET[varname] self._json_content = None - extra_context['json'] = None - try: - url = utils.get_templated_url(self.url, context) - except utils.UnknownTemplateVariableError: - logger = logging.getLogger(__name__) - logger.warning('unknown variable in template URL (%s)', self.url) - return extra_context - json_response = utils.requests.get(url, - headers={'Accept': 'application/json'}, - remote_service='auto', - cache_duration=self.cache_duration, - without_user=True, - raise_if_not_cached=not(context.get('synchronous')), - invalidate_cache=invalidate_cache, - ) - if json_response.status_code == 200: + + data_urls = [{'key': 'json', 'url': self.url, 'cache_duration': self.cache_duration}] + data_urls.extend(self.additional_data or []) + + for data_url_dict in data_urls: + extra_context[data_url_dict['key']] = None + + for data_url_dict in data_urls: + data_key = data_url_dict['key'] try: - self._json_content = json.loads(json_response.content) - except ValueError: + url = utils.get_templated_url(data_url_dict['url'], context) + except utils.UnknownTemplateVariableError: logger = logging.getLogger(__name__) - logger.error('invalid json content (%s)', url) - extra_context['json'] = self._json_content + logger.warning('unknown variable in template URL (%s)', self.url) + return extra_context + json_response = utils.requests.get(url, + headers={'Accept': 'application/json'}, + remote_service='auto', + cache_duration=data_url_dict.get('cache_duration', self.cache_duration), + without_user=True, + raise_if_not_cached=not(context.get('synchronous')), + invalidate_cache=invalidate_cache, + ) + if json_response.status_code == 200: + try: + extra_context[data_key] = json.loads(json_response.content) + except ValueError: + logger = logging.getLogger(__name__) + logger.error('invalid json content (%s)', url) + break + + # update context with data key so it can be used in future + # templated URLs + context[data_key] = extra_context[data_key] + + self._json_content = extra_context['json'] + return extra_context @property @@ -1004,6 +1027,10 @@ class ConfigJsonCell(JsonCellBase): JsonCellBase.actions) @property + def additional_data(self): + return settings.JSON_CELL_TYPES[self.key].get('additional-data') + + @property def template_name(self): return 'combo/json/%s.html' % self.key @@ -1019,7 +1046,7 @@ class ConfigJsonCell(JsonCellBase): return config_form_class def get_cell_extra_context(self, context, **kwargs): - context.update(self.parameters) # early push for templated URLs + context.update(copy.copy(self.parameters)) # early push for templated URLs ctx = super(ConfigJsonCell, self).get_cell_extra_context(context, **kwargs) ctx['parameters'] = self.parameters ctx.update(self.parameters) diff --git a/tests/test_cells.py b/tests/test_cells.py index 393e8ee..8de44ee 100644 --- a/tests/test_cells.py +++ b/tests/test_cells.py @@ -364,3 +364,33 @@ def test_json_force_async(): assert cell.render(Context({'synchronous': True})) == 'world2' # rerun with stuff in cache assert cell.render(Context({})) == 'world2' + +def test_config_json_cell_additional_url(app): + page = Page(title='example page', slug='index') + page.save() + + with override_settings(JSON_CELL_TYPES={ + 'test-config-json-cell': { + 'name': 'Foobar', + 'url': 'http://foo', + 'additional-data': [ + {'key': 'plop', 'url': 'http://bar'}, + ] + }}, + TEMPLATE_DIRS=['%s/templates-1' % os.path.abspath(os.path.dirname(__file__))]): + cell = ConfigJsonCell() + cell.key = 'test-config-json-cell' + cell.page = page + cell.title = 'Example Site' + cell.order = 0 + cell.save() + + with mock.patch('combo.utils.requests.get') as requests_get: + data = {'data': 'toto'} + requests_get.return_value = mock.Mock(content=json.dumps(data), status_code=200) + url = reverse('combo-public-ajax-page-cell', + kwargs={'page_pk': page.id, 'cell_reference': cell.get_reference()}) + resp = app.get(url) + assert len(requests_get.mock_calls) == 2 + assert requests_get.mock_calls[0][1][0] == 'http://foo' + assert requests_get.mock_calls[1][1][0] == 'http://bar' -- 2.13.1