diff --git a/source/jormungandr/jormungandr/scenarios/new_default.py b/source/jormungandr/jormungandr/scenarios/new_default.py index 6eabfd9fe4..5ffd77cbe1 100644 --- a/source/jormungandr/jormungandr/scenarios/new_default.py +++ b/source/jormungandr/jormungandr/scenarios/new_default.py @@ -82,6 +82,7 @@ get_pt_object_from_json, json_address_from_uri, is_olympic_site, + entrypoint_uri_refocus, ) from jormungandr.error import generate_error from jormungandr.utils import Coords @@ -1750,14 +1751,17 @@ def get_entrypoint_detail(self, entrypoint, instance, request_id): ) if detail: - return detail + # Transform address in (from, to) to poi with ES + return entrypoint_uri_refocus(detail, entrypoint) if not isinstance(instance.autocomplete, GeocodeJson): bragi = global_autocomplete.get(app.config.get('DEFAULT_AUTOCOMPLETE_BACKEND', 'bragi')) if bragi: # if the instance's autocomplete is not a geocodejson autocomplete, we also check in the # global autocomplete instance - return bragi.get_object_by_uri(entrypoint, instances=[instance], request_id=request_id) + detail = bragi.get_object_by_uri(entrypoint, instances=[instance], request_id=request_id) + # Transform address in (from, to) to poi with ES + return entrypoint_uri_refocus(detail, entrypoint) return None diff --git a/source/jormungandr/jormungandr/tests/utils_test.py b/source/jormungandr/jormungandr/tests/utils_test.py index c06b330169..772a969921 100644 --- a/source/jormungandr/jormungandr/tests/utils_test.py +++ b/source/jormungandr/jormungandr/tests/utils_test.py @@ -39,9 +39,9 @@ read_best_boarding_positions, read_origin_destination_data, make_origin_destination_key, - portable_min, get_last_pt_section, get_first_pt_section, + entrypoint_uri_refocus, ) import pytz from jormungandr import app @@ -403,3 +403,132 @@ def test_get_olympic_site_pt_section_journey_only_street_network_section(): last_section = get_last_pt_section(pb_j) assert first_section.duration == 1 assert last_section.duration == 3 + + +def test_entrypoint_uri_refocus_none_value(): + res = entrypoint_uri_refocus(None, "123") + assert res is None + + +def test_entrypoint_uri_refocus_embedded_type_not_address(): + stop_area = { + "id": "stop_area:123", + "name": "Stop area (Paris)", + "quality": 0, + "embedded_type": "stop_area", + "stop_area": { + "id": "stop_area:123", + "coord": {"lat": "48.845971", "lon": "2.339872"}, + "label": "Stop area (Paris)", + "name": "Stop area", + }, + } + res = entrypoint_uri_refocus(stop_area, stop_area["id"]) + assert res["id"] == stop_area["id"] + assert res["name"] == stop_area["name"] + assert res["embedded_type"] == stop_area["embedded_type"] + assert res["stop_area"]["id"] == stop_area["stop_area"]["id"] + assert res["stop_area"]["label"] == stop_area["stop_area"]["label"] + assert res["stop_area"]["name"] == stop_area["stop_area"]["name"] + assert res["stop_area"]["coord"]["lat"] == stop_area["stop_area"]["coord"]["lat"] + assert res["stop_area"]["coord"]["lon"] == stop_area["stop_area"]["coord"]["lon"] + + +def test_without_within_zones(): + address = { + "id": "2.339872;48.845971", + "name": "58BIS Boulevard Saint-Michel (Paris)", + "quality": 0, + "embedded_type": "address", + "address": { + "id": "2.339872;48.845971", + "coord": {"lat": "48.845971", "lon": "2.339872"}, + "house_number": 58, + "label": "58BIS Boulevard Saint-Michel (Paris)", + "name": "58BIS Boulevard Saint-Michel", + }, + } + res = entrypoint_uri_refocus(address, address["id"]) + assert res["id"] == address["id"] + assert res["name"] == address["name"] + assert res["embedded_type"] == address["embedded_type"] + assert res["address"]["id"] == address["address"]["id"] + assert res["address"]["label"] == address["address"]["label"] + assert res["address"]["name"] == address["address"]["name"] + assert res["address"]["coord"]["lat"] == address["address"]["coord"]["lat"] + assert res["address"]["coord"]["lon"] == address["address"]["coord"]["lon"] + + +def test_with_empty_within_zones(): + address = { + "id": "2.339872;48.845971", + "name": "58BIS Boulevard Saint-Michel (Paris)", + "quality": 0, + "embedded_type": "address", + "address": { + "id": "2.339872;48.845971", + "coord": {"lat": "48.845971", "lon": "2.339872"}, + "house_number": 58, + "label": "58BIS Boulevard Saint-Michel (Paris)", + "name": "58BIS Boulevard Saint-Michel", + }, + "within_zones": [], + } + res = entrypoint_uri_refocus(address, address["id"]) + assert res["id"] == address["id"] + assert res["name"] == address["name"] + assert res["embedded_type"] == address["embedded_type"] + assert res["address"]["id"] == address["address"]["id"] + assert res["address"]["label"] == address["address"]["label"] + assert res["address"]["name"] == address["address"]["name"] + assert res["address"]["coord"]["lat"] == address["address"]["coord"]["lat"] + assert res["address"]["coord"]["lon"] == address["address"]["coord"]["lon"] + + +def test_address_with_within_zones(): + poi = { + "id": "poi:10309", + "name": "Jardin du Luxembourg (Paris)", + "quality": 0, + "embedded_type": "poi", + "poi": { + "id": "poi:10309", + "coord": {"lat": "48.8487134929", "lon": "2.33642846001"}, + "label": "Jardin du Luxembourg (Paris)", + "name": "Jardin du Luxembourg", + "poi_type": {"id": "poi_type:jardin", "name": "Jardin"}, + "children": [ + { + "id": "poi:osm:node:24908972", + "name": "Porte Saint-Michel", + "label": "Porte Saint-Michel (Paris)", + "coord": {"lon": "2.340268", "lat": "48.8468553"}, + "type": "poi", + "poi_type": {"id": "poi_type:access_point", "name": "Point d'accès"}, + } + ], + }, + } + address = { + "id": "2.339872;48.845971", + "name": "58BIS Boulevard Saint-Michel (Paris)", + "quality": 0, + "embedded_type": "address", + "address": { + "id": "2.339872;48.845971", + "coord": {"lat": "48.845971", "lon": "2.339872"}, + "house_number": 58, + "label": "58BIS Boulevard Saint-Michel (Paris)", + "name": "58BIS Boulevard Saint-Michel", + }, + "within_zones": [poi], + } + res = entrypoint_uri_refocus(address, address["id"]) + assert res["id"] == poi["id"] + assert res["name"] == poi["name"] + assert res["embedded_type"] == poi["embedded_type"] + assert res["poi"]["id"] == poi["poi"]["id"] + assert res["poi"]["label"] == poi["poi"]["label"] + assert res["poi"]["name"] == poi["poi"]["name"] + assert res["poi"]["coord"]["lat"] == address["address"]["coord"]["lat"] + assert res["poi"]["coord"]["lon"] == address["address"]["coord"]["lon"] diff --git a/source/jormungandr/jormungandr/utils.py b/source/jormungandr/jormungandr/utils.py index 3677778be2..8fb2e4507b 100644 --- a/source/jormungandr/jormungandr/utils.py +++ b/source/jormungandr/jormungandr/utils.py @@ -494,6 +494,36 @@ def get_pt_object_from_json(dict_pt_object, instance): return pt_object +def replace_address_with_custom_poi(dict_pt_object, uri): + new_poi = next( + ( + wz + for wz in dict_pt_object.get("within_zones", []) + if MAP_STRING_PTOBJECT_TYPE.get(wz.get("embedded_type")) == type_pb2.POI + and wz.get("poi", {}).get("children", []) + ), + None, + ) + if not new_poi: + return dict_pt_object + if not is_coord(uri): + return dict_pt_object + lon, lat = get_lon_lat(uri) + # We're putting back the coordinate of the end-user, who is in a POI area (with entrypoints). + # If we don't, barycenter of the POI area will be displayed which means nothing for the end user. + new_poi["poi"]["coord"]["lon"] = "{}".format(lon) + new_poi["poi"]["coord"]["lat"] = "{}".format(lat) + return new_poi + + +def entrypoint_uri_refocus(dict_pt_object, uri): + if not dict_pt_object: + return None + if MAP_STRING_PTOBJECT_TYPE.get(dict_pt_object.get("embedded_type")) == type_pb2.ADDRESS: + return replace_address_with_custom_poi(dict_pt_object, uri) + return dict_pt_object + + def json_address_from_uri(uri): if is_coord(uri): lon, lat = get_lon_lat(uri) diff --git a/source/jormungandr/tests/poi_access_point_tests.py b/source/jormungandr/tests/poi_access_point_tests.py index 9746de7862..164a23917e 100644 --- a/source/jormungandr/tests/poi_access_point_tests.py +++ b/source/jormungandr/tests/poi_access_point_tests.py @@ -49,6 +49,9 @@ from_addr_uri = "addr:{}".format(s_coord) to_addr_uri = "addr:{}".format(r_coord) +from_addr_within_zone_uri = "{}".format(s_coord) +to_addr_within_zone_uri = "{}".format(r_coord) + FROM_POI = { "features": [ { @@ -145,6 +148,61 @@ ] } +FROM_ADDRESS_WITH_WITHIN_ZONES = { + "features": [ + { + "type": "Feature", + "geometry": {"coordinates": [s_lon, s_lat], "type": "Point"}, + "properties": { + "geocoding": { + "id": from_addr_within_zone_uri, + "type": "house", + "label": "10 Rue bob (City)", + "name": "10 Rue bob", + "housenumber": "10", + "street": "Rue bob", + "postcode": "36500", + "city": "City", + } + }, + } + ], + "zones": [ + { + "type": "Zone", + "geometry": {"coordinates": [s_lon, s_lat], "type": "Point"}, + "properties": { + "geocoding": { + "id": from_poi_uri, + "type": "poi", + "label": "Jardin (City)", + "name": "Jardin", + "city": "Paris", + "poi_types": [{"id": "poi_type:jardin", "name": "Jardin"}], + "children": [ + { + "type": "poi", + "id": "poi:from:porte1", + "label": "Jardin: Porte 1 (City)", + "name": "Jardin: Porte 1", + "coord": {"lon": s_lon + 0.0000000005, "lat": s_lat + 0.0000000005}, + "poi_type": {"id": "poi_type:access_point", "name": "Point d'accès"}, + }, + { + "type": "poi", + "id": "poi:from:porte2", + "label": "Jardin: Porte 2 (City)", + "name": "Jardin: Porte 2", + "coord": {"lon": s_lon + 0.0000000008, "lat": s_lat + 0.0000000008}, + "poi_type": {"id": "poi_type:access_point", "name": "Point d'accès"}, + }, + ], + } + }, + } + ], +} + TO_ADDRESS = { "features": [ @@ -167,6 +225,61 @@ ] } +TO_ADDRESS_WITHIN_ZONES = { + "features": [ + { + "type": "Feature", + "geometry": {"coordinates": [r_lon, r_lat], "type": "Point"}, + "properties": { + "geocoding": { + "id": to_addr_within_zone_uri, + "type": "house", + "label": "10 Rue Victor (City)", + "name": "10 Rue Victor", + "housenumber": "10", + "street": "Rue Victor", + "postcode": "36500", + "city": "City", + } + }, + } + ], + "zones": [ + { + "type": "Zone", + "geometry": {"coordinates": [r_lon, r_lat], "type": "Point"}, + "properties": { + "geocoding": { + "id": to_poi_uri, + "type": "poi", + "label": "Jardin (City)", + "name": "Jardin", + "city": "Paris", + "poi_types": [{"id": "poi_type:jardin", "name": "Jardin"}], + "children": [ + { + "type": "poi", + "id": "poi:to:porte3", + "label": "Jardin: Porte 3 (City)", + "name": "Jardin: Porte 3", + "coord": {"lon": r_lon + 0.0000000005, "lat": r_lat + 0.0000000005}, + "poi_type": {"id": "poi_type:access_point", "name": "Point d'accès"}, + }, + { + "type": "poi", + "id": "poi:to:porte4", + "label": "Jardin: Porte 4 (City)", + "name": "Jardin: Porte 4", + "coord": {"lon": r_lon + 0.0000000008, "lat": r_lat + 0.0000000008}, + "poi_type": {"id": "poi_type:access_point", "name": "Point d'accès"}, + }, + ], + } + }, + } + ], +} + MOCKED_INSTANCE_CONF = {"scenario": "distributed", 'instance_config': {'default_autocomplete': 'bragi'}} @@ -634,3 +747,168 @@ def test_from_poi_to_poi_without_poi_access_points(self): assert last_journey["sections"][0]["from"]["id"] == from_poi_uri assert last_journey["sections"][0]["to"]["id"] == to_poi_uri assert "vias" not in last_journey["sections"][0] + + +MOCKED_INSTANCE_CONF = { + "scenario": "distributed", + 'instance_config': {'use_multi_reverse': True, 'default_autocomplete': 'bragi'}, +} + + +@dataset({'main_routing_test': MOCKED_INSTANCE_CONF}, global_config={'activate_bragi': True}) +class TestJourneysDistributedPoiAccessPointFromToAddress(AbstractTestFixture): + def test_from_address_with_within_zones_to_poi(self): + url = 'https://host_of_bragi' + to_place_params = {'timeout': 200, 'pt_dataset[]': 'main_routing_test'} + from_place_params = {'reverse_timeout': 200, 'within_timeout': 200, 'pt_dataset[]': 'main_routing_test'} + from_place = "{}/multi-reverse?lon={}&lat={}&{}".format( + url, s_lon, s_lat, urlencode(from_place_params, doseq=True) + ) + to_place = "{}/features/{}?{}".format(url, to_poi_uri, urlencode(to_place_params, doseq=True)) + with requests_mock.Mocker() as m: + m.get(from_place, json=FROM_ADDRESS_WITH_WITHIN_ZONES) + m.get(to_place, json=TO_POI) + response = self.query_region( + template_journey_query.format(place_from=from_addr_within_zone_uri, place_to=to_poi_uri), + display=True, + ) + check_best(response) + journeys = response["journeys"] + assert len(journeys) == 2 + first_journey = journeys[0] + assert len(first_journey["sections"]) == 3 + assert first_journey["sections"][0]["mode"] == "walking" + assert first_journey["sections"][0]["type"] == "street_network" + assert first_journey["sections"][0]["from"]["id"] == from_poi_uri + assert first_journey["sections"][0]["from"]["embedded_type"] == 'poi' + assert first_journey["sections"][0]["from"]["name"] == 'Jardin (City)' + + assert first_journey["sections"][2]["mode"] == "walking" + assert first_journey["sections"][2]["type"] == "street_network" + assert first_journey["sections"][2]["to"]["id"] == to_poi_uri + assert first_journey["sections"][2]["to"]["embedded_type"] == 'poi' + assert first_journey["sections"][2]["to"]["name"] == 'Jardin (City)' + assert len(first_journey["sections"][2]["vias"]) == 1 + assert first_journey["sections"][2]["vias"][0]["id"] == 'poi:to:porte3' + assert first_journey["sections"][2]["vias"][0]["name"] == 'Jardin: Porte 3' + assert first_journey["sections"][2]["vias"][0]["access_point"]["embedded_type"] == 'poi_access_point' + path = first_journey["sections"][2]["path"] + assert len(path) == 3 + assert path[2]["length"] == 0 + assert path[2]["name"] == "Jardin: Porte 3" + assert path[2]["instruction"] == "Then enter Jardin (City) via Jardin: Porte 3." + assert path[2]["via_uri"] == 'poi:to:porte3' + + # direct path + last_journey = journeys[1] + assert len(last_journey["sections"]) == 1 + assert last_journey["sections"][0]["mode"] == "walking" + assert last_journey["sections"][0]["type"] == "street_network" + assert last_journey["sections"][0]["from"]["id"] == from_poi_uri + assert last_journey["sections"][0]["to"]["id"] == to_poi_uri + vias = last_journey["sections"][0]["vias"] + assert len(vias) == 2 + assert vias[0]["id"] == 'poi:from:porte1' + assert vias[0]["name"] == 'Jardin: Porte 1' + assert vias[0]["access_point"]["embedded_type"] == 'poi_access_point' + + assert vias[1]["id"] == 'poi:to:porte3' + assert vias[1]["name"] == 'Jardin: Porte 3' + assert vias[1]["access_point"]["embedded_type"] == 'poi_access_point' + + first_path = last_journey["sections"][0]["path"][0] + assert first_path["length"] == 0 + assert first_path["name"] == "Jardin: Porte 1" + assert first_path["instruction"] == 'Exit Jardin (City) via Jardin: Porte 1.' + assert first_path["via_uri"] == 'poi:from:porte1' + + last_path = last_journey["sections"][0]["path"][-1] + assert last_path["length"] == 0 + assert last_path["name"] == "Jardin: Porte 3" + assert last_path["instruction"] == "Then enter Jardin (City) via Jardin: Porte 3." + assert last_path["via_uri"] == 'poi:to:porte3' + + def test_from_poi_to_address_within_zones(self): + url = 'https://host_of_bragi' + params = {'timeout': 200, 'pt_dataset[]': 'main_routing_test'} + from_place = "{}/features/{}?{}".format(url, from_poi_uri, urlencode(params, doseq=True)) + + to_place_params = {'reverse_timeout': 200, 'within_timeout': 200, 'pt_dataset[]': 'main_routing_test'} + to_place = "{}/multi-reverse?lon={}&lat={}&{}".format( + url, r_lon, r_lat, urlencode(to_place_params, doseq=True) + ) + + with requests_mock.Mocker() as m: + m.get(from_place, json=FROM_POI) + m.get(to_place, json=TO_ADDRESS_WITHIN_ZONES) + response = self.query_region( + template_journey_query.format(place_from=from_poi_uri, place_to=to_addr_within_zone_uri) + + "&_access_points=true", + display=True, + ) + check_best(response) + journeys = response["journeys"] + assert len(journeys) == 2 + first_journey = journeys[0] + assert len(first_journey["sections"]) == 3 + first_section = first_journey["sections"][0] + assert first_section["mode"] == "walking" + assert first_section["type"] == "street_network" + assert first_section["from"]["id"] == from_poi_uri + assert first_section["from"]["name"] == 'Jardin (City)' + + assert len(first_section["vias"]) == 2 + assert first_section["vias"][0]["id"] == 'poi:from:porte1' + assert first_section["vias"][0]["name"] == 'Jardin: Porte 1' + assert first_section["vias"][0]["access_point"]["embedded_type"] == 'poi_access_point' + assert first_section["vias"][1]["id"] == 'access_point:B1' + assert first_section["vias"][1]["name"] == 'access_point:B1' + assert first_section["vias"][1]["access_point"]["embedded_type"] == 'pt_access_point' + + path = first_section["path"] + first_path = path[0] + last_path = path[-1] + assert first_path["length"] == 0 + assert first_path["name"] == "Jardin: Porte 1" + assert first_path["instruction"] == "Exit Jardin (City) via Jardin: Porte 1." + assert first_path["via_uri"] == 'poi:from:porte1' + assert last_path["length"] == 1 + assert last_path["name"] == 'access_point:B1' + assert last_path["instruction"] == 'Then enter stop_point:stopB (Condom) via access_point:B1.' + assert last_path["via_uri"] == 'access_point:B1' + + last_section = first_journey["sections"][2] + assert last_section["mode"] == "walking" + assert last_section["type"] == "street_network" + assert last_section["to"]["id"] == to_poi_uri + assert last_section["to"]["name"] == 'Jardin (City)' + assert last_section["to"]["embedded_type"] == 'poi' + + assert len(last_section["vias"]) == 2 + assert last_section["vias"][0]["id"] == 'poi:to:porte3' + assert last_section["vias"][0]["name"] == 'Jardin: Porte 3' + assert last_section["vias"][0]["access_point"]["embedded_type"] == 'poi_access_point' + assert last_section["vias"][1]["id"] == 'access_point:A2' + assert last_section["vias"][1]["name"] == 'access_point:A2' + assert last_section["vias"][1]["access_point"]["embedded_type"] == 'pt_access_point' + + # direct path + last_journey = journeys[1] + assert len(last_journey["sections"]) == 1 + first_section = last_journey["sections"][0] + assert first_section["mode"] == "walking" + assert first_section["type"] == "street_network" + assert first_section["from"]["id"] == from_poi_uri + assert first_section["to"]["id"] == to_poi_uri + + assert len(first_section["vias"]) == 2 + assert first_section["vias"][0]["id"] == 'poi:from:porte1' + assert first_section["vias"][0]["name"] == 'Jardin: Porte 1' + assert first_section["vias"][0]["access_point"]["embedded_type"] == 'poi_access_point' + + path = last_journey["sections"][0]["path"] + first_path = path[0] + assert first_path["length"] == 0 + assert first_path["name"] == "Jardin: Porte 1" + assert first_path["instruction"] == "Exit Jardin (City) via Jardin: Porte 1." + assert first_path["via_uri"] == 'poi:from:porte1'