maps: delegate circle param to geojson service (#41993)

This commit is contained in:
Lauréline Guérin 2020-04-30 10:52:04 +02:00
parent 8aa3fa52fc
commit 87e9957f0b
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
5 changed files with 112 additions and 6 deletions

View File

@ -55,7 +55,7 @@ class MapLayerForm(forms.ModelForm):
else:
todelete_fields = [
'geojson_url', 'marker_colour', 'icon', 'icon_colour', 'cache_duration',
'include_user_identifier', 'properties', 'geojson_query_parameter']
'include_user_identifier', 'properties', 'geojson_query_parameter', 'geojson_accepts_circle_param']
for field in todelete_fields:
if field in self.fields:
del self.fields[field]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('maps', '0013_geojson_query_parameter'),
]
operations = [
migrations.AddField(
model_name='maplayer',
name='geojson_accepts_circle_param',
field=models.BooleanField(default=False, verbose_name='GeoJSON URL accepts a "cirle" parameter'),
),
]

View File

@ -136,6 +136,9 @@ class MapLayer(models.Model):
max_length=100,
blank=True,
help_text=_('Name of the parameter to use for querying the GeoJSON layer (typically, q)'))
geojson_accepts_circle_param = models.BooleanField(
_('GeoJSON URL accepts a "cirle" parameter'),
default=False)
class Meta:
ordering = ('label',)
@ -193,6 +196,19 @@ class MapLayer(models.Model):
req.prepare_url(geojson_url, {'q': request.GET[query_parameter]})
geojson_url = req.url
distance = center_lat = center_lng = None
try:
distance = float(request.GET['distance'])
center_lat = float(request.GET['lat'])
center_lng = float(request.GET['lng'])
distance_params = True
except (ValueError, KeyError):
distance_params = False
if request and self.geojson_accepts_circle_param and distance_params:
req = PreparedRequest()
req.prepare_url(geojson_url, {'circle': '%s,%s,%s' % (center_lng, center_lat, distance)})
geojson_url = req.url
response = requests.get(
geojson_url,
remote_service='auto',
@ -222,10 +238,7 @@ class MapLayer(models.Model):
feature['properties'] = dict(
[x for x in feature['properties'].items() if x[0] in properties])
if request and request.GET.get('distance'):
distance = float(request.GET['distance'])
center_lat = float(request.GET['lat'])
center_lng = float(request.GET['lng'])
if request and not self.geojson_accepts_circle_param and distance_params:
geod = pyproj.Geod(ellps='WGS84')
south_lat = geod.fwd(center_lng, center_lat, 180, distance)[1]
north_lat = geod.fwd(center_lng, center_lat, 0, distance)[1]

View File

@ -8,7 +8,6 @@ from django.contrib.auth.models import User
from django.contrib.auth.models import Group
from django.urls import reverse
from django.test.client import RequestFactory
from django.utils.html import escape
from combo.data.models import Page
from combo.apps.maps.models import MapLayer, Map, MapLayerOptions
@ -363,6 +362,20 @@ def test_get_geojson(app, layer, user):
resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=100')
assert len(json.loads(resp.text)['features']) == 0
# missing params
resp = app.get(geojson_url + '?lat=48.84&distance=10')
assert len(json.loads(resp.text)['features']) == 2
resp = app.get(geojson_url + '?lng=2.54&distance=10')
assert len(json.loads(resp.text)['features']) == 2
# bad params
resp = app.get(geojson_url + '?lng=foo&lat=48.84&distance=10')
assert len(json.loads(resp.text)['features']) == 2
resp = app.get(geojson_url + '?lng=2.54&lat=foo&distance=10')
assert len(json.loads(resp.text)['features']) == 2
resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=foo')
assert len(json.loads(resp.text)['features']) == 2
# check on multiple words
with mock.patch('combo.utils.requests_wrapper.RequestsSession.request') as requests_get:
requests_get.return_value = mock.Mock(
@ -466,6 +479,64 @@ def test_get_geojson_query_parameter(app, layer, user):
assert len(json.loads(resp.text)['features']) == 2
def test_get_geojson_accepts_circle_param(app, layer, user):
page = Page.objects.create(title='xxx', slug='new', template_name='standard')
cell = Map.objects.create(page=page, placeholder='content', order=0, public=True)
layer.geojson_url = 'http://example.org/geojson'
layer.save()
MapLayerOptions.objects.create(map_cell=cell, map_layer=layer)
geojson_url = reverse('mapcell-geojson', kwargs={'cell_id': cell.pk, 'layer_slug': layer.slug})
mock_get = mock.Mock(
content=SAMPLE_GEOJSON_CONTENT,
json=lambda: json.loads(SAMPLE_GEOJSON_CONTENT),
status_code=200)
# circle param not accepted
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url)
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 2
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=1000')
assert len(json.loads(resp.text)['features']) == 1
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 1
# circle param accepted
layer.geojson_accepts_circle_param = True
layer.save()
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url)
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 2
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=1000')
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson?circle=2.54%2C48.84%2C1000.0'
assert len(json.loads(resp.text)['features']) == 2
# missing params
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url + '?lat=48.84&distance=1000')
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 2
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url + '?lng=2.54&distance=1000')
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 2
# bad params
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url + '?lng=foo&lat=48.84&distance=1000')
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 2
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url + '?lng=2.54&lat=foo&distance=1000')
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 2
with mock.patch('combo.utils.requests.get', return_value=mock_get) as requests_get:
resp = app.get(geojson_url + '?lng=2.54&lat=48.84&distance=foo')
assert requests_get.call_args_list[0][0][0] == 'http://example.org/geojson'
assert len(json.loads(resp.text)['features']) == 2
def test_get_geojson_properties(app, layer, user):
page = Page(title='xxx', slug='new', template_name='standard')
page.save()

View File

@ -68,6 +68,7 @@ def test_add_geojson_layer(app, admin_user):
assert resp.form['icon_colour'].value == '#000000'
resp.form['icon_colour'] = '#FFFFFF'
resp.form['geojson_query_parameter'] = 'foobar'
resp.form['geojson_accepts_circle_param'] = True
resp = resp.forms[0].submit()
assert resp.location.endswith('/manage/maps/')
assert MapLayer.objects.count() == 1
@ -75,6 +76,7 @@ def test_add_geojson_layer(app, admin_user):
assert layer.label == 'Test'
assert layer.slug == 'test'
assert layer.geojson_query_parameter == 'foobar'
assert layer.geojson_accepts_circle_param is True
assert layer.kind == 'geojson'
@ -91,6 +93,7 @@ def test_add_tiles_layer(app, admin_user):
assert 'icon_colour' not in resp.context['form'].fields
assert 'properties' not in resp.context['form'].fields
assert 'geojson_query_parameter' not in resp.context['form'].fields
assert 'geojson_accepts_circle_param' not in resp.context['form'].fields
resp.forms[0]['label'] = 'Test'
resp.forms[0]['tiles_template_url'] = 'http://somedomain.com/blabla/{z}/{x}/{y}{r}.png'
resp.forms[0]['tiles_attribution'] = 'Foo bar'