Merge pull request #466 from CartoDB/Added_TomTom_services
[Leapfrog] Adding TomTom services
This commit is contained in:
commit
20a610d1d8
4
NEWS.md
4
NEWS.md
@ -1,3 +1,7 @@
|
|||||||
|
May 7th, 2018
|
||||||
|
=============
|
||||||
|
* Version `0.24.0` of the client, `0.31.0` of the server, and ' 0.18.0` of the python library.
|
||||||
|
* Support for TomTom routing, geocoding and isolines.
|
||||||
|
|
||||||
March 28th, 2018
|
March 28th, 2018
|
||||||
================
|
================
|
||||||
|
@ -171,6 +171,15 @@ SELECT CDB_Conf_SetConf(
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### TomTom configuration
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT CDB_Conf_SetConf(
|
||||||
|
'tomtom_conf',
|
||||||
|
'{"routing": {"api_keys": ["your_api_key"], "monthly_quota": 999999}, "geocoder": {"api_keys": ["your_api_key"], "monthly_quota": 999999}, "isolines": {"api_keys": ["your_api_key"], "monthly_quota": 1500000}}'
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
#### Data Observatory
|
#### Data Observatory
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
202
client/cdb_dataservices_client--0.23.0--0.24.0.sql
Normal file
202
client/cdb_dataservices_client--0.23.0--0.24.0.sql
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||||
|
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
|
\echo Use "ALTER EXTENSION cdb_dataservices_client UPDATE TO '0.24.0'" to load this file. \quit
|
||||||
|
|
||||||
|
-- Make sure we have a sane search path to create/update the extension
|
||||||
|
SET search_path = "$user",cartodb,public,cdb_dataservices_client;
|
||||||
|
|
||||||
|
-- HERE goes your code to upgrade/downgrade
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_tomtom_geocode_street_point (searchtext text ,city text DEFAULT NULL ,state_province text DEFAULT NULL ,country text DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
DECLARE
|
||||||
|
ret Geometry;
|
||||||
|
username text;
|
||||||
|
orgname text;
|
||||||
|
BEGIN
|
||||||
|
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||||
|
RAISE EXCEPTION 'The api_key must be provided';
|
||||||
|
END IF;
|
||||||
|
SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text);
|
||||||
|
-- JSON value stored "" is taken as literal
|
||||||
|
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||||
|
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT cdb_dataservices_client._cdb_tomtom_geocode_street_point(username, orgname, searchtext, city, state_province, country) INTO ret; RETURN ret;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_tomtom_isochrone (source geometry(Geometry, 4326) ,mode text ,range integer[] ,options text[] DEFAULT ARRAY[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_client.isoline AS $$
|
||||||
|
DECLARE
|
||||||
|
|
||||||
|
username text;
|
||||||
|
orgname text;
|
||||||
|
BEGIN
|
||||||
|
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||||
|
RAISE EXCEPTION 'The api_key must be provided';
|
||||||
|
END IF;
|
||||||
|
SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text);
|
||||||
|
-- JSON value stored "" is taken as literal
|
||||||
|
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||||
|
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN QUERY SELECT * FROM cdb_dataservices_client._cdb_tomtom_isochrone(username, orgname, source, mode, range, options);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_tomtom_isodistance (source geometry(Geometry, 4326) ,mode text ,range integer[] ,options text[] DEFAULT ARRAY[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_client.isoline AS $$
|
||||||
|
DECLARE
|
||||||
|
|
||||||
|
username text;
|
||||||
|
orgname text;
|
||||||
|
BEGIN
|
||||||
|
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||||
|
RAISE EXCEPTION 'The api_key must be provided';
|
||||||
|
END IF;
|
||||||
|
SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text);
|
||||||
|
-- JSON value stored "" is taken as literal
|
||||||
|
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||||
|
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN QUERY SELECT * FROM cdb_dataservices_client._cdb_tomtom_isodistance(username, orgname, source, mode, range, options);
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_tomtom_geocode_street_point_exception_safe (searchtext text ,city text DEFAULT NULL ,state_province text DEFAULT NULL ,country text DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
DECLARE
|
||||||
|
ret Geometry;
|
||||||
|
username text;
|
||||||
|
orgname text;
|
||||||
|
_returned_sqlstate TEXT;
|
||||||
|
_message_text TEXT;
|
||||||
|
_pg_exception_context TEXT;
|
||||||
|
BEGIN
|
||||||
|
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||||
|
RAISE EXCEPTION 'The api_key must be provided';
|
||||||
|
END IF;
|
||||||
|
SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text);
|
||||||
|
-- JSON value stored "" is taken as literal
|
||||||
|
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||||
|
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
SELECT cdb_dataservices_client._cdb_tomtom_geocode_street_point(username, orgname, searchtext, city, state_province, country) INTO ret; RETURN ret;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
GET STACKED DIAGNOSTICS _returned_sqlstate = RETURNED_SQLSTATE,
|
||||||
|
_message_text = MESSAGE_TEXT,
|
||||||
|
_pg_exception_context = PG_EXCEPTION_CONTEXT;
|
||||||
|
RAISE WARNING USING ERRCODE = _returned_sqlstate, MESSAGE = _message_text, DETAIL = _pg_exception_context;
|
||||||
|
RETURN ret;
|
||||||
|
END;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_tomtom_isochrone_exception_safe (source geometry(Geometry, 4326) ,mode text ,range integer[] ,options text[] DEFAULT ARRAY[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_client.isoline AS $$
|
||||||
|
DECLARE
|
||||||
|
|
||||||
|
username text;
|
||||||
|
orgname text;
|
||||||
|
_returned_sqlstate TEXT;
|
||||||
|
_message_text TEXT;
|
||||||
|
_pg_exception_context TEXT;
|
||||||
|
BEGIN
|
||||||
|
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||||
|
RAISE EXCEPTION 'The api_key must be provided';
|
||||||
|
END IF;
|
||||||
|
SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text);
|
||||||
|
-- JSON value stored "" is taken as literal
|
||||||
|
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||||
|
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
RETURN QUERY SELECT * FROM cdb_dataservices_client._cdb_tomtom_isochrone(username, orgname, source, mode, range, options);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
GET STACKED DIAGNOSTICS _returned_sqlstate = RETURNED_SQLSTATE,
|
||||||
|
_message_text = MESSAGE_TEXT,
|
||||||
|
_pg_exception_context = PG_EXCEPTION_CONTEXT;
|
||||||
|
RAISE WARNING USING ERRCODE = _returned_sqlstate, MESSAGE = _message_text, DETAIL = _pg_exception_context;
|
||||||
|
|
||||||
|
END;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_tomtom_isodistance_exception_safe (source geometry(Geometry, 4326) ,mode text ,range integer[] ,options text[] DEFAULT ARRAY[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_client.isoline AS $$
|
||||||
|
DECLARE
|
||||||
|
|
||||||
|
username text;
|
||||||
|
orgname text;
|
||||||
|
_returned_sqlstate TEXT;
|
||||||
|
_message_text TEXT;
|
||||||
|
_pg_exception_context TEXT;
|
||||||
|
BEGIN
|
||||||
|
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
|
||||||
|
RAISE EXCEPTION 'The api_key must be provided';
|
||||||
|
END IF;
|
||||||
|
SELECT u, o INTO username, orgname FROM cdb_dataservices_client._cdb_entity_config() AS (u text, o text);
|
||||||
|
-- JSON value stored "" is taken as literal
|
||||||
|
IF username IS NULL OR username = '' OR username = '""' THEN
|
||||||
|
RAISE EXCEPTION 'Username is a mandatory argument, check it out';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
RETURN QUERY SELECT * FROM cdb_dataservices_client._cdb_tomtom_isodistance(username, orgname, source, mode, range, options);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
GET STACKED DIAGNOSTICS _returned_sqlstate = RETURNED_SQLSTATE,
|
||||||
|
_message_text = MESSAGE_TEXT,
|
||||||
|
_pg_exception_context = PG_EXCEPTION_CONTEXT;
|
||||||
|
RAISE WARNING USING ERRCODE = _returned_sqlstate, MESSAGE = _message_text, DETAIL = _pg_exception_context;
|
||||||
|
|
||||||
|
END;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE 'plpgsql' SECURITY DEFINER STABLE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_geocode_street_point (username text, orgname text, searchtext text, city text, state_province text, country text);
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_tomtom_geocode_street_point (username text, orgname text, searchtext text, city text DEFAULT NULL, state_province text DEFAULT NULL, country text DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
CONNECT cdb_dataservices_client._server_conn_str();
|
||||||
|
|
||||||
|
SELECT cdb_dataservices_server.cdb_tomtom_geocode_street_point (username, orgname, searchtext, city, state_province, country);
|
||||||
|
|
||||||
|
$$ LANGUAGE plproxy VOLATILE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_isochrone (username text, orgname text, source geometry(Geometry, 4326), mode text, range integer[], options text[]);
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_tomtom_isochrone (username text, orgname text, source geometry(Geometry, 4326), mode text, range integer[], options text[] DEFAULT ARRAY[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_client.isoline AS $$
|
||||||
|
CONNECT cdb_dataservices_client._server_conn_str();
|
||||||
|
|
||||||
|
SELECT * FROM cdb_dataservices_server.cdb_tomtom_isochrone (username, orgname, source, mode, range, options);
|
||||||
|
|
||||||
|
$$ LANGUAGE plproxy VOLATILE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_isodistance (username text, orgname text, source geometry(Geometry, 4326), mode text, range integer[], options text[]);
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_tomtom_isodistance (username text, orgname text, source geometry(Geometry, 4326), mode text, range integer[], options text[] DEFAULT ARRAY[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_client.isoline AS $$
|
||||||
|
CONNECT cdb_dataservices_client._server_conn_str();
|
||||||
|
|
||||||
|
SELECT * FROM cdb_dataservices_server.cdb_tomtom_isodistance (username, orgname, source, mode, range, options);
|
||||||
|
|
||||||
|
$$ LANGUAGE plproxy VOLATILE PARALLEL UNSAFE;
|
||||||
|
|
||||||
|
GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_tomtom_geocode_street_point(searchtext text, city text, state_province text, country text) TO publicuser;
|
||||||
|
GRANT EXECUTE ON FUNCTION cdb_dataservices_client._cdb_tomtom_geocode_street_point_exception_safe(searchtext text, city text, state_province text, country text ) TO publicuser;
|
||||||
|
|
||||||
|
GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_tomtom_isochrone(source geometry(Geometry, 4326), mode text, range integer[], options text[]) TO publicuser;
|
||||||
|
GRANT EXECUTE ON FUNCTION cdb_dataservices_client._cdb_tomtom_isochrone_exception_safe(source geometry(Geometry, 4326), mode text, range integer[], options text[] ) TO publicuser;
|
||||||
|
|
||||||
|
GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_tomtom_isodistance(source geometry(Geometry, 4326), mode text, range integer[], options text[]) TO publicuser;
|
||||||
|
GRANT EXECUTE ON FUNCTION cdb_dataservices_client._cdb_tomtom_isodistance_exception_safe(source geometry(Geometry, 4326), mode text, range integer[], options text[] ) TO publicuser;
|
25
client/cdb_dataservices_client--0.24.0--0.23.0.sql
Normal file
25
client/cdb_dataservices_client--0.24.0--0.23.0.sql
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||||
|
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
|
\echo Use "ALTER EXTENSION cdb_dataservices_client UPDATE TO '0.23.0'" to load this file. \quit
|
||||||
|
|
||||||
|
-- Make sure we have a sane search path to create/update the extension
|
||||||
|
SET search_path = "$user",cartodb,public,cdb_dataservices_client;
|
||||||
|
|
||||||
|
-- HERE goes your code to upgrade/downgrade
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_tomtom_geocode_street_point (text, text, text, text);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_tomtom_isochrone (geometry(Geometry, 4326), text, integer[], text[]);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_tomtom_isodistance (geometry(Geometry, 4326), text, integer[], text[]);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_geocode_street_point_exception_safe (text, text, text, text);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_isochrone_exception_safe (geometry(Geometry, 4326), text, integer[], text[]);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_isodistance_exception_safe (geometry(Geometry, 4326), text, integer[], text[]);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_geocode_street_point (username text, orgname text, searchtext text, city text, state_province text, country text);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_isochrone (username text, orgname text, source geometry(Geometry, 4326), mode text, range integer[], options text[]);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_tomtom_isodistance (username text, orgname text, source geometry(Geometry, 4326), mode text, range integer[], options text[]);
|
4960
client/cdb_dataservices_client--0.24.0.sql
Normal file
4960
client/cdb_dataservices_client--0.24.0.sql
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
comment = 'CartoDB dataservices client API extension'
|
comment = 'CartoDB dataservices client API extension'
|
||||||
default_version = '0.23.0'
|
default_version = '0.24.0'
|
||||||
requires = 'plproxy, cartodb'
|
requires = 'plproxy, cartodb'
|
||||||
superuser = true
|
superuser = true
|
||||||
schema = cdb_dataservices_client
|
schema = cdb_dataservices_client
|
||||||
|
@ -94,6 +94,14 @@
|
|||||||
- { name: state_province, type: text, default: 'NULL'}
|
- { name: state_province, type: text, default: 'NULL'}
|
||||||
- { name: country, type: text, default: 'NULL'}
|
- { name: country, type: text, default: 'NULL'}
|
||||||
|
|
||||||
|
- name: cdb_tomtom_geocode_street_point
|
||||||
|
return_type: Geometry
|
||||||
|
params:
|
||||||
|
- { name: searchtext, type: text}
|
||||||
|
- { name: city, type: text, default: 'NULL'}
|
||||||
|
- { name: state_province, type: text, default: 'NULL'}
|
||||||
|
- { name: country, type: text, default: 'NULL'}
|
||||||
|
|
||||||
- name: cdb_mapzen_geocode_street_point
|
- name: cdb_mapzen_geocode_street_point
|
||||||
return_type: Geometry
|
return_type: Geometry
|
||||||
params:
|
params:
|
||||||
@ -132,6 +140,16 @@
|
|||||||
- { name: range, type: "integer[]" }
|
- { name: range, type: "integer[]" }
|
||||||
- { name: options, type: "text[]", default: 'ARRAY[]::text[]' }
|
- { name: options, type: "text[]", default: 'ARRAY[]::text[]' }
|
||||||
|
|
||||||
|
- name: cdb_tomtom_isochrone
|
||||||
|
return_type: SETOF cdb_dataservices_client.isoline
|
||||||
|
multi_row: true
|
||||||
|
multi_field: true
|
||||||
|
params:
|
||||||
|
- { name: source, type: "geometry(Geometry, 4326)" }
|
||||||
|
- { name: mode, type: text }
|
||||||
|
- { name: range, type: "integer[]" }
|
||||||
|
- { name: options, type: "text[]", default: 'ARRAY[]::text[]' }
|
||||||
|
|
||||||
- name: cdb_mapzen_isochrone
|
- name: cdb_mapzen_isochrone
|
||||||
return_type: SETOF cdb_dataservices_client.isoline
|
return_type: SETOF cdb_dataservices_client.isoline
|
||||||
multi_row: true
|
multi_row: true
|
||||||
@ -152,6 +170,16 @@
|
|||||||
- { name: range, type: "integer[]" }
|
- { name: range, type: "integer[]" }
|
||||||
- { name: options, type: "text[]", default: 'ARRAY[]::text[]' }
|
- { name: options, type: "text[]", default: 'ARRAY[]::text[]' }
|
||||||
|
|
||||||
|
- name: cdb_tomtom_isodistance
|
||||||
|
return_type: SETOF cdb_dataservices_client.isoline
|
||||||
|
multi_row: true
|
||||||
|
multi_field: true
|
||||||
|
params:
|
||||||
|
- { name: source, type: "geometry(Geometry, 4326)" }
|
||||||
|
- { name: mode, type: text }
|
||||||
|
- { name: range, type: "integer[]" }
|
||||||
|
- { name: options, type: "text[]", default: 'ARRAY[]::text[]' }
|
||||||
|
|
||||||
- name: cdb_mapzen_isodistance
|
- name: cdb_mapzen_isodistance
|
||||||
return_type: SETOF cdb_dataservices_client.isoline
|
return_type: SETOF cdb_dataservices_client.isoline
|
||||||
multi_row: true
|
multi_row: true
|
||||||
|
470
server/extension/cdb_dataservices_server--0.30.5--0.31.0.sql
Normal file
470
server/extension/cdb_dataservices_server--0.30.5--0.31.0.sql
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||||
|
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
|
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.31.0'" to load this file. \quit
|
||||||
|
|
||||||
|
-- HERE goes your code to upgrade/downgrade
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_route_with_waypoints(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
waypoints geometry(Point, 4326)[],
|
||||||
|
mode TEXT)
|
||||||
|
RETURNS cdb_dataservices_server.simple_route AS $$
|
||||||
|
from cartodb_services.tools import ServiceManager
|
||||||
|
from cartodb_services.tomtom import TomTomRouting
|
||||||
|
from cartodb_services.tomtom.types import TRANSPORT_MODE_TO_TOMTOM
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from cartodb_services.tools.polyline import polyline_to_linestring
|
||||||
|
from cartodb_services.refactor.service.tomtom_routing_config import TomTomRoutingConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('routing', TomTomRoutingConfigBuilder, username, orgname, GD)
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
|
||||||
|
try:
|
||||||
|
client = TomTomRouting(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
if not waypoints or len(waypoints) < 2:
|
||||||
|
service_manager.logger.info("Empty origin or destination")
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
|
||||||
|
if len(waypoints) > 25:
|
||||||
|
service_manager.logger.info("Too many waypoints (max 25)")
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
|
||||||
|
waypoint_coords = []
|
||||||
|
for waypoint in waypoints:
|
||||||
|
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % waypoint)[0]['lat']
|
||||||
|
lon = plpy.execute("SELECT ST_X('%s') AS lon" % waypoint)[0]['lon']
|
||||||
|
waypoint_coords.append(Coordinate(lon,lat))
|
||||||
|
|
||||||
|
profile = TRANSPORT_MODE_TO_TOMTOM.get(mode)
|
||||||
|
|
||||||
|
resp = client.directions(waypoint_coords, profile)
|
||||||
|
if resp and resp.shape:
|
||||||
|
shape_linestring = polyline_to_linestring(resp.shape)
|
||||||
|
if shape_linestring:
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
return [shape_linestring, resp.length, int(round(resp.duration))]
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to calculate TomTom routing', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to calculate TomTom routing')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_route_point_to_point(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
origin geometry(Point, 4326),
|
||||||
|
destination geometry(Point, 4326),
|
||||||
|
mode TEXT,
|
||||||
|
options text[] DEFAULT ARRAY[]::text[],
|
||||||
|
units text DEFAULT 'kilometers')
|
||||||
|
RETURNS cdb_dataservices_server.simple_route AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_routing_config = GD["user_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
params = {'origin': origin, 'destination': destination, 'mode': mode, 'options': options, 'units': units}
|
||||||
|
|
||||||
|
with metrics('cdb_route_with_point', user_routing_config, logger, params):
|
||||||
|
waypoints = [origin, destination]
|
||||||
|
|
||||||
|
if user_routing_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapzen_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
else:
|
||||||
|
raise Exception('Requested routing method is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_route_with_waypoints(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
waypoints geometry(Point, 4326)[],
|
||||||
|
mode TEXT,
|
||||||
|
options text[] DEFAULT ARRAY[]::text[],
|
||||||
|
units text DEFAULT 'kilometers')
|
||||||
|
RETURNS cdb_dataservices_server.simple_route AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_routing_config = GD["user_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
params = {'waypoints': waypoints, 'mode': mode, 'options': options, 'units': units}
|
||||||
|
|
||||||
|
with metrics('cdb_route_with_waypoints', user_routing_config, logger, params):
|
||||||
|
if user_routing_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapzen_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
else:
|
||||||
|
raise Exception('Requested routing method is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger,LoggerConfig
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
params = {'searchtext': searchtext, 'city': city, 'state_province': state_province, 'country': country}
|
||||||
|
|
||||||
|
with metrics('cdb_geocode_street_point', user_geocoder_config, logger, params):
|
||||||
|
if user_geocoder_config.heremaps_geocoder:
|
||||||
|
here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.google_geocoder:
|
||||||
|
google_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.mapzen_geocoder:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(mapzen_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.mapbox_geocoder:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.tomtom_geocoder:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
else:
|
||||||
|
raise Exception('Requested geocoder is not available')
|
||||||
|
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
# The configuration is retrieved but no checks are performed on it
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||||
|
|
||||||
|
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
from iso3166 import countries
|
||||||
|
from cartodb_services.tools import ServiceManager, QuotaExceededException
|
||||||
|
from cartodb_services.tomtom import TomTomGeocoder
|
||||||
|
from cartodb_services.tools.country import country_to_iso3
|
||||||
|
from cartodb_services.refactor.service.tomtom_geocoder_config import TomTomGeocoderConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('geocoder', TomTomGeocoderConfigBuilder, username, orgname, GD)
|
||||||
|
|
||||||
|
try:
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
geocoder = TomTomGeocoder(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
country_iso3166 = None
|
||||||
|
if country:
|
||||||
|
country_iso3 = country_to_iso3(country)
|
||||||
|
if country_iso3:
|
||||||
|
country_iso3166 = countries.get(country_iso3).alpha2.lower()
|
||||||
|
|
||||||
|
coordinates = geocoder.geocode(searchtext=searchtext, city=city,
|
||||||
|
state_province=state_province,
|
||||||
|
country=country_iso3166)
|
||||||
|
if coordinates:
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||||
|
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||||
|
return point['st_setsrid']
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return None
|
||||||
|
except QuotaExceededException as qe:
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
return None
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to geocode street point using TomTom', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to geocode street point using TomTom')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isodistance(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
source geometry(Geometry, 4326),
|
||||||
|
mode TEXT,
|
||||||
|
data_range integer[],
|
||||||
|
options text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.tools import ServiceManager
|
||||||
|
from cartodb_services.tomtom import TomTomIsolines
|
||||||
|
from cartodb_services.tomtom.types import TRANSPORT_MODE_TO_TOMTOM
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from cartodb_services.refactor.service.tomtom_isolines_config import TomTomIsolinesConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('isolines', TomTomIsolinesConfigBuilder, username, orgname, GD)
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
|
||||||
|
try:
|
||||||
|
tomtom_isolines = TomTomIsolines(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
if source:
|
||||||
|
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
|
||||||
|
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
|
||||||
|
origin = Coordinate(lon,lat)
|
||||||
|
else:
|
||||||
|
raise Exception('source is NULL')
|
||||||
|
|
||||||
|
profile = TRANSPORT_MODE_TO_TOMTOM.get(mode)
|
||||||
|
|
||||||
|
# -- TODO Support options properly
|
||||||
|
isolines = {}
|
||||||
|
for r in data_range:
|
||||||
|
isoline = tomtom_isolines.calculate_isodistance(origin, r, profile)
|
||||||
|
isolines[r] = isoline
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for r in data_range:
|
||||||
|
|
||||||
|
if len(isolines[r]) >= 3:
|
||||||
|
# -- TODO encapsulate this block into a func/method
|
||||||
|
locations = isolines[r] + [ isolines[r][0] ] # close the polygon repeating the first point
|
||||||
|
wkt_coordinates = ','.join(["%f %f" % (l.longitude, l.latitude) for l in locations])
|
||||||
|
sql = "SELECT ST_CollectionExtract(ST_MakeValid(ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326)),3) as geom".format(wkt_coordinates)
|
||||||
|
multipolygon = plpy.execute(sql, 1)[0]['geom']
|
||||||
|
else:
|
||||||
|
multipolygon = None
|
||||||
|
|
||||||
|
result.append([source, r, multipolygon])
|
||||||
|
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
service_manager.quota_service.increment_isolines_service_use(len(isolines))
|
||||||
|
return result
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to get TomTom isolines', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to get TomTom isolines')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isochrones(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
source geometry(Geometry, 4326),
|
||||||
|
mode TEXT,
|
||||||
|
data_range integer[],
|
||||||
|
options text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.tools import ServiceManager
|
||||||
|
from cartodb_services.tomtom import TomTomIsolines
|
||||||
|
from cartodb_services.tomtom.types import TRANSPORT_MODE_TO_TOMTOM
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from cartodb_services.tools.coordinates import coordinates_to_polygon
|
||||||
|
from cartodb_services.refactor.service.tomtom_isolines_config import TomTomIsolinesConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('isolines', TomTomIsolinesConfigBuilder, username, orgname, GD)
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
|
||||||
|
try:
|
||||||
|
tomtom_isolines = TomTomIsolines(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
if source:
|
||||||
|
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
|
||||||
|
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
|
||||||
|
origin = Coordinate(lon,lat)
|
||||||
|
else:
|
||||||
|
raise Exception('source is NULL')
|
||||||
|
|
||||||
|
profile = TRANSPORT_MODE_TO_TOMTOM.get(mode)
|
||||||
|
|
||||||
|
resp = tomtom_isolines.calculate_isochrone(origin, data_range, profile)
|
||||||
|
|
||||||
|
if resp:
|
||||||
|
result = []
|
||||||
|
for isochrone in resp:
|
||||||
|
result_polygon = coordinates_to_polygon(isochrone.coordinates)
|
||||||
|
if result_polygon:
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
result.append([source, isochrone.duration, result_polygon])
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
result.append([source, isochrone.duration, None])
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
service_manager.quota_service.increment_isolines_service_use(len(result))
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return []
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to get TomTom isochrones', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to get TomTom isochrones')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
if user_isolines_config.google_services_user:
|
||||||
|
raise Exception('This service is not available for google service users.')
|
||||||
|
|
||||||
|
params = {'source': source, 'mode': mode, 'range': range, 'options': options}
|
||||||
|
|
||||||
|
with metrics('cdb_isodistance', user_isolines_config, logger, params):
|
||||||
|
if user_isolines_config.heremaps_provider:
|
||||||
|
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapzen_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_tomtom_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
|
else:
|
||||||
|
raise Exception('Requested isolines provider is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
-- tomtom isodistance
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
|
|
||||||
|
return result
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
if user_isolines_config.google_services_user:
|
||||||
|
raise Exception('This service is not available for google service users.')
|
||||||
|
|
||||||
|
params = {'source': source, 'mode': mode, 'range': range, 'options': options}
|
||||||
|
|
||||||
|
with metrics('cdb_isochrone', user_isolines_config, logger, params):
|
||||||
|
if user_isolines_config.heremaps_provider:
|
||||||
|
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapzen_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_tomtom_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
|
else:
|
||||||
|
raise Exception('Requested isolines provider is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
|
||||||
|
-- tomtom isochrone
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
|
return result
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
182
server/extension/cdb_dataservices_server--0.31.0--0.30.5.sql
Normal file
182
server/extension/cdb_dataservices_server--0.31.0--0.30.5.sql
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
--DO NOT MODIFY THIS FILE, IT IS GENERATED AUTOMATICALLY FROM SOURCES
|
||||||
|
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||||
|
\echo Use "ALTER EXTENSION cdb_dataservices_server UPDATE TO '0.30.5'" to load this file. \quit
|
||||||
|
|
||||||
|
-- HERE goes your code to upgrade/downgrade
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_tomtom_route_with_waypoints(TEXT, TEXT, geometry(Point, 4326)[], TEXT);
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_route_point_to_point(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
origin geometry(Point, 4326),
|
||||||
|
destination geometry(Point, 4326),
|
||||||
|
mode TEXT,
|
||||||
|
options text[] DEFAULT ARRAY[]::text[],
|
||||||
|
units text DEFAULT 'kilometers')
|
||||||
|
RETURNS cdb_dataservices_server.simple_route AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_routing_config = GD["user_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
with metrics('cdb_route_with_point', user_routing_config, logger):
|
||||||
|
waypoints = [origin, destination]
|
||||||
|
|
||||||
|
if user_routing_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapzen_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
else:
|
||||||
|
raise Exception('Requested routing method is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE ;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_route_with_waypoints(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
waypoints geometry(Point, 4326)[],
|
||||||
|
mode TEXT,
|
||||||
|
options text[] DEFAULT ARRAY[]::text[],
|
||||||
|
units text DEFAULT 'kilometers')
|
||||||
|
RETURNS cdb_dataservices_server.simple_route AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_routing_config = GD["user_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
with metrics('cdb_route_with_waypoints', user_routing_config, logger):
|
||||||
|
if user_routing_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapzen_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
else:
|
||||||
|
raise Exception('Requested routing method is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE ;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger,LoggerConfig
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
with metrics('cdb_geocode_street_point', user_geocoder_config, logger):
|
||||||
|
if user_geocoder_config.heremaps_geocoder:
|
||||||
|
here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.google_geocoder:
|
||||||
|
google_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_google_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(google_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.mapzen_geocoder:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(mapzen_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.mapbox_geocoder:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
else:
|
||||||
|
raise Exception('Requested geocoder is not available')
|
||||||
|
|
||||||
|
$$ LANGUAGE plpythonu STABLE ;
|
||||||
|
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_tomtom_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_tomtom_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_tomtom_isodistance(TEXT, TEXT, geometry(Geometry, 4326), TEXT, integer[], text[]);
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_tomtom_isochrones(TEXT, TEXT, geometry(Geometry, 4326), TEXT, integer[], text[]);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
if user_isolines_config.google_services_user:
|
||||||
|
raise Exception('This service is not available for google service users.')
|
||||||
|
|
||||||
|
with metrics('cb_isodistance', user_isolines_config, logger):
|
||||||
|
if user_isolines_config.heremaps_provider:
|
||||||
|
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapzen_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
||||||
|
else:
|
||||||
|
raise Exception('Requested isolines provider is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE ;
|
||||||
|
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_tomtom_isodistance(TEXT, TEXT, geometry(Geometry, 4326), TEXT, integer[], text[]);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.metrics import metrics
|
||||||
|
from cartodb_services.tools import Logger
|
||||||
|
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||||
|
logger_config = GD["logger_config"]
|
||||||
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
|
if user_isolines_config.google_services_user:
|
||||||
|
raise Exception('This service is not available for google service users.')
|
||||||
|
|
||||||
|
with metrics('cb_isochrone', user_isolines_config, logger):
|
||||||
|
if user_isolines_config.heremaps_provider:
|
||||||
|
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapzen_provider:
|
||||||
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapzen_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.mapbox_provider:
|
||||||
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
||||||
|
else:
|
||||||
|
raise Exception('Requested isolines provider is not available')
|
||||||
|
$$ LANGUAGE plpythonu STABLE ;
|
||||||
|
|
||||||
|
|
||||||
|
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_tomtom_isochrone(TEXT, TEXT, geometry(Geometry, 4326), TEXT, integer[], text[]);
|
3658
server/extension/cdb_dataservices_server--0.31.0.sql
Normal file
3658
server/extension/cdb_dataservices_server--0.31.0.sql
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
comment = 'CartoDB dataservices server extension'
|
comment = 'CartoDB dataservices server extension'
|
||||||
default_version = '0.30.5'
|
default_version = '0.31.0'
|
||||||
requires = 'plpythonu, plproxy, postgis, cdb_geocoder'
|
requires = 'plpythonu, plproxy, postgis, cdb_geocoder'
|
||||||
superuser = true
|
superuser = true
|
||||||
schema = cdb_dataservices_server
|
schema = cdb_dataservices_server
|
||||||
|
@ -65,6 +65,67 @@ RETURNS cdb_dataservices_server.simple_route AS $$
|
|||||||
service_manager.quota_service.increment_total_service_use()
|
service_manager.quota_service.increment_total_service_use()
|
||||||
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_route_with_waypoints(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
waypoints geometry(Point, 4326)[],
|
||||||
|
mode TEXT)
|
||||||
|
RETURNS cdb_dataservices_server.simple_route AS $$
|
||||||
|
from cartodb_services.tools import ServiceManager
|
||||||
|
from cartodb_services.tomtom import TomTomRouting
|
||||||
|
from cartodb_services.tomtom.types import TRANSPORT_MODE_TO_TOMTOM
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from cartodb_services.tools.polyline import polyline_to_linestring
|
||||||
|
from cartodb_services.refactor.service.tomtom_routing_config import TomTomRoutingConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('routing', TomTomRoutingConfigBuilder, username, orgname, GD)
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
|
||||||
|
try:
|
||||||
|
client = TomTomRouting(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
if not waypoints or len(waypoints) < 2:
|
||||||
|
service_manager.logger.info("Empty origin or destination")
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
|
||||||
|
if len(waypoints) > 25:
|
||||||
|
service_manager.logger.info("Too many waypoints (max 25)")
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
|
||||||
|
waypoint_coords = []
|
||||||
|
for waypoint in waypoints:
|
||||||
|
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % waypoint)[0]['lat']
|
||||||
|
lon = plpy.execute("SELECT ST_X('%s') AS lon" % waypoint)[0]['lon']
|
||||||
|
waypoint_coords.append(Coordinate(lon,lat))
|
||||||
|
|
||||||
|
profile = TRANSPORT_MODE_TO_TOMTOM.get(mode)
|
||||||
|
|
||||||
|
resp = client.directions(waypoint_coords, profile)
|
||||||
|
if resp and resp.shape:
|
||||||
|
shape_linestring = polyline_to_linestring(resp.shape)
|
||||||
|
if shape_linestring:
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
return [shape_linestring, resp.length, int(round(resp.duration))]
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return [None, None, None]
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to calculate TomTom routing', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to calculate TomTom routing')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_route_with_waypoints(
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_route_with_waypoints(
|
||||||
username TEXT,
|
username TEXT,
|
||||||
orgname TEXT,
|
orgname TEXT,
|
||||||
|
@ -18,7 +18,9 @@ RETURNS cdb_dataservices_server.simple_route AS $$
|
|||||||
logger_config = GD["logger_config"]
|
logger_config = GD["logger_config"]
|
||||||
logger = Logger(logger_config)
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
with metrics('cdb_route_with_point', user_routing_config, logger):
|
params = {'origin': origin, 'destination': destination, 'mode': mode, 'options': options, 'units': units}
|
||||||
|
|
||||||
|
with metrics('cdb_route_with_point', user_routing_config, logger, params):
|
||||||
waypoints = [origin, destination]
|
waypoints = [origin, destination]
|
||||||
|
|
||||||
if user_routing_config.mapzen_provider:
|
if user_routing_config.mapzen_provider:
|
||||||
@ -29,6 +31,10 @@ RETURNS cdb_dataservices_server.simple_route AS $$
|
|||||||
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
||||||
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
else:
|
else:
|
||||||
raise Exception('Requested routing method is not available')
|
raise Exception('Requested routing method is not available')
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
@ -53,7 +59,9 @@ RETURNS cdb_dataservices_server.simple_route AS $$
|
|||||||
logger_config = GD["logger_config"]
|
logger_config = GD["logger_config"]
|
||||||
logger = Logger(logger_config)
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
with metrics('cdb_route_with_waypoints', user_routing_config, logger):
|
params = {'waypoints': waypoints, 'mode': mode, 'options': options, 'units': units}
|
||||||
|
|
||||||
|
with metrics('cdb_route_with_waypoints', user_routing_config, logger, params):
|
||||||
if user_routing_config.mapzen_provider:
|
if user_routing_config.mapzen_provider:
|
||||||
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
result = plpy.execute(mapzen_plan, [username, orgname, waypoints, mode])
|
result = plpy.execute(mapzen_plan, [username, orgname, waypoints, mode])
|
||||||
@ -62,6 +70,10 @@ RETURNS cdb_dataservices_server.simple_route AS $$
|
|||||||
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapbox_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
result = plpy.execute(mapbox_plan, [username, orgname, waypoints, mode])
|
||||||
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
|
elif user_routing_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_route_with_waypoints($1, $2, $3, $4) as route;", ["text", "text", "geometry(Point, 4326)[]", "text"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, waypoints, mode])
|
||||||
|
return [result[0]['shape'],result[0]['length'], result[0]['duration']]
|
||||||
else:
|
else:
|
||||||
raise Exception('Requested routing method is not available')
|
raise Exception('Requested routing method is not available')
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
@ -12,7 +12,9 @@ RETURNS Geometry AS $$
|
|||||||
logger_config = GD["logger_config"]
|
logger_config = GD["logger_config"]
|
||||||
logger = Logger(logger_config)
|
logger = Logger(logger_config)
|
||||||
|
|
||||||
with metrics('cdb_geocode_street_point', user_geocoder_config, logger):
|
params = {'searchtext': searchtext, 'city': city, 'state_province': state_province, 'country': country}
|
||||||
|
|
||||||
|
with metrics('cdb_geocode_street_point', user_geocoder_config, logger, params):
|
||||||
if user_geocoder_config.heremaps_geocoder:
|
if user_geocoder_config.heremaps_geocoder:
|
||||||
here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
here_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_here_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
return plpy.execute(here_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
@ -25,6 +27,9 @@ RETURNS Geometry AS $$
|
|||||||
elif user_geocoder_config.mapbox_geocoder:
|
elif user_geocoder_config.mapbox_geocoder:
|
||||||
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
elif user_geocoder_config.tomtom_geocoder:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
else:
|
else:
|
||||||
raise Exception('Requested geocoder is not available')
|
raise Exception('Requested geocoder is not available')
|
||||||
|
|
||||||
@ -82,8 +87,21 @@ RETURNS Geometry AS $$
|
|||||||
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||||
|
|
||||||
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
mapbox_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapbox_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
return plpy.execute(mapzen_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
return plpy.execute(mapbox_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
# The configuration is retrieved but no checks are performed on it
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_geocoder_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_geocoder_config = GD["user_geocoder_config_{0}".format(username)]
|
||||||
|
|
||||||
|
tomtom_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_tomtom_geocode_street_point($1, $2, $3, $4, $5, $6) as point; ", ["text", "text", "text", "text", "text", "text"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, searchtext, city, state_province, country], 1)[0]['point']
|
||||||
|
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
@ -233,8 +251,54 @@ RETURNS Geometry AS $$
|
|||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
import sys
|
import sys
|
||||||
service_manager.quota_service.increment_failed_service_use()
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
service_manager.logger.error('Error trying to geocode street point using mapbox', sys.exc_info(), data={"username": username, "orgname": orgname})
|
service_manager.logger.error('Error trying to geocode street point using Mapbox', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
raise Exception('Error trying to geocode street point using mapbox')
|
raise Exception('Error trying to geocode street point using Mapbox')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_geocode_street_point(username TEXT, orgname TEXT, searchtext TEXT, city TEXT DEFAULT NULL, state_province TEXT DEFAULT NULL, country TEXT DEFAULT NULL)
|
||||||
|
RETURNS Geometry AS $$
|
||||||
|
from iso3166 import countries
|
||||||
|
from cartodb_services.tools import ServiceManager, QuotaExceededException
|
||||||
|
from cartodb_services.tomtom import TomTomGeocoder
|
||||||
|
from cartodb_services.tools.country import country_to_iso3
|
||||||
|
from cartodb_services.refactor.service.tomtom_geocoder_config import TomTomGeocoderConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('geocoder', TomTomGeocoderConfigBuilder, username, orgname, GD)
|
||||||
|
|
||||||
|
try:
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
geocoder = TomTomGeocoder(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
country_iso3166 = None
|
||||||
|
if country:
|
||||||
|
country_iso3 = country_to_iso3(country)
|
||||||
|
if country_iso3:
|
||||||
|
country_iso3166 = countries.get(country_iso3).alpha2.lower()
|
||||||
|
|
||||||
|
coordinates = geocoder.geocode(searchtext=searchtext, city=city,
|
||||||
|
state_province=state_province,
|
||||||
|
country=country_iso3166)
|
||||||
|
if coordinates:
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
plan = plpy.prepare("SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326); ", ["double precision", "double precision"])
|
||||||
|
point = plpy.execute(plan, [coordinates[0], coordinates[1]], 1)[0]
|
||||||
|
return point['st_setsrid']
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return None
|
||||||
|
except QuotaExceededException as qe:
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
return None
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to geocode street point using TomTom', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to geocode street point using TomTom')
|
||||||
finally:
|
finally:
|
||||||
service_manager.quota_service.increment_total_service_use()
|
service_manager.quota_service.increment_total_service_use()
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
@ -188,6 +188,70 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
service_manager.quota_service.increment_total_service_use()
|
service_manager.quota_service.increment_total_service_use()
|
||||||
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isodistance(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
source geometry(Geometry, 4326),
|
||||||
|
mode TEXT,
|
||||||
|
data_range integer[],
|
||||||
|
options text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.tools import ServiceManager
|
||||||
|
from cartodb_services.tomtom import TomTomIsolines
|
||||||
|
from cartodb_services.tomtom.types import TRANSPORT_MODE_TO_TOMTOM
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from cartodb_services.refactor.service.tomtom_isolines_config import TomTomIsolinesConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('isolines', TomTomIsolinesConfigBuilder, username, orgname, GD)
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
|
||||||
|
try:
|
||||||
|
tomtom_isolines = TomTomIsolines(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
if source:
|
||||||
|
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
|
||||||
|
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
|
||||||
|
origin = Coordinate(lon,lat)
|
||||||
|
else:
|
||||||
|
raise Exception('source is NULL')
|
||||||
|
|
||||||
|
profile = TRANSPORT_MODE_TO_TOMTOM.get(mode)
|
||||||
|
|
||||||
|
# -- TODO Support options properly
|
||||||
|
isolines = {}
|
||||||
|
for r in data_range:
|
||||||
|
isoline = tomtom_isolines.calculate_isodistance(origin, r, profile)
|
||||||
|
isolines[r] = isoline
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for r in data_range:
|
||||||
|
|
||||||
|
if len(isolines[r]) >= 3:
|
||||||
|
# -- TODO encapsulate this block into a func/method
|
||||||
|
locations = isolines[r] + [ isolines[r][0] ] # close the polygon repeating the first point
|
||||||
|
wkt_coordinates = ','.join(["%f %f" % (l.longitude, l.latitude) for l in locations])
|
||||||
|
sql = "SELECT ST_CollectionExtract(ST_MakeValid(ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326)),3) as geom".format(wkt_coordinates)
|
||||||
|
multipolygon = plpy.execute(sql, 1)[0]['geom']
|
||||||
|
else:
|
||||||
|
multipolygon = None
|
||||||
|
|
||||||
|
result.append([source, r, multipolygon])
|
||||||
|
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
service_manager.quota_service.increment_isolines_service_use(len(isolines))
|
||||||
|
return result
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to get TomTom isolines', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to get TomTom isolines')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isochrones(
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isochrones(
|
||||||
username TEXT,
|
username TEXT,
|
||||||
orgname TEXT,
|
orgname TEXT,
|
||||||
@ -311,3 +375,63 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
finally:
|
finally:
|
||||||
service_manager.quota_service.increment_total_service_use()
|
service_manager.quota_service.increment_total_service_use()
|
||||||
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_tomtom_isochrones(
|
||||||
|
username TEXT,
|
||||||
|
orgname TEXT,
|
||||||
|
source geometry(Geometry, 4326),
|
||||||
|
mode TEXT,
|
||||||
|
data_range integer[],
|
||||||
|
options text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
from cartodb_services.tools import ServiceManager
|
||||||
|
from cartodb_services.tomtom import TomTomIsolines
|
||||||
|
from cartodb_services.tomtom.types import TRANSPORT_MODE_TO_TOMTOM
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from cartodb_services.tools.coordinates import coordinates_to_polygon
|
||||||
|
from cartodb_services.refactor.service.tomtom_isolines_config import TomTomIsolinesConfigBuilder
|
||||||
|
|
||||||
|
import cartodb_services
|
||||||
|
cartodb_services.init(plpy, GD)
|
||||||
|
|
||||||
|
service_manager = ServiceManager('isolines', TomTomIsolinesConfigBuilder, username, orgname, GD)
|
||||||
|
service_manager.assert_within_limits()
|
||||||
|
|
||||||
|
try:
|
||||||
|
tomtom_isolines = TomTomIsolines(service_manager.config.tomtom_api_key, service_manager.logger, service_manager.config.service_params)
|
||||||
|
|
||||||
|
if source:
|
||||||
|
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']
|
||||||
|
lon = plpy.execute("SELECT ST_X('%s') AS lon" % source)[0]['lon']
|
||||||
|
origin = Coordinate(lon,lat)
|
||||||
|
else:
|
||||||
|
raise Exception('source is NULL')
|
||||||
|
|
||||||
|
profile = TRANSPORT_MODE_TO_TOMTOM.get(mode)
|
||||||
|
|
||||||
|
resp = tomtom_isolines.calculate_isochrone(origin, data_range, profile)
|
||||||
|
|
||||||
|
if resp:
|
||||||
|
result = []
|
||||||
|
for isochrone in resp:
|
||||||
|
result_polygon = coordinates_to_polygon(isochrone.coordinates)
|
||||||
|
if result_polygon:
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
result.append([source, isochrone.duration, result_polygon])
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
result.append([source, isochrone.duration, None])
|
||||||
|
service_manager.quota_service.increment_success_service_use()
|
||||||
|
service_manager.quota_service.increment_isolines_service_use(len(result))
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
service_manager.quota_service.increment_empty_service_use()
|
||||||
|
return []
|
||||||
|
except BaseException as e:
|
||||||
|
import sys
|
||||||
|
service_manager.quota_service.increment_failed_service_use()
|
||||||
|
service_manager.logger.error('Error trying to get TomTom isochrones', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||||
|
raise Exception('Error trying to get TomTom isochrones')
|
||||||
|
finally:
|
||||||
|
service_manager.quota_service.increment_total_service_use()
|
||||||
|
$$ LANGUAGE plpythonu SECURITY DEFINER STABLE PARALLEL RESTRICTED;
|
||||||
|
@ -14,7 +14,9 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
if user_isolines_config.google_services_user:
|
if user_isolines_config.google_services_user:
|
||||||
raise Exception('This service is not available for google service users.')
|
raise Exception('This service is not available for google service users.')
|
||||||
|
|
||||||
with metrics('cb_isodistance', user_isolines_config, logger):
|
params = {'source': source, 'mode': mode, 'range': range, 'options': options}
|
||||||
|
|
||||||
|
with metrics('cdb_isodistance', user_isolines_config, logger, params):
|
||||||
if user_isolines_config.heremaps_provider:
|
if user_isolines_config.heremaps_provider:
|
||||||
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
||||||
@ -24,6 +26,9 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
elif user_isolines_config.mapbox_provider:
|
elif user_isolines_config.mapbox_provider:
|
||||||
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_tomtom_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
else:
|
else:
|
||||||
raise Exception('Requested isolines provider is not available')
|
raise Exception('Requested isolines provider is not available')
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
@ -70,3 +75,17 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
-- tomtom isodistance
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isodistance(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_isodistance($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
|
|
||||||
|
return result
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
@ -14,7 +14,9 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
if user_isolines_config.google_services_user:
|
if user_isolines_config.google_services_user:
|
||||||
raise Exception('This service is not available for google service users.')
|
raise Exception('This service is not available for google service users.')
|
||||||
|
|
||||||
with metrics('cb_isochrone', user_isolines_config, logger):
|
params = {'source': source, 'mode': mode, 'range': range, 'options': options}
|
||||||
|
|
||||||
|
with metrics('cdb_isochrone', user_isolines_config, logger, params):
|
||||||
if user_isolines_config.heremaps_provider:
|
if user_isolines_config.heremaps_provider:
|
||||||
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
here_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_here_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
return plpy.execute(here_plan, [username, orgname, source, mode, range, options])
|
||||||
@ -24,6 +26,9 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
elif user_isolines_config.mapbox_provider:
|
elif user_isolines_config.mapbox_provider:
|
||||||
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
mapbox_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_mapbox_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
return plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
||||||
|
elif user_isolines_config.tomtom_provider:
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server.cdb_tomtom_isochrone($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
return plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
else:
|
else:
|
||||||
raise Exception('Requested isolines provider is not available')
|
raise Exception('Requested isolines provider is not available')
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
@ -68,3 +73,16 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
|||||||
result = plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
result = plpy.execute(mapbox_plan, [username, orgname, source, mode, range, options])
|
||||||
return result
|
return result
|
||||||
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
|
||||||
|
-- tomtom isochrone
|
||||||
|
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_tomtom_isochrone(username TEXT, orgname TEXT, source geometry(Geometry, 4326), mode TEXT, range integer[], options text[] DEFAULT array[]::text[])
|
||||||
|
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||||
|
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||||
|
plpy.execute("SELECT cdb_dataservices_server._get_isolines_routing_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||||
|
user_isolines_config = GD["user_isolines_routing_config_{0}".format(username)]
|
||||||
|
|
||||||
|
tomtom_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_tomtom_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||||
|
result = plpy.execute(tomtom_plan, [username, orgname, source, mode, range, options])
|
||||||
|
return result
|
||||||
|
$$ LANGUAGE plpythonu STABLE PARALLEL RESTRICTED;
|
||||||
|
@ -39,6 +39,12 @@ SELECT cartodb.cdb_conf_setconf('mapbox_conf', '{"routing": {"api_keys": ["routi
|
|||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT cartodb.cdb_conf_setconf('tomtom_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "isolines": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}');
|
||||||
|
cdb_conf_setconf
|
||||||
|
------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT cartodb.cdb_conf_setconf('logger_conf', '{"geocoder_log_path": "/dev/null"}');
|
SELECT cartodb.cdb_conf_setconf('logger_conf', '{"geocoder_log_path": "/dev/null"}');
|
||||||
cdb_conf_setconf
|
cdb_conf_setconf
|
||||||
------------------
|
------------------
|
||||||
|
@ -16,6 +16,7 @@ SELECT cartodb.cdb_conf_setconf('redis_metadata_config', '{"redis_host": "localh
|
|||||||
SELECT cartodb.cdb_conf_setconf('heremaps_conf', '{"geocoder": {"app_id": "dummy_id", "app_code": "dummy_code", "geocoder_cost_per_hit": 1}, "isolines": {"app_id": "dummy_id", "app_code": "dummy_code"}}');
|
SELECT cartodb.cdb_conf_setconf('heremaps_conf', '{"geocoder": {"app_id": "dummy_id", "app_code": "dummy_code", "geocoder_cost_per_hit": 1}, "isolines": {"app_id": "dummy_id", "app_code": "dummy_code"}}');
|
||||||
SELECT cartodb.cdb_conf_setconf('mapzen_conf', '{"routing": {"api_key": "routing_dummy_api_key", "monthly_quota": 1500000}, "geocoder": {"api_key": "geocoder_dummy_api_key", "monthly_quota": 1500000}, "matrix": {"api_key": "matrix_dummy_api_key", "monthly_quota": 1500000}}');
|
SELECT cartodb.cdb_conf_setconf('mapzen_conf', '{"routing": {"api_key": "routing_dummy_api_key", "monthly_quota": 1500000}, "geocoder": {"api_key": "geocoder_dummy_api_key", "monthly_quota": 1500000}, "matrix": {"api_key": "matrix_dummy_api_key", "monthly_quota": 1500000}}');
|
||||||
SELECT cartodb.cdb_conf_setconf('mapbox_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "matrix": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}');
|
SELECT cartodb.cdb_conf_setconf('mapbox_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "matrix": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}');
|
||||||
|
SELECT cartodb.cdb_conf_setconf('tomtom_conf', '{"routing": {"api_keys": ["routing_dummy_api_key"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["geocoder_dummy_api_key"], "monthly_quota": 1500000}, "isolines": {"api_keys": ["matrix_dummy_api_key"], "monthly_quota": 1500000}}');
|
||||||
SELECT cartodb.cdb_conf_setconf('logger_conf', '{"geocoder_log_path": "/dev/null"}');
|
SELECT cartodb.cdb_conf_setconf('logger_conf', '{"geocoder_log_path": "/dev/null"}');
|
||||||
SELECT cartodb.cdb_conf_setconf('data_observatory_conf', '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=contrib_regression user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}, "monthly_quota": 100000}');
|
SELECT cartodb.cdb_conf_setconf('data_observatory_conf', '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=contrib_regression user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}, "monthly_quota": 100000}');
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@ class RoutingConfig(ServiceConfig):
|
|||||||
ROUTING_PROVIDER_KEY = 'routing_provider'
|
ROUTING_PROVIDER_KEY = 'routing_provider'
|
||||||
MAPZEN_PROVIDER = 'mapzen'
|
MAPZEN_PROVIDER = 'mapzen'
|
||||||
MAPBOX_PROVIDER = 'mapbox'
|
MAPBOX_PROVIDER = 'mapbox'
|
||||||
|
TOMTOM_PROVIDER = 'tomtom'
|
||||||
DEFAULT_PROVIDER = MAPBOX_PROVIDER
|
DEFAULT_PROVIDER = MAPBOX_PROVIDER
|
||||||
QUOTA_KEY = 'mapzen_routing_quota'
|
QUOTA_KEY = 'mapzen_routing_quota'
|
||||||
SOFT_LIMIT_KEY = 'soft_mapzen_routing_limit'
|
SOFT_LIMIT_KEY = 'soft_mapzen_routing_limit'
|
||||||
@ -153,6 +154,9 @@ class RoutingConfig(ServiceConfig):
|
|||||||
elif self._routing_provider == self.MAPBOX_PROVIDER:
|
elif self._routing_provider == self.MAPBOX_PROVIDER:
|
||||||
self._mapbox_api_keys = self._db_config.mapbox_routing_api_keys
|
self._mapbox_api_keys = self._db_config.mapbox_routing_api_keys
|
||||||
self._mapbox_service_params = self._db_config.mapbox_routing_service_params
|
self._mapbox_service_params = self._db_config.mapbox_routing_service_params
|
||||||
|
elif self._routing_provider == self.TOMTOM_PROVIDER:
|
||||||
|
self._tomtom_api_keys = self._db_config.tomtom_routing_api_keys
|
||||||
|
self._tomtom_service_params = self._db_config.tomtom_routing_service_params
|
||||||
self._routing_quota = self._get_effective_monthly_quota(self.QUOTA_KEY)
|
self._routing_quota = self._get_effective_monthly_quota(self.QUOTA_KEY)
|
||||||
self._set_soft_limit()
|
self._set_soft_limit()
|
||||||
self._period_end_date = date_parse(self._redis_config[self.PERIOD_END_DATE])
|
self._period_end_date = date_parse(self._redis_config[self.PERIOD_END_DATE])
|
||||||
@ -163,6 +167,8 @@ class RoutingConfig(ServiceConfig):
|
|||||||
return 'routing_mapzen'
|
return 'routing_mapzen'
|
||||||
elif self._routing_provider == self.MAPBOX_PROVIDER:
|
elif self._routing_provider == self.MAPBOX_PROVIDER:
|
||||||
return 'routing_mapbox'
|
return 'routing_mapbox'
|
||||||
|
elif self._routing_provider == self.TOMTOM_PROVIDER:
|
||||||
|
return 'routing_tomtom'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def provider(self):
|
def provider(self):
|
||||||
@ -192,6 +198,18 @@ class RoutingConfig(ServiceConfig):
|
|||||||
def mapbox_service_params(self):
|
def mapbox_service_params(self):
|
||||||
return self._mapbox_service_params
|
return self._mapbox_service_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_provider(self):
|
||||||
|
return self._routing_provider == self.TOMTOM_PROVIDER
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_api_keys(self):
|
||||||
|
return self._tomtom_api_keys
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_service_params(self):
|
||||||
|
return self._tomtom_service_params
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def routing_quota(self):
|
def routing_quota(self):
|
||||||
return self._routing_quota
|
return self._routing_quota
|
||||||
@ -228,6 +246,7 @@ class IsolinesRoutingConfig(ServiceConfig):
|
|||||||
GEOCODER_PROVIDER_KEY = 'geocoder_provider'
|
GEOCODER_PROVIDER_KEY = 'geocoder_provider'
|
||||||
MAPZEN_PROVIDER = 'mapzen'
|
MAPZEN_PROVIDER = 'mapzen'
|
||||||
MAPBOX_PROVIDER = 'mapbox'
|
MAPBOX_PROVIDER = 'mapbox'
|
||||||
|
TOMTOM_PROVIDER = 'tomtom'
|
||||||
HEREMAPS_PROVIDER = 'heremaps'
|
HEREMAPS_PROVIDER = 'heremaps'
|
||||||
DEFAULT_PROVIDER = MAPBOX_PROVIDER
|
DEFAULT_PROVIDER = MAPBOX_PROVIDER
|
||||||
METRICS_LOG_KEY = 'isolines_log_path'
|
METRICS_LOG_KEY = 'isolines_log_path'
|
||||||
@ -261,6 +280,9 @@ class IsolinesRoutingConfig(ServiceConfig):
|
|||||||
self._mapbox_matrix_api_keys = self._db_config.mapbox_matrix_api_keys
|
self._mapbox_matrix_api_keys = self._db_config.mapbox_matrix_api_keys
|
||||||
self._mapbox_matrix_service_params = db_config.mapbox_matrix_service_params
|
self._mapbox_matrix_service_params = db_config.mapbox_matrix_service_params
|
||||||
self._mapbox_isochrones_service_params = db_config.mapbox_isochrones_service_params
|
self._mapbox_isochrones_service_params = db_config.mapbox_isochrones_service_params
|
||||||
|
elif self._isolines_provider == self.TOMTOM_PROVIDER:
|
||||||
|
self._tomtom_isolinesx_api_keys = self._db_config.tomtom_isolines_api_keys
|
||||||
|
self._tomtom_isolines_service_params = db_config.tomtom_isolines_service_params
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def service_type(self):
|
def service_type(self):
|
||||||
@ -270,6 +292,8 @@ class IsolinesRoutingConfig(ServiceConfig):
|
|||||||
return 'mapzen_isolines'
|
return 'mapzen_isolines'
|
||||||
elif self._isolines_provider == self.MAPBOX_PROVIDER:
|
elif self._isolines_provider == self.MAPBOX_PROVIDER:
|
||||||
return 'mapbox_isolines'
|
return 'mapbox_isolines'
|
||||||
|
elif self._isolines_provider == self.TOMTOM_PROVIDER:
|
||||||
|
return 'tomtom_isolines'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def google_services_user(self):
|
def google_services_user(self):
|
||||||
@ -331,6 +355,18 @@ class IsolinesRoutingConfig(ServiceConfig):
|
|||||||
def mapbox_provider(self):
|
def mapbox_provider(self):
|
||||||
return self._isolines_provider == self.MAPBOX_PROVIDER
|
return self._isolines_provider == self.MAPBOX_PROVIDER
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_isolines_api_keys(self):
|
||||||
|
return self._tomtom_isolines_api_keys
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_isolines_service_params(self):
|
||||||
|
return self._tomtom_isolines_service_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_provider(self):
|
||||||
|
return self._isolines_provider == self.TOMTOM_PROVIDER
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def heremaps_provider(self):
|
def heremaps_provider(self):
|
||||||
return self._isolines_provider == self.HEREMAPS_PROVIDER
|
return self._isolines_provider == self.HEREMAPS_PROVIDER
|
||||||
@ -389,6 +425,8 @@ class GeocoderConfig(ServiceConfig):
|
|||||||
GEOCODER_PROVIDER = 'geocoder_provider'
|
GEOCODER_PROVIDER = 'geocoder_provider'
|
||||||
MAPBOX_GEOCODER = 'mapbox'
|
MAPBOX_GEOCODER = 'mapbox'
|
||||||
MAPBOX_GEOCODER_API_KEYS = 'mapbox_geocoder_api_keys'
|
MAPBOX_GEOCODER_API_KEYS = 'mapbox_geocoder_api_keys'
|
||||||
|
TOMTOM_GEOCODER = 'tomtom'
|
||||||
|
TOMTOM_GEOCODER_API_KEYS = 'tomtom_geocoder_api_keys'
|
||||||
QUOTA_KEY = 'geocoding_quota'
|
QUOTA_KEY = 'geocoding_quota'
|
||||||
SOFT_LIMIT_KEY = 'soft_geocoding_limit'
|
SOFT_LIMIT_KEY = 'soft_geocoding_limit'
|
||||||
USERNAME_KEY = 'username'
|
USERNAME_KEY = 'username'
|
||||||
@ -418,6 +456,9 @@ class GeocoderConfig(ServiceConfig):
|
|||||||
elif self._geocoder_provider == self.MAPBOX_GEOCODER:
|
elif self._geocoder_provider == self.MAPBOX_GEOCODER:
|
||||||
if not self.mapbox_api_keys:
|
if not self.mapbox_api_keys:
|
||||||
raise ConfigException("""Mapbox config is not set up""")
|
raise ConfigException("""Mapbox config is not set up""")
|
||||||
|
elif self._geocoder_provider == self.TOMTOM_GEOCODER:
|
||||||
|
if not self.tomtom_api_keys:
|
||||||
|
raise ConfigException("""TomTom config is not set up""")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -453,6 +494,10 @@ class GeocoderConfig(ServiceConfig):
|
|||||||
self._mapbox_api_keys = db_config.mapbox_geocoder_api_keys
|
self._mapbox_api_keys = db_config.mapbox_geocoder_api_keys
|
||||||
self._cost_per_hit = 0
|
self._cost_per_hit = 0
|
||||||
self._mapbox_service_params = db_config.mapbox_geocoder_service_params
|
self._mapbox_service_params = db_config.mapbox_geocoder_service_params
|
||||||
|
elif self._geocoder_provider == self.TOMTOM_GEOCODER:
|
||||||
|
self._tomtom_api_keys = db_config.tomtom_geocoder_api_keys
|
||||||
|
self._cost_per_hit = 0
|
||||||
|
self._tomtom_service_params = db_config.tomtom_geocoder_service_params
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def service_type(self):
|
def service_type(self):
|
||||||
@ -462,6 +507,8 @@ class GeocoderConfig(ServiceConfig):
|
|||||||
return 'geocoder_mapzen'
|
return 'geocoder_mapzen'
|
||||||
elif self._geocoder_provider == self.MAPBOX_GEOCODER:
|
elif self._geocoder_provider == self.MAPBOX_GEOCODER:
|
||||||
return 'geocoder_mapbox'
|
return 'geocoder_mapbox'
|
||||||
|
elif self._geocoder_provider == self.TOMTOM_GEOCODER:
|
||||||
|
return 'geocoder_tomtom'
|
||||||
elif self._geocoder_provider == self.NOKIA_GEOCODER:
|
elif self._geocoder_provider == self.NOKIA_GEOCODER:
|
||||||
return 'geocoder_here'
|
return 'geocoder_here'
|
||||||
|
|
||||||
@ -481,6 +528,10 @@ class GeocoderConfig(ServiceConfig):
|
|||||||
def mapbox_geocoder(self):
|
def mapbox_geocoder(self):
|
||||||
return self._geocoder_provider == self.MAPBOX_GEOCODER
|
return self._geocoder_provider == self.MAPBOX_GEOCODER
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_geocoder(self):
|
||||||
|
return self._geocoder_provider == self.TOMTOM_GEOCODER
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def google_client_id(self):
|
def google_client_id(self):
|
||||||
return self._google_maps_client_id
|
return self._google_maps_client_id
|
||||||
@ -532,6 +583,14 @@ class GeocoderConfig(ServiceConfig):
|
|||||||
def mapbox_service_params(self):
|
def mapbox_service_params(self):
|
||||||
return self._mapbox_service_params
|
return self._mapbox_service_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_api_keys(self):
|
||||||
|
return self._tomtom_api_keys
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_service_params(self):
|
||||||
|
return self._tomtom_service_params
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_high_resolution(self):
|
def is_high_resolution(self):
|
||||||
return True
|
return True
|
||||||
@ -562,6 +621,7 @@ class ServicesDBConfig:
|
|||||||
self._get_here_config()
|
self._get_here_config()
|
||||||
self._get_mapzen_config()
|
self._get_mapzen_config()
|
||||||
self._get_mapbox_config()
|
self._get_mapbox_config()
|
||||||
|
self._get_tomtom_config()
|
||||||
self._get_data_observatory_config()
|
self._get_data_observatory_config()
|
||||||
|
|
||||||
def _get_server_config(self):
|
def _get_server_config(self):
|
||||||
@ -625,6 +685,22 @@ class ServicesDBConfig:
|
|||||||
self._mapbox_geocoder_quota = mapbox_conf['geocoder']['monthly_quota']
|
self._mapbox_geocoder_quota = mapbox_conf['geocoder']['monthly_quota']
|
||||||
self._mapbox_geocoder_service_params = mapbox_conf['geocoder'].get('service', {})
|
self._mapbox_geocoder_service_params = mapbox_conf['geocoder'].get('service', {})
|
||||||
|
|
||||||
|
def _get_tomtom_config(self):
|
||||||
|
tomtom_conf_json = self._get_conf('tomtom_conf')
|
||||||
|
if not tomtom_conf_json:
|
||||||
|
raise ConfigException('TomTom configuration missing')
|
||||||
|
else:
|
||||||
|
tomtom_conf = json.loads(tomtom_conf_json)
|
||||||
|
self._tomtom_isolines_api_keys = tomtom_conf['isolines']['api_keys']
|
||||||
|
self._tomtom_isolines_quota = tomtom_conf['isolines']['monthly_quota']
|
||||||
|
self._tomtom_isolines_service_params = tomtom_conf.get('isolines', {}).get('service', {})
|
||||||
|
self._tomtom_routing_api_keys = tomtom_conf['routing']['api_keys']
|
||||||
|
self._tomtom_routing_quota = tomtom_conf['routing']['monthly_quota']
|
||||||
|
self._tomtom_routing_service_params = tomtom_conf['routing'].get('service', {})
|
||||||
|
self._tomtom_geocoder_api_keys = tomtom_conf['geocoder']['api_keys']
|
||||||
|
self._tomtom_geocoder_quota = tomtom_conf['geocoder']['monthly_quota']
|
||||||
|
self._tomtom_geocoder_service_params = tomtom_conf['geocoder'].get('service', {})
|
||||||
|
|
||||||
def _get_data_observatory_config(self):
|
def _get_data_observatory_config(self):
|
||||||
do_conf_json = self._get_conf('data_observatory_conf')
|
do_conf_json = self._get_conf('data_observatory_conf')
|
||||||
if not do_conf_json:
|
if not do_conf_json:
|
||||||
@ -758,6 +834,42 @@ class ServicesDBConfig:
|
|||||||
def mapbox_geocoder_service_params(self):
|
def mapbox_geocoder_service_params(self):
|
||||||
return self._mapbox_geocoder_service_params
|
return self._mapbox_geocoder_service_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_isolines_api_keys(self):
|
||||||
|
return self._tomtom_isolines_api_keys
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_isolines_monthly_quota(self):
|
||||||
|
return self._tomtom_isolines_quota
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_isolines_service_params(self):
|
||||||
|
return self._tomtom_isolines_service_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_routing_api_keys(self):
|
||||||
|
return self._tomtom_routing_api_keys
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_routing_monthly_quota(self):
|
||||||
|
return self._tomtom_routing_quota
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_routing_service_params(self):
|
||||||
|
return self._tomtom_routing_service_params
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_geocoder_api_keys(self):
|
||||||
|
return self._tomtom_geocoder_api_keys
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_geocoder_monthly_quota(self):
|
||||||
|
return self._tomtom_geocoder_quota
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_geocoder_service_params(self):
|
||||||
|
return self._tomtom_geocoder_service_params
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data_observatory_connection_str(self):
|
def data_observatory_connection_str(self):
|
||||||
return self._data_observatory_connection_str
|
return self._data_observatory_connection_str
|
||||||
|
@ -69,25 +69,16 @@ class QuotaChecker:
|
|||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
""" Check if the current user quota surpasses the current quota """
|
""" Check if the current user quota surpasses the current quota """
|
||||||
if re.match('geocoder_*',
|
if re.match('^geocoder_',
|
||||||
self._user_service_config.service_type) is not None:
|
self._user_service_config.service_type) is not None:
|
||||||
return self.__check_geocoder_quota()
|
return self.__check_geocoder_quota()
|
||||||
elif re.match('here_isolines',
|
elif re.match('.*_isolines$',
|
||||||
self._user_service_config.service_type) is not None:
|
self._user_service_config.service_type) is not None:
|
||||||
return self.__check_isolines_quota()
|
return self.__check_isolines_quota()
|
||||||
elif re.match('mapzen_isolines',
|
elif re.match('^routing_',
|
||||||
self._user_service_config.service_type) is not None:
|
|
||||||
return self.__check_isolines_quota()
|
|
||||||
elif re.match('mapbox_isolines',
|
|
||||||
self._user_service_config.service_type) is not None:
|
|
||||||
return self.__check_isolines_quota()
|
|
||||||
elif re.match('routing_mapzen',
|
|
||||||
self._user_service_config.service_type) is not None:
|
self._user_service_config.service_type) is not None:
|
||||||
return self.__check_routing_quota()
|
return self.__check_routing_quota()
|
||||||
elif re.match('routing_mapbox',
|
elif re.match('^obs_',
|
||||||
self._user_service_config.service_type) is not None:
|
|
||||||
return self.__check_routing_quota()
|
|
||||||
elif re.match('obs_*',
|
|
||||||
self._user_service_config.service_type) is not None:
|
self._user_service_config.service_type) is not None:
|
||||||
return self.__check_data_observatory_quota()
|
return self.__check_data_observatory_quota()
|
||||||
else:
|
else:
|
||||||
|
@ -22,8 +22,10 @@ class UserMetricsService:
|
|||||||
SERVICE_HERE_ISOLINES = 'here_isolines'
|
SERVICE_HERE_ISOLINES = 'here_isolines'
|
||||||
SERVICE_MAPZEN_ISOLINES = 'mapzen_isolines'
|
SERVICE_MAPZEN_ISOLINES = 'mapzen_isolines'
|
||||||
SERVICE_MAPBOX_ISOLINES = 'mapbox_isolines'
|
SERVICE_MAPBOX_ISOLINES = 'mapbox_isolines'
|
||||||
|
SERVICE_TOMTOM_ISOLINES = 'tomtom_isolines'
|
||||||
SERVICE_MAPZEN_ROUTING = 'routing_mapzen'
|
SERVICE_MAPZEN_ROUTING = 'routing_mapzen'
|
||||||
SERVICE_MAPBOX_ROUTING = 'routing_mapbox'
|
SERVICE_MAPBOX_ROUTING = 'routing_mapbox'
|
||||||
|
SERVICE_TOMTOM_ROUTING = 'routing_tomtom'
|
||||||
SERVICE_OBSERVATORY = 'obs_general'
|
SERVICE_OBSERVATORY = 'obs_general'
|
||||||
DAY_OF_MONTH_ZERO_PADDED = '%d'
|
DAY_OF_MONTH_ZERO_PADDED = '%d'
|
||||||
|
|
||||||
@ -36,10 +38,12 @@ class UserMetricsService:
|
|||||||
def used_quota(self, service_type, date):
|
def used_quota(self, service_type, date):
|
||||||
if service_type in [self.SERVICE_HERE_ISOLINES,
|
if service_type in [self.SERVICE_HERE_ISOLINES,
|
||||||
self.SERVICE_MAPZEN_ISOLINES,
|
self.SERVICE_MAPZEN_ISOLINES,
|
||||||
self.SERVICE_MAPBOX_ISOLINES]:
|
self.SERVICE_MAPBOX_ISOLINES,
|
||||||
|
self.SERVICE_TOMTOM_ISOLINES]:
|
||||||
return self.__used_isolines_quota(service_type, date)
|
return self.__used_isolines_quota(service_type, date)
|
||||||
elif service_type in [self.SERVICE_MAPZEN_ROUTING,
|
elif service_type in [self.SERVICE_MAPZEN_ROUTING,
|
||||||
self.SERVICE_MAPBOX_ROUTING]:
|
self.SERVICE_MAPBOX_ROUTING,
|
||||||
|
self.SERVICE_TOMTOM_ROUTING]:
|
||||||
return self.__used_routing_quota(service_type, date)
|
return self.__used_routing_quota(service_type, date)
|
||||||
elif service_type == self.SERVICE_OBSERVATORY:
|
elif service_type == self.SERVICE_OBSERVATORY:
|
||||||
return self.__used_observatory_quota(service_type, date)
|
return self.__used_observatory_quota(service_type, date)
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
from dateutil.parser import parse as date_parse
|
||||||
|
from cartodb_services.refactor.service.utils import round_robin
|
||||||
|
from cartodb_services.tomtom.types import TOMTOM_GEOCODER_APIKEY_ROUNDROBIN
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomGeocoderConfig(object):
|
||||||
|
"""
|
||||||
|
Configuration needed to operate the TomTom geocoder service.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
geocoding_quota,
|
||||||
|
soft_geocoding_limit,
|
||||||
|
period_end_date,
|
||||||
|
cost_per_hit,
|
||||||
|
log_path,
|
||||||
|
tomtom_api_keys,
|
||||||
|
username,
|
||||||
|
organization,
|
||||||
|
service_params,
|
||||||
|
GD):
|
||||||
|
self._geocoding_quota = geocoding_quota
|
||||||
|
self._soft_geocoding_limit = soft_geocoding_limit
|
||||||
|
self._period_end_date = period_end_date
|
||||||
|
self._cost_per_hit = cost_per_hit
|
||||||
|
self._log_path = log_path
|
||||||
|
self._tomtom_api_keys = tomtom_api_keys
|
||||||
|
self._username = username
|
||||||
|
self._organization = organization
|
||||||
|
self._service_params = service_params
|
||||||
|
self._GD = GD
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_type(self):
|
||||||
|
return 'geocoder_tomtom'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provider(self):
|
||||||
|
return 'tomtom'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_high_resolution(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def geocoding_quota(self):
|
||||||
|
return self._geocoding_quota
|
||||||
|
|
||||||
|
@property
|
||||||
|
def soft_geocoding_limit(self):
|
||||||
|
return self._soft_geocoding_limit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def period_end_date(self):
|
||||||
|
return self._period_end_date
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cost_per_hit(self):
|
||||||
|
return self._cost_per_hit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log_path(self):
|
||||||
|
return self._log_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_api_key(self):
|
||||||
|
return round_robin(self._tomtom_api_keys, self._GD,
|
||||||
|
TOMTOM_GEOCODER_APIKEY_ROUNDROBIN)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def username(self):
|
||||||
|
return self._username
|
||||||
|
|
||||||
|
@property
|
||||||
|
def organization(self):
|
||||||
|
return self._organization
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_params(self):
|
||||||
|
return self._service_params
|
||||||
|
|
||||||
|
# TODO: for BW compat, remove
|
||||||
|
@property
|
||||||
|
def google_geocoder(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomGeocoderConfigBuilder(object):
|
||||||
|
|
||||||
|
def __init__(self, server_conf, user_conf, org_conf, username, orgname, GD):
|
||||||
|
self._server_conf = server_conf
|
||||||
|
self._user_conf = user_conf
|
||||||
|
self._org_conf = org_conf
|
||||||
|
self._username = username
|
||||||
|
self._orgname = orgname
|
||||||
|
self._GD = GD
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
tomtom_server_conf = self._server_conf.get('tomtom_conf')
|
||||||
|
tomtom_api_keys = tomtom_server_conf['geocoder']['api_keys']
|
||||||
|
tomtom_service_params = tomtom_server_conf['geocoder'].get('service', {})
|
||||||
|
|
||||||
|
geocoding_quota = self._get_quota()
|
||||||
|
soft_geocoding_limit = self._user_conf.get('soft_geocoding_limit').lower() == 'true'
|
||||||
|
cost_per_hit = 0
|
||||||
|
period_end_date_str = self._org_conf.get('period_end_date') or self._user_conf.get('period_end_date')
|
||||||
|
period_end_date = date_parse(period_end_date_str)
|
||||||
|
|
||||||
|
logger_conf = self._server_conf.get('logger_conf')
|
||||||
|
log_path = logger_conf.get('geocoder_log_path', None)
|
||||||
|
|
||||||
|
return TomTomGeocoderConfig(geocoding_quota,
|
||||||
|
soft_geocoding_limit,
|
||||||
|
period_end_date,
|
||||||
|
cost_per_hit,
|
||||||
|
log_path,
|
||||||
|
tomtom_api_keys,
|
||||||
|
self._username,
|
||||||
|
self._orgname,
|
||||||
|
tomtom_service_params,
|
||||||
|
self._GD)
|
||||||
|
|
||||||
|
def _get_quota(self):
|
||||||
|
geocoding_quota = self._org_conf.get('geocoding_quota') or self._user_conf.get('geocoding_quota')
|
||||||
|
if geocoding_quota is '':
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return int(geocoding_quota)
|
@ -0,0 +1,123 @@
|
|||||||
|
from dateutil.parser import parse as date_parse
|
||||||
|
from cartodb_services.refactor.service.utils import round_robin
|
||||||
|
from cartodb_services.tomtom.types import TOMTOM_ISOLINES_APIKEY_ROUNDROBIN
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomIsolinesConfig(object):
|
||||||
|
"""
|
||||||
|
Configuration needed to operate the TomTom directions service.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
isolines_quota,
|
||||||
|
soft_isolines_limit,
|
||||||
|
period_end_date,
|
||||||
|
cost_per_hit,
|
||||||
|
log_path,
|
||||||
|
tomtom_api_keys,
|
||||||
|
username,
|
||||||
|
organization,
|
||||||
|
service_params,
|
||||||
|
GD):
|
||||||
|
self._isolines_quota = isolines_quota
|
||||||
|
self._soft_isolines_limit = soft_isolines_limit
|
||||||
|
self._period_end_date = period_end_date
|
||||||
|
self._cost_per_hit = cost_per_hit
|
||||||
|
self._log_path = log_path
|
||||||
|
self._tomtom_api_keys = tomtom_api_keys
|
||||||
|
self._username = username
|
||||||
|
self._organization = organization
|
||||||
|
self._service_params = service_params
|
||||||
|
self._GD = GD
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_type(self):
|
||||||
|
return 'tomtom_isolines'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provider(self):
|
||||||
|
return 'tomtom'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_high_resolution(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def isolines_quota(self):
|
||||||
|
return self._isolines_quota
|
||||||
|
|
||||||
|
@property
|
||||||
|
def soft_isolines_limit(self):
|
||||||
|
return self._soft_isolines_limit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def period_end_date(self):
|
||||||
|
return self._period_end_date
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cost_per_hit(self):
|
||||||
|
return self._cost_per_hit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log_path(self):
|
||||||
|
return self._log_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_api_key(self):
|
||||||
|
return round_robin(self._tomtom_api_keys, self._GD,
|
||||||
|
TOMTOM_ISOLINES_APIKEY_ROUNDROBIN)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def username(self):
|
||||||
|
return self._username
|
||||||
|
|
||||||
|
@property
|
||||||
|
def organization(self):
|
||||||
|
return self._organization
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_params(self):
|
||||||
|
return self._service_params
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomIsolinesConfigBuilder(object):
|
||||||
|
|
||||||
|
def __init__(self, server_conf, user_conf, org_conf, username, orgname, GD):
|
||||||
|
self._server_conf = server_conf
|
||||||
|
self._user_conf = user_conf
|
||||||
|
self._org_conf = org_conf
|
||||||
|
self._username = username
|
||||||
|
self._orgname = orgname
|
||||||
|
self._GD = GD
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
tomtom_server_conf = self._server_conf.get('tomtom_conf')
|
||||||
|
tomtom_api_keys = tomtom_server_conf['isolines']['api_keys']
|
||||||
|
tomtom_service_params = tomtom_server_conf['isolines'].get('service', {})
|
||||||
|
|
||||||
|
isolines_quota = self._get_quota()
|
||||||
|
soft_isolines_limit = self._user_conf.get('soft_here_isolines_limit').lower() == 'true'
|
||||||
|
cost_per_hit = 0
|
||||||
|
period_end_date_str = self._org_conf.get('period_end_date') or self._user_conf.get('period_end_date')
|
||||||
|
period_end_date = date_parse(period_end_date_str)
|
||||||
|
|
||||||
|
logger_conf = self._server_conf.get('logger_conf')
|
||||||
|
log_path = logger_conf.get('isolines_log_path', None)
|
||||||
|
|
||||||
|
return TomTomIsolinesConfig(isolines_quota,
|
||||||
|
soft_isolines_limit,
|
||||||
|
period_end_date,
|
||||||
|
cost_per_hit,
|
||||||
|
log_path,
|
||||||
|
tomtom_api_keys,
|
||||||
|
self._username,
|
||||||
|
self._orgname,
|
||||||
|
tomtom_service_params,
|
||||||
|
self._GD)
|
||||||
|
|
||||||
|
def _get_quota(self):
|
||||||
|
isolines_quota = self._org_conf.get('here_isolines_quota') or self._user_conf.get('here_isolines_quota')
|
||||||
|
if isolines_quota is '':
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return int(isolines_quota)
|
@ -0,0 +1,131 @@
|
|||||||
|
from dateutil.parser import parse as date_parse
|
||||||
|
from cartodb_services.refactor.service.utils import round_robin
|
||||||
|
from cartodb_services.tomtom.types import TOMTOM_ROUTING_APIKEY_ROUNDROBIN
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomRoutingConfig(object):
|
||||||
|
"""
|
||||||
|
Configuration needed to operate the TomTom directions service.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
routing_quota,
|
||||||
|
soft_routing_limit,
|
||||||
|
monthly_quota,
|
||||||
|
period_end_date,
|
||||||
|
cost_per_hit,
|
||||||
|
log_path,
|
||||||
|
tomtom_api_keys,
|
||||||
|
username,
|
||||||
|
organization,
|
||||||
|
service_params,
|
||||||
|
GD):
|
||||||
|
self._routing_quota = routing_quota
|
||||||
|
self._soft_routing_limit = soft_routing_limit
|
||||||
|
self._monthly_quota = monthly_quota
|
||||||
|
self._period_end_date = period_end_date
|
||||||
|
self._cost_per_hit = cost_per_hit
|
||||||
|
self._log_path = log_path
|
||||||
|
self._tomtom_api_keys = tomtom_api_keys
|
||||||
|
self._username = username
|
||||||
|
self._organization = organization
|
||||||
|
self._service_params = service_params
|
||||||
|
self._GD = GD
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_type(self):
|
||||||
|
return 'routing_tomtom'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def provider(self):
|
||||||
|
return 'tomtom'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_high_resolution(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def routing_quota(self):
|
||||||
|
return self._routing_quota
|
||||||
|
|
||||||
|
@property
|
||||||
|
def soft_limit(self):
|
||||||
|
return self._soft_routing_limit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def monthly_quota(self):
|
||||||
|
return self._monthly_quota
|
||||||
|
|
||||||
|
@property
|
||||||
|
def period_end_date(self):
|
||||||
|
return self._period_end_date
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cost_per_hit(self):
|
||||||
|
return self._cost_per_hit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def log_path(self):
|
||||||
|
return self._log_path
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tomtom_api_key(self):
|
||||||
|
return round_robin(self._tomtom_api_keys, self._GD,
|
||||||
|
TOMTOM_ROUTING_APIKEY_ROUNDROBIN)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def username(self):
|
||||||
|
return self._username
|
||||||
|
|
||||||
|
@property
|
||||||
|
def organization(self):
|
||||||
|
return self._organization
|
||||||
|
|
||||||
|
@property
|
||||||
|
def service_params(self):
|
||||||
|
return self._service_params
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomRoutingConfigBuilder(object):
|
||||||
|
|
||||||
|
def __init__(self, server_conf, user_conf, org_conf, username, orgname, GD):
|
||||||
|
self._server_conf = server_conf
|
||||||
|
self._user_conf = user_conf
|
||||||
|
self._org_conf = org_conf
|
||||||
|
self._username = username
|
||||||
|
self._orgname = orgname
|
||||||
|
self._GD = GD
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
tomtom_server_conf = self._server_conf.get('tomtom_conf')
|
||||||
|
tomtom_api_keys = tomtom_server_conf['routing']['api_keys']
|
||||||
|
monthly_quota = tomtom_server_conf['routing']['monthly_quota']
|
||||||
|
tomtom_service_params = tomtom_server_conf['routing'].get('service', {})
|
||||||
|
|
||||||
|
routing_quota = self._get_quota()
|
||||||
|
soft_routing_limit = self._user_conf.get('soft_mapzen_routing_limit').lower() == 'true'
|
||||||
|
cost_per_hit = 0
|
||||||
|
period_end_date_str = self._org_conf.get('period_end_date') or self._user_conf.get('period_end_date')
|
||||||
|
period_end_date = date_parse(period_end_date_str)
|
||||||
|
|
||||||
|
logger_conf = self._server_conf.get('logger_conf')
|
||||||
|
log_path = logger_conf.get('routing_log_path', None)
|
||||||
|
|
||||||
|
return TomTomRoutingConfig(routing_quota,
|
||||||
|
soft_routing_limit,
|
||||||
|
monthly_quota,
|
||||||
|
period_end_date,
|
||||||
|
cost_per_hit,
|
||||||
|
log_path,
|
||||||
|
tomtom_api_keys,
|
||||||
|
self._username,
|
||||||
|
self._orgname,
|
||||||
|
tomtom_service_params,
|
||||||
|
self._GD)
|
||||||
|
|
||||||
|
def _get_quota(self):
|
||||||
|
routing_quota = self._org_conf.get('mapzen_routing_quota') or self._user_conf.get('mapzen_routing_quota')
|
||||||
|
if routing_quota is '':
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return int(routing_quota)
|
@ -0,0 +1,3 @@
|
|||||||
|
from geocoder import TomTomGeocoder
|
||||||
|
from routing import TomTomRouting, TomTomRoutingResponse
|
||||||
|
from isolines import TomTomIsolines, TomTomIsochronesResponse
|
@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/local/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from uritemplate import URITemplate
|
||||||
|
from cartodb_services.metrics import Traceable
|
||||||
|
from cartodb_services.tools.exceptions import ServiceException
|
||||||
|
from cartodb_services.tools.qps import qps_retry
|
||||||
|
from cartodb_services.tools.normalize import normalize
|
||||||
|
|
||||||
|
BASEURI = ('https://api.tomtom.com/search/2/geocode/'
|
||||||
|
'{searchtext}.JSON'
|
||||||
|
'?key={apiKey}'
|
||||||
|
'&limit=1')
|
||||||
|
ENTRY_RESULTS = 'results'
|
||||||
|
ENTRY_POSITION = 'position'
|
||||||
|
ENTRY_LON = 'lon'
|
||||||
|
ENTRY_LAT = 'lat'
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomGeocoder(Traceable):
|
||||||
|
'''
|
||||||
|
Python wrapper for the TomTom Geocoder service.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, apikey, logger, service_params=None):
|
||||||
|
service_params = service_params or {}
|
||||||
|
self._apikey = apikey
|
||||||
|
self._logger = logger
|
||||||
|
|
||||||
|
def _uri(self, searchtext, countries=None):
|
||||||
|
baseuri = BASEURI + '&countrySet={}'.format(countries) \
|
||||||
|
if countries else BASEURI
|
||||||
|
uri = URITemplate(baseuri).expand(apiKey=self._apikey,
|
||||||
|
searchtext=searchtext.encode('utf-8'))
|
||||||
|
return uri
|
||||||
|
|
||||||
|
def _parse_geocoder_response(self, response):
|
||||||
|
json_response = json.loads(response)
|
||||||
|
|
||||||
|
if json_response and json_response[ENTRY_RESULTS]:
|
||||||
|
result = json_response[ENTRY_RESULTS][0]
|
||||||
|
return self._extract_lng_lat_from_feature(result)
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _extract_lng_lat_from_feature(self, result):
|
||||||
|
position = result[ENTRY_POSITION]
|
||||||
|
longitude = position[ENTRY_LON]
|
||||||
|
latitude = position[ENTRY_LAT]
|
||||||
|
return [longitude, latitude]
|
||||||
|
|
||||||
|
def _validate_input(self, searchtext, city=None, state_province=None,
|
||||||
|
country=None):
|
||||||
|
if searchtext and searchtext.strip():
|
||||||
|
return True
|
||||||
|
elif city:
|
||||||
|
return True
|
||||||
|
elif state_province:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
@qps_retry(qps=5)
|
||||||
|
def geocode(self, searchtext, city=None, state_province=None,
|
||||||
|
country=None):
|
||||||
|
if searchtext:
|
||||||
|
searchtext = searchtext.decode('utf-8')
|
||||||
|
if city:
|
||||||
|
city = city.decode('utf-8')
|
||||||
|
if state_province:
|
||||||
|
state_province = state_province.decode('utf-8')
|
||||||
|
if country:
|
||||||
|
country = country.decode('utf-8')
|
||||||
|
|
||||||
|
if not self._validate_input(searchtext, city, state_province, country):
|
||||||
|
return []
|
||||||
|
|
||||||
|
address = []
|
||||||
|
if searchtext and searchtext.strip():
|
||||||
|
address.append(normalize(searchtext))
|
||||||
|
if city:
|
||||||
|
address.append(normalize(city))
|
||||||
|
if state_province:
|
||||||
|
address.append(normalize(state_province))
|
||||||
|
|
||||||
|
uri = self._uri(searchtext=', '.join(address), countries=country)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(uri)
|
||||||
|
|
||||||
|
if response.status_code == requests.codes.ok:
|
||||||
|
return self._parse_geocoder_response(response.text)
|
||||||
|
elif response.status_code == requests.codes.bad_request:
|
||||||
|
return []
|
||||||
|
elif response.status_code == requests.codes.unprocessable_entity:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
raise ServiceException(response.status_code, response)
|
||||||
|
except requests.Timeout as te:
|
||||||
|
# In case of timeout we want to stop the job because the server
|
||||||
|
# could be down
|
||||||
|
self._logger.error('Timeout connecting to TomTom geocoding server',
|
||||||
|
te)
|
||||||
|
raise ServiceException('Error geocoding {0} using TomTom'.format(
|
||||||
|
searchtext), None)
|
||||||
|
except requests.ConnectionError as ce:
|
||||||
|
# Don't raise the exception to continue with the geocoding job
|
||||||
|
self._logger.error('Error connecting to TomTom geocoding server',
|
||||||
|
exception=ce)
|
||||||
|
return []
|
@ -0,0 +1,140 @@
|
|||||||
|
'''
|
||||||
|
Python implementation for TomTom services based isolines.
|
||||||
|
'''
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from uritemplate import URITemplate
|
||||||
|
|
||||||
|
from cartodb_services.tools.exceptions import ServiceException
|
||||||
|
from cartodb_services.tools.qps import qps_retry
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from types import (DEFAULT_PROFILE, VALID_PROFILES, DEFAULT_DEPARTAT,
|
||||||
|
MAX_SPEEDS)
|
||||||
|
|
||||||
|
BASEURI = ('https://api.tomtom.com/routing/1/calculateReachableRange/'
|
||||||
|
'{origin}'
|
||||||
|
'/json'
|
||||||
|
'?key={apikey}'
|
||||||
|
'&timeBudgetInSec={time}'
|
||||||
|
'&travelMode={travelmode}'
|
||||||
|
'&departAt={departat}')
|
||||||
|
|
||||||
|
ENTRY_REACHABLERANGE = 'reachableRange'
|
||||||
|
ENTRY_BOUNDARY = 'boundary'
|
||||||
|
ENTRY_LATITUDE = 'latitude'
|
||||||
|
ENTRY_LONGITUDE = 'longitude'
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomIsolines():
|
||||||
|
'''
|
||||||
|
Python wrapper for TomTom services based isolines.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, apikey, logger, service_params=None):
|
||||||
|
service_params = service_params or {}
|
||||||
|
self._apikey = apikey
|
||||||
|
self._logger = logger
|
||||||
|
|
||||||
|
def _uri(self, origin, time_range, profile=DEFAULT_PROFILE,
|
||||||
|
date_time=DEFAULT_DEPARTAT):
|
||||||
|
uri = URITemplate(BASEURI).expand(apikey=self._apikey,
|
||||||
|
origin=origin,
|
||||||
|
time=time_range,
|
||||||
|
travelmode=profile,
|
||||||
|
departat=date_time)
|
||||||
|
return uri
|
||||||
|
|
||||||
|
def _validate_profile(self, profile):
|
||||||
|
if profile not in VALID_PROFILES:
|
||||||
|
raise ValueError('{profile} is not a valid profile. '
|
||||||
|
'Valid profiles are: {valid_profiles}'.format(
|
||||||
|
profile=profile,
|
||||||
|
valid_profiles=', '.join(
|
||||||
|
[x for x in VALID_PROFILES])))
|
||||||
|
|
||||||
|
def _parse_coordinates(self, boundary):
|
||||||
|
return [Coordinate(c[ENTRY_LONGITUDE], c[ENTRY_LATITUDE]) for c in boundary]
|
||||||
|
|
||||||
|
def _parse_reachablerange_response(self, response):
|
||||||
|
json_response = json.loads(response)
|
||||||
|
|
||||||
|
if json_response:
|
||||||
|
reachable_range = json_response[ENTRY_REACHABLERANGE]
|
||||||
|
|
||||||
|
return self._parse_coordinates(reachable_range[ENTRY_BOUNDARY])
|
||||||
|
|
||||||
|
@qps_retry(qps=5)
|
||||||
|
def _calculate_isoline(self, origin, time_range,
|
||||||
|
profile=DEFAULT_PROFILE,
|
||||||
|
date_time=DEFAULT_DEPARTAT):
|
||||||
|
origin = '{lat},{lon}'.format(lat=origin.latitude,
|
||||||
|
lon=origin.longitude)
|
||||||
|
|
||||||
|
uri = self._uri(origin, time_range, profile, date_time)
|
||||||
|
try:
|
||||||
|
response = requests.get(uri)
|
||||||
|
|
||||||
|
if response.status_code == requests.codes.ok:
|
||||||
|
return self._parse_reachablerange_response(response.text)
|
||||||
|
elif response.status_code == requests.codes.bad_request:
|
||||||
|
return []
|
||||||
|
elif response.status_code == requests.codes.unprocessable_entity:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
raise ServiceException(response.status_code, response)
|
||||||
|
except requests.Timeout as te:
|
||||||
|
# In case of timeout we want to stop the job because the server
|
||||||
|
# could be down
|
||||||
|
self._logger.error('Timeout connecting to TomTom calculateReachableRange service',
|
||||||
|
te)
|
||||||
|
raise ServiceException('Error getting calculateReachableRange data from TomTom',
|
||||||
|
None)
|
||||||
|
except requests.ConnectionError as ce:
|
||||||
|
# Don't raise the exception to continue with the geocoding job
|
||||||
|
self._logger.error('Error connecting to TomTom calculateReachableRange service',
|
||||||
|
exception=ce)
|
||||||
|
return []
|
||||||
|
|
||||||
|
def calculate_isochrone(self, origin, time_ranges,
|
||||||
|
profile=DEFAULT_PROFILE,
|
||||||
|
date_time=DEFAULT_DEPARTAT):
|
||||||
|
self._validate_profile(profile)
|
||||||
|
|
||||||
|
isochrones = []
|
||||||
|
for time_range in time_ranges:
|
||||||
|
coordinates = self._calculate_isoline(origin=origin,
|
||||||
|
time_range=time_range,
|
||||||
|
profile=profile,
|
||||||
|
date_time=date_time)
|
||||||
|
isochrones.append(TomTomIsochronesResponse(coordinates,
|
||||||
|
time_range))
|
||||||
|
return isochrones
|
||||||
|
|
||||||
|
def calculate_isodistance(self, origin, distance_range,
|
||||||
|
profile=DEFAULT_PROFILE,
|
||||||
|
date_time=DEFAULT_DEPARTAT):
|
||||||
|
self._validate_profile(profile)
|
||||||
|
|
||||||
|
max_speed = MAX_SPEEDS[profile]
|
||||||
|
time_range = distance_range / max_speed
|
||||||
|
|
||||||
|
return self._calculate_isoline(origin=origin,
|
||||||
|
time_range=time_range,
|
||||||
|
profile=profile,
|
||||||
|
date_time=date_time)
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomIsochronesResponse:
|
||||||
|
|
||||||
|
def __init__(self, coordinates, duration):
|
||||||
|
self._coordinates = coordinates
|
||||||
|
self._duration = duration
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coordinates(self):
|
||||||
|
return self._coordinates
|
||||||
|
|
||||||
|
@property
|
||||||
|
def duration(self):
|
||||||
|
return self._duration
|
@ -0,0 +1,144 @@
|
|||||||
|
'''
|
||||||
|
Python client for the TomTom Routing service.
|
||||||
|
'''
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from uritemplate import URITemplate
|
||||||
|
from cartodb_services.metrics import Traceable
|
||||||
|
from cartodb_services.tools import PolyLine
|
||||||
|
from cartodb_services.tools.coordinates import (validate_coordinates,
|
||||||
|
marshall_coordinates)
|
||||||
|
from cartodb_services.tools.exceptions import ServiceException
|
||||||
|
from cartodb_services.tools.qps import qps_retry
|
||||||
|
from types import (DEFAULT_PROFILE, VALID_PROFILES, DEFAULT_DEPARTAT)
|
||||||
|
|
||||||
|
BASEURI = ('https://api.tomtom.com/routing/1/calculateRoute/'
|
||||||
|
'{coordinates}'
|
||||||
|
'/json'
|
||||||
|
'?key={apikey}'
|
||||||
|
'&travelMode={travelmode}'
|
||||||
|
'&departAt={departat}'
|
||||||
|
'&computeBestOrder=true')
|
||||||
|
|
||||||
|
NUM_WAYPOINTS_MIN = 2
|
||||||
|
NUM_WAYPOINTS_MAX = 20
|
||||||
|
|
||||||
|
ENTRY_ROUTES = 'routes'
|
||||||
|
ENTRY_SUMMARY = 'summary'
|
||||||
|
ENTRY_LENGTH = 'lengthInMeters'
|
||||||
|
ENTRY_TIME = 'travelTimeInSeconds'
|
||||||
|
ENTRY_LEGS = 'legs'
|
||||||
|
ENTRY_POINTS = 'points'
|
||||||
|
ENTRY_LATITUDE = 'latitude'
|
||||||
|
ENTRY_LONGITUDE = 'longitude'
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomRouting(Traceable):
|
||||||
|
'''
|
||||||
|
Python wrapper for the TomTom Routing service.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, apikey, logger, service_params=None):
|
||||||
|
service_params = service_params or {}
|
||||||
|
self._apikey = apikey
|
||||||
|
self._logger = logger
|
||||||
|
|
||||||
|
def _uri(self, coordinates, profile=DEFAULT_PROFILE,
|
||||||
|
date_time=DEFAULT_DEPARTAT):
|
||||||
|
uri = URITemplate(BASEURI).expand(apikey=self._apikey,
|
||||||
|
coordinates=coordinates,
|
||||||
|
travelmode=profile,
|
||||||
|
departat=date_time)
|
||||||
|
return uri
|
||||||
|
|
||||||
|
def _validate_profile(self, profile):
|
||||||
|
if profile not in VALID_PROFILES:
|
||||||
|
raise ValueError('{profile} is not a valid profile. '
|
||||||
|
'Valid profiles are: {valid_profiles}'.format(
|
||||||
|
profile=profile,
|
||||||
|
valid_profiles=', '.join(
|
||||||
|
[x for x in VALID_PROFILES])))
|
||||||
|
|
||||||
|
def _marshall_coordinates(self, coordinates):
|
||||||
|
return ':'.join(['{lat},{lon}'.format(lat=coordinate.latitude,
|
||||||
|
lon=coordinate.longitude)
|
||||||
|
for coordinate in coordinates])
|
||||||
|
|
||||||
|
def _parse_routing_response(self, response):
|
||||||
|
json_response = json.loads(response)
|
||||||
|
|
||||||
|
if json_response:
|
||||||
|
route = json_response[ENTRY_ROUTES][0] # Force the first route
|
||||||
|
|
||||||
|
geometry = self._parse_legs(route[ENTRY_LEGS])
|
||||||
|
summary = route[ENTRY_SUMMARY]
|
||||||
|
distance = summary[ENTRY_LENGTH]
|
||||||
|
duration = summary[ENTRY_TIME]
|
||||||
|
|
||||||
|
return TomTomRoutingResponse(geometry, distance, duration)
|
||||||
|
else:
|
||||||
|
return TomTomRoutingResponse(None, None, None)
|
||||||
|
|
||||||
|
def _parse_legs(self, legs):
|
||||||
|
geometry = []
|
||||||
|
for leg in legs:
|
||||||
|
points = leg[ENTRY_POINTS]
|
||||||
|
for point in points:
|
||||||
|
geometry.append((point[ENTRY_LATITUDE],
|
||||||
|
point[ENTRY_LONGITUDE]))
|
||||||
|
return geometry
|
||||||
|
|
||||||
|
@qps_retry(qps=5)
|
||||||
|
def directions(self, waypoints, profile=DEFAULT_PROFILE,
|
||||||
|
date_time=DEFAULT_DEPARTAT):
|
||||||
|
self._validate_profile(profile)
|
||||||
|
validate_coordinates(waypoints, NUM_WAYPOINTS_MIN, NUM_WAYPOINTS_MAX)
|
||||||
|
|
||||||
|
coordinates = self._marshall_coordinates(waypoints)
|
||||||
|
|
||||||
|
uri = self._uri(coordinates, profile, date_time)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(uri)
|
||||||
|
|
||||||
|
if response.status_code == requests.codes.ok:
|
||||||
|
return self._parse_routing_response(response.text)
|
||||||
|
elif response.status_code == requests.codes.bad_request:
|
||||||
|
return TomTomRoutingResponse(None, None, None)
|
||||||
|
elif response.status_code == requests.codes.unprocessable_entity:
|
||||||
|
return TomTomRoutingResponse(None, None, None)
|
||||||
|
else:
|
||||||
|
raise ServiceException(response.status_code, response)
|
||||||
|
except requests.Timeout as te:
|
||||||
|
# In case of timeout we want to stop the job because the server
|
||||||
|
# could be down
|
||||||
|
self._logger.error('Timeout connecting to TomTom routing service',
|
||||||
|
te)
|
||||||
|
raise ServiceException('Error getting routing data from TomTom',
|
||||||
|
None)
|
||||||
|
except requests.ConnectionError as ce:
|
||||||
|
# Don't raise the exception to continue with the geocoding job
|
||||||
|
self._logger.error('Error connecting to TomTom routing service',
|
||||||
|
exception=ce)
|
||||||
|
return TomTomRoutingResponse(None, None, None)
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomRoutingResponse:
|
||||||
|
|
||||||
|
def __init__(self, shape, length, duration):
|
||||||
|
self._shape = shape
|
||||||
|
self._length = length
|
||||||
|
self._duration = duration
|
||||||
|
|
||||||
|
@property
|
||||||
|
def shape(self):
|
||||||
|
return self._shape
|
||||||
|
|
||||||
|
@property
|
||||||
|
def length(self):
|
||||||
|
return self._length
|
||||||
|
|
||||||
|
@property
|
||||||
|
def duration(self):
|
||||||
|
return self._duration
|
@ -0,0 +1,26 @@
|
|||||||
|
TOMTOM_ROUTING_APIKEY_ROUNDROBIN = 'tomtom_routing_apikey_roundrobin'
|
||||||
|
TOMTOM_GEOCODER_APIKEY_ROUNDROBIN = 'tomtom_geocoder_apikey_roundrobin'
|
||||||
|
TOMTOM_ISOLINES_APIKEY_ROUNDROBIN = 'tomtom_isolines_apikey_roundrobin'
|
||||||
|
|
||||||
|
PROFILE_DRIVING = 'car'
|
||||||
|
PROFILE_CYCLING = 'bicycle'
|
||||||
|
PROFILE_WALKING = 'pedestrian'
|
||||||
|
DEFAULT_PROFILE = PROFILE_DRIVING
|
||||||
|
|
||||||
|
DEFAULT_DEPARTAT = 'now'
|
||||||
|
|
||||||
|
VALID_PROFILES = [PROFILE_DRIVING,
|
||||||
|
PROFILE_CYCLING,
|
||||||
|
PROFILE_WALKING]
|
||||||
|
|
||||||
|
MAX_SPEEDS = {
|
||||||
|
PROFILE_WALKING: 3.3333333, # In m/s, assuming 12km/h walking speed
|
||||||
|
PROFILE_CYCLING: 16.67, # In m/s, assuming 60km/h max speed
|
||||||
|
PROFILE_DRIVING: 41.67 # In m/s, assuming 140km/h max speed
|
||||||
|
}
|
||||||
|
|
||||||
|
TRANSPORT_MODE_TO_TOMTOM = {
|
||||||
|
'car': 'car',
|
||||||
|
'walk': 'pedestrian',
|
||||||
|
'bicycle': 'bicycle',
|
||||||
|
}
|
@ -10,7 +10,7 @@ from setuptools import setup, find_packages
|
|||||||
setup(
|
setup(
|
||||||
name='cartodb_services',
|
name='cartodb_services',
|
||||||
|
|
||||||
version='0.17.6',
|
version='0.18.0',
|
||||||
|
|
||||||
description='CartoDB Services API Python Library',
|
description='CartoDB Services API Python Library',
|
||||||
|
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def mapbox_api_key():
|
def mapbox_api_key():
|
||||||
"""Returns Mapbox API key. Requires setting MAPBOX_API_KEY environment variable."""
|
"""Returns Mapbox API key. Requires setting MAPBOX_API_KEY environment variable."""
|
||||||
return os.environ['MAPBOX_API_KEY']
|
return os.environ['MAPBOX_API_KEY']
|
||||||
|
|
||||||
|
|
||||||
|
def tomtom_api_key():
|
||||||
|
"""Returns TomTom API key. Requires setting TOMTOM_API_KEY environment variable."""
|
||||||
|
return os.environ['TOMTOM_API_KEY']
|
||||||
|
@ -7,7 +7,7 @@ from cartodb_services.metrics.config import *
|
|||||||
|
|
||||||
class TestGeocoderUserConfig(TestCase):
|
class TestGeocoderUserConfig(TestCase):
|
||||||
|
|
||||||
GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'google']
|
GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom', 'google']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.redis_conn = MockRedis()
|
self.redis_conn = MockRedis()
|
||||||
@ -28,6 +28,9 @@ class TestGeocoderUserConfig(TestCase):
|
|||||||
elif geocoder_provider == 'mapbox':
|
elif geocoder_provider == 'mapbox':
|
||||||
assert geocoder_config.mapbox_geocoder is True
|
assert geocoder_config.mapbox_geocoder is True
|
||||||
assert geocoder_config.geocoding_quota == 100
|
assert geocoder_config.geocoding_quota == 100
|
||||||
|
elif geocoder_provider == 'tomtom':
|
||||||
|
assert geocoder_config.tomtom_geocoder is True
|
||||||
|
assert geocoder_config.geocoding_quota == 100
|
||||||
elif geocoder_provider == 'google':
|
elif geocoder_provider == 'google':
|
||||||
assert geocoder_config.google_geocoder is True
|
assert geocoder_config.google_geocoder is True
|
||||||
assert geocoder_config.geocoding_quota is None
|
assert geocoder_config.geocoding_quota is None
|
||||||
@ -81,7 +84,7 @@ class TestGeocoderUserConfig(TestCase):
|
|||||||
|
|
||||||
class TestGeocoderOrgConfig(TestCase):
|
class TestGeocoderOrgConfig(TestCase):
|
||||||
|
|
||||||
GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'google']
|
GEOCODER_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom', 'google']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.redis_conn = MockRedis()
|
self.redis_conn = MockRedis()
|
||||||
@ -107,6 +110,9 @@ class TestGeocoderOrgConfig(TestCase):
|
|||||||
elif geocoder_provider == 'mapbox':
|
elif geocoder_provider == 'mapbox':
|
||||||
assert geocoder_config.mapbox_geocoder is True
|
assert geocoder_config.mapbox_geocoder is True
|
||||||
assert geocoder_config.geocoding_quota == 200
|
assert geocoder_config.geocoding_quota == 200
|
||||||
|
elif geocoder_provider == 'tomtom':
|
||||||
|
assert geocoder_config.tomtom_geocoder is True
|
||||||
|
assert geocoder_config.geocoding_quota == 200
|
||||||
elif geocoder_provider == 'google':
|
elif geocoder_provider == 'google':
|
||||||
assert geocoder_config.google_geocoder is True
|
assert geocoder_config.google_geocoder is True
|
||||||
assert geocoder_config.geocoding_quota is None
|
assert geocoder_config.geocoding_quota is None
|
||||||
@ -167,7 +173,7 @@ class TestGeocoderOrgConfig(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
class TestIsolinesUserConfig(TestCase):
|
class TestIsolinesUserConfig(TestCase):
|
||||||
ISOLINES_PROVIDERS = ['heremaps', 'mapzen', 'mapbox']
|
ISOLINES_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.redis_conn = MockRedis()
|
self.redis_conn = MockRedis()
|
||||||
@ -183,6 +189,8 @@ class TestIsolinesUserConfig(TestCase):
|
|||||||
assert isolines_config.service_type is 'mapzen_isolines'
|
assert isolines_config.service_type is 'mapzen_isolines'
|
||||||
elif isolines_provider is 'mapbox':
|
elif isolines_provider is 'mapbox':
|
||||||
assert isolines_config.service_type is 'mapbox_isolines'
|
assert isolines_config.service_type is 'mapbox_isolines'
|
||||||
|
elif isolines_provider is 'tomtom':
|
||||||
|
assert isolines_config.service_type is 'tomtom_isolines'
|
||||||
else:
|
else:
|
||||||
assert isolines_config.service_type is 'here_isolines'
|
assert isolines_config.service_type is 'here_isolines'
|
||||||
assert isolines_config.isolines_quota == 100
|
assert isolines_config.isolines_quota == 100
|
||||||
@ -226,7 +234,7 @@ class TestIsolinesUserConfig(TestCase):
|
|||||||
|
|
||||||
class TestIsolinesOrgConfig(TestCase):
|
class TestIsolinesOrgConfig(TestCase):
|
||||||
|
|
||||||
ISOLINES_PROVIDERS = ['heremaps', 'mapzen', 'mapbox']
|
ISOLINES_PROVIDERS = ['heremaps', 'mapzen', 'mapbox', 'tomtom']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.redis_conn = MockRedis()
|
self.redis_conn = MockRedis()
|
||||||
|
@ -80,6 +80,7 @@ def plpy_mock_config():
|
|||||||
plpy_mock._define_result("CDB_Conf_GetConf\('heremaps_conf'\)", [{'conf': '{"geocoder": {"app_id": "app_id", "app_code": "code", "geocoder_cost_per_hit": 1}, "isolines": {"app_id": "app_id", "app_code": "code"}}'}])
|
plpy_mock._define_result("CDB_Conf_GetConf\('heremaps_conf'\)", [{'conf': '{"geocoder": {"app_id": "app_id", "app_code": "code", "geocoder_cost_per_hit": 1}, "isolines": {"app_id": "app_id", "app_code": "code"}}'}])
|
||||||
plpy_mock._define_result("CDB_Conf_GetConf\('mapzen_conf'\)", [{'conf': '{"routing": {"api_key": "api_key_rou", "monthly_quota": 1500000}, "geocoder": {"api_key": "api_key_geo", "monthly_quota": 1500000}, "matrix": {"api_key": "api_key_mat", "monthly_quota": 1500000}}'}])
|
plpy_mock._define_result("CDB_Conf_GetConf\('mapzen_conf'\)", [{'conf': '{"routing": {"api_key": "api_key_rou", "monthly_quota": 1500000}, "geocoder": {"api_key": "api_key_geo", "monthly_quota": 1500000}, "matrix": {"api_key": "api_key_mat", "monthly_quota": 1500000}}'}])
|
||||||
plpy_mock._define_result("CDB_Conf_GetConf\('mapbox_conf'\)", [{'conf': '{"routing": {"api_keys": ["api_key_rou"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["api_key_geo"], "monthly_quota": 1500000}, "matrix": {"api_keys": ["api_key_mat"], "monthly_quota": 1500000}}'}])
|
plpy_mock._define_result("CDB_Conf_GetConf\('mapbox_conf'\)", [{'conf': '{"routing": {"api_keys": ["api_key_rou"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["api_key_geo"], "monthly_quota": 1500000}, "matrix": {"api_keys": ["api_key_mat"], "monthly_quota": 1500000}}'}])
|
||||||
|
plpy_mock._define_result("CDB_Conf_GetConf\('tomtom_conf'\)", [{'conf': '{"routing": {"api_keys": ["api_key_rou"], "monthly_quota": 1500000}, "geocoder": {"api_keys": ["api_key_geo"], "monthly_quota": 1500000}, "isolines": {"api_keys": ["api_key_mat"], "monthly_quota": 1500000}}'}])
|
||||||
plpy_mock._define_result("CDB_Conf_GetConf\('logger_conf'\)", [{'conf': '{"geocoder_log_path": "/dev/null"}'}])
|
plpy_mock._define_result("CDB_Conf_GetConf\('logger_conf'\)", [{'conf': '{"geocoder_log_path": "/dev/null"}'}])
|
||||||
plpy_mock._define_result("CDB_Conf_GetConf\('data_observatory_conf'\)", [{'conf': '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}}'}])
|
plpy_mock._define_result("CDB_Conf_GetConf\('data_observatory_conf'\)", [{'conf': '{"connection": {"whitelist": ["ethervoid"], "production": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}}'}])
|
||||||
plpy_mock._define_result("CDB_Conf_GetConf\('server_conf'\)", [{'conf': '{"environment": "testing"}'}])
|
plpy_mock._define_result("CDB_Conf_GetConf\('server_conf'\)", [{'conf': '{"environment": "testing"}'}])
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from mock import Mock
|
||||||
|
from cartodb_services.tomtom import TomTomGeocoder
|
||||||
|
from cartodb_services.tools.exceptions import ServiceException
|
||||||
|
from credentials import tomtom_api_key
|
||||||
|
|
||||||
|
INVALID_APIKEY = 'invalid_apikey'
|
||||||
|
VALID_ADDRESS = u'Mantería 3, Valladolid'.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomGeocoderTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.geocoder = TomTomGeocoder(apikey=tomtom_api_key(), logger=Mock())
|
||||||
|
|
||||||
|
def test_invalid_token(self):
|
||||||
|
invalid_geocoder = TomTomGeocoder(apikey=INVALID_APIKEY, logger=Mock())
|
||||||
|
with self.assertRaises(ServiceException):
|
||||||
|
invalid_geocoder.geocode(VALID_ADDRESS)
|
||||||
|
|
||||||
|
def test_valid_request(self):
|
||||||
|
place = self.geocoder.geocode(VALID_ADDRESS)
|
||||||
|
|
||||||
|
assert place
|
||||||
|
|
||||||
|
def test_valid_request_namedplace(self):
|
||||||
|
place = self.geocoder.geocode(searchtext='Barcelona')
|
||||||
|
|
||||||
|
assert place
|
||||||
|
|
||||||
|
def test_valid_request_namedplace2(self):
|
||||||
|
place = self.geocoder.geocode(searchtext='New York', country='us')
|
||||||
|
|
||||||
|
assert place
|
||||||
|
|
||||||
|
def test_odd_characters(self):
|
||||||
|
place = self.geocoder.geocode(searchtext='Barcelona; "Spain"')
|
||||||
|
|
||||||
|
assert place
|
||||||
|
|
||||||
|
def test_empty_request(self):
|
||||||
|
place = self.geocoder.geocode(searchtext='', country=None, city=None, state_province=None)
|
||||||
|
|
||||||
|
assert place == []
|
||||||
|
|
||||||
|
def test_empty_search_text_request(self):
|
||||||
|
place = self.geocoder.geocode(searchtext=' ', country='us', city=None, state_province="")
|
||||||
|
|
||||||
|
assert place == []
|
||||||
|
|
||||||
|
def test_unknown_place_request(self):
|
||||||
|
place = self.geocoder.geocode(searchtext='[unknown]', country='ch', state_province=None, city=None)
|
||||||
|
|
||||||
|
assert place == []
|
@ -0,0 +1,33 @@
|
|||||||
|
import unittest
|
||||||
|
from mock import Mock
|
||||||
|
from cartodb_services.tomtom.isolines import TomTomIsolines, DEFAULT_PROFILE
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
|
||||||
|
from credentials import tomtom_api_key
|
||||||
|
|
||||||
|
VALID_ORIGIN = Coordinate(-73.989, 40.733)
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomIsolinesTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.tomtom_isolines = TomTomIsolines(apikey=tomtom_api_key(),
|
||||||
|
logger=Mock())
|
||||||
|
|
||||||
|
def test_calculate_isochrone(self):
|
||||||
|
time_ranges = [300, 900]
|
||||||
|
solution = self.tomtom_isolines.calculate_isochrone(
|
||||||
|
origin=VALID_ORIGIN,
|
||||||
|
profile=DEFAULT_PROFILE,
|
||||||
|
time_ranges=time_ranges)
|
||||||
|
|
||||||
|
assert solution
|
||||||
|
|
||||||
|
def test_calculate_isodistance(self):
|
||||||
|
distance_range = 10000
|
||||||
|
solution = self.tomtom_isolines.calculate_isodistance(
|
||||||
|
origin=VALID_ORIGIN,
|
||||||
|
profile=DEFAULT_PROFILE,
|
||||||
|
distance_range=distance_range)
|
||||||
|
|
||||||
|
assert solution
|
@ -0,0 +1,52 @@
|
|||||||
|
import unittest
|
||||||
|
from mock import Mock
|
||||||
|
from cartodb_services.tomtom import TomTomRouting
|
||||||
|
from cartodb_services.tomtom.routing import DEFAULT_PROFILE
|
||||||
|
from cartodb_services.tools.exceptions import ServiceException
|
||||||
|
from cartodb_services.tools import Coordinate
|
||||||
|
from credentials import tomtom_api_key
|
||||||
|
|
||||||
|
INVALID_APIKEY = 'invalid_apikey'
|
||||||
|
VALID_WAYPOINTS = [Coordinate(13.42936, 52.50931),
|
||||||
|
Coordinate(13.43872, 52.50274)]
|
||||||
|
NUM_WAYPOINTS_MAX = 20
|
||||||
|
INVALID_WAYPOINTS_EMPTY = []
|
||||||
|
INVALID_WAYPOINTS_MIN = [Coordinate(13.42936, 52.50931)]
|
||||||
|
INVALID_WAYPOINTS_MAX = [Coordinate(13.42936, 52.50931)
|
||||||
|
for x in range(0, NUM_WAYPOINTS_MAX + 2)]
|
||||||
|
VALID_PROFILE = DEFAULT_PROFILE
|
||||||
|
INVALID_PROFILE = 'invalid_profile'
|
||||||
|
|
||||||
|
|
||||||
|
class TomTomRoutingTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.routing = TomTomRouting(apikey=tomtom_api_key(), logger=Mock())
|
||||||
|
|
||||||
|
def test_invalid_profile(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self.routing.directions(VALID_WAYPOINTS, INVALID_PROFILE)
|
||||||
|
|
||||||
|
def test_invalid_waypoints_empty(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self.routing.directions(INVALID_WAYPOINTS_EMPTY, VALID_PROFILE)
|
||||||
|
|
||||||
|
def test_invalid_waypoints_min(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self.routing.directions(INVALID_WAYPOINTS_MIN, VALID_PROFILE)
|
||||||
|
|
||||||
|
def test_invalid_waypoints_max(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self.routing.directions(INVALID_WAYPOINTS_MAX, VALID_PROFILE)
|
||||||
|
|
||||||
|
def test_invalid_token(self):
|
||||||
|
invalid_routing = TomTomRouting(apikey=INVALID_APIKEY, logger=Mock())
|
||||||
|
with self.assertRaises(ServiceException):
|
||||||
|
invalid_routing.directions(VALID_WAYPOINTS,
|
||||||
|
VALID_PROFILE)
|
||||||
|
|
||||||
|
def test_valid_request(self):
|
||||||
|
route = self.routing.directions(VALID_WAYPOINTS, VALID_PROFILE)
|
||||||
|
|
||||||
|
assert route.shape
|
||||||
|
assert route.length
|
||||||
|
assert route.duration
|
Loading…
Reference in New Issue
Block a user