def test_geonames_add_bbox(self): in_result = { "type": "Feature", "geometry": {"type": "Point", "coordinates": [102.18947, 17.77036]}, "properties": { "id": "1608462", "gid": "geonames:locality:1608462", "layer": "locality", "source": "geonames", "source_id": "1608462", "name": "Nam Som", "confidence": 0.957, "accuracy": "centroid", "country": "Thailand", "country_gid": "whosonfirst:country:85632293", "country_a": "THA", "region": "Udon Thani", "region_gid": "whosonfirst:region:85678869", "county": "Nam Som", "county_gid": "whosonfirst:county:1108731585", "locality": "Nam Som", "locality_gid": "geonames:locality:1608462", "label": "Nam Som, Thailand", }, } geocode = Geocode() result = geocode.add_bbox(in_result) self.assertEqual(result, in_result)
def geocode(request): geocode = Geocode() if request.GET.get('search'): result = geocode.search(request.GET.get('search')) return HttpResponse(content=json.dumps(result), status=200, content_type="application/json") if request.GET.get('result'): result = geocode.add_bbox(json.loads(request.GET.get('result'))) return HttpResponse(content=json.dumps(result), status=200, content_type="application/json") else: return HttpResponse(status=204, content_type="application/json")
def test_pelias_add_bbox(self): in_result = { "type": "Feature", "geometry": {"type": "Point", "coordinates": [102.18947, 17.77036]}, "properties": {"id": "1608462", "gid": "geonames:locality:1608462", "layer": "locality", "source": "geonames", "source_id": "1608462", "name": "Nam Som", "confidence": 0.957, "accuracy": "centroid", "country": "Thailand", "country_gid": "whosonfirst:country:85632293", "country_a": "THA", "region": "Udon Thani", "region_gid": "whosonfirst:region:85678869", "county": "Nam Som", "county_gid": "whosonfirst:county:1108731585", "locality": "Nam Som", "locality_gid": "geonames:locality:1608462", "label": "Nam Som, Thailand" } } api_response = { "geocoding": { "version": "0.2", "attribution": "/v1/attribution", "query": { "ids": [{"source": "whosonfirst", "layer": "county", "id": "1108731585"}], "private": False, "lang": {"name": "English", "iso6391": "en", "iso6393": "eng", "defaulted": False} }, "engine": { "name": "Pelias", "author": "Mapzen", "version": "1.0" }, "timestamp": 1510925466405 }, "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Point", "coordinates": [102.227634, 17.743244] }, "properties": { "id": "1108731585", "gid": "whosonfirst:county:1108731585", "layer": "county", "source": "whosonfirst", "source_id": "1108731585", "name": "Nam Som", "accuracy": "centroid", "country": "Thailand", "country_gid": "whosonfirst:country:85632293", "country_a": "THA", "region": "Udon Thani", "region_gid": "whosonfirst:region:85678869", "county": "Nam Som", "county_gid": "whosonfirst:county:1108731585", "label": "Nam Som, Thailand" }, "bbox": [102.020749821, 17.6291659858, 102.33623593, 17.8795015544] } ], "bbox": [102.020749821, 17.6291659858, 102.33623593, 17.8795015544] } self.mock_requests.get(settings.GEOCODING_UPDATE_URL, text=json.dumps(api_response), status_code=200) expected_bbox = api_response.get('bbox') geocode = Geocode() result = geocode.add_bbox(in_result) self.assertEqual(result.get('type'), 'Feature') self.assertEqual(result.get('bbox'), expected_bbox) self.assertEqual(result.get('properties').get('bbox'), expected_bbox)
def test_geonames_add_bbox(self): in_result = { "type": "Feature", "geometry": {"type": "Point", "coordinates": [102.18947, 17.77036]}, "properties": {"id": "1608462", "gid": "geonames:locality:1608462", "layer": "locality", "source": "geonames", "source_id": "1608462", "name": "Nam Som", "confidence": 0.957, "accuracy": "centroid", "country": "Thailand", "country_gid": "whosonfirst:country:85632293", "country_a": "THA", "region": "Udon Thani", "region_gid": "whosonfirst:region:85678869", "county": "Nam Som", "county_gid": "whosonfirst:county:1108731585", "locality": "Nam Som", "locality_gid": "geonames:locality:1608462", "label": "Nam Som, Thailand" } } geocode = Geocode() result = geocode.add_bbox(in_result) self.assertEqual(result, in_result)
def geocode_test(self, api_response): self.mock_requests.get(settings.GEOCODING_API_URL, text=json.dumps(api_response), status_code=200) geocode = Geocode() result = geocode.search("test") self.assertIsNotNone(result.get("features")) self.assertEqual(result.get("type"), "FeatureCollection") self.assertIsInstance(result.get("bbox"), list) for feature in result.get("features"): self.assertIsInstance(feature.get("bbox"), list) properties = feature.get("properties") self.assertIsInstance(properties, dict) self.assertIsNotNone(feature.get('geometry')) for property in GeocodeAdapter._properties: self.assertTrue(property in properties)
def geocode_test(self, api_response, mock_get_session): mock_get_session.return_value = self.session self.adapter.register_uri("GET", settings.GEOCODING_API_URL, text=json.dumps(api_response), status_code=200) geocode = Geocode() result = geocode.search("test") self.assertIsNotNone(result.get("features")) self.assertEqual(result.get("type"), "FeatureCollection") self.assertIsInstance(result.get("bbox"), list) for feature in result.get("features"): self.assertIsInstance(feature.get("bbox"), list) properties = feature.get("properties") self.assertIsInstance(properties, dict) self.assertIsNotNone(feature.get("geometry")) self.assertIsNotNone(feature.get("properties", {}).get("context_name")) for property in GeocodeAdapter._properties: self.assertTrue(property in properties)
def test_pelias_polygon_geometry(self, mock_get_session): mock_get_session.return_value = self.session polygonCoordinates = [[[0, 1], [1, 0], [0, 3]]] bbox = [-71.1912490997, 42.227911131, -70.9227798807, 42.3969775021] api_response = { "features": [ { "type": "Feature", "geometry": {"type": "Polygon", "coordinates": polygonCoordinates}, "properties": {}, "bbox": bbox, } ] } self.adapter.register_uri("GET", settings.GEOCODING_API_URL, text=json.dumps(api_response), status_code=200) geocode = Geocode() result = geocode.search("test") self.assertEqual(result.get("features")[0].get("geometry").get("coordinates"), polygonCoordinates)
def test_pelias_point_geometry(self): bbox = [-71.1912490997, 42.227911131, -70.9227798807, 42.3969775021] api_response = { "features": [ { "type": "Feature", "geometry": { "type":"Point", "coordinates": [] }, "bbox": bbox } ] } self.mock_requests.get(settings.GEOCODING_API_URL, text=json.dumps(api_response), status_code=200) geocode = Geocode() result = geocode.search("test") self.assertEqual(result.get('features')[0].get('geometry').get('coordinates'), [[[-71.1912490997, 42.227911131], [-70.9227798807, 42.227911131], [-70.9227798807, 42.3969775021], [-71.1912490997, 42.3969775021], [-71.1912490997, 42.227911131]]])
def test_pelias_polygon_geometry(self): polygonCoordinates = [[[0, 1], [1, 0], [0, 3]]] bbox = [-71.1912490997, 42.227911131, -70.9227798807, 42.3969775021] api_response = { "features": [{ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": polygonCoordinates }, "bbox": bbox }] } self.mock_requests.get(settings.GEOCODING_API_URL, text=json.dumps(api_response), status_code=200) geocode = Geocode() result = geocode.search("test") self.assertEqual( result.get('features')[0].get('geometry').get('coordinates'), polygonCoordinates)
def test_pelias_add_bbox(self, get_cert_info, mock_get_session): mock_get_session.return_value = self.session get_cert_info.return_value = None in_result = { "type": "Feature", "geometry": {"type": "Point", "coordinates": [102.18947, 17.77036]}, "properties": { "id": "1608462", "gid": "geonames:locality:1608462", "layer": "locality", "source": "geonames", "source_id": "1608462", "name": "Nam Som", "confidence": 0.957, "accuracy": "centroid", "country": "Thailand", "country_gid": "whosonfirst:country:85632293", "country_a": "THA", "region": "Udon Thani", "region_gid": "whosonfirst:region:85678869", "county": "Nam Som", "county_gid": "whosonfirst:county:1108731585", "locality": "Nam Som", "locality_gid": "geonames:locality:1608462", "label": "Nam Som, Thailand", }, } api_response = { "geocoding": { "version": "0.2", "attribution": "/v1/attribution", "query": { "ids": [{"source": "whosonfirst", "layer": "county", "id": "1108731585"}], "private": False, "lang": {"name": "English", "iso6391": "en", "iso6393": "eng", "defaulted": False}, }, "engine": {"name": "Pelias", "author": "Mapzen", "version": "1.0"}, "timestamp": 1510925466405, }, "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": {"type": "Point", "coordinates": [102.227634, 17.743244]}, "properties": { "id": "1108731585", "gid": "whosonfirst:county:1108731585", "layer": "county", "source": "whosonfirst", "source_id": "1108731585", "name": "Nam Som", "accuracy": "centroid", "country": "Thailand", "country_gid": "whosonfirst:country:85632293", "country_a": "THA", "region": "Udon Thani", "region_gid": "whosonfirst:region:85678869", "county": "Nam Som", "county_gid": "whosonfirst:county:1108731585", "label": "Nam Som, Thailand", }, "bbox": [102.020749821, 17.6291659858, 102.33623593, 17.8795015544], } ], "bbox": [102.020749821, 17.6291659858, 102.33623593, 17.8795015544], } self.adapter.register_uri("GET", settings.GEOCODING_UPDATE_URL, text=json.dumps(api_response), status_code=200) expected_bbox = api_response.get("bbox") geocode = Geocode() result = geocode.add_bbox(in_result) self.assertEqual(result.get("type"), "Feature") self.assertEqual(result.get("bbox"), expected_bbox) self.assertEqual(result.get("properties").get("bbox"), expected_bbox)
def search(request): """ Detects the query type and calls the relevant geocoder to get results :param request: User request which should include a query parameter :return: A geojson with features matching the search query """ q = request.GET.get('query', None) if not q: return HttpResponse(status=204, content_type="application/json") error_string = "An unknown error occurred while querying for results, please contact an administrator." degree_range = 0.05 if is_mgrs(q): # check for necessary settings if getattr(settings, 'CONVERT_API_URL') is None: return HttpResponse('No Convert API specified', status=501) if getattr(settings, 'REVERSE_GEOCODING_API_URL') is None: return HttpResponse('No Reverse Geocode API specified', status=501) # make call to convert which should return a geojson feature of the MGRS location convert = CoordinateConverter() try: mgrs_data = convert.get(q) except Exception: return HttpResponse(content=error_string, status=500) # if no feature geom return nothing if not mgrs_data or not mgrs_data.get('geometry'): return HttpResponse(status=204, content_type="application/json") features = [] # save the mgrs feature to return later if not mgrs_data.get('properties'): mgrs_data['properties'] = {} mgrs_data['properties']['bbox'] = [ mgrs_data.get('geometry').get('coordinates')[0] - degree_range, mgrs_data.get('geometry').get('coordinates')[1] - degree_range, mgrs_data.get('geometry').get('coordinates')[0] + degree_range, mgrs_data.get('geometry').get('coordinates')[1] + degree_range ] mgrs_data['source'] = 'MGRS' features.append(mgrs_data) # call reverse to get a list of results near the mgrs feature reverse = ReverseGeocode() try: result = reverse.search({ "point.lat": mgrs_data.get('geometry').get('coordinates')[1], "point.lon": mgrs_data.get('geometry').get('coordinates')[0] }) except Exception: return HttpResponse(content=error_string, status=500) if result.get('features'): # add the mgrs feature with the search results and return together result['features'] = features + result['features'] return HttpResponse(content=json.dumps(result), status=200, content_type="application/json") # if no results just return the MGRS feature in the response return HttpResponse(content=json.dumps({'features': features}), status=200, content_type="application/json") elif is_lat_lon(q): coords = is_lat_lon(q) # if no reverse url return 501 if getattr(settings, 'REVERSE_GEOCODING_API_URL') is None: return HttpResponse('No Reverse Geocode API specified', status=501) # make call to reverse geocode reverse = ReverseGeocode() try: result = reverse.search({ "point.lat": coords[0], "point.lon": coords[1] }) except Exception: return HttpResponse(content=error_string, status=500) # create a feature representing the exact lat/lon being searched point_feature = { "geometry": { "type": "Point", "coordinates": [coords[1], coords[0]] }, "source": "Coordinate", "type": "Feature", "properties": { "name": "{0} {1}, {2} {3}".format( coords[0] if coords[0] >= 0 else coords[0] * -1, "N" if coords[0] >= 0 else "S", coords[1] if coords[1] >= 0 else coords[1] * -1, "E" if coords[1] >= 0 else "W"), "bbox": [ coords[1] - degree_range, coords[0] - degree_range, coords[1] + degree_range, coords[0] + degree_range ] } } # if there are results add the point feature and return them together if result.get('features'): result.get('features').insert(0, point_feature) return HttpResponse(content=json.dumps(result), status=200, content_type="application/json") # if there are no results return only the point feature features = {'features': [point_feature]} return HttpResponse(content=json.dumps(features), status=200, content_type="application/json") else: # make call to geocode with search geocode = Geocode() try: result = geocode.search(q) except Exception as e: logger.error(e) return HttpResponse(content=error_string, status=500) return HttpResponse(content=json.dumps(result), status=200, content_type="application/json")
def search(request): """ Detects the query type and calls the relevant geocoder to get results :param request: User request which should include a query parameter :return: A geojson with features matching the search query """ q = request.GET.get('query', None) if not q: return HttpResponse(status=204, content_type="application/json") error_string = "An unknown error occurred while querying for results, please contact an administrator." degree_range = 0.05 if is_mgrs(q): # check for necessary settings if getattr(settings, 'CONVERT_API_URL') is None: return HttpResponse('No Convert API specified', status=501) if getattr(settings, 'REVERSE_GEOCODING_API_URL') is None: return HttpResponse('No Reverse Geocode API specified', status=501) # make call to convert which should return a geojson feature of the MGRS location convert = CoordinateConverter() try: mgrs_data = convert.get(q) except Exception: return HttpResponse( content=error_string, status=500 ) # if no feature geom return nothing if not mgrs_data or not mgrs_data.get('geometry'): return HttpResponse(status=204, content_type="application/json") features = [] # save the mgrs feature to return later if not mgrs_data.get('properties'): mgrs_data['properties'] = {} mgrs_data['properties']['bbox'] = [ mgrs_data.get('geometry').get('coordinates')[0] - degree_range, mgrs_data.get('geometry').get('coordinates')[1] - degree_range, mgrs_data.get('geometry').get('coordinates')[0] + degree_range, mgrs_data.get('geometry').get('coordinates')[1] + degree_range ] mgrs_data['source'] = 'MGRS' features.append(mgrs_data) # call reverse to get a list of results near the mgrs feature reverse = ReverseGeocode() try: result = reverse.search({ "point.lat": mgrs_data.get('geometry').get('coordinates')[1], "point.lon": mgrs_data.get('geometry').get('coordinates')[0] }) except Exception: return HttpResponse( content=error_string, status=500 ) if result.get('features'): # add the mgrs feature with the search results and return together result['features'] = features + result['features'] return HttpResponse(content=json.dumps(result), status=200, content_type="application/json") # if no results just return the MGRS feature in the response return HttpResponse(content=json.dumps({'features': features}), status=200, content_type="application/json") elif is_lat_lon(q): coords = is_lat_lon(q) # if no reverse url return 501 if getattr(settings, 'REVERSE_GEOCODING_API_URL') is None: return HttpResponse('No Reverse Geocode API specified', status=501) # make call to reverse geocode reverse = ReverseGeocode() try: result = reverse.search({ "point.lat": coords[0], "point.lon": coords[1] }) except Exception: return HttpResponse( content=error_string, status=500 ) # create a feature representing the exact lat/lon being searched point_feature = { "geometry": { "type": "Point", "coordinates": [coords[1], coords[0]] }, "source": "Coordinate", "type": "Feature", "properties": { "name": "{0} {1}, {2} {3}".format( coords[0] if coords[0] >= 0 else coords[0] * -1, "N" if coords[0] >= 0 else "S", coords[1] if coords[1] >= 0 else coords[1] * -1, "E" if coords[1] >= 0 else "W" ), "bbox": [ coords[1] - degree_range, coords[0] - degree_range, coords[1] + degree_range, coords[0] + degree_range ] } } # if there are results add the point feature and return them together if result.get('features'): result.get('features').insert(0, point_feature) return HttpResponse(content=json.dumps(result), status=200, content_type="application/json") # if there are no results return only the point feature features = {'features': [point_feature]} return HttpResponse(content=json.dumps(features), status=200, content_type="application/json") else: # make call to geocode with search geocode = Geocode() try: result = geocode.search(q) except Exception as e: logger.error(e) return HttpResponse( content=error_string, status=500 ) return HttpResponse(content=json.dumps(result), status=200, content_type="application/json")