Projet

Général

Profil

0001-opendatasoft-add-facet-filters-50212.patch

Nicolas Roche, 12 avril 2021 12:54

Télécharger (8,4 ko)

Voir les différences:

Subject: [PATCH] opendatasoft: add facet filters (#50212)

 .../migrations/0002_auto_20210409_1143.py     | 33 +++++++++++++++++++
 passerelle/apps/opendatasoft/models.py        |  8 +++++
 tests/test_opendatasoft.py                    | 20 +++++++++++
 3 files changed, 61 insertions(+)
 create mode 100644 passerelle/apps/opendatasoft/migrations/0002_auto_20210409_1143.py
passerelle/apps/opendatasoft/migrations/0002_auto_20210409_1143.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2021-04-09 09:43
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
        ('opendatasoft', '0001_initial'),
12
    ]
13

  
14
    operations = [
15
        migrations.AddField(
16
            model_name='query',
17
            name='filter_expression',
18
            field=models.TextField(
19
                blank=True,
20
                help_text='Specify refine and exclude facet expressions separated by &',
21
                verbose_name='filter',
22
            ),
23
        ),
24
        migrations.AlterField(
25
            model_name='opendatasoft',
26
            name='service_url',
27
            field=models.CharField(
28
                help_text='URL without ending "api/records/1.0/search/"',
29
                max_length=256,
30
                verbose_name='Site URL',
31
            ),
32
        ),
33
    ]
passerelle/apps/opendatasoft/models.py
88 88
        params = {
89 89
            'dataset': dataset,
90 90
            'q': query,
91 91
        }
92 92
        if self.api_key:
93 93
            params.update({'apikey': self.api_key})
94 94
        if limit:
95 95
            params.update({'rows': limit})
96
        params.update(kwargs)  # filter expressions
96 97

  
97 98
        result_response = self.requests.get(url, params=params)
98 99
        err_desc = result_response.json().get('error')
99 100
        if err_desc:
100 101
            return {'err': 1, 'err_desc': err_desc}
101 102

  
102 103
        result = []
103 104
        for record in result_response.json().get('records'):
......
137 138
        help_text=_('dataset to query'),
138 139
    )
139 140
    text_template = models.TextField(
140 141
        verbose_name=_('Text template'),
141 142
        help_text=_("Use Django's template syntax. Attributes can be accessed through {{ attributes.name }}"),
142 143
        validators=[validate_template],
143 144
        blank=True,
144 145
    )
146
    filter_expression = models.TextField(
147
        verbose_name=_('filter'),
148
        help_text=_('Specify refine and exclude facet expressions separated by &'),
149
        blank=True,
150
    )
145 151

  
146 152
    delete_view = 'opendatasoft-query-delete'
147 153
    edit_view = 'opendatasoft-query-edit'
148 154

  
149 155
    def q(self, request, **kwargs):
156
        filters = urlparse.parse_qs(self.filter_expression)
157
        kwargs.update(filters)
150 158
        return self.resource.search(request, dataset=self.dataset, text_template=self.text_template, **kwargs)
151 159

  
152 160
    def as_endpoint(self):
153 161
        endpoint = super(Query, self).as_endpoint(path=self.resource.q.endpoint_info.name)
154 162

  
155 163
        search_endpoint = self.resource.search.endpoint_info
156 164
        endpoint.func = search_endpoint.func
157 165
        endpoint.show_undocumented_params = False
tests/test_opendatasoft.py
140 140
def query(connector):
141 141
    return Query.objects.create(
142 142
        resource=connector,
143 143
        name='Référenciel adresses de test',
144 144
        slug='my_query',
145 145
        description='Rechercher une adresse',
146 146
        dataset='referentiel-adresse-test',
147 147
        text_template='{{numero}} {{nom_rue|safe}} {{nom_commun}}',
148
        filter_expression='refine.source=Ville et Eurométropole de Strasbourg&exclude.numero=42&exclude.numero=43',
148 149
    )
149 150

  
150 151

  
151 152
def test_views(db, admin_user, app, connector):
152 153
    app = login(app)
153 154
    resp = app.get('/opendatasoft/my_connector/', status=200)
154 155
    resp = resp.click('New Query')
155 156
    resp.form['name'] = 'my query'
......
187 188

  
188 189
@mock.patch('passerelle.utils.Request.get')
189 190
def test_search_using_q(mocked_get, app, connector):
190 191
    endpoint = utils.generic_endpoint_url('opendatasoft', 'search', slug=connector.slug)
191 192
    assert endpoint == '/opendatasoft/my_connector/search'
192 193
    params = {
193 194
        'dataset': 'referentiel-adresse-test',
194 195
        'text_template': '{{numero}} {{nom_rue|safe}} {{nom_commun}}',
196
        'refine.source': 'Ville et Eurométropole de Strasbourg',
197
        'exclude.numero': ['42', '43'],
195 198
        'q': "rue de l'aubepine",
196 199
        'rows': 3,
197 200
    }
198 201
    mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_Q_SEARCH, status_code=200)
199 202
    resp = app.get(endpoint, params=params, status=200)
200 203
    assert not resp.json['err']
201 204
    assert len(resp.json['data']) == 3
202 205
    # check order is kept
......
217 220

  
218 221
@mock.patch('passerelle.utils.Request.get')
219 222
def test_search_using_id(mocked_get, app, connector):
220 223
    endpoint = utils.generic_endpoint_url('opendatasoft', 'search', slug=connector.slug)
221 224
    assert endpoint == '/opendatasoft/my_connector/search'
222 225
    params = {
223 226
        'dataset': 'referentiel-adresse-test',
224 227
        'text_template': '{{numero}} {{nom_rue|safe}} {{nom_commun}}',
228
        'refine.source': 'Ville et Eurométropole de Strasbourg',
229
        'exclude.numero': ['42', '43'],
225 230
        'id': '7cafcd5c692773e8b863587b2d38d6be82e023d8',
226 231
    }
227 232
    mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_ID_SEARCH, status_code=200)
228 233
    resp = app.get(endpoint, params=params, status=200)
229 234
    assert len(resp.json['data']) == 1
230 235
    assert resp.json['data'][0]['text'] == "19 RUE DE L'AUBEPINE Lipsheim"
231 236

  
232 237

  
......
234 239
def test_query_q_using_q(mocked_get, app, query):
235 240
    endpoint = '/opendatasoft/my_connector/q/my_query/'
236 241
    params = {
237 242
        'q': "rue de l'aubepine",
238 243
        'rows': 3,
239 244
    }
240 245
    mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_Q_SEARCH, status_code=200)
241 246
    resp = app.get(endpoint, params=params, status=200)
247
    assert mocked_get.call_args[1]['params'] == {
248
        'dataset': 'referentiel-adresse-test',
249
        'q': "rue de l'aubepine",
250
        'apikey': 'my_secret',
251
        'rows': '3',
252
        'refine.source': ['Ville et Eurométropole de Strasbourg'],
253
        'exclude.numero': ['42', '43'],
254
    }
242 255
    assert not resp.json['err']
243 256
    assert len(resp.json['data']) == 3
244 257
    # check order is kept
245 258
    assert [x['id'] for x in resp.json['data']] == [
246 259
        'e00cf6161e52a4c8fe510b2b74d4952036cb3473',
247 260
        '7cafcd5c692773e8b863587b2d38d6be82e023d8',
248 261
        '0984a5e1745701f71c91af73ce764e1f7132e0ff',
249 262
    ]
......
260 273
@mock.patch('passerelle.utils.Request.get')
261 274
def test_query_q_using_id(mocked_get, app, query):
262 275
    endpoint = '/opendatasoft/my_connector/q/my_query/'
263 276
    params = {
264 277
        'id': '7cafcd5c692773e8b863587b2d38d6be82e023d8',
265 278
    }
266 279
    mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_ID_SEARCH, status_code=200)
267 280
    resp = app.get(endpoint, params=params, status=200)
281
    assert mocked_get.call_args[1]['params'] == {
282
        'dataset': 'referentiel-adresse-test',
283
        'q': 'recordid:7cafcd5c692773e8b863587b2d38d6be82e023d8',
284
        'apikey': 'my_secret',
285
        'refine.source': ['Ville et Eurométropole de Strasbourg'],
286
        'exclude.numero': ['42', '43'],
287
    }
268 288
    assert len(resp.json['data']) == 1
269 289
    assert resp.json['data'][0]['text'] == "19 RUE DE L'AUBEPINE Lipsheim"
270 290

  
271 291

  
272 292
def test_opendatasoft_query_unicity(admin_user, app, connector, query):
273 293
    connector2 = OpenDataSoft.objects.create(
274 294
        slug='my_connector2',
275 295
        api_key='my_secret',
276
-