Projet

Général

Profil

0001-query-check-slug-and-name-unicity-in-forms-43002.patch

Lauréline Guérin, 02 juin 2020 15:27

Télécharger (18 ko)

Voir les différences:

Subject: [PATCH] query: check slug and name unicity in forms (#43002)

 passerelle/apps/arcgis/forms.py       | 27 ++++++++++
 passerelle/apps/arcgis/views.py       | 16 ++----
 passerelle/apps/opendatasoft/forms.py | 27 ++++++++++
 passerelle/apps/opendatasoft/views.py | 16 ++----
 passerelle/apps/opengis/forms.py      |  3 +-
 passerelle/apps/opengis/views.py      |  7 +--
 passerelle/base/forms.py              | 24 +++++++++
 tests/test_arcgis.py                  | 72 ++++++++++++++++++++++++++-
 tests/test_opendatasoft.py            | 66 +++++++++++++++++++++++-
 tests/test_opengis.py                 | 65 +++++++++++++++++++++++-
 10 files changed, 292 insertions(+), 31 deletions(-)
 create mode 100644 passerelle/apps/arcgis/forms.py
 create mode 100644 passerelle/apps/opendatasoft/forms.py
passerelle/apps/arcgis/forms.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2020 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from django import forms
18

  
19
from passerelle.base.forms import BaseQueryFormMixin
20
from . import models
21

  
22

  
23
class QueryForm(BaseQueryFormMixin, forms.ModelForm):
24
    class Meta:
25
        model = models.Query
26
        fields = '__all__'
27
        exclude = ['resource']
passerelle/apps/arcgis/views.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from django import forms
18 17
from django.views.generic import UpdateView, CreateView, DeleteView
19 18

  
20 19
from passerelle.base.mixins import ResourceChildViewMixin
21 20

  
22 21
from . import models
23

  
24

  
25
class QueryForm(forms.ModelForm):
26
    class Meta:
27
        model = models.Query
28
        fields = '__all__'
29
        exclude = ['resource']
22
from .forms import QueryForm
30 23

  
31 24

  
32 25
class QueryNew(ResourceChildViewMixin, CreateView):
33 26
    model = models.Query
34 27
    form_class = QueryForm
35 28

  
36
    def form_valid(self, form):
37
        form.instance.resource = self.resource
38
        return super(QueryNew, self).form_valid(form)
29
    def get_form_kwargs(self):
30
        kwargs = super(QueryNew, self).get_form_kwargs()
31
        kwargs['instance'] = self.model(resource=self.resource)
32
        return kwargs
39 33

  
40 34
    def get_changed_url(self):
41 35
        return self.object.get_absolute_url()
passerelle/apps/opendatasoft/forms.py
1
# passerelle - uniform access to multiple data sources and services
2
# Copyright (C) 2020 Entr'ouvert
3
#
4
# This program is free software: you can redistribute it and/or modify it
5
# under the terms of the GNU Affero General Public License as published
6
# by the Free Software Foundation, either version 3 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU Affero General Public License for more details.
13
#
14
# You should have received a copy of the GNU Affero General Public License
15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

  
17
from django import forms
18

  
19
from passerelle.base.forms import BaseQueryFormMixin
20
from . import models
21

  
22

  
23
class QueryForm(BaseQueryFormMixin, forms.ModelForm):
24
    class Meta:
25
        model = models.Query
26
        fields = '__all__'
27
        exclude = ['resource']
passerelle/apps/opendatasoft/views.py
14 14
# You should have received a copy of the GNU Affero General Public License
15 15
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 16

  
17
from django import forms
18 17
from django.views.generic import UpdateView, CreateView, DeleteView
19 18

  
20 19
from passerelle.base.mixins import ResourceChildViewMixin
21 20

  
22 21
from . import models
23

  
24

  
25
class QueryForm(forms.ModelForm):
26
    class Meta:
27
        model = models.Query
28
        fields = '__all__'
29
        exclude = ['resource']
22
from .forms import QueryForm
30 23

  
31 24

  
32 25
class QueryNew(ResourceChildViewMixin, CreateView):
......
34 27
    form_class = QueryForm
35 28
    template_name = "passerelle/manage/resource_child_form.html"
36 29

  
37
    def form_valid(self, form):
38
        form.instance.resource = self.resource
39
        return super(QueryNew, self).form_valid(form)
30
    def get_form_kwargs(self):
31
        kwargs = super(QueryNew, self).get_form_kwargs()
32
        kwargs['instance'] = self.model(resource=self.resource)
33
        return kwargs
40 34

  
41 35

  
42 36
class QueryEdit(ResourceChildViewMixin, UpdateView):
passerelle/apps/opengis/forms.py
19 19
from django import forms
20 20
from django.utils.translation import ugettext_lazy as _
21 21

  
22
from passerelle.base.forms import BaseQueryFormMixin
22 23
from . import models
23 24

  
24 25

  
25
class QueryForm(forms.ModelForm):
26
class QueryForm(BaseQueryFormMixin, forms.ModelForm):
26 27
    class Meta:
27 28
        model = models.Query
28 29
        fields = '__all__'
passerelle/apps/opengis/views.py
26 26
    model = models.Query
27 27
    form_class = QueryForm
28 28

  
29
    def form_valid(self, form):
30
        form.instance.resource = self.resource
31
        return super(QueryNew, self).form_valid(form)
29
    def get_form_kwargs(self):
30
        kwargs = super(QueryNew, self).get_form_kwargs()
31
        kwargs['instance'] = self.model(resource=self.resource)
32
        return kwargs
32 33

  
33 34
    def get_changed_url(self):
34 35
        return self.object.get_absolute_url()
passerelle/base/forms.py
33 33
class ImportSiteForm(forms.Form):
34 34
    site_json = forms.FileField(label=_('Site Export File'))
35 35
    import_users = forms.BooleanField(label=_('Import users and access rights'), required=False)
36

  
37

  
38
class BaseQueryFormMixin(object):
39
    def clean_slug(self):
40
        slug = self.cleaned_data['slug']
41

  
42
        queryset = self.instance.resource.queries.filter(slug=slug)
43
        if self.instance.pk:
44
            queryset = queryset.exclude(pk=self.instance.pk)
45
        if queryset.exists():
46
            raise forms.ValidationError(_('A query with this slug already exists'))
47

  
48
        return slug
49

  
50
    def clean_name(self):
51
        name = self.cleaned_data['name']
52

  
53
        queryset = self.instance.resource.queries.filter(name=name)
54
        if self.instance.pk:
55
            queryset = queryset.exclude(pk=self.instance.pk)
56
        if queryset.exists():
57
            raise forms.ValidationError(_('A query with this name already exists'))
58

  
59
        return name
tests/test_arcgis.py
6 6
import mock
7 7
import utils
8 8

  
9
from django.core.exceptions import ValidationError
9
from django.contrib.auth.models import User
10 10
from django.contrib.contenttypes.models import ContentType
11
from django.core.exceptions import ValidationError
11 12

  
12 13
from passerelle.apps.arcgis.models import ArcGIS, validate_where, SqlFormatter, Query
13 14
from passerelle.base.models import ApiUser, AccessRight
14 15
from passerelle.utils import import_site
15 16

  
17
from test_manager import login
18

  
19
pytestmark = pytest.mark.django_db
20

  
16 21
# from http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/fold/serv/MapServer/1
17 22
STATES = '''{
18 23
   "fieldAliases" : {
......
80 85

  
81 86

  
82 87
@pytest.fixture
83
def arcgis(db):
88
def admin_user():
89
    return User.objects.create_superuser('admin', email=None, password='admin')
90

  
91

  
92
@pytest.fixture
93
def arcgis():
84 94
    return ArcGIS.objects.create(slug='test',
85 95
                                 base_url='https://arcgis.example.net/')
86 96

  
......
417 427
    assert '<span class="param-name">adress</span>' in resp.text
418 428

  
419 429

  
430
def test_arcgis_query_unicity(admin_user, app, arcgis):
431
    query = Query.objects.create(
432
        resource=arcgis,
433
        name='Test Query',
434
        slug='test-query',
435
    )
436

  
437
    arcgis2 = ArcGIS.objects.create(
438
        slug='test2',
439
        base_url='https://arcgis.example.net/')
440
    Query.objects.create(
441
        resource=arcgis2,
442
        name='Foo Bar',
443
        slug='foo-bar',
444
    )
445

  
446
    app = login(app)
447
    resp = app.get('/manage/arcgis/%s/query/new/' % arcgis.slug)
448
    resp.form['slug'] = query.slug
449
    resp.form['name'] = 'Foo Bar'
450
    resp.form['service'] = 'Foo'
451
    resp = resp.form.submit()
452
    assert resp.status_code == 200
453
    assert Query.objects.filter(resource=arcgis).count() == 1
454
    assert 'A query with this slug already exists' in resp.text
455
    resp.form['slug'] = 'foo-bar'
456
    resp.form['name'] = query.name
457
    resp.form['service'] = 'Foo'
458
    resp = resp.form.submit()
459
    assert Query.objects.filter(resource=arcgis).count() == 1
460
    assert resp.status_code == 200
461
    assert 'A query with this name already exists' in resp.text
462
    resp.form['slug'] = 'foo-bar'
463
    resp.form['name'] = 'Foo Bar'
464
    resp.form['service'] = 'Foo'
465
    resp = resp.form.submit()
466
    assert resp.status_code == 302
467
    assert Query.objects.filter(resource=arcgis).count() == 2
468
    new_query = Query.objects.latest('pk')
469
    assert new_query.resource == arcgis
470

  
471
    resp = app.get('/manage/arcgis/%s/query/%s/' % (arcgis.slug, new_query.pk))
472
    resp.form['slug'] = query.slug
473
    resp.form['name'] = 'Foo Bar'
474
    resp = resp.form.submit()
475
    assert resp.status_code == 200
476
    assert 'A query with this slug already exists' in resp.text
477
    resp.form['slug'] = 'foo-bar'
478
    resp.form['name'] = query.name
479
    resp = resp.form.submit()
480
    assert resp.status_code == 200
481
    assert 'A query with this name already exists' in resp.text
482
    resp.form['slug'] = 'foo-bar'
483
    resp.form['name'] = 'Foo Bar'
484
    resp = resp.form.submit()
485
    assert resp.status_code == 302
486

  
487

  
420 488
def test_export_import(query):
421 489
    assert ArcGIS.objects.count() == 1
422 490
    assert Query.objects.count() == 1
tests/test_opendatasoft.py
21 21

  
22 22
import utils
23 23

  
24
from django.contrib.auth.models import User
25

  
24 26
from passerelle.apps.opendatasoft.models import OpenDataSoft, Query
25 27
from passerelle.utils import import_site
26 28

  
27
from test_manager import login, admin_user
29
from test_manager import login
30

  
31
pytestmark = pytest.mark.django_db
28 32

  
29 33

  
30 34
FAKED_CONTENT_Q_SEARCH = json.dumps({
......
155 159

  
156 160

  
157 161
@pytest.fixture
158
def connector(db):
162
def admin_user():
163
    return User.objects.create_superuser('admin', email=None, password='admin')
164

  
165

  
166
@pytest.fixture
167
def connector():
159 168
    return utils.setup_access_rights(OpenDataSoft.objects.create(
160 169
        slug='my_connector',
161 170
        api_key='my_secret',
......
289 298
    resp = app.get(endpoint, params=params, status=200)
290 299
    assert len(resp.json['data']) == 1
291 300
    assert resp.json['data'][0]['text'] == "19 RUE DE L'AUBEPINE Lipsheim"
301

  
302

  
303
def test_opendatasoft_query_unicity(admin_user, app, connector, query):
304
    connector2 = OpenDataSoft.objects.create(
305
        slug='my_connector2',
306
        api_key='my_secret',
307
    )
308
    Query.objects.create(
309
        resource=connector2,
310
        name='Foo Bar',
311
        slug='foo-bar',
312
    )
313

  
314
    app = login(app)
315
    resp = app.get('/manage/opendatasoft/%s/query/new/' % connector.slug)
316
    resp.form['slug'] = query.slug
317
    resp.form['name'] = 'Foo Bar'
318
    resp.form['dataset'] = 'my-dataset'
319
    resp = resp.form.submit()
320
    assert resp.status_code == 200
321
    assert Query.objects.filter(resource=connector).count() == 1
322
    assert 'A query with this slug already exists' in resp.text
323
    resp.form['slug'] = 'foo-bar'
324
    resp.form['name'] = query.name
325
    resp.form['dataset'] = 'my-dataset'
326
    resp = resp.form.submit()
327
    assert Query.objects.filter(resource=connector).count() == 1
328
    assert resp.status_code == 200
329
    assert 'A query with this name already exists' in resp.text
330
    resp.form['slug'] = 'foo-bar'
331
    resp.form['name'] = 'Foo Bar'
332
    resp.form['dataset'] = 'my-dataset'
333
    resp = resp.form.submit()
334
    assert resp.status_code == 302
335
    assert Query.objects.filter(resource=connector).count() == 2
336
    new_query = Query.objects.latest('pk')
337
    assert new_query.resource == connector
338

  
339
    resp = app.get('/manage/opendatasoft/%s/query/%s/' % (connector.slug, new_query.pk))
340
    resp.form['slug'] = query.slug
341
    resp.form['name'] = 'Foo Bar'
342
    resp = resp.form.submit()
343
    assert resp.status_code == 200
344
    assert 'A query with this slug already exists' in resp.text
345
    resp.form['slug'] = 'foo-bar'
346
    resp.form['name'] = query.name
347
    resp = resp.form.submit()
348
    assert resp.status_code == 200
349
    assert 'A query with this name already exists' in resp.text
350
    resp.form['slug'] = 'foo-bar'
351
    resp.form['name'] = 'Foo Bar'
352
    resp = resp.form.submit()
353
    assert resp.status_code == 302
tests/test_opengis.py
2 2
import mock
3 3
import pytest
4 4

  
5
from django.contrib.auth.models import User
5 6
from django.core.management import call_command
6 7

  
7 8
from passerelle.apps.opengis.models import OpenGIS, Query, FeatureCache
8 9
from passerelle.base.models import Job
9 10
from passerelle.utils import import_site
10 11

  
12
from test_manager import login
13

  
11 14
import utils
12 15

  
16
pytestmark = pytest.mark.django_db
17

  
13 18
FAKE_FEATURE_INFO = '''<?xml version="1.0" encoding="UTF-8"?>
14 19
<msGMLOutput
15 20
      xmlns:gml="http://www.opengis.net/gml"
......
314 319

  
315 320

  
316 321
@pytest.fixture
317
def connector(db):
322
def admin_user():
323
    return User.objects.create_superuser('admin', email=None, password='admin')
324

  
325

  
326
@pytest.fixture
327
def connector():
318 328
    return utils.setup_access_rights(OpenGIS.objects.create(
319 329
        slug='test',
320 330
        wms_service_url='http://example.net/wms',
......
805 815
    assert 'extra parameter' in resp.json['err_desc']
806 816

  
807 817

  
818
def test_opengis_query_unicity(admin_user, app, connector, query):
819
    connector2 = OpenGIS.objects.create(
820
        slug='test2',
821
        wms_service_url='http://example.net/wms',
822
        wfs_service_url='http://example.net/wfs')
823
    Query.objects.create(
824
        resource=connector2,
825
        name='Foo Bar',
826
        slug='foo-bar',
827
    )
828

  
829
    app = login(app)
830
    resp = app.get('/manage/opengis/%s/query/new/' % connector.slug)
831
    resp.form['slug'] = query.slug
832
    resp.form['name'] = 'Foo Bar'
833
    resp.form['typename'] = 'foo'
834
    resp = resp.form.submit()
835
    assert resp.status_code == 200
836
    assert Query.objects.filter(resource=connector).count() == 1
837
    assert 'A query with this slug already exists' in resp.text
838
    resp.form['slug'] = 'foo-bar'
839
    resp.form['name'] = query.name
840
    resp.form['typename'] = 'foo'
841
    resp = resp.form.submit()
842
    assert Query.objects.filter(resource=connector).count() == 1
843
    assert resp.status_code == 200
844
    assert 'A query with this name already exists' in resp.text
845
    resp.form['slug'] = 'foo-bar'
846
    resp.form['name'] = 'Foo Bar'
847
    resp.form['typename'] = 'foo'
848
    resp = resp.form.submit()
849
    assert resp.status_code == 302
850
    assert Query.objects.filter(resource=connector).count() == 2
851
    new_query = Query.objects.latest('pk')
852
    assert new_query.resource == connector
853

  
854
    resp = app.get('/manage/opengis/%s/query/%s/' % (connector.slug, new_query.pk))
855
    resp.form['slug'] = query.slug
856
    resp.form['name'] = 'Foo Bar'
857
    resp = resp.form.submit()
858
    assert resp.status_code == 200
859
    assert 'A query with this slug already exists' in resp.text
860
    resp.form['slug'] = 'foo-bar'
861
    resp.form['name'] = query.name
862
    resp = resp.form.submit()
863
    assert resp.status_code == 200
864
    assert 'A query with this name already exists' in resp.text
865
    resp.form['slug'] = 'foo-bar'
866
    resp.form['name'] = 'Foo Bar'
867
    resp = resp.form.submit()
868
    assert resp.status_code == 302
869

  
870

  
808 871
def test_opengis_export_import(query):
809 872
    assert OpenGIS.objects.count() == 1
810 873
    assert Query.objects.count() == 1
811
-