From 53008981d025219d2173c5f39fac25ab3a88dda6 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 1 Apr 2021 14:33:12 +0200
Subject: [PATCH] opendatasoft: do not escape on template rendering (#52614)

---
 passerelle/apps/opendatasoft/models.py | 7 ++-----
 tests/test_opendatasoft.py             | 6 +++---
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/passerelle/apps/opendatasoft/models.py b/passerelle/apps/opendatasoft/models.py
index 1be003b9..fb5e4d47 100644
--- a/passerelle/apps/opendatasoft/models.py
+++ b/passerelle/apps/opendatasoft/models.py
@@ -11,23 +11,21 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU Affero General Public License for more details.
 #
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from django.db import models
 from django.shortcuts import get_object_or_404
-from django.template import Context, Template
 from django.urls import reverse
-from django.utils.encoding import force_text
 from django.utils.six.moves.urllib import parse as urlparse
 from django.utils.translation import ugettext_lazy as _
 
-from passerelle.utils.templates import validate_template
+from passerelle.utils.templates import render_to_string, validate_template
 from passerelle.base.models import BaseResource, BaseQuery
 from passerelle.utils.api import endpoint
 
 
 class OpenDataSoft(BaseResource):
     service_url = models.CharField(
         _('Site URL'),
         max_length=256,
@@ -100,18 +98,17 @@ class OpenDataSoft(BaseResource):
             return {'err': 1, 'err_desc': err_desc}
 
         result = []
         for record in result_response.json().get('records'):
             data = {}
             for key, value in record.get('fields').items():
                 data[key] = value
             data['id'] = record.get('recordid')
-            template = Template(text_template)
-            data['text'] = template.render(Context(data)).strip()
+            data['text'] = render_to_string(text_template, data).strip()
             result.append(data)
 
         return {'data': result}
 
     @endpoint(
         name='q',
         description=_('Query'),
         pattern=r'^(?P<query_slug>[\w:_-]+)/$',
diff --git a/tests/test_opendatasoft.py b/tests/test_opendatasoft.py
index 1f435235..bb272a26 100644
--- a/tests/test_opendatasoft.py
+++ b/tests/test_opendatasoft.py
@@ -139,17 +139,17 @@ def connector():
 @pytest.fixture
 def query(connector):
     return Query.objects.create(
         resource=connector,
         name='Référenciel adresses de test',
         slug='my_query',
         description='Rechercher une adresse',
         dataset='referentiel-adresse-test',
-        text_template='{{numero}} {{nom_rue|safe}} {{nom_commun}}',
+        text_template='{{numero}} {{nom_rue}} {{nom_commun}}',
     )
 
 
 def test_views(db, admin_user, app, connector):
     app = login(app)
     resp = app.get('/opendatasoft/my_connector/', status=200)
     resp = resp.click('New Query')
     resp.form['name'] = 'my query'
@@ -186,17 +186,17 @@ def test_search_empty_contents(mocked_get, app, connector):
 
 
 @mock.patch('passerelle.utils.Request.get')
 def test_search_using_q(mocked_get, app, connector):
     endpoint = utils.generic_endpoint_url('opendatasoft', 'search', slug=connector.slug)
     assert endpoint == '/opendatasoft/my_connector/search'
     params = {
         'dataset': 'referentiel-adresse-test',
-        'text_template': '{{numero}} {{nom_rue|safe}} {{nom_commun}}',
+        'text_template': '{{numero}} {{nom_rue}} {{nom_commun}}',
         'q': "rue de l'aubepine",
         'rows': 3,
     }
     mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_Q_SEARCH, status_code=200)
     resp = app.get(endpoint, params=params, status=200)
     assert not resp.json['err']
     assert len(resp.json['data']) == 3
     # check order is kept
@@ -216,17 +216,17 @@ def test_search_using_q(mocked_get, app, connector):
 
 
 @mock.patch('passerelle.utils.Request.get')
 def test_search_using_id(mocked_get, app, connector):
     endpoint = utils.generic_endpoint_url('opendatasoft', 'search', slug=connector.slug)
     assert endpoint == '/opendatasoft/my_connector/search'
     params = {
         'dataset': 'referentiel-adresse-test',
-        'text_template': '{{numero}} {{nom_rue|safe}} {{nom_commun}}',
+        'text_template': '{{numero}} {{nom_rue}} {{nom_commun}}',
         'id': '7cafcd5c692773e8b863587b2d38d6be82e023d8',
     }
     mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_ID_SEARCH, status_code=200)
     resp = app.get(endpoint, params=params, status=200)
     assert len(resp.json['data']) == 1
     assert resp.json['data'][0]['text'] == "19 RUE DE L'AUBEPINE Lipsheim"
 
 
-- 
2.30.2

