base_adresse: add parameter type=housenumber to prevent users from picking street addresses (#76376)
gitea/passerelle/pipeline/head This commit looks good
Details
gitea/passerelle/pipeline/head This commit looks good
Details
This commit is contained in:
parent
8e215185ec
commit
84cd51957e
|
@ -125,10 +125,24 @@ class BaseAdresse(AddressResource):
|
||||||
'Prioritize results according to coordinates. "lat" parameter must also be present.'
|
'Prioritize results according to coordinates. "lat" parameter must also be present.'
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
'type': {
|
||||||
|
'description': _(
|
||||||
|
'Type of address to return, housenumber, street, locality, municipality or all. Default is all.'
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def addresses(
|
def addresses(
|
||||||
self, request, id=None, q=None, zipcode='', citycode=None, lat=None, lon=None, page_limit=5
|
self,
|
||||||
|
request,
|
||||||
|
id=None,
|
||||||
|
q=None,
|
||||||
|
zipcode='',
|
||||||
|
citycode=None,
|
||||||
|
lat=None,
|
||||||
|
lon=None,
|
||||||
|
page_limit=5,
|
||||||
|
type=None,
|
||||||
):
|
):
|
||||||
if id is not None:
|
if id is not None:
|
||||||
return self.get_by_id(request, id=id, citycode=citycode)
|
return self.get_by_id(request, id=id, citycode=citycode)
|
||||||
|
@ -156,6 +170,8 @@ class BaseAdresse(AddressResource):
|
||||||
if self.latitude and self.longitude or lat and lon:
|
if self.latitude and self.longitude or lat and lon:
|
||||||
query_args['lat'] = lat or self.latitude
|
query_args['lat'] = lat or self.latitude
|
||||||
query_args['lon'] = lon or self.longitude
|
query_args['lon'] = lon or self.longitude
|
||||||
|
if type in ('housenumber', 'street', 'locality', 'municipality'):
|
||||||
|
query_args['type'] = type
|
||||||
query = urlencode(query_args)
|
query = urlencode(query_args)
|
||||||
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
|
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
|
||||||
|
|
||||||
|
@ -167,7 +183,8 @@ class BaseAdresse(AddressResource):
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for feature in result_response.json().get('features'):
|
features = result_response.json().get('features')
|
||||||
|
for feature in features:
|
||||||
if not feature['geometry']['type'] == 'Point':
|
if not feature['geometry']['type'] == 'Point':
|
||||||
continue # skip unknown
|
continue # skip unknown
|
||||||
data = self.format_address_data(feature)
|
data = self.format_address_data(feature)
|
||||||
|
@ -177,7 +194,6 @@ class BaseAdresse(AddressResource):
|
||||||
)
|
)
|
||||||
if not created:
|
if not created:
|
||||||
address.update_timestamp()
|
address.update_timestamp()
|
||||||
|
|
||||||
return {'data': result}
|
return {'data': result}
|
||||||
|
|
||||||
def get_by_id(self, request, id, citycode=None):
|
def get_by_id(self, request, id, citycode=None):
|
||||||
|
@ -236,13 +252,25 @@ class BaseAdresse(AddressResource):
|
||||||
'Prioritize results according to coordinates. "lon" parameter must be present.'
|
'Prioritize results according to coordinates. "lon" parameter must be present.'
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
'type': {
|
||||||
|
'description': _(
|
||||||
|
'Type of address to return, housenumber, street, locality, municipality or all. Default is all.'
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def search(self, request, q, zipcode='', citycode=None, lat=None, lon=None, **kwargs):
|
def search(self, request, q, zipcode='', citycode=None, lat=None, lon=None, type=None, **kwargs):
|
||||||
if kwargs.get('format', 'json') != 'json':
|
if kwargs.get('format', 'json') != 'json':
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
result = self.addresses(
|
result = self.addresses(
|
||||||
request, q=q, zipcode=zipcode, citycode=citycode, lat=lat, lon=lon, page_limit=1
|
request,
|
||||||
|
q=q,
|
||||||
|
zipcode=zipcode,
|
||||||
|
citycode=citycode,
|
||||||
|
lat=lat,
|
||||||
|
lon=lon,
|
||||||
|
page_limit=1,
|
||||||
|
type=type,
|
||||||
)
|
)
|
||||||
return result['data']
|
return result['data']
|
||||||
|
|
||||||
|
@ -251,15 +279,23 @@ class BaseAdresse(AddressResource):
|
||||||
parameters={
|
parameters={
|
||||||
'lat': {'description': _('Latitude'), 'example_value': 48.833708},
|
'lat': {'description': _('Latitude'), 'example_value': 48.833708},
|
||||||
'lon': {'description': _('Longitude'), 'example_value': 2.323349},
|
'lon': {'description': _('Longitude'), 'example_value': 2.323349},
|
||||||
|
'type': {
|
||||||
|
'description': _(
|
||||||
|
'Type of address to return, housenumber, street, locality, municipality or all. Default is all.'
|
||||||
|
)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def reverse(self, request, lat, lon, **kwargs):
|
def reverse(self, request, lat, lon, type=None, **kwargs):
|
||||||
if kwargs.get('format', 'json') != 'json':
|
if kwargs.get('format', 'json') != 'json':
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
scheme, netloc, path, params, query, fragment = urlparse.urlparse(self.service_url)
|
scheme, netloc, path, params, query, fragment = urlparse.urlparse(self.service_url)
|
||||||
path = urlparse.urljoin(path, 'reverse/')
|
path = urlparse.urljoin(path, 'reverse/')
|
||||||
query = urlencode({'lat': lat, 'lon': lon})
|
query_dict = {'lat': lat, 'lon': lon}
|
||||||
|
if type in ('housenumber', 'street', 'locality', 'municipality'):
|
||||||
|
query_dict['type'] = type
|
||||||
|
query = urlencode(query_dict)
|
||||||
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
|
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -211,6 +211,21 @@ def test_base_adresse_search(mocked_get, app, base_adresse):
|
||||||
assert data['display_name'] == 'Rue Roger Halope 49000 Angers'
|
assert data['display_name'] == 'Rue Roger Halope 49000 Angers'
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch('passerelle.utils.Request.get')
|
||||||
|
def test_base_adresse_search_type_housenumber(mocked_get, app, base_adresse):
|
||||||
|
endpoint = tests.utils.generic_endpoint_url('base-adresse', 'search', slug=base_adresse.slug)
|
||||||
|
mocked_get.return_value = tests.utils.FakedResponse(content=FAKED_CONTENT, status_code=200)
|
||||||
|
app.get(endpoint, params={'q': 'plop'}, status=200)
|
||||||
|
assert 'type=' not in mocked_get.call_args[0][0]
|
||||||
|
|
||||||
|
for type in ['housenumber', 'street', 'locality', 'municipality']:
|
||||||
|
app.get(endpoint, params={'q': 'plop', 'type': type}, status=200)
|
||||||
|
assert f'type={type}' in mocked_get.call_args[0][0]
|
||||||
|
|
||||||
|
app.get(endpoint, params={'q': 'plop', 'type': 'foo'}, status=200)
|
||||||
|
assert 'type=foo' not in mocked_get.call_args[0][0]
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('passerelle.utils.Request.get')
|
@mock.patch('passerelle.utils.Request.get')
|
||||||
def test_base_adresse_search_limit_to_200(mocked_get, app, base_adresse):
|
def test_base_adresse_search_limit_to_200(mocked_get, app, base_adresse):
|
||||||
endpoint = tests.utils.generic_endpoint_url('base-adresse', 'search', slug=base_adresse.slug)
|
endpoint = tests.utils.generic_endpoint_url('base-adresse', 'search', slug=base_adresse.slug)
|
||||||
|
@ -366,6 +381,18 @@ def test_base_adresse_reverse_path(mocked_get, app, base_adresse):
|
||||||
assert mocked_get.call_args[0][0].startswith('http://example.net/path/reverse/?')
|
assert mocked_get.call_args[0][0].startswith('http://example.net/path/reverse/?')
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch('passerelle.utils.Request.get')
|
||||||
|
def test_base_adresse_reverse_type_housenumber(mocked_get, app, base_adresse):
|
||||||
|
mocked_get.return_value = tests.utils.FakedResponse(content=json.dumps({'features': []}), status_code=200)
|
||||||
|
app.get('/base-adresse/%s/reverse?lon=-0.593775&lat=47.474633' % base_adresse.slug)
|
||||||
|
assert 'type=' not in mocked_get.call_args[0][0]
|
||||||
|
app.get('/base-adresse/%s/reverse?lon=-0.593775&lat=47.474633&type=truc' % base_adresse.slug)
|
||||||
|
assert 'type=' not in mocked_get.call_args[0][0]
|
||||||
|
for type in ['housenumber', 'street', 'locality', 'municipality']:
|
||||||
|
app.get(f'/base-adresse/%s/reverse?lon=-0.593775&lat=47.474633&type={type}' % base_adresse.slug)
|
||||||
|
assert f'type={type}' in mocked_get.call_args[0][0]
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('passerelle.utils.Request.get')
|
@mock.patch('passerelle.utils.Request.get')
|
||||||
def test_base_adresse_reverse_api_timeout(mocked_get, app, base_adresse):
|
def test_base_adresse_reverse_api_timeout(mocked_get, app, base_adresse):
|
||||||
mocked_get.side_effect = ConnectionError('Remote end closed connection without response')
|
mocked_get.side_effect = ConnectionError('Remote end closed connection without response')
|
||||||
|
|
Loading…
Reference in New Issue