Compare commits
68 Commits
0.18.0-ser
...
python-0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f716fbb502 | ||
|
|
98fa248fff | ||
|
|
7c348dee0f | ||
|
|
bdeaadf33f | ||
|
|
a977bc97ab | ||
|
|
51face5593 | ||
|
|
a60a6f04b1 | ||
|
|
190c9888d0 | ||
|
|
77b2ac9155 | ||
|
|
8edbf33ff1 | ||
|
|
bd439d8985 | ||
|
|
16259862dd | ||
|
|
7c816be5e5 | ||
|
|
77f4f3e7ff | ||
|
|
4b714b3845 | ||
|
|
59ed8b88a3 | ||
|
|
ab4584bed3 | ||
|
|
2b2691d0b9 | ||
|
|
3524aabd9e | ||
|
|
9c6eabc59e | ||
|
|
0d92eb4ba8 | ||
|
|
769b740ba4 | ||
|
|
c2ede37d75 | ||
|
|
4c75c5f261 | ||
|
|
f07d2f9302 | ||
|
|
37a3214f67 | ||
|
|
efb10e43e4 | ||
|
|
1dc6060570 | ||
|
|
a2da597e00 | ||
|
|
4af5975ac1 | ||
|
|
579d11ebd5 | ||
|
|
a1eae3934c | ||
|
|
d70d149eed | ||
|
|
decc7626a8 | ||
|
|
abbb227ad5 | ||
|
|
970927375e | ||
|
|
6f2883be5d | ||
|
|
06df5a84c4 | ||
|
|
5d94a852e4 | ||
|
|
f0474852f2 | ||
|
|
975efb0f92 | ||
|
|
7f963d2f7a | ||
|
|
8396eae733 | ||
|
|
25cd40164a | ||
|
|
dfaa037475 | ||
|
|
c92ab9c207 | ||
|
|
2e6f37af56 | ||
|
|
95dda082e7 | ||
|
|
9f9034f4f1 | ||
|
|
603fbbbc3f | ||
|
|
3fa686ec65 | ||
|
|
429a71ef37 | ||
|
|
b2cdb1c74b | ||
|
|
84061dec4f | ||
|
|
7a32ace1ac | ||
|
|
7a56dc698f | ||
|
|
eb7188235d | ||
|
|
3e059003b6 | ||
|
|
0e38af6ecd | ||
|
|
b00edf218a | ||
|
|
6f9feb07a0 | ||
|
|
2c76fa4501 | ||
|
|
4169bc0f88 | ||
|
|
6b56c4ad0d | ||
|
|
1f8fb28449 | ||
|
|
7fd13f416d | ||
|
|
f41a30316e | ||
|
|
5499bd1e69 |
25
NEWS.md
25
NEWS.md
@@ -1,3 +1,28 @@
|
||||
November 29st, 2016
|
||||
===================
|
||||
* Version 0.20.0 of the server and version 0.12.0 of the python library
|
||||
* Added integration with the new Mapzen isochrones functionality
|
||||
|
||||
November 25st, 2016
|
||||
===================
|
||||
* Version 0.19.0 of the server, version 0.11.0 of the python library and version 0.13.0 of the client
|
||||
* functions to check the quota, both server and client
|
||||
* removed the no_params from the templates (this caused trouble, not needed anymore)
|
||||
* bug fixes: observatory quota, quotas as integers, mapzen geocoder soft limit as bool
|
||||
|
||||
November 21st, 2016
|
||||
===================
|
||||
* Version 0.18.1 of the server and version 0.12.1 of the client
|
||||
* Add new fields to the obs_meta_geometry due to new changes introduced in the DO 1.1.2 release
|
||||
|
||||
November 11st, 2016
|
||||
===================
|
||||
* Version 0.18.0 of the server and version 0.12.0 of the client
|
||||
* Added obs_legacybuildermetada functions to grab the needed metadata in the builder while making a data enrichment analysis. Closes #286
|
||||
* Added metadata functions that will be used in the future to gather the metadata for the new data enrichment UI. Closes #287
|
||||
* Fixed integration test for street geocoding
|
||||
* Makefile now has a new task to create a new release in the client part, as was in the server, using make release NEW_VERSION=x.x.x
|
||||
|
||||
November 7st, 2016
|
||||
==================
|
||||
* Version 0.17.0 of the server and version 0.10.0 of the python package
|
||||
|
||||
115
client/cdb_dataservices_client--0.12.1--0.13.0.sql
Normal file
115
client/cdb_dataservices_client--0.12.1--0.13.0.sql
Normal file
@@ -0,0 +1,115 @@
|
||||
--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.13.0'" to load this file. \quit
|
||||
|
||||
-- Added for consistency (SELECT func instead of SELECT * FROM)
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_dumpversion ()
|
||||
RETURNS text AS $$
|
||||
DECLARE
|
||||
ret text;
|
||||
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._obs_dumpversion(username, orgname) INTO ret;
|
||||
RETURN ret;
|
||||
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_dumpversion (username text, organization_name text)
|
||||
RETURNS text AS $$
|
||||
CONNECT cdb_dataservices_client._server_conn_str();
|
||||
|
||||
SELECT cdb_dataservices_server.obs_dumpversion (username, organization_name);
|
||||
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
|
||||
-- For quotas and services configuration
|
||||
CREATE TYPE cdb_dataservices_client.service_type AS ENUM (
|
||||
'isolines',
|
||||
'hires_geocoder',
|
||||
'routing',
|
||||
'observatory'
|
||||
);
|
||||
|
||||
CREATE TYPE cdb_dataservices_client.service_quota_info AS (
|
||||
service cdb_dataservices_client.service_type,
|
||||
monthly_quota NUMERIC,
|
||||
used_quota NUMERIC,
|
||||
soft_limit BOOLEAN,
|
||||
provider TEXT
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_service_quota_info ()
|
||||
RETURNS SETOF service_quota_info 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_service_quota_info(username, orgname);
|
||||
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_enough_quota (service TEXT ,input_size NUMERIC)
|
||||
RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
ret BOOLEAN;
|
||||
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_enough_quota(username, orgname, service, input_size) INTO ret;
|
||||
RETURN ret;
|
||||
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_quota_info (username text, organization_name text)
|
||||
RETURNS SETOF service_quota_info AS $$
|
||||
CONNECT cdb_dataservices_client._server_conn_str();
|
||||
|
||||
SELECT * FROM cdb_dataservices_server.cdb_service_quota_info (username, organization_name);
|
||||
|
||||
$$ LANGUAGE plproxy;
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_enough_quota (username text, organization_name text, service TEXT, input_size NUMERIC)
|
||||
RETURNS BOOLEAN AS $$
|
||||
CONNECT cdb_dataservices_client._server_conn_str();
|
||||
|
||||
SELECT cdb_dataservices_server.cdb_enough_quota (username, organization_name, service, input_size);
|
||||
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
|
||||
GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_service_quota_info() TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_enough_quota(service TEXT, input_size NUMERIC) TO publicuser;
|
||||
44
client/cdb_dataservices_client--0.13.0--0.12.1.sql
Normal file
44
client/cdb_dataservices_client--0.13.0--0.12.1.sql
Normal file
@@ -0,0 +1,44 @@
|
||||
--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.12.1'" to load this file. \quit
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_dumpversion ()
|
||||
RETURNS text AS $$
|
||||
DECLARE
|
||||
ret text;
|
||||
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 * FROM cdb_dataservices_client._obs_dumpversion(username, orgname) INTO ret;
|
||||
RETURN ret;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_dumpversion (username text, organization_name text)
|
||||
RETURNS text AS $$
|
||||
CONNECT cdb_dataservices_client._server_conn_str();
|
||||
|
||||
SELECT * FROM cdb_dataservices_server.obs_dumpversion (username, organization_name);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_enough_quota (username text, organization_name text, service TEXT, input_size NUMERIC);
|
||||
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_quota_info (username text, organization_name text);
|
||||
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_enough_quota (service TEXT ,input_size NUMERIC)
|
||||
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_service_quota_info ();
|
||||
|
||||
DROP TYPE IF EXISTS cdb_dataservices_client.service_quota_info;
|
||||
|
||||
DROP TYPE IF EXISTS cdb_dataservices_client.service_type;
|
||||
1986
client/cdb_dataservices_client--0.13.0.sql
Normal file
1986
client/cdb_dataservices_client--0.13.0.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
comment = 'CartoDB dataservices client API extension'
|
||||
default_version = '0.12.0'
|
||||
default_version = '0.13.0'
|
||||
requires = 'plproxy, cartodb'
|
||||
superuser = true
|
||||
schema = cdb_dataservices_client
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
--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.12.1'" to load this file. \quit
|
||||
|
||||
-- HERE goes your code to upgrade/downgrade
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE score numeric;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE numtiles bigint;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE notnull_percent numeric;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE numgeoms numeric;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE percentfill numeric;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE estnumgeoms numeric;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE meanmediansize numeric;
|
||||
@@ -0,0 +1,12 @@
|
||||
--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.12.0'" to load this file. \quit
|
||||
|
||||
-- HERE goes your code to upgrade/downgrade
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE score;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE numtiles;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE notnull_percent;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE numgeoms;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE percentfill;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE estnumgeoms;
|
||||
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE meanmediansize;
|
||||
1987
client/old_versions/cdb_dataservices_client--0.12.1.sql
Normal file
1987
client/old_versions/cdb_dataservices_client--0.12.1.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -323,7 +323,6 @@
|
||||
|
||||
- name: obs_dumpversion
|
||||
return_type: text
|
||||
no_params: true
|
||||
params:
|
||||
- {}
|
||||
|
||||
@@ -377,3 +376,16 @@
|
||||
multi_field: true
|
||||
params:
|
||||
- { name: aggregate_type, type: text, default: 'NULL' }
|
||||
|
||||
- name: cdb_service_quota_info
|
||||
return_type: SETOF service_quota_info
|
||||
multi_row: true
|
||||
multi_field: true
|
||||
params:
|
||||
- {}
|
||||
|
||||
- name: cdb_enough_quota
|
||||
return_type: BOOLEAN
|
||||
params:
|
||||
- { name: service, type: TEXT }
|
||||
- { name: input_size, type: NUMERIC }
|
||||
@@ -36,10 +36,6 @@ class SqlTemplateRenderer
|
||||
@function_signature['multi_row']
|
||||
end
|
||||
|
||||
def no_params
|
||||
@function_signature['no_params']
|
||||
end
|
||||
|
||||
def user_config_key
|
||||
@function_signature['user_config_key']
|
||||
end
|
||||
@@ -49,11 +45,11 @@ class SqlTemplateRenderer
|
||||
end
|
||||
|
||||
def params
|
||||
@function_signature['params'].reject(&:empty?).map { |p| "#{p['name']}"}.join(', ')
|
||||
@function_signature['params'].reject(&:empty?).map { |p| "#{p['name']}"}
|
||||
end
|
||||
|
||||
def params_with_type
|
||||
@function_signature['params'].reject(&:empty?).map { |p| "#{p['name']} #{p['type']}" }.join(', ')
|
||||
@function_signature['params'].reject(&:empty?).map { |p| "#{p['name']} #{p['type']}" }
|
||||
end
|
||||
|
||||
def params_with_type_and_default
|
||||
@@ -64,7 +60,7 @@ class SqlTemplateRenderer
|
||||
"#{p['name']} #{p['type']}"
|
||||
end
|
||||
end
|
||||
return parameters.join(', ')
|
||||
return parameters
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
-- These are the only ones with permissions to publicuser role
|
||||
-- and should also be the only ones with SECURITY DEFINER
|
||||
|
||||
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>.<%= name %> (<%= params_with_type_and_default %>)
|
||||
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>.<%= name %> (<%= params_with_type_and_default.join(' ,') %>)
|
||||
RETURNS <%= return_type %> AS $$
|
||||
DECLARE
|
||||
<% if not multi_row %>ret <%= return_type %>;<% end %>
|
||||
@@ -21,15 +21,12 @@ BEGIN
|
||||
END IF;
|
||||
<% if multi_row %>
|
||||
RETURN QUERY
|
||||
SELECT * FROM <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(username, orgname, <%= params %>);
|
||||
SELECT * FROM <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= ['username', 'orgname'].concat(params).join(', ') %>);
|
||||
<% elsif multi_field %>
|
||||
SELECT * FROM <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(username, orgname, <%= params %>) INTO ret;
|
||||
RETURN ret;
|
||||
<% elsif no_params %>
|
||||
SELECT * FROM <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(username, orgname) INTO ret;
|
||||
SELECT * FROM <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= ['username', 'orgname'].concat(params).join(', ') %>) INTO ret;
|
||||
RETURN ret;
|
||||
<% else %>
|
||||
SELECT <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(username, orgname, <%= params %>) INTO ret;
|
||||
SELECT <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= ['username', 'orgname'].concat(params).join(', ') %>) INTO ret;
|
||||
RETURN ret;
|
||||
<% end %>
|
||||
END;
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
<% if no_params %>
|
||||
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %> (username text, organization_name text)
|
||||
<% else %>
|
||||
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %> (username text, organization_name text, <%= params_with_type_and_default %>)
|
||||
<% end %>
|
||||
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %> (<%= ['username text', 'organization_name text'].concat(params_with_type_and_default).join(', ') %>)
|
||||
RETURNS <%= return_type %> AS $$
|
||||
CONNECT <%= DATASERVICES_CLIENT_SCHEMA %>._server_conn_str();
|
||||
<% if multi_field %>
|
||||
SELECT * FROM <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (username, organization_name, <%= params %>);
|
||||
<% elsif no_params %>
|
||||
SELECT * FROM <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (username, organization_name);
|
||||
SELECT * FROM <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (<%= ['username', 'organization_name'].concat(params).join(', ') %>);
|
||||
<% else %>
|
||||
SELECT <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (username, organization_name, <%= params %>);
|
||||
SELECT <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (<%= ['username', 'organization_name'].concat(params).join(', ') %>);
|
||||
<% end %>
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
@@ -1 +1 @@
|
||||
GRANT EXECUTE ON FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>.<%= name %>(<%= params_with_type %>) TO publicuser;
|
||||
GRANT EXECUTE ON FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>.<%= name %>(<%= params_with_type.join(', ') %>) TO publicuser;
|
||||
|
||||
@@ -15,6 +15,23 @@ CREATE TYPE cdb_dataservices_client.obs_meta_numerator AS (numer_id text, numer_
|
||||
|
||||
CREATE TYPE cdb_dataservices_client.obs_meta_denominator AS (denom_id text, denom_name text, denom_description text, denom_weight text, denom_license text, denom_source text, denom_type text, denom_aggregate text, denom_extra jsonb, denom_tags jsonb, valid_numer boolean, valid_geom boolean, valid_timespan boolean);
|
||||
|
||||
CREATE TYPE cdb_dataservices_client.obs_meta_geometry AS (geom_id text, geom_name text, geom_description text, geom_weight text, geom_aggregate text, geom_license text, geom_source text, valid_numer boolean, valid_denom boolean, valid_timespan boolean);
|
||||
CREATE TYPE cdb_dataservices_client.obs_meta_geometry AS (geom_id text, geom_name text, geom_description text, geom_weight text, geom_aggregate text, geom_license text, geom_source text, valid_numer boolean, valid_denom boolean, valid_timespan boolean, score numeric, numtiles bigint, notnull_percent numeric, numgeoms numeric, percentfill numeric, estnumgeoms numeric, meanmediansize numeric);
|
||||
|
||||
CREATE TYPE cdb_dataservices_client.obs_meta_timespan AS (timespan_id text, timespan_name text, timespan_description text, timespan_weight text, timespan_aggregate text, timespan_license text, timespan_source text, valid_numer boolean, valid_denom boolean, valid_geom boolean);
|
||||
|
||||
|
||||
-- For quotas and services configuration
|
||||
CREATE TYPE cdb_dataservices_client.service_type AS ENUM (
|
||||
'isolines',
|
||||
'hires_geocoder',
|
||||
'routing',
|
||||
'observatory'
|
||||
);
|
||||
|
||||
CREATE TYPE cdb_dataservices_client.service_quota_info AS (
|
||||
service cdb_dataservices_client.service_type,
|
||||
monthly_quota NUMERIC,
|
||||
used_quota NUMERIC,
|
||||
soft_limit BOOLEAN,
|
||||
provider TEXT
|
||||
);
|
||||
|
||||
@@ -215,7 +215,7 @@ INSERT INTO {tablename} (the_geom) SELECT cdb_geocode_namedplace_point('New York
|
||||
|
||||
## Postal Code Geocoder
|
||||
|
||||
This function geocodes your data into point, or polygon, geometries for postal codes. The postal code polygon geocoder covers the United States, France, Australia and Canada; a request for a different country will return an empty response.
|
||||
These functions geocode your data into point, or polygon, geometries for postal codes. The postal code geocoder covers the United States, France, Australia and Canada; a request for a different country will return an empty response.
|
||||
|
||||
**Note:** For the USA, US Census [Zip Code Tabulation Areas](https://www.census.gov/geo/reference/zctas.html) (ZCTA) are used to reference geocodes for USPS postal codes service areas. See the [FAQs](https://carto.com/docs/faqs/datasets-and-data/#why-does-carto-use-census-bureau-zctas-and-not-usps-zip-codes-for-postal-codes) about datasets and data for details.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ _The Data Services API is collaborating with [Mapzen](https://mapzen.com/), and
|
||||
|
||||
By using the SQL API to query the Data Services API functions, you can manage specific operations and the corresponding geometries (a `polygon` or a `point`), according to the input information.
|
||||
|
||||
The Data Services API decouples the geocoding and isoline services from the CARTO Editor. The API allows you to geocode data (from single rows, complete datasets, or simple inputs) and to perform trade areas analysis (computing isodistances or isochrones) programatically, through authenticated requests.
|
||||
The Data Services API also exposes its services directly through CARTO Builder. For example, you can geocode data (from single rows, complete datasets, or simple inputs) and perform trade areas analysis (computing isodistances or isochrones) programatically, through authenticated SQL requests, or by using the ANALYSIS options.
|
||||
|
||||
The geometries provided by this API are projected in the projection [WGS 84 SRID 4326](http://spatialreference.org/ref/epsg/wgs-84/).
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Name | Type | Description | Accepted values
|
||||
--- | --- | --- | ---
|
||||
`origin` | `geometry(Point)` | Origin point, in 4326 projection, which defines the start location. |
|
||||
`destination` | `geometry(Point)` | Destination point, in 4326 projection, which defines the end location. |
|
||||
`mode` | `text` | Type of transport used to calculate the isolines. | `car`, `walk`, `bicycle` or `public_transport`
|
||||
`mode` | `text` | Type of transport used to calculate the routes. | `car`, `walk`, `bicycle` or `public_transport`
|
||||
`options` | `text[]` | (Optional) Multiple options to add more capabilities to the analysis. See [Optional routing parameters](#optional-routing-parameters) for details.
|
||||
`units` | `text` | Unit used to represent the length of the route. | `kilometers`, `miles`. By default is `kilometers`
|
||||
|
||||
@@ -47,7 +47,7 @@ Returns a route that goes from origin to destination and whose path travels thro
|
||||
Name | Type | Description | Accepted values
|
||||
--- | --- | --- | ---
|
||||
`waypoints` | `geometry(Point)[]` | Array of ordered points, in 4326 projection, which defines the origin point, one or more locations for the route path to travel through, and the destination. The first element of the array defines the origin and the last element the destination of the route. |
|
||||
`mode` | `text` | Type of transport used to calculate the isolines. | `car`, `walk`, `bicycle` or `public_transport`
|
||||
`mode` | `text` | Type of transport used to calculate the routes. | `car`, `walk`, `bicycle` or `public_transport`
|
||||
`options` | `text[]` | (Optional) Multiple options to add more capabilities to the analysis. See [Optional routing parameters](#optional-routing-parameters) for details.
|
||||
`units` | `text` | Unit used to represent the length of the route. | `kilometers`, `miles`. By default is `kilometers`
|
||||
|
||||
|
||||
187
server/extension/cdb_dataservices_server--0.19.0--0.20.0.sql
Normal file
187
server/extension/cdb_dataservices_server--0.19.0--0.20.0.sql
Normal file
@@ -0,0 +1,187 @@
|
||||
--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.20.0'" to load this file. \quit
|
||||
|
||||
-- HERE goes your code to upgrade/downgrade
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_mapzen_isolines(TEXT, TEXT, TEXT, geometry(Geometry, 4326), TEXT, integer[], text[]);
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isodistance(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
source geometry(Geometry, 4326),
|
||||
mode TEXT,
|
||||
data_range integer[],
|
||||
options text[])
|
||||
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
import json
|
||||
from cartodb_services.mapzen import MatrixClient, MapzenIsolines
|
||||
from cartodb_services.metrics import QuotaService
|
||||
from cartodb_services.tools import Logger,LoggerConfig
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_isolines_routing_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)
|
||||
quota_service = QuotaService(user_isolines_routing_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
raise Exception('You have reached the limit of your quota')
|
||||
|
||||
try:
|
||||
client = MatrixClient(user_isolines_routing_config.mapzen_matrix_api_key, logger)
|
||||
mapzen_isolines = MapzenIsolines(client, logger)
|
||||
|
||||
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 = {'lat': lat, 'lon': lon}
|
||||
else:
|
||||
raise Exception('source is NULL')
|
||||
|
||||
# -- TODO Support options properly
|
||||
isolines = {}
|
||||
for r in data_range:
|
||||
isoline = mapzen_isolines.calculate_isodistance(origin, mode, r)
|
||||
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['lon'], l['lat']) for l in locations])
|
||||
sql = "SELECT ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326) as geom".format(wkt_coordinates)
|
||||
multipolygon = plpy.execute(sql, 1)[0]['geom']
|
||||
else:
|
||||
multipolygon = None
|
||||
|
||||
result.append([source, r, multipolygon])
|
||||
|
||||
quota_service.increment_success_service_use()
|
||||
quota_service.increment_isolines_service_use(len(isolines))
|
||||
return result
|
||||
except BaseException as e:
|
||||
import sys
|
||||
quota_service.increment_failed_service_use()
|
||||
logger.error('Error trying to get mapzen isolines', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||
raise Exception('Error trying to get mapzen isolines')
|
||||
finally:
|
||||
quota_service.increment_total_service_use()
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isochrones(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
source geometry(Geometry, 4326),
|
||||
mode TEXT,
|
||||
data_range integer[],
|
||||
options text[])
|
||||
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
import json
|
||||
from cartodb_services.mapzen import MatrixClient, MapzenIsochrones
|
||||
from cartodb_services.metrics import QuotaService
|
||||
from cartodb_services.tools import Logger,LoggerConfig
|
||||
from cartodb_services.mapzen.types import coordinates_to_polygon
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_isolines_routing_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)
|
||||
# -- Check the quota
|
||||
quota_service = QuotaService(user_isolines_routing_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
raise Exception('You have reached the limit of your quota')
|
||||
|
||||
try:
|
||||
mapzen_isochrones = MapzenIsochrones(user_isolines_routing_config.mapzen_matrix_api_key,
|
||||
logger)
|
||||
|
||||
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 = {'lat': lat, 'lon': lon}
|
||||
else:
|
||||
raise Exception('source is NULL')
|
||||
|
||||
resp = mapzen_isochrones.isochrone(origin, mode, data_range)
|
||||
|
||||
if resp:
|
||||
result = []
|
||||
for isochrone in resp:
|
||||
result_polygon = coordinates_to_polygon(isochrone.coordinates)
|
||||
if result_polygon:
|
||||
quota_service.increment_success_service_use()
|
||||
result.append([source, isochrone.duration, result_polygon])
|
||||
else:
|
||||
quota_service.increment_empty_service_use()
|
||||
result.append([source, isochrone.duration, None])
|
||||
quota_service.increment_success_service_use()
|
||||
quota_service.increment_isolines_service_use(len(result))
|
||||
return result
|
||||
else:
|
||||
quota_service.increment_empty_service_use()
|
||||
return []
|
||||
except BaseException as e:
|
||||
import sys
|
||||
quota_service.increment_failed_service_use()
|
||||
logger.error('Error trying to get mapzen isochrones', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||
raise Exception('Error trying to get mapzen isochrones')
|
||||
finally:
|
||||
quota_service.increment_total_service_use()
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_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)]
|
||||
|
||||
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[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||
|
||||
return result
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_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)]
|
||||
|
||||
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||
return result
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
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])
|
||||
else:
|
||||
raise Exception('Requested isolines provider is not available')
|
||||
$$ LANGUAGE plpythonu;
|
||||
121
server/extension/cdb_dataservices_server--0.20.0--0.19.0.sql
Normal file
121
server/extension/cdb_dataservices_server--0.20.0--0.19.0.sql
Normal file
@@ -0,0 +1,121 @@
|
||||
--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.19.0'" to load this file. \quit
|
||||
|
||||
-- HERE goes your code to upgrade/downgrade
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_mapzen_isodistance(TEXT, TEXT, geometry(Geometry, 4326), TEXT, integer[], text[]);
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_mapzen_isochrones(TEXT, TEXT, geometry(Geometry, 4326), TEXT, integer[], text[]);
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isolines(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
isotype TEXT,
|
||||
source geometry(Geometry, 4326),
|
||||
mode TEXT,
|
||||
data_range integer[],
|
||||
options text[])
|
||||
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
import json
|
||||
from cartodb_services.mapzen import MatrixClient, MapzenIsolines
|
||||
from cartodb_services.metrics import QuotaService
|
||||
from cartodb_services.tools import Logger,LoggerConfig
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_isolines_routing_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)
|
||||
quota_service = QuotaService(user_isolines_routing_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
raise Exception('You have reached the limit of your quota')
|
||||
|
||||
try:
|
||||
client = MatrixClient(user_isolines_routing_config.mapzen_matrix_api_key, logger)
|
||||
mapzen_isolines = MapzenIsolines(client, logger)
|
||||
|
||||
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 = {'lat': lat, 'lon': lon}
|
||||
else:
|
||||
raise Exception('source is NULL')
|
||||
|
||||
# -- TODO Support options properly
|
||||
isolines = {}
|
||||
for r in data_range:
|
||||
isoline = mapzen_isolines.calculate_isodistance(origin, mode, r)
|
||||
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['lon'], l['lat']) for l in locations])
|
||||
sql = "SELECT ST_MPolyFromText('MULTIPOLYGON((({0})))', 4326) as geom".format(wkt_coordinates)
|
||||
multipolygon = plpy.execute(sql, 1)[0]['geom']
|
||||
else:
|
||||
multipolygon = None
|
||||
|
||||
result.append([source, r, multipolygon])
|
||||
|
||||
quota_service.increment_success_service_use()
|
||||
quota_service.increment_isolines_service_use(len(isolines))
|
||||
return result
|
||||
except BaseException as e:
|
||||
import sys
|
||||
quota_service.increment_failed_service_use()
|
||||
logger.error('Error trying to get mapzen isolines', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||
raise Exception('Error trying to get mapzen isolines')
|
||||
finally:
|
||||
quota_service.increment_total_service_use()
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_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)]
|
||||
type = 'isochrone'
|
||||
|
||||
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isolines($1, $2, $3, $4, $5, $6, $7) as isoline; ", ["text", "text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, type, source, mode, range, options])
|
||||
return result
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_mapzen_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)]
|
||||
type = 'isodistance'
|
||||
|
||||
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isolines($1, $2, $3, $4, $5, $6, $7) as isoline; ", ["text", "text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, type, source, mode, range, options])
|
||||
|
||||
return result
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
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 $$
|
||||
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)]
|
||||
|
||||
if user_isolines_config.google_services_user:
|
||||
raise Exception('This service is not available for google service users.')
|
||||
|
||||
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])
|
||||
else:
|
||||
raise Exception('Requested isolines provider is not available')
|
||||
$$ LANGUAGE plpythonu;
|
||||
2730
server/extension/cdb_dataservices_server--0.20.0.sql
Normal file
2730
server/extension/cdb_dataservices_server--0.20.0.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
comment = 'CartoDB dataservices server extension'
|
||||
default_version = '0.18.0'
|
||||
default_version = '0.20.0'
|
||||
requires = 'plpythonu, plproxy, postgis, cdb_geocoder'
|
||||
superuser = true
|
||||
schema = cdb_dataservices_server
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
--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.18.1'" to load this file. \quit
|
||||
|
||||
-- HERE goes your code to upgrade/downgrade
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE score numeric;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE numtiles bigint;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE notnull_percent numeric;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE numgeoms numeric;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE percentfill numeric;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE estnumgeoms numeric;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE meanmediansize numeric;
|
||||
@@ -0,0 +1,12 @@
|
||||
--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.18.0'" to load this file. \quit
|
||||
|
||||
-- HERE goes your code to upgrade/downgrade
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE score;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE numtiles;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE notnull_percent;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE numgeoms;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE percentfill;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE estnumgeoms;
|
||||
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE meanmediansize;
|
||||
@@ -0,0 +1,109 @@
|
||||
--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.19.0'" to load this file. \quit
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'service_type') THEN
|
||||
CREATE TYPE cdb_dataservices_server.service_type AS ENUM (
|
||||
'isolines',
|
||||
'hires_geocoder',
|
||||
'routing',
|
||||
'observatory'
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'service_quota_info') THEN
|
||||
CREATE TYPE cdb_dataservices_server.service_quota_info AS (
|
||||
service cdb_dataservices_server.service_type,
|
||||
monthly_quota NUMERIC,
|
||||
used_quota NUMERIC,
|
||||
soft_limit BOOLEAN,
|
||||
provider TEXT
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_quota_info(
|
||||
username TEXT,
|
||||
orgname TEXT)
|
||||
RETURNS SETOF cdb_dataservices_server.service_quota_info AS $$
|
||||
from cartodb_services.metrics.user import UserMetricsService
|
||||
from datetime import date
|
||||
|
||||
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
|
||||
today = date.today()
|
||||
ret = []
|
||||
|
||||
#-- Isolines
|
||||
service = 'isolines'
|
||||
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)]
|
||||
user_service = UserMetricsService(user_isolines_config, redis_conn)
|
||||
|
||||
monthly_quota = user_isolines_config.isolines_quota
|
||||
used_quota = user_service.used_quota(user_isolines_config.service_type, today)
|
||||
soft_limit = user_isolines_config.soft_isolines_limit
|
||||
provider = user_isolines_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
#-- Hires Geocoder
|
||||
service = 'hires_geocoder'
|
||||
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_service = UserMetricsService(user_geocoder_config, redis_conn)
|
||||
|
||||
monthly_quota = user_geocoder_config.geocoding_quota
|
||||
used_quota = user_service.used_quota(user_geocoder_config.service_type, today)
|
||||
soft_limit = user_geocoder_config.soft_geocoding_limit
|
||||
provider = user_geocoder_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
#-- Routing
|
||||
service = 'routing'
|
||||
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)]
|
||||
user_service = UserMetricsService(user_routing_config, redis_conn)
|
||||
|
||||
monthly_quota = user_routing_config.monthly_quota
|
||||
used_quota = user_service.used_quota(user_routing_config.service_type, today)
|
||||
soft_limit = user_routing_config.soft_limit
|
||||
provider = user_routing_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
#-- Observatory
|
||||
service = 'observatory'
|
||||
plpy.execute("SELECT cdb_dataservices_server._get_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||
user_obs_config = GD["user_obs_config_{0}".format(username)]
|
||||
user_service = UserMetricsService(user_obs_config, redis_conn)
|
||||
|
||||
monthly_quota = user_obs_config.monthly_quota
|
||||
used_quota = user_service.used_quota(user_obs_config.service_type, today)
|
||||
soft_limit = user_obs_config.soft_limit
|
||||
provider = user_obs_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
return ret
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_enough_quota(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
service_ TEXT,
|
||||
input_size NUMERIC)
|
||||
returns BOOLEAN AS $$
|
||||
DECLARE
|
||||
params cdb_dataservices_server.service_quota_info;
|
||||
BEGIN
|
||||
SELECT * INTO params
|
||||
FROM cdb_dataservices_server.cdb_service_quota_info(username, orgname) AS p
|
||||
WHERE p.service = service_::cdb_dataservices_server.service_type;
|
||||
RETURN params.soft_limit OR ((params.used_quota + input_size) <= params.monthly_quota);
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
2564
server/extension/old_versions/cdb_dataservices_server--0.18.1.sql
Normal file
2564
server/extension/old_versions/cdb_dataservices_server--0.18.1.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
--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.18.1'" to load this file. \quit
|
||||
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_enough_quota(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
service_ TEXT,
|
||||
input_size NUMERIC);
|
||||
|
||||
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_service_quota_info(
|
||||
username TEXT,
|
||||
orgname TEXT);
|
||||
|
||||
DROP TYPE IF EXISTS cdb_dataservices_server.service_quota_info;
|
||||
|
||||
DROP TYPE IF EXISTS cdb_dataservices_server.service_type;
|
||||
2669
server/extension/old_versions/cdb_dataservices_server--0.19.0.sql
Normal file
2669
server/extension/old_versions/cdb_dataservices_server--0.19.0.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@ RETURNS SETOF cdb_dataservices_server.obs_meta_denominator AS $$
|
||||
SELECT * FROM cdb_observatory.OBS_GetAvailableDenominators(bounds, filter_tags, numer_id, geom_id, timespan);
|
||||
$$ LANGUAGE plproxy;
|
||||
|
||||
CREATE TYPE cdb_dataservices_server.obs_meta_geometry AS (geom_id text, geom_name text, geom_description text, geom_weight text, geom_aggregate text, geom_license text, geom_source text, valid_numer boolean, valid_denom boolean, valid_timespan boolean);
|
||||
CREATE TYPE cdb_dataservices_server.obs_meta_geometry AS (geom_id text, geom_name text, geom_description text, geom_weight text, geom_aggregate text, geom_license text, geom_source text, valid_numer boolean, valid_denom boolean, valid_timespan boolean, score numeric, numtiles bigint, notnull_percent numeric, numgeoms numeric, percentfill numeric, estnumgeoms numeric, meanmediansize numeric);
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetAvailableGeometries(
|
||||
username TEXT,
|
||||
|
||||
105
server/extension/sql/200_quotas.sql
Normal file
105
server/extension/sql/200_quotas.sql
Normal file
@@ -0,0 +1,105 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'service_type') THEN
|
||||
CREATE TYPE cdb_dataservices_server.service_type AS ENUM (
|
||||
'isolines',
|
||||
'hires_geocoder',
|
||||
'routing',
|
||||
'observatory'
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'service_quota_info') THEN
|
||||
CREATE TYPE cdb_dataservices_server.service_quota_info AS (
|
||||
service cdb_dataservices_server.service_type,
|
||||
monthly_quota NUMERIC,
|
||||
used_quota NUMERIC,
|
||||
soft_limit BOOLEAN,
|
||||
provider TEXT
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_quota_info(
|
||||
username TEXT,
|
||||
orgname TEXT)
|
||||
RETURNS SETOF cdb_dataservices_server.service_quota_info AS $$
|
||||
from cartodb_services.metrics.user import UserMetricsService
|
||||
from datetime import date
|
||||
|
||||
plpy.execute("SELECT cdb_dataservices_server._connect_to_redis('{0}')".format(username))
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
|
||||
today = date.today()
|
||||
ret = []
|
||||
|
||||
#-- Isolines
|
||||
service = 'isolines'
|
||||
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)]
|
||||
user_service = UserMetricsService(user_isolines_config, redis_conn)
|
||||
|
||||
monthly_quota = user_isolines_config.isolines_quota
|
||||
used_quota = user_service.used_quota(user_isolines_config.service_type, today)
|
||||
soft_limit = user_isolines_config.soft_isolines_limit
|
||||
provider = user_isolines_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
#-- Hires Geocoder
|
||||
service = 'hires_geocoder'
|
||||
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_service = UserMetricsService(user_geocoder_config, redis_conn)
|
||||
|
||||
monthly_quota = user_geocoder_config.geocoding_quota
|
||||
used_quota = user_service.used_quota(user_geocoder_config.service_type, today)
|
||||
soft_limit = user_geocoder_config.soft_geocoding_limit
|
||||
provider = user_geocoder_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
#-- Routing
|
||||
service = 'routing'
|
||||
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)]
|
||||
user_service = UserMetricsService(user_routing_config, redis_conn)
|
||||
|
||||
monthly_quota = user_routing_config.monthly_quota
|
||||
used_quota = user_service.used_quota(user_routing_config.service_type, today)
|
||||
soft_limit = user_routing_config.soft_limit
|
||||
provider = user_routing_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
#-- Observatory
|
||||
service = 'observatory'
|
||||
plpy.execute("SELECT cdb_dataservices_server._get_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
|
||||
user_obs_config = GD["user_obs_config_{0}".format(username)]
|
||||
user_service = UserMetricsService(user_obs_config, redis_conn)
|
||||
|
||||
monthly_quota = user_obs_config.monthly_quota
|
||||
used_quota = user_service.used_quota(user_obs_config.service_type, today)
|
||||
soft_limit = user_obs_config.soft_limit
|
||||
provider = user_obs_config.provider
|
||||
ret += [[service, monthly_quota, used_quota, soft_limit, provider]]
|
||||
|
||||
return ret
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_enough_quota(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
service_ TEXT,
|
||||
input_size NUMERIC)
|
||||
returns BOOLEAN AS $$
|
||||
DECLARE
|
||||
params cdb_dataservices_server.service_quota_info;
|
||||
BEGIN
|
||||
SELECT * INTO params
|
||||
FROM cdb_dataservices_server.cdb_service_quota_info(username, orgname) AS p
|
||||
WHERE p.service = service_::cdb_dataservices_server.service_type;
|
||||
RETURN params.soft_limit OR ((params.used_quota + input_size) <= params.monthly_quota);
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
@@ -57,11 +57,9 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
quota_service.increment_total_service_use()
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isolines(
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isodistance(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
isotype TEXT,
|
||||
source geometry(Geometry, 4326),
|
||||
mode TEXT,
|
||||
data_range integer[],
|
||||
@@ -78,7 +76,6 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
|
||||
logger_config = GD["logger_config"]
|
||||
logger = Logger(logger_config)
|
||||
# -- Check the quota
|
||||
quota_service = QuotaService(user_isolines_routing_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
raise Exception('You have reached the limit of your quota')
|
||||
@@ -96,14 +93,9 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
|
||||
# -- TODO Support options properly
|
||||
isolines = {}
|
||||
if isotype == 'isodistance':
|
||||
for r in data_range:
|
||||
isoline = mapzen_isolines.calculate_isodistance(origin, mode, r)
|
||||
isolines[r] = isoline
|
||||
elif isotype == 'isochrone':
|
||||
for r in data_range:
|
||||
isoline = mapzen_isolines.calculate_isochrone(origin, mode, r)
|
||||
isolines[r] = isoline
|
||||
for r in data_range:
|
||||
isoline = mapzen_isolines.calculate_isodistance(origin, mode, r)
|
||||
isolines[r] = isoline
|
||||
|
||||
result = []
|
||||
for r in data_range:
|
||||
@@ -130,3 +122,67 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
finally:
|
||||
quota_service.increment_total_service_use()
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_isochrones(
|
||||
username TEXT,
|
||||
orgname TEXT,
|
||||
source geometry(Geometry, 4326),
|
||||
mode TEXT,
|
||||
data_range integer[],
|
||||
options text[])
|
||||
RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
import json
|
||||
from cartodb_services.mapzen import MatrixClient, MapzenIsochrones
|
||||
from cartodb_services.metrics import QuotaService
|
||||
from cartodb_services.tools import Logger,LoggerConfig
|
||||
from cartodb_services.mapzen.types import coordinates_to_polygon
|
||||
|
||||
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
|
||||
user_isolines_routing_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)
|
||||
# -- Check the quota
|
||||
quota_service = QuotaService(user_isolines_routing_config, redis_conn)
|
||||
if not quota_service.check_user_quota():
|
||||
raise Exception('You have reached the limit of your quota')
|
||||
|
||||
try:
|
||||
mapzen_isochrones = MapzenIsochrones(user_isolines_routing_config.mapzen_matrix_api_key,
|
||||
logger)
|
||||
|
||||
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 = {'lat': lat, 'lon': lon}
|
||||
else:
|
||||
raise Exception('source is NULL')
|
||||
|
||||
resp = mapzen_isochrones.isochrone(origin, mode, data_range)
|
||||
|
||||
if resp:
|
||||
result = []
|
||||
for isochrone in resp:
|
||||
result_polygon = coordinates_to_polygon(isochrone.coordinates)
|
||||
if result_polygon:
|
||||
quota_service.increment_success_service_use()
|
||||
result.append([source, isochrone.duration, result_polygon])
|
||||
else:
|
||||
quota_service.increment_empty_service_use()
|
||||
result.append([source, isochrone.duration, None])
|
||||
quota_service.increment_success_service_use()
|
||||
quota_service.increment_isolines_service_use(len(result))
|
||||
return result
|
||||
else:
|
||||
quota_service.increment_empty_service_use()
|
||||
return []
|
||||
except BaseException as e:
|
||||
import sys
|
||||
quota_service.increment_failed_service_use()
|
||||
logger.error('Error trying to get mapzen isochrones', sys.exc_info(), data={"username": username, "orgname": orgname})
|
||||
raise Exception('Error trying to get mapzen isochrones')
|
||||
finally:
|
||||
quota_service.increment_total_service_use()
|
||||
$$ LANGUAGE plpythonu SECURITY DEFINER;
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
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.')
|
||||
|
||||
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])
|
||||
else:
|
||||
raise Exception('Requested isolines provider is not available')
|
||||
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])
|
||||
else:
|
||||
raise Exception('Requested isolines provider is not available')
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
-- heremaps isodistance
|
||||
@@ -40,10 +47,9 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
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)]
|
||||
type = 'isodistance'
|
||||
|
||||
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isolines($1, $2, $3, $4, $5, $6, $7) as isoline; ", ["text", "text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, type, source, mode, range, options])
|
||||
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[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||
|
||||
return result
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
@@ -47,9 +47,8 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
|
||||
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)]
|
||||
type = 'isochrone'
|
||||
|
||||
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isolines($1, $2, $3, $4, $5, $6, $7) as isoline; ", ["text", "text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, type, source, mode, range, options])
|
||||
mapzen_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._cdb_mapzen_isochrones($1, $2, $3, $4, $5, $6) as isoline; ", ["text", "text", "geometry(geometry, 4326)", "text", "integer[]", "text[]"])
|
||||
result = plpy.execute(mapzen_plan, [username, orgname, source, mode, range, options])
|
||||
return result
|
||||
$$ LANGUAGE plpythonu;
|
||||
|
||||
@@ -29,12 +29,12 @@ NOTE: a system installation is required at present because the library is meant
|
||||
|
||||
|
||||
## Running the unit tests
|
||||
Just run `nosetests`
|
||||
Just run `nosetests test/`
|
||||
```shell
|
||||
$ nosetests
|
||||
.................................................
|
||||
$ nosetests test/
|
||||
......................................................................................................
|
||||
----------------------------------------------------------------------
|
||||
Ran 49 tests in 0.131s
|
||||
Ran 102 tests in 0.122s
|
||||
|
||||
OK
|
||||
```
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import json
|
||||
import requests
|
||||
|
||||
from requests.adapters import HTTPAdapter
|
||||
from exceptions import *
|
||||
from cartodb_services.metrics import Traceable
|
||||
|
||||
@@ -17,6 +18,7 @@ class HereMapsGeocoder(Traceable):
|
||||
DEFAULT_GEN = 9
|
||||
READ_TIMEOUT = 60
|
||||
CONNECT_TIMEOUT = 10
|
||||
MAX_RETRIES=3
|
||||
|
||||
ADDRESS_PARAMS = [
|
||||
'city',
|
||||
@@ -88,7 +90,10 @@ class HereMapsGeocoder(Traceable):
|
||||
'gen': self.gen
|
||||
}
|
||||
request_params.update(params)
|
||||
response = requests.get(self.host, params=request_params,
|
||||
# TODO Extract HTTP client wrapper
|
||||
session = requests.Session()
|
||||
session.mount(self.host, HTTPAdapter(self.MAX_RETRIES))
|
||||
response = session.get(self.host, params=request_params,
|
||||
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
|
||||
self.add_response_data(response, self._logger)
|
||||
if response.status_code == requests.codes.ok:
|
||||
|
||||
@@ -2,6 +2,7 @@ import requests
|
||||
import json
|
||||
|
||||
from exceptions import WrongParams
|
||||
from requests.adapters import HTTPAdapter
|
||||
from cartodb_services.metrics import Traceable
|
||||
|
||||
|
||||
@@ -13,6 +14,7 @@ class HereMapsRoutingIsoline(Traceable):
|
||||
ISOLINE_PATH = '/routing/7.2/calculateisoline.json'
|
||||
READ_TIMEOUT = 60
|
||||
CONNECT_TIMEOUT = 10
|
||||
MAX_RETRIES = 3
|
||||
|
||||
ACCEPTED_MODES = {
|
||||
"walk": "pedestrian",
|
||||
@@ -53,6 +55,9 @@ class HereMapsRoutingIsoline(Traceable):
|
||||
data_range,
|
||||
range_type,
|
||||
parsed_options)
|
||||
# TODO Extract HTTP client wrapper
|
||||
session = requests.Session()
|
||||
session.mount(self._url, HTTPAdapter(self.MAX_RETRIES))
|
||||
response = requests.get(self._url, params=request_params,
|
||||
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
|
||||
self.add_response_data(response, self._logger)
|
||||
|
||||
@@ -2,3 +2,4 @@ from routing import MapzenRouting, MapzenRoutingResponse
|
||||
from isolines import MapzenIsolines
|
||||
from geocoder import MapzenGeocoder
|
||||
from matrix_client import MatrixClient
|
||||
from isochrones import MapzenIsochrones
|
||||
|
||||
@@ -2,6 +2,7 @@ import requests
|
||||
import json
|
||||
import re
|
||||
|
||||
from requests.adapters import HTTPAdapter
|
||||
from exceptions import WrongParams, MalformedResult, ServiceException
|
||||
from qps import qps_retry
|
||||
from cartodb_services.tools import Coordinate, PolyLine
|
||||
@@ -14,6 +15,7 @@ class MapzenGeocoder(Traceable):
|
||||
BASE_URL = 'https://search.mapzen.com/v1/search'
|
||||
READ_TIMEOUT = 60
|
||||
CONNECT_TIMEOUT = 10
|
||||
MAX_RETRIES = 3
|
||||
|
||||
def __init__(self, app_key, logger, base_url=BASE_URL):
|
||||
self._app_key = app_key
|
||||
@@ -27,7 +29,10 @@ class MapzenGeocoder(Traceable):
|
||||
state_province,
|
||||
country, search_type)
|
||||
try:
|
||||
response = requests.get(self._url, params=request_params,
|
||||
# TODO Extract HTTP client wrapper
|
||||
session = requests.Session()
|
||||
session.mount(self._url, HTTPAdapter(self.MAX_RETRIES))
|
||||
response = session.get(self._url, params=request_params,
|
||||
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
|
||||
self.add_response_data(response, self._logger)
|
||||
if response.status_code == requests.codes.ok:
|
||||
@@ -49,7 +54,7 @@ class MapzenGeocoder(Traceable):
|
||||
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 Mapzen geocoding server')
|
||||
self._logger.error('Timeout connecting to Mapzen geocoding server', te)
|
||||
raise ServiceException('Error trying to geocode {0} using mapzen'.format(searchtext),
|
||||
None)
|
||||
except requests.ConnectionError as e:
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
|
||||
from requests.adapters import HTTPAdapter
|
||||
from exceptions import WrongParams, MalformedResult, ServiceException
|
||||
from qps import qps_retry
|
||||
|
||||
|
||||
class MapzenIsochrones:
|
||||
'A Mapzen Isochrones wrapper for python'
|
||||
|
||||
BASE_URL = 'https://matrix.mapzen.com/isochrone'
|
||||
READ_TIMEOUT = 60
|
||||
CONNECT_TIMEOUT = 10
|
||||
MAX_RETRIES = 1
|
||||
|
||||
ACCEPTED_MODES = {
|
||||
"walk": "pedestrian",
|
||||
"car": "auto"
|
||||
}
|
||||
|
||||
def __init__(self, app_key, logger, base_url=BASE_URL):
|
||||
self._app_key = app_key
|
||||
self._url = base_url
|
||||
self._logger = logger
|
||||
|
||||
@qps_retry(qps=7)
|
||||
def isochrone(self, locations, costing, ranges):
|
||||
request_params = self._parse_request_params(locations, costing,
|
||||
ranges)
|
||||
try:
|
||||
# TODO Extract HTTP client wrapper
|
||||
session = requests.Session()
|
||||
session.mount(self._url, HTTPAdapter(self.MAX_RETRIES))
|
||||
response = session.get(self._url, params=request_params,
|
||||
timeout=(self.CONNECT_TIMEOUT,
|
||||
self.READ_TIMEOUT))
|
||||
|
||||
if response.status_code is requests.codes.ok:
|
||||
return self._parse_response(response)
|
||||
elif response.status_code == requests.codes.bad_request:
|
||||
return []
|
||||
else:
|
||||
self._logger.error('Error trying to get isochrones from mapzen',
|
||||
data={"response_status": response.status_code,
|
||||
"response_reason": response.reason,
|
||||
"response_content": response.text,
|
||||
"reponse_url": response.url,
|
||||
"response_headers": response.headers,
|
||||
"locations": locations,
|
||||
"costing": costing})
|
||||
raise ServiceException('Error trying to get isochrones from mapzen',
|
||||
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 Mapzen isochrones server', exception=te)
|
||||
raise ServiceException('Error trying to calculate isochrones using mapzen',
|
||||
None)
|
||||
except requests.ConnectionError as e:
|
||||
# Don't raise the exception to continue with the geocoding job
|
||||
self._logger.error('Error connecting to Mapzen isochrones server',
|
||||
exception=e)
|
||||
return []
|
||||
|
||||
def _parse_request_params(self, locations, costing, ranges):
|
||||
if costing in self.ACCEPTED_MODES:
|
||||
mode_source = self.ACCEPTED_MODES[costing]
|
||||
else:
|
||||
raise WrongParams("{0} is not an accepted mode".format(costing))
|
||||
|
||||
contours = []
|
||||
for r in ranges:
|
||||
# range is in seconds but mapzen uses minutes
|
||||
range_minutes = r / 60
|
||||
contours.append({"time": range_minutes, "color": 'tbd'})
|
||||
request_params = {
|
||||
'json': json.dumps({'locations': [locations],
|
||||
'costing': mode_source,
|
||||
'contours': contours,
|
||||
'generalize': 50,
|
||||
'denoise': .3}),
|
||||
'api_key': self._app_key
|
||||
}
|
||||
|
||||
return request_params
|
||||
|
||||
def _parse_response(self, response):
|
||||
try:
|
||||
json_response = response.json()
|
||||
isochrones = []
|
||||
for feature in json_response['features']:
|
||||
# Coordinates could have more than one isochrone. For the
|
||||
# moment we're getting the first polygon only
|
||||
coordinates = feature['geometry']['coordinates']
|
||||
duration = feature['properties']['contour']
|
||||
mapzen_response = MapzenIsochronesResponse(coordinates,
|
||||
duration)
|
||||
isochrones.append(mapzen_response)
|
||||
return isochrones
|
||||
except IndexError:
|
||||
return []
|
||||
except KeyError:
|
||||
self._logger.error('Non existing key for mapzen isochrones response',
|
||||
data={"response_status": response.status_code,
|
||||
"response_reason": response.reason,
|
||||
"response_content": response.text,
|
||||
"reponse_url": response.url,
|
||||
"response_headers": response.headers})
|
||||
raise MalformedResult()
|
||||
except ValueError:
|
||||
# JSON decode error
|
||||
self._logger.error('JSON decode error for Mapzen isochrones',
|
||||
data={"response_status": response.status_code,
|
||||
"response_reason": response.reason,
|
||||
"response_content": response.text,
|
||||
"reponse_url": response.url,
|
||||
"response_headers": response.headers})
|
||||
return []
|
||||
|
||||
|
||||
class MapzenIsochronesResponse:
|
||||
|
||||
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
|
||||
@@ -55,7 +55,7 @@ class QPSService:
|
||||
|
||||
def retry(self, first_request_time, retry_count):
|
||||
elapsed = datetime.now() - first_request_time
|
||||
if elapsed.microseconds > (self._retry_timeout * 1000.0):
|
||||
if elapsed.microseconds > (self._retry_timeout * 1000.0 * 1000.0):
|
||||
raise TimeoutException()
|
||||
|
||||
# inverse qps * (1.5 ^ i) is an increased sleep time of 1.5x per
|
||||
|
||||
@@ -2,6 +2,7 @@ import requests
|
||||
import json
|
||||
import re
|
||||
|
||||
from requests.adapters import HTTPAdapter
|
||||
from exceptions import WrongParams, MalformedResult, ServiceException
|
||||
from qps import qps_retry
|
||||
from cartodb_services.tools import Coordinate, PolyLine
|
||||
@@ -14,6 +15,7 @@ class MapzenRouting(Traceable):
|
||||
PRODUCTION_ROUTING_BASE_URL = 'https://valhalla.mapzen.com/route'
|
||||
READ_TIMEOUT = 60
|
||||
CONNECT_TIMEOUT = 10
|
||||
MAX_RETRIES=3
|
||||
|
||||
ACCEPTED_MODES = {
|
||||
"walk": "pedestrian",
|
||||
@@ -46,7 +48,10 @@ class MapzenRouting(Traceable):
|
||||
mode_param,
|
||||
units)
|
||||
request_params = self.__parse_request_parameters(json_request_params)
|
||||
response = requests.get(self._url, params=request_params,
|
||||
# TODO Extract HTTP client wrapper
|
||||
session = requests.Session()
|
||||
session.mount(self._url, HTTPAdapter(self.MAX_RETRIES))
|
||||
response = session.get(self._url, params=request_params,
|
||||
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
|
||||
self.add_response_data(response, self._logger)
|
||||
if response.status_code == requests.codes.ok:
|
||||
|
||||
@@ -19,6 +19,24 @@ def polyline_to_linestring(polyline):
|
||||
|
||||
return geometry
|
||||
|
||||
|
||||
def coordinates_to_polygon(coordinates):
|
||||
"""Convert a Mapzen coordinates to a PostGIS polygon"""
|
||||
result_coordinates = []
|
||||
for coordinate in coordinates:
|
||||
result_coordinates.append("%s %s" % (coordinate[0], coordinate[1]))
|
||||
wkt_coordinates = ','.join(result_coordinates)
|
||||
|
||||
try:
|
||||
sql = "SELECT ST_MakePolygon(ST_GeomFromText('LINESTRING({0})', 4326)) as geom".format(wkt_coordinates)
|
||||
geometry = plpy.execute(sql, 1)[0]['geom']
|
||||
except BaseException as e:
|
||||
plpy.warning("Can't generate POLYGON from coordinates: {0}".format(e))
|
||||
geometry = None
|
||||
|
||||
return geometry
|
||||
|
||||
|
||||
def country_to_iso3(country):
|
||||
""" Convert country to its iso3 code """
|
||||
try:
|
||||
|
||||
@@ -94,7 +94,7 @@ class ObservatorySnapshotConfig(DataObservatoryConfig):
|
||||
self._soft_limit = False
|
||||
self._monthly_quota = 0
|
||||
if self.QUOTA_KEY in self._redis_config:
|
||||
self._monthly_quota = float(self._redis_config[self.QUOTA_KEY])
|
||||
self._monthly_quota = int(self._redis_config[self.QUOTA_KEY])
|
||||
self._connection_str = self._db_config.data_observatory_connection_str
|
||||
|
||||
@property
|
||||
@@ -118,7 +118,7 @@ class ObservatoryConfig(DataObservatoryConfig):
|
||||
self._soft_limit = False
|
||||
self._monthly_quota = 0
|
||||
if self.QUOTA_KEY in self._redis_config:
|
||||
self._monthly_quota = float(self._redis_config[self.QUOTA_KEY])
|
||||
self._monthly_quota = int(self._redis_config[self.QUOTA_KEY])
|
||||
self._connection_str = self._db_config.data_observatory_connection_str
|
||||
|
||||
@property
|
||||
@@ -218,7 +218,7 @@ class IsolinesRoutingConfig(ServiceConfig):
|
||||
self._geocoder_provider = filtered_config[self.GEOCODER_PROVIDER_KEY].lower()
|
||||
self._period_end_date = date_parse(filtered_config[self.PERIOD_END_DATE])
|
||||
if self._isolines_provider == self.HEREMAPS_PROVIDER:
|
||||
self._isolines_quota = float(filtered_config[self.QUOTA_KEY])
|
||||
self._isolines_quota = int(filtered_config[self.QUOTA_KEY])
|
||||
self._heremaps_app_id = db_config.heremaps_isolines_app_id
|
||||
self._heremaps_app_code = db_config.heremaps_isolines_app_code
|
||||
if filtered_config[self.SOFT_LIMIT_KEY].lower() == 'true':
|
||||
@@ -361,7 +361,7 @@ class GeocoderConfig(ServiceConfig):
|
||||
self._geocoder_provider = filtered_config[self.GEOCODER_PROVIDER].lower()
|
||||
else:
|
||||
self._geocoder_provider = self.DEFAULT_PROVIDER
|
||||
self._geocoding_quota = float(filtered_config[self.QUOTA_KEY])
|
||||
self._geocoding_quota = int(filtered_config[self.QUOTA_KEY])
|
||||
self._period_end_date = date_parse(filtered_config[self.PERIOD_END_DATE])
|
||||
if filtered_config[self.SOFT_LIMIT_KEY].lower() == 'true':
|
||||
self._soft_geocoding_limit = True
|
||||
|
||||
@@ -9,6 +9,7 @@ class UserMetricsService:
|
||||
SERVICE_GEOCODER_CACHE = 'geocoder_cache'
|
||||
SERVICE_HERE_ISOLINES = 'here_isolines'
|
||||
SERVICE_MAPZEN_ROUTING = 'routing_mapzen'
|
||||
SERVICE_OBSERVATORY = 'obs_general'
|
||||
DAY_OF_MONTH_ZERO_PADDED = '%d'
|
||||
|
||||
def __init__(self, user_geocoder_config, redis_connection):
|
||||
@@ -22,6 +23,8 @@ class UserMetricsService:
|
||||
return self.__used_isolines_quota(service_type, date)
|
||||
elif service_type == self.SERVICE_MAPZEN_ROUTING:
|
||||
return self.__used_routing_quota(service_type, date)
|
||||
elif service_type == self.SERVICE_OBSERVATORY:
|
||||
return self.__used_observatory_quota(service_type, date)
|
||||
else:
|
||||
return self.__used_geocoding_quota(service_type, date)
|
||||
|
||||
@@ -72,6 +75,19 @@ class UserMetricsService:
|
||||
|
||||
return current_use
|
||||
|
||||
def __used_observatory_quota(self, service_type, date):
|
||||
date_from, date_to = self.__current_billing_cycle()
|
||||
current_use = 0
|
||||
success_responses = self.get_metrics(service_type,
|
||||
'success_responses', date_from,
|
||||
date_to)
|
||||
empty_responses = self.get_metrics(service_type,
|
||||
'empty_responses', date_from,
|
||||
date_to)
|
||||
current_use += (success_responses + empty_responses)
|
||||
|
||||
return current_use
|
||||
|
||||
def increment_service_use(self, service_type, metric, date=date.today(),
|
||||
amount=1):
|
||||
""" Increment the services uses in monthly and daily basis"""
|
||||
@@ -88,11 +104,11 @@ class UserMetricsService:
|
||||
redis_prefix = self.__parse_redis_prefix(key_prefix, entity_name,
|
||||
service, metric, date)
|
||||
score = self._redis_connection.zscore(redis_prefix, date.day)
|
||||
aggregated_metric += score if score else 0
|
||||
aggregated_metric += int(score) if score else 0
|
||||
zero_padded_day = date.strftime(self.DAY_OF_MONTH_ZERO_PADDED)
|
||||
if str(date.day) != zero_padded_day:
|
||||
score = self._redis_connection.zscore(redis_prefix, zero_padded_day)
|
||||
aggregated_metric += score if score else 0
|
||||
aggregated_metric += int(score) if score else 0
|
||||
|
||||
return aggregated_metric
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ class MapzenGeocoderConfigBuilder(object):
|
||||
geocoding_quota = mapzen_server_conf['geocoder']['monthly_quota']
|
||||
mapzen_api_key = mapzen_server_conf['geocoder']['api_key']
|
||||
|
||||
soft_geocoding_limit = self._user_conf.get('soft_geocoding_limit')
|
||||
soft_geocoding_limit = self._user_conf.get('soft_geocoding_limit').lower() == 'true'
|
||||
|
||||
cost_per_hit=0
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class Logger:
|
||||
|
||||
LEVELS = {'debug': 1, 'info': 2, 'warning': 3, 'error': 4}
|
||||
@@ -66,7 +65,7 @@ class Logger:
|
||||
if self._rollbar_activated():
|
||||
try:
|
||||
if exception:
|
||||
rollbar.report_exc_info(exception, extra_data=data,
|
||||
rollbar.report_exc_info(sys.exc_info(), extra_data=data,
|
||||
level=level)
|
||||
else:
|
||||
rollbar.report_message(text, level, extra_data=data)
|
||||
@@ -102,7 +101,7 @@ class Logger:
|
||||
def _parse_log_extra_data(self, exception, data):
|
||||
extra_data = {}
|
||||
if exception:
|
||||
type_, value_, traceback_ = exception
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
exception_traceback = traceback.format_tb(traceback_)
|
||||
extra_data = {"exception_type": type_, "exception_message": value_,
|
||||
"exception_traceback": exception_traceback,
|
||||
|
||||
@@ -10,7 +10,7 @@ from setuptools import setup, find_packages
|
||||
setup(
|
||||
name='cartodb_services',
|
||||
|
||||
version='0.10.0',
|
||||
version='0.12.2',
|
||||
|
||||
description='CartoDB Services API Python Library',
|
||||
|
||||
|
||||
@@ -128,8 +128,8 @@ class HereMapsRoutingIsolineTestCase(unittest.TestCase):
|
||||
MALFORMED_RESPONSE = """{"manolo": "escobar"}"""
|
||||
|
||||
def setUp(self):
|
||||
logger = Mock()
|
||||
self.routing = HereMapsRoutingIsoline(None, None, logger)
|
||||
self.logger = Mock()
|
||||
self.routing = HereMapsRoutingIsoline(None, None, self.logger)
|
||||
self.isoline_url = "{0}{1}".format(HereMapsRoutingIsoline.PRODUCTION_ROUTING_BASE_URL,
|
||||
HereMapsRoutingIsoline.ISOLINE_PATH)
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import mock
|
||||
import unittest
|
||||
import requests_mock
|
||||
from mock import Mock
|
||||
|
||||
from cartodb_services.mapzen import MapzenIsochrones
|
||||
from cartodb_services.mapzen.exceptions import ServiceException
|
||||
|
||||
requests_mock.Mocker.TEST_PREFIX = 'test_'
|
||||
|
||||
@requests_mock.Mocker()
|
||||
class MapzenIsochronesTestCase(unittest.TestCase):
|
||||
MAPZEN_ISOCHRONES_URL = 'https://matrix.mapzen.com/isochrone'
|
||||
|
||||
ERROR_RESPONSE = """{
|
||||
"error_code": 171,
|
||||
"error": "No suitable edges near location",
|
||||
"status_code": 400,
|
||||
"status": "Bad Request"
|
||||
}"""
|
||||
|
||||
GOOD_RESPONSE = """{"features":[{"properties":{"opacity":0.33,"contour":15,"color":"tbd"},"type":"Feature","geometry":{"coordinates":[[-3.702579,40.430893],[-3.702193,40.430122],[-3.702579,40.430893]],"type":"LineString"}},{"properties":{"opacity":0.33,"contour":5,"color":"tbd"},"type":"Feature","geometry":{"coordinates":[[-3.703050,40.424995],[-3.702546,40.424694],[-3.703050,40.424995]],"type":"LineString"}}],"type":"FeatureCollection"}"""
|
||||
|
||||
def setUp(self):
|
||||
self.logger = Mock()
|
||||
self.mapzen_isochrones = MapzenIsochrones('matrix-xxxxx', self.logger)
|
||||
|
||||
def test_calculate_isochrone(self, req_mock):
|
||||
req_mock.register_uri('GET', self.MAPZEN_ISOCHRONES_URL,
|
||||
text=self.GOOD_RESPONSE)
|
||||
|
||||
response = self.mapzen_isochrones.isochrone([-41.484375, 28.993727],
|
||||
'walk', [300, 900])
|
||||
|
||||
self.assertEqual(len(response), 2)
|
||||
self.assertEqual(response[0].coordinates, [[-3.702579,40.430893],[-3.702193,40.430122],[-3.702579,40.430893]])
|
||||
self.assertEqual(response[0].duration, 15)
|
||||
self.assertEqual(response[1].coordinates, [[-3.703050,40.424995],[-3.702546,40.424694],[-3.703050,40.424995]])
|
||||
self.assertEqual(response[1].duration, 5)
|
||||
|
||||
def test_calculate_isochrone_error_400_returns_empty(self, req_mock):
|
||||
req_mock.register_uri('GET', self.MAPZEN_ISOCHRONES_URL,
|
||||
text=self.ERROR_RESPONSE, status_code=400)
|
||||
|
||||
response = self.mapzen_isochrones.isochrone([-41.484375, 28.993727],
|
||||
'walk', [300, 900])
|
||||
self.assertEqual(response, [])
|
||||
|
||||
def test_calculate_isochrone_error_500_returns_exception(self, req_mock):
|
||||
req_mock.register_uri('GET', self.MAPZEN_ISOCHRONES_URL,
|
||||
text=self.ERROR_RESPONSE, status_code=500)
|
||||
with self.assertRaises(ServiceException):
|
||||
self.mapzen_isochrones.isochrone([-41.484375, 28.993727],
|
||||
'walk', [300, 900])
|
||||
@@ -282,7 +282,7 @@ class TestDataObservatoryFunctions(TestCase):
|
||||
def test_if_obs_get_available_timespans_is_ok(self):
|
||||
query = "SELECT timespan_id FROM OBS_GetAvailableTimespans() LIMIT 1;&api_key={0}".format(self.env_variables['api_key'])
|
||||
result = IntegrationTestHelper.execute_query(self.sql_api_url, query)
|
||||
assert_not_equal(result['geom_id'], None)
|
||||
assert_not_equal(result['timespan_id'], None)
|
||||
|
||||
def test_if_obs_get_available_timespans_without_api_key_raise_error(self):
|
||||
query = "SELECT timespan_id FROM OBS_GetAvailableTimespans() LIMIT 1;"
|
||||
|
||||
Reference in New Issue
Block a user