Compare commits

...

201 Commits

Author SHA1 Message Date
Mario de Frutos
71ed0dcc4f Merge pull request #375 from CartoDB/development
Release server 0.24.2 and python library 0.15.1
2017-05-26 14:26:38 +02:00
Mario de Frutos
8ea1ffc425 Added chages to NEWS.md 2017-05-26 13:11:37 +02:00
Mario de Frutos
12ffc44efb Server extension version 0.24.2 release artifacts 2017-05-26 12:46:57 +02:00
Mario de Frutos
402c14e6ca Merge pull request #373 from CartoDB/371_fix_namedplace_fallback
Fix for namedplaces geocoding functions fallback
2017-05-26 12:45:47 +02:00
Mario de Frutos
ad6ed9a9bc Bump version for DS 2017-05-26 12:41:42 +02:00
Mario de Frutos
ac854a94af Fixed fallback to internal geocoder in nameplaces geocoding functions
- Fixed fallback becuase we have to use spiexceptions in this case
because we retrieve the configuration usig plpy.execute fuctions that
wrap any exception into a spiexception.

- In case we don't want to use Mapzen, we could leave the api_key empty
becuase we arise a ConfigException if the Mapzen api_key is empty so
we are able to make fallback. Right now we can't remove the mapzen
configuration because it'll fail when the InternalGeocoderConfig try to
load the ServiceDBConfig

This is a dirty hack, we should improve how the DB config is loaded. See
2017-05-26 12:41:41 +02:00
Mario de Frutos
61efb66aba Add an extra check for google credentials
If the user has a wrong base64 padded secret key the googlemaps
python library is returning "TypeError: Incorrect padding" which
is very hard to understand. So now we check if the secret key is
a valid base64 string
2017-05-26 11:51:32 +02:00
Mario de Frutos
ddcc7162fb Merge pull request #369 from CartoDB/setted-does-not-exist
Fixed bad spelling of past participle of verb set in NEWS and error messages
2017-05-24 15:47:52 +02:00
Rafael Porres Molina
37eeab5b9e past participle of set is set 2017-05-24 15:41:12 +02:00
Rafa de la Torre
97961a02df Update exception_safe.md
User's and orgs are not part of the client interface, removed those parameters.
2017-05-23 13:01:18 +02:00
Rafa de la Torre
d7fad6d8d3 Prepare release of server v0.24.1 2017-05-16 17:58:34 +02:00
Rafa de la Torre
188767e15a Merge pull request #367 from CartoDB/366-fix-empty-table-case
366 fix empty table case
2017-05-16 17:48:26 +02:00
Rafa de la Torre
59a8cafc74 Fix another empty table case #366 2017-05-16 17:20:16 +02:00
Rafa de la Torre
4ef6083344 Test for OBS_GetData(geomrefs TEXT[], params JSON) #366 2017-05-16 17:19:40 +02:00
Rafa de la Torre
b50637d36f Fix return type of OBS_GetData #366 2017-05-16 16:23:13 +02:00
Rafa de la Torre
c653914694 Add test for empty table response #366 2017-05-16 16:18:42 +02:00
Rafa de la Torre
921ef46eb8 Use contrib_regression as obs backend #366 2017-05-16 15:59:34 +02:00
Rafa de la Torre
4c46effc9b Add new params at the end #361 2017-05-09 16:36:03 +02:00
Rafa de la Torre
8bb1943dca Remove reference to PR that can be confusing 2017-05-09 16:33:34 +02:00
Rafa de la Torre
b4075818be Update NEWS.md 2017-05-09 16:28:09 +02:00
Rafa de la Torre
a7d322bcd8 Prepare new version of the client #361
Changes in TYPEs obs_meta_geometry and obs_meta_timespan
2017-05-04 17:54:49 +02:00
Rafa de la Torre
4c5183e9bd Prepare new version of the server #361
Changes in TYPEs obs_meta_geometry and obs_meta_timespan
2017-05-04 17:54:49 +02:00
Rafa de la Torre
a432b9af7d Merge pull request #360 from CartoDB/obs-getavailablegeometries-tags
Add geom_tags to getavailablegeometries
2017-05-04 16:59:00 +02:00
Rafa de la Torre
b8a69356d4 Merge remote-tracking branch 'origin/development' into obs-getavailablegeometries-tags 2017-05-04 14:48:02 +02:00
Mario de Frutos
d1b1a6b1e5 Merge pull request #363 from CartoDB/change_readme
Improve the install steps in the README
2017-04-21 17:02:21 +02:00
Mario de Frutos
63dbfa27b5 Improve the install steps in the README 2017-04-21 12:55:15 +02:00
Javier Goizueta
b7ea87cc11 Merge branch 'master' into development 2017-04-12 15:24:36 +02:00
Guido Fioravantti
6654b69212 Update README.md 2017-04-12 15:20:43 +02:00
Javier Goizueta
d95155af71 Merge pull request #362 from CartoDB/fix_rate_limits_doc
Fix the rate limits documentation
2017-04-12 15:16:26 +02:00
Javier Goizueta
160409c8c0 Fix the rate limits documentation
The service name used to store the geocoding rate limits is geocoder, not geocoding.
2017-04-12 13:34:16 +02:00
John Krauss
8b031a3016 add tags to getavailablegeometries, and a few additional columns to obs_getavailabletimespans 2017-04-10 18:15:19 +00:00
Guido Fioravantti
607c8e82c9 Update README.md 2017-04-05 16:56:48 +02:00
Javier Goizueta
8917a1c63f Merge pull request #359 from CartoDB/development
New release with geocoding rate limits
2017-03-31 10:43:05 +02:00
Javier Goizueta
524d15c1a9 Fix uses of cartodb cdb_conf functions 2017-03-30 18:10:53 +02:00
Javier Goizueta
c0b0a58d35 Missing changes in source 2017-03-30 18:03:45 +02:00
Javier Goizueta
7ec0a3ab66 Missing changes in v23 script 2017-03-30 18:03:25 +02:00
Javier Goizueta
e55338de90 Fix functions to write cdb_conf
Two problems fixe with this functions ported from the cartodb extension:
* There was an incorrect reference to the cartodb scchema
* They need to be SECURITY DEFINER to be usable with the geocoder_api role
2017-03-30 16:33:12 +02:00
Javier Goizueta
e247fda694 Fix superuser template functions
Superuser functions were overriding their user/org parameters with the
values from the database/role, so the user was incorrect.
2017-03-30 13:18:38 +02:00
Javier Goizueta
2ec38e93f0 Fix migration script permissions for superuser functions 2017-03-29 17:46:31 +02:00
Javier Goizueta
2197edb467 Fix bugs in geocoding server functions 2017-03-29 16:20:59 +02:00
Javier Goizueta
88c43bab2f Add missing functions to migration scripts 2017-03-29 13:08:28 +02:00
Javier Goizueta
aac89e0236 New versions 0.16.0 (client), 0.23.0 (server), 0.15.0 (python) 2017-03-28 17:53:40 +02:00
Javier Goizueta
f0b0a9e7f2 Merge pull request #355 from CartoDB/346-user-rate-limits
Service rate limits
2017-03-28 17:48:46 +02:00
Javier Goizueta
c74bb85f26 Merge branch 'development' into 346-user-rate-limits
# Conflicts:
#	README.md

Fixes in documentation merged from development:

* Remove cd into dataservices-api: all example snippets have comments about the intended  initial path
* Installing the python module was missing (replaced by installing dependencies);
  it should not be necessary in general to use the upgrade options to install dependencies
2017-03-28 15:01:01 +02:00
Rafa de la Torre
77dfda11d9 Merge pull request #353 from CartoDB/udpate-docs
Fix links and improve readability
2017-03-28 11:53:07 +02:00
Javier Goizueta
2c15110255 Rename constructor arguments for consistency 2017-03-28 10:53:16 +02:00
Javier Goizueta
6b86acfaa3 Fix indentation 2017-03-28 10:44:25 +02:00
Javier Goizueta
4b18e1f601 Rename variable 2017-03-28 10:42:03 +02:00
Javier Goizueta
970d828768 Remove unneeded ERB options 2017-03-28 10:39:23 +02:00
Javier Goizueta
39878ef542 Rename some template functions internal terms
* credentials => user_org
* private => superuser
2017-03-28 10:37:21 +02:00
Javier Goizueta
2d6b73cb9d Add some examples to the documentation 2017-03-28 10:19:58 +02:00
Javier Goizueta
b1e765c639 Clarify what configuration is retrieved by cdb_service_get_rate_limit 2017-03-28 09:54:00 +02:00
Guido Fioravantti
63eb4e3198 Update README.md 2017-03-27 12:57:41 -04:00
Guido Fioravantti
164ef42cba Update README.md 2017-03-24 17:31:29 -04:00
Guido Fioravantti
f2616590ec Update README.md 2017-03-24 17:30:15 -04:00
Guido Fioravantti
b717674af7 Update README.md 2017-03-24 17:28:03 -04:00
Javier Goizueta
c379593d89 Fix rate limits documentation 2017-03-23 15:59:13 +01:00
Javier Goizueta
41c5271de1 Fix documentation 2017-03-22 17:01:03 +01:00
Javier Goizueta
e850d5c72e Add rate limits documentation 2017-03-22 16:57:15 +01:00
Javier Goizueta
7101c8d8e8 Expose client-side rate limit configuration interface
The client functions to make configuration changes are not publicly available
(require a super user) and they have username, orgname parameters like the
server-sixe functions
2017-03-22 16:31:45 +01:00
Javier Goizueta
ef09840525 Implement server-side rate limits configuration interface 2017-03-21 17:58:33 +01:00
Javier Goizueta
cf7460c27d Fix functions schema 2017-03-21 16:17:39 +01:00
Javier Goizueta
63c03894cc Fix bugs 2017-03-21 15:45:05 +01:00
Javier Goizueta
942c6ac63d Fix indentation 2017-03-21 15:44:50 +01:00
Javier Goizueta
208469f534 Add rate limits configuration writing tests 2017-03-21 15:43:33 +01:00
Javier Goizueta
73f97128ed Reorganization of configuration modules, fix circular dependencies
The new module cartodb_services/config is intended for services configuration objects
Some legacy configuration objects remain under cartodb_services/metrics.
The refactored configuration backends are also not moved here
2017-03-21 15:42:53 +01:00
Javier Goizueta
945c6cd685 WIP: support for storing rate limits configuration 2017-03-16 19:12:39 +01:00
Javier Goizueta
7f6c19b292 Minor changes for clarity
* ServiceManager check method renamed as assert_within_limits
* Legacy classes moved to separate files
2017-03-16 17:59:22 +01:00
Javier Goizueta
87e37e1a26 Fix typo 2017-03-16 17:55:27 +01:00
Javier Goizueta
9a04ad06a0 Move rate limits out of Config
The (legacy) Config object rate limit-related modifications are reverted.
For the legacy case, configuration is handled in a specific RateLimits builder class.
2017-03-15 19:32:50 +01:00
Javier Goizueta
cebd7d2141 Apply ServiceManager to Google Geocoder
Note that the Goolge geocoder uses QuotaService to account for used quota,
but it doesn't have a quota limit.
2017-03-15 17:58:14 +01:00
Javier Goizueta
696bdb40b0 Fix incorrect import 2017-03-15 17:49:29 +01:00
Javier Goizueta
9d94f99b41 Remove incorrect README changes
A mistake was introduced when resolving merge conflicts
2017-03-15 13:04:14 +01:00
Javier Goizueta
680206a437 Missing import 2017-03-15 12:51:56 +01:00
Javier Goizueta
548d6b08db Debug SQL geocoding interface which uses ServiceManager 2017-03-15 12:47:11 +01:00
Javier Goizueta
77b5ff0b9e Fix problem with db config default arguments 2017-03-15 12:46:25 +01:00
Javier Goizueta
05b29967c7 Merge branch 'development' into 346-user-rate-limits
# Conflicts:
#	README.md
#	server/extension/sql/20_geocode_street.sql
#	server/lib/python/cartodb_services/cartodb_services/metrics/config.py
2017-03-14 19:00:53 +01:00
Javier Goizueta
6c5ca97468 Complete rate-limiting for Mapzen & Here gecoding
ServiceManager class has been introduced to handle service configuration at
SQL level (with a LegacyServiceManager alternative for non-refactored services).
These new classes take the responsibility of rate limits and quota checking.

Tests have been added for ServiceManager and rate limits, but currently they
check only the limits configuration since Lua support would be needed
to use rratelimit with MockRedis.
2017-03-14 18:51:18 +01:00
Rafa de la Torre
a64557b50e New version 0.14.1 of python library 2017-03-13 15:10:03 +01:00
Rafa de la Torre
d8da0a3782 Merge pull request #354 from CartoDB/development
Prepare new release of python library
2017-03-13 15:07:14 +01:00
Rafa de la Torre
01b96fe276 Merge pull request #352 from CartoDB/206-clean-up-non-zero-padded-reads
206 clean up non zero padded reads
2017-03-13 14:42:35 +01:00
Rafa de la Torre
4e14e9b0c0 Fix links and improve readability 2017-03-13 13:12:06 +01:00
Rafa de la Torre
26d025a5d1 Remove tests that no longer apply #206 2017-03-10 13:15:56 +01:00
Rafa de la Torre
80e7ed90a8 Make get_metrics read just zero-padded dates #206 2017-03-10 13:14:36 +01:00
Javier Goizueta
250d384d06 Geocoder, per user, cofigurable rate limits
WIP, specially the GeocoderConfig part is flaky and ugly
2017-03-09 18:42:48 +01:00
Rafa de la Torre
7e90529a00 Merge pull request #351 from CartoDB/master
Merging back release artifacts from master to development
2017-03-08 16:12:00 +01:00
Rafa de la Torre
cc13a35a58 Update release notes 2017-03-08 15:49:10 +01:00
Rafa de la Torre
ce62b647f8 Update release notes 2017-03-08 15:29:43 +01:00
Rafa de la Torre
c6c4255242 Server 0.22.0 version release artifacts 2017-03-08 15:22:58 +01:00
Rafa de la Torre
87a2e02721 Make more apparent what happens with make release
Instead of getting (deleted and untracked files):

  ```
  $ git status
  # On branch master
  # Your branch is ahead of 'origin/master' by 20 commits.
  #
  # Changes not staged for commit:
  #   (use "git add/rm <file>..." to update what will be committed)
  #   (use "git checkout -- <file>..." to discard changes in working directory)
  #
  #       deleted:    cdb_dataservices_server--0.20.0--0.21.0.sql
  #       deleted:    cdb_dataservices_server--0.21.0--0.20.0.sql
  #       deleted:    cdb_dataservices_server--0.21.0.sql
  #       modified:   cdb_dataservices_server.control
  #
  # Untracked files:
  #   (use "git add <file>..." to include in what will be committed)
  #
  #       cdb_dataservices_server--0.21.0--0.22.0.sql
  #       cdb_dataservices_server--0.22.0--0.21.0.sql
  #       cdb_dataservices_server--0.22.0.sql
  #       old_versions/cdb_dataservices_server--0.20.0--0.21.0.sql
  #       old_versions/cdb_dataservices_server--0.21.0--0.20.0.sql
  #       old_versions/cdb_dataservices_server--0.21.0.sql
  no changes added to commit (use "git add" and/or "git commit -a")
  ```

you'd get something like:

  ```
  $ git status
  # On branch master
  # Your branch is ahead of 'origin/master' by 20 commits.
  #
  # Changes to be committed:
  #   (use "git reset HEAD <file>..." to unstage)
  #
  #       renamed:    cdb_dataservices_server--0.20.0--0.21.0.sql -> old_versions/cdb_dataservices_server--0.20.0--0.21.0.sql
  #       renamed:    cdb_dataservices_server--0.21.0--0.20.0.sql -> old_versions/cdb_dataservices_server--0.21.0--0.20.0.sql
  #       renamed:    cdb_dataservices_server--0.21.0.sql -> old_versions/cdb_dataservices_server--0.21.0.sql
  #
  # Changes not staged for commit:
  #   (use "git add <file>..." to update what will be committed)
  #   (use "git checkout -- <file>..." to discard changes in working directory)
  #
  #       modified:   cdb_dataservices_server.control
  #
  # Untracked files:
  #   (use "git add <file>..." to include in what will be committed)
  #
  #       cdb_dataservices_server--0.21.0--0.22.0.sql
  #       cdb_dataservices_server--0.22.0--0.21.0.sql
  #       cdb_dataservices_server--0.22.0.sql
  ```

which is nicer IMHO.
2017-03-08 13:22:28 +01:00
Rafa de la Torre
fc1e05658e Bump version of python library to 0.14.0 2017-03-08 13:13:19 +01:00
Rafa de la Torre
b8ec3dc306 Merge pull request #342 from CartoDB/remove-mapzen-forcing-layers-equal-address
Remove the search_type if its address from the params sent to Mapzen
2017-03-08 13:07:07 +01:00
Rafa de la Torre
4822739fee Merge pull request #347 from CartoDB/343-config-services
Add configuration for Here and Mapzen services
2017-03-08 13:06:22 +01:00
Rafa de la Torre
ffdb6524da Fix bug: search_type can be None
Found via unit test:

```sh
$ nosetests -x test/
....................................................................................E
======================================================================
ERROR: test_geocode_address_with_valid_params (test.test_mapzengeocoder.MapzenGeocoderTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/requests_mock/mocker.py", line 177, in inner
    return func(*args, **kwargs)
  File "/home/ubuntu/src/dataservices-api/server/lib/python/cartodb_services/test/test_mapzengeocoder.py", line 100, in test_geocode_address_with_valid_params
    country='ESP')
  File "/home/ubuntu/src/dataservices-api/server/lib/python/cartodb_services/cartodb_services/mapzen/qps.py", line 28, in wrapped_function
    return QPSService(retry_timeout=timeout, queries_per_second=qps).call(original_function, *args, **kwargs)
  File "/home/ubuntu/src/dataservices-api/server/lib/python/cartodb_services/cartodb_services/mapzen/qps.py", line 53, in call
    raise e
AttributeError: 'NoneType' object has no attribute 'lower'

----------------------------------------------------------------------
Ran 85 tests in 0.140s

FAILED (errors=1)
```
2017-03-08 10:19:32 +01:00
Rafa de la Torre
82a7477d37 Beautify code 2017-03-08 10:14:37 +01:00
Javier Goizueta
5098b5e9e1 README restructuring
Add some headings for better readability
2017-03-07 17:52:46 +01:00
Javier Goizueta
41c16d8a54 Documentation and NEWS about new configuration parameters 2017-03-07 16:19:35 +01:00
Rafa de la Torre
049c8e8657 Merge branch 'development' into remove-mapzen-forcing-layers-equal-address 2017-03-07 14:56:55 +01:00
Rafa de la Torre
25ba9866ae Small PoC with rratelimit #346 2017-03-07 13:31:06 +01:00
Rafa de la Torre
6a3e17cb9e Fix some typos in README.md #346 2017-03-07 12:33:36 +01:00
Javier Goizueta
6dca3f4e58 Change default arguent value for clarity
It is valie to pass None in service_params arguments, so make it the default.
2017-03-06 19:01:05 +01:00
Javier Goizueta
d01170471e Missing @property 2017-03-06 18:58:00 +01:00
Javier Goizueta
89762c1a7f Use service params configuration in Mapzen services 2017-03-06 15:25:11 +01:00
Javier Goizueta
1081e81047 Add Mapzen service params to configuration 2017-03-06 14:34:23 +01:00
Javier Goizueta
29cdd8099a Add service configuration (URL, etc) for Mapzen Geocoding 2017-03-06 10:20:20 +01:00
Javier Goizueta
c0374f5800 Add service configuration (URL, etc) for Here Routing 2017-03-02 17:55:08 +01:00
Javier Goizueta
677d2acead Add service configuration (URL, etc) for Here Geocoding
See #343
2017-03-02 17:15:14 +01:00
Guido Fioravantti
457858a490 Update README.md 2017-02-28 18:24:19 +01:00
Guido Fioravantti
dde86e985c Update README.md 2017-02-28 12:41:27 +01:00
Mario de Frutos
be39f6e9ef Merge pull request #345 from CartoDB/update-git-protocol
Stop using git:// protocol
2017-02-28 12:25:31 +01:00
Guido Fioravantti
64c24628a0 Stop using git:// protocol
## Context

`https://` protocol [is prefered](https://help.github.com/articles/which-remote-url-should-i-use/#cloning-with-https-urls-recommended), plus using `git://` is messier in terms of permissions. 

Please consider changing your guide.
2017-02-28 12:16:14 +01:00
Mario de Frutos
eb5c7ec5c3 Merge pull request #341 from CartoDB/development
Release client 0.15.0 and server 0.21.0
2017-02-08 15:27:42 +01:00
Mario de Frutos
435a84f294 OBS_GetData functions shall increase the DO quota usage 2017-02-06 17:47:15 +01:00
nygeog
a9e942a48b remove the search_type if its address from the params sent to mapzen
remove the search_type if its address from the params sent to mapzen
2017-02-02 10:23:09 -05:00
Mario de Frutos
061956f250 Remove quota usage for obs_meta functions 2017-02-02 10:59:21 +01:00
Mario de Frutos
2621573d71 Extracted parameters from getmeta and getdata functions tests to fix
problems
2017-02-01 12:12:17 +01:00
Mario de Frutos
d7bb31be9a Client 0.15.0 version release artifacts 2017-02-01 10:52:56 +01:00
Mario de Frutos
3d94d1dfaf Server 0.21.0 version release artifacts 2017-02-01 10:19:32 +01:00
Mario de Frutos
c364c7f5ed Merge pull request #339 from CartoDB/obs-getdata-getmeta-wrappers
Obs_GetData OBS_GetMeta wrappers
2017-02-01 10:05:52 +01:00
Mario de Frutos
b2f9a10035 Change timespan for getboundaryid to 2015 2017-02-01 09:53:35 +01:00
Mario de Frutos
c550a5d4e9 Merge pull request #321 from CartoDB/fix-default-isolines-provider
Change default isolines provider
2017-02-01 09:41:21 +01:00
Mario de Frutos
b4fa0dd4fc Added integration tests for the new DO functions 2017-01-26 17:46:36 +01:00
Mario de Frutos
f0d96541b6 Fixed client tests 2017-01-26 17:00:56 +01:00
John Krauss
8094e79d0b fix some bugs in client test 2017-01-26 12:27:30 +01:00
John Krauss
bfd7df8c8a tmp commit 2017-01-26 12:27:29 +01:00
John Krauss
1f225e0978 fix extraneous newline in expectation 2017-01-26 12:27:29 +01:00
John Krauss
e81f005ce9 adding server tests, interface to generate client sql code 2017-01-26 12:27:29 +01:00
John Krauss
8204bb3451 fix error-causing raise (which obscures real error) 2017-01-26 12:27:29 +01:00
John Krauss
56de523498 add wrappers for getmeta, getdata(geoms) and getdata(ids) 2017-01-26 12:27:29 +01:00
Mario de Frutos
7fe8b6cccc Added CONTRIBUTING.md 2017-01-25 10:47:20 +01:00
piensaenpixel
ec3b99f258 Update quota_information.md 2017-01-11 12:45:59 +01:00
piensaenpixel
1a7e99b2fd Update quota_information.md 2017-01-11 12:43:51 +01:00
Rafa de la Torre
2ad9e508f5 Merge pull request #337 from CartoDB/335-fix-test-date-no-padding-bug
Fix tests: zero-pad months in redis key #335
2017-01-04 11:41:00 +01:00
Rafa de la Torre
a0dd7c7497 Fix tests: zero-pad months in redis key #335 2017-01-04 11:11:27 +01:00
Rafa de la Torre
9cbde7d319 Merge pull request #336 from CartoDB/master
Master
2017-01-03 15:10:00 +01:00
Rafa de la Torre
f7ecb30384 Merge pull request #333 from CartoDB/331-quota-info-doc
Add documentation about the quota information functions
2017-01-03 15:07:07 +01:00
Rafa de la Torre
6ca9e87035 Fix typo in doc: s/exceptio/exception #331 2017-01-03 14:55:48 +01:00
Rafa de la Torre
caa00c63fa Merge remote-tracking branch 'origin/development' into 331-quota-info-doc 2017-01-03 14:54:00 +01:00
csobier
dae8021efe applied copyedits to quote info docs 2017-01-03 08:35:57 -05:00
Javier Goizueta
ebbfae95cf Merge pull request #327 from CartoDB/mapzen_services_use_quotas
Mapzen services use quotas
2016-12-30 08:43:13 +01:00
Javier Goizueta
227c05bf70 Merge branch 'development' into mapzen_services_use_quotas
Bring in client 0.14.1 release
2016-12-30 08:29:54 +01:00
Rafa de la Torre
a800706249 Merge remote-tracking branch 'origin/master' into development 2016-12-29 17:27:56 +01:00
Rafa de la Torre
439f604a04 Merge pull request #334 from CartoDB/fix-cannot-find-geometry
Add cartodb to the search path
2016-12-29 12:43:34 +01:00
Rafa de la Torre
9791a5bada Add cartodb to the search path
See
https://github.com/CartoDB/dataservices-api/issues/324#issuecomment-269614566
2016-12-29 12:11:00 +01:00
Javier Goizueta
07616c468a Documantation fixes 2016-12-29 09:19:52 +01:00
Rafa de la Torre
9700ae966c Remove uneeded math for simplicity's sake 2016-12-28 14:44:48 +01:00
Javier Goizueta
bdf9627586 Fix typo
I needed to fix this; I felt some kitten was being killed somewhere
because of this. And it made baby Jesus cry.
2016-12-27 17:11:39 +01:00
Javier Goizueta
9abb81d0e7 Add documentation about the quota information functions
See #331
2016-12-27 16:51:52 +01:00
Mario de Frutos
80b23c62c3 QPS timeout was badly calculated
timedelta microseconds is just the microseconds part of the timedelta
object not the elapsed time in microseconds.

I've change to use the total_seconds method to get all the elapsed time
in seconds and transform to miliseconds.
2016-12-23 11:40:30 +01:00
Mario de Frutos
23a2de0321 Add mapzen isolines to the quota checker 2016-12-22 17:38:10 +01:00
Javier Goizueta
629555e193 Generate release 0.14.1
This release cantains no actual code changes, only the
use of search_path at the top of the install/migrate scripts
2016-12-21 11:40:55 +01:00
Javier Goizueta
af993fde55 Merge branch 'development'
Bring in the setting of the search_path in the client SQL scripts
2016-12-21 11:16:29 +01:00
Javier Goizueta
4be6c9f31d Merge pull request #330 from CartoDB/324-search-path
Set search path before installing/update the extension
2016-12-21 10:47:08 +01:00
Javier Goizueta
9ee1d045c8 Fix tests 2016-12-21 09:54:08 +01:00
Rafa de la Torre
360b5bd57f Merge remote-tracking branch 'origin/development' into mapzen_services_use_quotas
Solve merge conflict in setup.py (version of python lib).
2016-12-20 18:14:01 +01:00
Javier Goizueta
ed1386d571 Merge branch 'development' 2016-12-20 16:43:42 +01:00
Javier Goizueta
32010669e8 New version of the python lib
To fix bug with period end date; see #322
2016-12-20 16:39:19 +01:00
Javier Goizueta
b0f10d1680 Merge pull request #329 from CartoDB/322-period_end_date
Fix problem with period end dates
2016-12-20 16:33:39 +01:00
Mario de Frutos
38754fec26 Cover refactor mapzen geocoder config with tests 2016-12-20 16:17:42 +01:00
Mario de Frutos
356135672b Sanitize quota get in the refactor part 2016-12-20 16:17:42 +01:00
Mario de Frutos
4d0abf9026 Bump python library version 2016-12-20 16:17:42 +01:00
Mario de Frutos
0672f2752b Improve tests and add more unit tests for the quota functionality 2016-12-20 16:17:41 +01:00
Javier Goizueta
18df3368ef Set search path before installing/update the extension
See #324
2016-12-20 12:57:40 +01:00
Javier Goizueta
b5514aea60 Avoid invalid end of period dates
Fixes #322
2016-12-20 12:48:36 +01:00
Javier Goizueta
53acd4d30e Add tests that reveal end-of-period date problem
See #322
2016-12-20 12:41:54 +01:00
Mario de Frutos
6c71d73498 Use the current quota for mapzen services 2016-12-20 11:52:06 +01:00
Rafa de la Torre
a00fca6d13 Update README.md
Add a bit about versioning stuff
2016-12-16 18:00:22 +01:00
Rafa de la Torre
29caaf9297 Update README.md
Remove misleading paragraph about `requirements.txt` and `setup.py` dependencies. Refer to https://packaging.python.org/requirements/ for an authoritative discussion.
2016-12-16 18:00:22 +01:00
Rafa de la Torre
6e134d1ea6 Update exception_safe.md 2016-12-15 19:10:18 +01:00
Rafa de la Torre
59ae4a5492 Merge pull request #325 from CartoDB/exception-safe-doc
Add Exception-safe documentaion
2016-12-15 19:06:37 +01:00
Javier Goizueta
b3e67afd92 Add internal documentaion about exception-safe functions 2016-12-15 19:03:12 +01:00
Rafa de la Torre
5b8fd70bdd Merge remote-tracking branch 'origin/development' 2016-12-14 17:23:09 +01:00
Rafa de la Torre
15438db59b Client 0.14.0 control and upgrade/downgrade files 2016-12-14 16:52:40 +01:00
Rafa de la Torre
0918f91bfa Merge pull request #323 from CartoDB/314-exception-safe-public-funcs
314 exception safe public funcs
2016-12-14 16:34:09 +01:00
Rafa de la Torre
3c60f3e93b Minor improvement for test #314
Make sure we return an empty record and that the mentioned code is never
reached.
2016-12-14 13:30:30 +01:00
Rafa de la Torre
8692fb12ca Add test case for multi_field #314 2016-12-14 12:57:51 +01:00
Rafa de la Torre
4523b2e04d Add test for multi_row case #314 2016-12-14 12:53:51 +01:00
Rafa de la Torre
5c8dbe91eb Add test for simple interface case #314 2016-12-14 12:39:56 +01:00
Rafa de la Torre
99b76afc33 Some versioning facilities for make release #314 2016-12-14 12:08:26 +01:00
Rafa de la Torre
c97f03b2e3 Add generated file to .gitignore #314 2016-12-14 12:06:51 +01:00
Rafa de la Torre
cd653bc496 Add diagnostics info to rest of cases #314 2016-12-14 10:35:44 +01:00
Rafa de la Torre
610cfaab57 Move exception info vars to the top #314 2016-12-14 10:33:50 +01:00
Rafa de la Torre
58b1713a0d Make the functions private #314 2016-12-14 10:27:43 +01:00
Rafa de la Torre
842be0ba85 Add diagnostics info to warning #314 2016-12-13 19:19:03 +01:00
Javier Goizueta
55a467f2df Merge branch 'development'
merge python 0.12.3 release
2016-12-13 18:13:14 +01:00
Javier Goizueta
4fc90626ab New version of the python lib
New release to change number of http connection retries to 1
2016-12-13 18:03:37 +01:00
Javier Goizueta
16cce3bddc Merge pull request #320 from CartoDB/317-revert-retries
Revert number of isochrone retries to 3
2016-12-13 18:00:48 +01:00
Rafa de la Torre
dbd5911a2a Implement the multi_field case #314 2016-12-13 17:00:55 +01:00
Rafa de la Torre
e53a39875e Implement the multi_row case #314 2016-12-13 16:51:11 +01:00
Rafa de la Torre
4cd72616ca Fix the no multi_row, no multi_field case #314
Fix for the `ERROR:  control reached end of function without RETURN` but
now need to implement for the two other cases.
2016-12-13 16:46:58 +01:00
Rafa de la Torre
fae7889fe3 First take at producing exception-safe functions #314 2016-12-13 16:27:38 +01:00
Javier Goizueta
1f53af65b9 Set number of http connection retries to 1
Change the maximum number of retries for connection to external services to 1.
2016-12-13 11:32:22 +01:00
Javier Goizueta
96a147a242 The default isolines provider should be Mapzen 2016-12-13 10:19:27 +01:00
Javier Goizueta
79fb796180 Fix bug in retries usage; mantain behaviour
The number of retries was being passed as the pool size parameter.
This is corrected but number of retries changed to 1 to maintain previous behaviour.
2016-12-13 10:07:10 +01:00
Rafa de la Torre
0adb5164d7 Update README.md
Add a bit about versioning stuff
2016-12-12 17:54:02 +01:00
Rafa de la Torre
147e0ab567 Update README.md
Remove misleading paragraph about `requirements.txt` and `setup.py` dependencies. Refer to https://packaging.python.org/requirements/ for an authoritative discussion.
2016-12-12 17:42:46 +01:00
Javier Goizueta
2953fda75c Revert num of isochrone retries to 3
See #317
2016-12-12 12:14:10 +01:00
Rafa de la Torre
f716fbb502 Merge pull request #318 from CartoDB/317-timeouts-patch
317 timeouts patch
2016-12-07 16:50:44 +01:00
Rafa de la Torre
98fa248fff New version of the python lib #317 2016-12-07 16:39:28 +01:00
Rafa de la Torre
7c348dee0f Mapzen isochrones: tweak retry params #317 2016-12-07 16:38:47 +01:00
Rafa de la Torre
bdeaadf33f Fix QPS: Compare everything in microseconds #317 2016-12-07 16:37:25 +01:00
127 changed files with 44469 additions and 431 deletions

11
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,11 @@
Contributing
---
The issue tracker is at [github.com/CartoDB/dataservices-api](https://github.com/CartoDB/dataservices-api).
We love pull requests from everyone, see [Contributing to Open Source on GitHub](https://guides.github.com/activities/contributing-to-open-source/#contributing).
## Submitting Contributions
* You will need to sign a Contributor License Agreement (CLA) before making a submission. [Learn more here](https://carto.com/contributions).

55
NEWS.md
View File

@@ -1,3 +1,54 @@
May 26th, 2017
=============
* Version `0.24.2` of the server
* Fixed fallback logic for namedplaces geocoding functions
* Version `0.15.1` of the python library
* Fixed some typos and improve exception messages
* Added a check for the google client credentials in order to improve the error message
May 16th, 2017
=============
* Version `0.24.1` of the server
* Fixed an interface mismatch between DS API and OBS backend, when returning no data. See #366
May 9th, 2017
=============
* Version `0.17.0` of the client and version `0.24.0` of the server
* Fixed some missing return values documented but not present.
* `OBS_GetAvailableGeometries` now returns `geom_type`, `geom_extra` and `geom_tags` in addition to existing values.
* `OBS_GetAvailableTimespans` now returns `timespan_type`, `timespan_extra`, `timespan_tags` in addition to existing values.
March 28th, 2017
================
* Version 0.16.0 of the client, version 0.23.0 of the server and version 0.15.0 of the python library
* Added support for rate-limiting the geocoding services. See #365
March 13th, 2017
================
* Version `0.14.1` of the python library:
* Clean up code that reads from non zero padded date keys #206
March 8th, 2017
===============
* Version 0.22.0 of the server and version 0.14.0 of the python library
* New optional configuration parameters for external services can be provided through `cdb_conf`:
- In `heremaps_conf`, under `geocoder.service`: `json_url`, `connect_timeout`, `read_timeout`, `max_retries`, `gen`
- In `heremaps_conf`, under `isolines.service`: `base_url`, `connect_timeout`, `read_timeout`, `max_retries`, `isoline_path`
- In `mapzen_conf`, under `geocoder.service`: `base_url`, `connect_timeout`, `read_timeout`, `max_retries`
- In `mapzen_conf`, under `routing.service`: `base_url`, `connect_timeout`, `read_timeout`
- In `mapzen_conf`, under `matrix.service`: `one_to_many_url`, `connect_timeout`, `read_timeout`
- In `mapzen_conf`, under `isochrones.service`: `base_url`, `connect_timeout`, `read_timeout`, `max_retries`
* Strictly speaking, version 0.14.0 of the python library is not compatible with 0.13.0, but the changes are made on method signatures with default values that were not used from the PG extension.
* Improvements to the Mapzen geocoder client, that should yield better results overall. See #342
February 2st, 2017
===================
* Version 0.21.0 of the server and version 0.15.0 of the client
* Added functions `OBS_GetData` and `OBS_GetMeta`
* Default isolines provider changed to `mapzen` instead of `heremaps`
November 29st, 2016
===================
* Version 0.20.0 of the server and version 0.12.0 of the python library
@@ -117,7 +168,7 @@ July 25, 2016
===========
* Release server 0.13.3
* Add provider per service
* Default provider in case the provider is not setted
* Default provider in case the provider is not set
* Refactor and improvements in the multiprovider services functions
https://github.com/CartoDB/dataservices-api/releases/tag/0.13.3-server
@@ -433,7 +484,7 @@ https://github.com/CartoDB/dataservices-api/releases/tag/0.3.0-server
Feb 4, 2016:
===========
* Release server 0.2.0
* Logic for the google geocoder so the users with this geocoder setted up can use street level geocoding too
* Logic for the google geocoder so the users with this geocoder set up can use street level geocoding too
* Refactor of the python library in order to reflect the change to a services extension more than only geocoder
https://github.com/CartoDB/dataservices-api/releases/tag/0.2.0-server

285
README.md
View File

@@ -23,78 +23,259 @@ Steps to deploy a new Data Services API version :
### Local install instructions
- install data services geocoder extension
```
git clone git@github.com:CartoDB/data-services.git
cd data-services/geocoder/extension
sudo make install
```
- install observatory extension
```
git clone git@github.com:CartoDB/observatory-extension.git
cd observatory
sudo make install
```
- install server and client extensions
```
# in your workspace root path
git clone https://github.com/CartoDB/dataservices-api.git
cd dataservices-api
cd client && sudo make install
cd -
cd server/extension && sudo make install
```
- install python library
```
cd server/lib/python/cartodb_services && sudo pip install --upgrade .
# in dataservices-api repo root path:
cd server/lib/python/cartodb_services && pip install -r requirements.txt && sudo pip install . --upgrade
```
- install extensions in user database
- Create a database to hold all the server part and a user for it
```sql
CREATE DATABASE dataservices_db ENCODING = 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8';
CREATE USER dataservices_user;
```
- Install needed extensions in `dataservices_db` database
```
create extension cdb_geocoder;
create extension plproxy;
create extension observatory;
create extension cdb_dataservices_server;
create extension cdb_dataservices_client;
psql -U postgres -d dataservices_db -c "BEGIN;CREATE EXTENSION IF NOT EXISTS plproxy; COMMIT" -e
psql -U postgres -d dataservices_db -c "BEGIN;CREATE EXTENSION IF NOT EXISTS cdb_dataservices_server; COMMIT" -e
```
- add configuration for different services in server database
- [optional] install internal geocoder
- Make the extension available in postgres
```
git clone https://github.com/CartoDB/data-services.git
cd data-services/geocoder/extension
sudo make install
```
- Make sure you have `wget` installed because is needed for the next step.
```
# If sentinel is used:
SELECT CDB_Conf_SetConf('redis_metadata_config', '{"sentinel_host": "localhost", "sentinel_port": 26379, "sentinel_master_id": "mymaster", "timeout": 0.1, "redis_db": 5}');
SELECT CDB_Conf_SetConf('redis_metrics_config', '{"sentinel_host": "localhost", "sentinel_port": 26379, "sentinel_master_id": "mymaster", "timeout": 0.1, "redis_db": 5}');
# If sentinel is not used
SELECT CDB_Conf_SetConf('redis_metadata_config', '{"redis_host": "localhost", "redis_port": 6379, "sentinel_master_id": "", "timeout": 0.1, "redis_db": 5}');
SELECT CDB_Conf_SetConf('redis_metrics_config', '{"redis_host": "localhost", "redis_port": 6379, "sentinel_master_id": "", "timeout": 0.1, "redis_db": 5}');
SELECT CDB_Conf_SetConf('heremaps_conf', '{"geocoder": {"app_id": "here_geocoder_app_id", "app_code": "here_geocoder_app_code", "geocoder_cost_per_hit": "1"}, "isolines" : {"app_id": "here_isolines_app_id", "app_code": "here_geocoder_app_code"}}');
SELECT CDB_Conf_SetConf('user_config', '{"is_organization": false, "entity_name": "<YOUR_USERNAME>"}')
SELECT CDB_Conf_SetConf('mapzen_conf', '{"routing": {"api_key": "valhalla_app_key", "monthly_quota": 999999}, "geocoder": {"api_key": "search_app_key", "monthly_quota": 999999}, "matrix": {"api_key": "[your_matrix_key]", "monthly_quota": 1500000}}');
SELECT CDB_Conf_SetConf('logger_conf', '{"geocoder_log_path": "/tmp/geocodings.log", [ "min_log_level": "[debug|info|warning|error]", "rollbar_api_key": "SERVER_SIDE_API_KEY", "log_file_path": "LOG_FILE_PATH"]}');
SELECT CDB_Conf_SetConf('data_observatory_conf', '{"connection": {"whitelist": [], "production": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}}');
- Go to `geocoder` folder and execute the `geocoder_dowload_dumps` script to download the internal geocoder data.
# Environment to decide: rollbar message, which servers for third party use, etc. If not setted uses production by default (current behavior)
SELECT CDB_Conf_SetConf('server_conf', '{"environment": "[development|staging|production]"}')
```
- Once the data is downloaded, execute this command:
```bash
geocoder_restore_dump postgres dataservices_db {DOWNLOADED_DUMPS_FOLDER}/*.sql
```
- configure the user DB:
- Now we have to make available the extension to be installed by postgres. Follow [this](https://github.com/CartoDB/data-services/tree/master/geocoder/extension) instructions.
```sql
-- Point to the dataservices server DB (you can use a specific database for the server or your same user's):
SELECT CDB_Conf_SetConf('geocoder_server_config', '{ "connection_str": "host=localhost port=5432 dbname=<SERVER_DB_NAME> user=postgres"}');
- Now install the extension with:
```
psql -U postgres -d dataservices_db -c "BEGIN;CREATE EXTENSION IF NOT EXISTS cdb_geocoder; COMMIT" -e
```
SELECT CDB_Conf_SetConf('user_config', '{"is_organization": false, "entity_name": "<YOUR_USERNAME>"}');
```
- [optional] install data observatory extension
- Make the extension available in postgresql to be installed
```
git clone https://github.com/CartoDB/observatory-extension.git
cd observatory
sudo make install
```
- This extension needs data, dumps are not available so we're going to use the test fixtures to make it work. Execute:
```
psql -U postgres -d dataservices_db -f src/pg/test/fixtures/load_fixtures.sql
```
- Give permission to execute and select to the `dataservices_user` user:
```
psql -U postgres -d dataservices_db -c "BEGIN;CREATE EXTENSION IF NOT EXISTS observatoru; COMMIT" -e
psql -U postgres -d dataservices_db -c "BEGIN;GRANT SELECT ON ALL TABLES IN SCHEMA cdb_observatory TO dataservices_user; COMMIT" -e
psql -U postgres -d dataservices_db -c "BEGIN;GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_observatory TO dataservices_user; COMMIT" -e
psql -U postgres -d dataservices_db -c "BEGIN;GRANT SELECT ON ALL TABLES IN SCHEMA observatory TO dataservices_user; COMMIT" -e
psql -U postgres -d dataservices_db -c "BEGIN;GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA observatory TO dataservices_user; COMMIT" -e
```
- configure the search path in order to be able to execute the functions without using the schema:
### Server configuration
```
ALTER ROLE "<USER_ROLE>" SET search_path="$user", public, cartodb, cdb_dataservices_client;
```
Configuration for the different services must be stored in the server database using `CDB_Conf_SetConf()`.
#### Redis configuration
If sentinel is used:
```sql
SELECT CDB_Conf_SetConf(
'redis_metadata_config',
'{"sentinel_host": "localhost", "sentinel_port": 26379, "sentinel_master_id": "mymaster", "timeout": 0.1, "redis_db": 5}'
);
SELECT CDB_Conf_SetConf(
'redis_metrics_config',
'{"sentinel_host": "localhost", "sentinel_port": 26379, "sentinel_master_id": "mymaster", "timeout": 0.1, "redis_db": 5}'
);
```
If sentinel is not used:
```sql
SELECT CDB_Conf_SetConf(
'redis_metadata_config',
'{"redis_host": "localhost", "redis_port": 6379, "sentinel_master_id": "", "timeout": 0.1, "redis_db": 5}'
);
SELECT CDB_Conf_SetConf(
'redis_metrics_config',
'{"redis_host": "localhost", "redis_port": 6379, "sentinel_master_id": "", "timeout": 0.1, "redis_db": 5}'
);
```
#### Users/Organizations
```sql
SELECT CDB_Conf_SetConf(
'user_config',
'{"is_organization": false, "entity_name": "<YOUR_USERNAME>"}'
);
```
#### HERE configuration
```sql
SELECT CDB_Conf_SetConf(
'heremaps_conf',
'{"geocoder": {"app_id": "here_geocoder_app_id", "app_code": "here_geocoder_app_code", "geocoder_cost_per_hit": "1"}, "isolines" : {"app_id": "here_isolines_app_id", "app_code": "here_geocoder_app_code"}}'
);
```
#### Mapzen configuration
```sql
SELECT CDB_Conf_SetConf(
'mapzen_conf',
'{"routing": {"api_key": "valhalla_app_key", "monthly_quota": 999999}, "geocoder": {"api_key": "search_app_key", "monthly_quota": 999999}, "matrix": {"api_key": "[your_matrix_key]", "monthly_quota": 1500000}}'
);
```
#### Data Observatory
```sql
SELECT CDB_Conf_SetConf(
'data_observatory_conf',
'{"connection": {"whitelist": [], "production": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api", "staging": "host=localhost port=5432 dbname=dataservices_db user=geocoder_api"}}'
);
```
#### Logger
```sql
SELECT CDB_Conf_SetConf(
'logger_conf',
'{"geocoder_log_path": "/tmp/geocodings.log", [ "min_log_level": "[debug|info|warning|error]", "rollbar_api_key": "SERVER_SIDE_API_KEY", "log_file_path": "LOG_FILE_PATH"]}'
);
```
#### Environment
The execution environment (development/staging/production) affects rollbar messages and other details.
The production environment is used by default.
```sql
SELECT CDB_Conf_SetConf(
'server_conf',
'{"environment": "[development|staging|production]"}'
);
```
### Server optional configuration
External services (Mapzen, Here) can have optional configuration, which is only needed for using non-standard services, such as on-premise installations. We can add the service parameters to an existing configuration like this:
```
# Here geocoder
SELECT CDB_Conf_SetConf(
'heremaps_conf',
jsonb_set(
to_jsonb(CDB_Conf_GetConf('heremaps_conf')),
'{geocoder, service}',
'{"json_url":"https://geocoder.api.here.com/6.2/geocode.json","gen":9,"read_timeout":60,"connect_timeout":10,"max_retries":1}'
)::json
);
# Here isolines
SELECT CDB_Conf_SetConf(
'heremaps_conf',
jsonb_set(
to_jsonb(CDB_Conf_GetConf('heremaps_conf')),
'{isolines, service}',
'{"base_url":"https://isoline.route.api.here.com","isoline_path":"/routing/7.2/calculateisoline.json","read_timeout":60,"connect_timeout":10,"max_retries":1}'
)::json
);
# Mapzen geocoder
SELECT CDB_Conf_SetConf(
'mapzen_conf',
jsonb_set(
to_jsonb(CDB_Conf_GetConf('mapzen_conf')),
'{geocoder, service}',
'{"base_url":"https://search.mapzen.com/v1/search","read_timeout":60,"connect_timeout":10,"max_retries":1}'
)::json
);
# Mapzen isochrones
SELECT CDB_Conf_SetConf(
'mapzen_conf',
jsonb_set(
to_jsonb(CDB_Conf_GetConf('mapzen_conf')),
'{isochrones, service}',
'{"base_url":"https://matrix.mapzen.com/isochrone","read_timeout":60,"connect_timeout":10,"max_retries":1}'
)::json
);
# Mapzen isolines (matrix service)
SELECT CDB_Conf_SetConf(
'mapzen_conf',
jsonb_set(
to_jsonb(CDB_Conf_GetConf('mapzen_conf')),
'{matrix, service}',
'{"base_url":"https://matrix.mapzen.com/one_to_many","read_timeout":60,"connect_timeout":10}'
)::json
);
# Mapzen routing
SELECT CDB_Conf_SetConf(
'mapzen_conf',
jsonb_set(
to_jsonb(CDB_Conf_GetConf('mapzen_conf')),
'{routing, service}',
'{"base_url":"https://valhalla.mapzen.com/route","read_timeout":60,"connect_timeout":10}'
)::json
);
```
### User database configuration
User (client) databases need also some configuration so that the client extension can access the server:
#### Users/Organizations
```sql
SELECT CDB_Conf_SetConf('user_config', '{"is_organization": false, "entity_name": "<YOUR_USERNAME>"}');
```
#### Dataservices server
The `geocoder_server_config` (the name is not accurate for historical reasons) entry points
to the dataservices server DB (you can use a specific database for the server or your same user's):
```sql
SELECT CDB_Conf_SetConf(
'geocoder_server_config',
'{ "connection_str": "host=localhost port=5432 dbname=<SERVER_DB_NAME> user=postgres"}'
);
```
#### Search path
The search path must be configured in order to be able to execute the functions without using the schema:
```sql
ALTER ROLE "<USER_ROLE>" SET search_path="$user", public, cartodb, cdb_dataservices_client;
```

3
client/.gitignore vendored
View File

@@ -2,9 +2,10 @@ results/
regression.diffs
regression.out
20_public_functions.sql
25_exception_safe_private_functions.sql
30_plproxy_functions.sql
90_grant_execute.sql
cdb_geocoder_client--0.0.1.sql
cdb_geocoder_client--0.1.0.sql
cdb_geocoder_client--0.2.0.sql
cdb_geocoder_client--0.3.0.sql
cdb_geocoder_client--0.3.0.sql

View File

@@ -57,9 +57,11 @@ all: $(DATA)
.PHONY: release
release: $(EXTENSION).control $(SOURCES_DATA)
test -n "$(NEW_VERSION)" # $$NEW_VERSION VARIABLE MISSING. Eg. make release NEW_VERSION=0.x.0
mv *.sql old_versions
git mv *.sql old_versions
$(SED) $(REPLACEMENTS) $(EXTENSION).control
git add $(EXTENSION).control
cat $(SOURCES_DATA_DIR)/*.sql > $(EXTENSION)--$(NEW_VERSION).sql
git add $(EXTENSION)--$(NEW_VERSION).sql
$(ERB) version=$(NEW_VERSION) upgrade_downgrade_template.erb > $(EXTENSION)--$(EXTVERSION)--$(NEW_VERSION).sql
$(ERB) version=$(EXTVERSION) upgrade_downgrade_template.erb > $(EXTENSION)--$(NEW_VERSION)--$(EXTVERSION).sql

View File

@@ -0,0 +1,14 @@
--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.17.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;
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE geom_type text;
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE geom_extra jsonb;
ALTER TYPE cdb_dataservices_client.obs_meta_geometry ADD ATTRIBUTE geom_tags jsonb;
ALTER TYPE cdb_dataservices_client.obs_meta_timespan ADD ATTRIBUTE timespan_type text;
ALTER TYPE cdb_dataservices_client.obs_meta_timespan ADD ATTRIBUTE timespan_extra jsonb;
ALTER TYPE cdb_dataservices_client.obs_meta_timespan ADD ATTRIBUTE timespan_tags jsonb;

View File

@@ -0,0 +1,14 @@
--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.16.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;
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE geom_type;
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE geom_extra;
ALTER TYPE cdb_dataservices_client.obs_meta_geometry DROP ATTRIBUTE geom_tags;
ALTER TYPE cdb_dataservices_client.obs_meta_timespan DROP ATTRIBUTE timespan_type;
ALTER TYPE cdb_dataservices_client.obs_meta_timespan DROP ATTRIBUTE timespan_extra;
ALTER TYPE cdb_dataservices_client.obs_meta_timespan DROP ATTRIBUTE timespan_tags;

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
comment = 'CartoDB dataservices client API extension'
default_version = '0.13.0'
default_version = '0.17.0'
requires = 'plproxy, cartodb'
superuser = true
schema = cdb_dataservices_client

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
--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
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_admin0_polygon_exception_safe(country_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_admin1_polygon_exception_safe(admin1_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_admin1_polygon_exception_safe(admin1_name text, country_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_namedplace_point_exception_safe(city_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_namedplace_point_exception_safe(city_name text, country_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_namedplace_point_exception_safe(city_name text, admin1_name text, country_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_postalcode_polygon_exception_safe(postal_code text, country_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_postalcode_point_exception_safe(postal_code text, country_name text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_ipaddress_point_exception_safe(ip_address text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_geocode_street_point_exception_safe(searchtext text, city text, state_province text, country text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_here_geocode_street_point_exception_safe(searchtext text, city text, state_province text, country text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_google_geocode_street_point_exception_safe(searchtext text, city text, state_province text, country text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_mapzen_geocode_street_point_exception_safe(searchtext text, city text, state_province text, country text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_isodistance_exception_safe(source geometry(Geometry, 4326), mode text, range integer[], options text[]);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_isochrone_exception_safe(source geometry(Geometry, 4326), mode text, range integer[], options text[]);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_mapzen_isochrone_exception_safe(source geometry(Geometry, 4326), mode text, range integer[], options text[]);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_mapzen_isodistance_exception_safe(source geometry(Geometry, 4326), mode text, range integer[], options text[]);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_route_point_to_point_exception_safe(origin geometry(Point, 4326), destination geometry(Point, 4326), mode text, options text[], units text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_route_with_waypoints_exception_safe(waypoints geometry(Point, 4326)[], mode text, options text[], units text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_get_demographic_snapshot_exception_safe(geom geometry(Geometry, 4326), time_span text, geometry_level text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_get_segment_snapshot_exception_safe(geom geometry(Geometry, 4326), geometry_level text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getdemographicsnapshot_exception_safe(geom geometry(Geometry, 4326), time_span text, geometry_level text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getsegmentsnapshot_exception_safe(geom geometry(Geometry, 4326), geometry_level text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundary_exception_safe(geom geometry(Geometry, 4326), boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundaryid_exception_safe(geom geometry(Geometry, 4326), boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundarybyid_exception_safe(geometry_id text, boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundariesbygeometry_exception_safe(geom geometry(Geometry, 4326), boundary_id text, time_span text, overlap_type text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getboundariesbypointandradius_exception_safe(geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text, overlap_type text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getpointsbygeometry_exception_safe(geom geometry(Geometry, 4326), boundary_id text, time_span text, overlap_type text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getpointsbypointandradius_exception_safe(geom geometry(Geometry, 4326), radius numeric, boundary_id text, time_span text, overlap_type text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getmeasure_exception_safe(geom Geometry, measure_id text, normalize text, boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getmeasurebyid_exception_safe(geom_ref text, measure_id text, boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getcategory_exception_safe(geom Geometry, category_id text, boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getuscensusmeasure_exception_safe(geom Geometry, name text, normalize text, boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getuscensuscategory_exception_safe(geom Geometry, name text, boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getpopulation_exception_safe(geom Geometry, normalize text, boundary_id text, time_span text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_search_exception_safe(search_term text, relevant_boundary text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getavailableboundaries_exception_safe(geom Geometry, timespan text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_dumpversion_exception_safe();
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getavailablenumerators_exception_safe(bounds geometry(Geometry, 4326), filter_tags text[], denom_id text, geom_id text, timespan text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getavailabledenominators_exception_safe(bounds geometry(Geometry, 4326), filter_tags text[], numer_id text, geom_id text, timespan text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getavailablegeometries_exception_safe(bounds geometry(Geometry, 4326), filter_tags text[], numer_id text, denom_id text, timespan text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getavailabletimespans_exception_safe(bounds geometry(Geometry, 4326), filter_tags text[], numer_id text, denom_id text, geom_id text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_legacybuildermetadata_exception_safe(aggregate_type text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_quota_info_exception_safe();
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_enough_quota_exception_safe(service TEXT, input_size NUMERIC);

View File

@@ -0,0 +1,9 @@
--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.14.1'" 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;
-- This release introduces no changes other than the use of
-- search path in the install and migration scripts

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
--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.14.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;
-- This release introduces no changes other than the use of
-- search path in the install and migration scripts

View File

@@ -0,0 +1,204 @@
--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.15.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.obs_getdata (geomvals geomval[] ,params json ,merge boolean DEFAULT true)
RETURNS TABLE(id int, data json) 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._obs_getdata(username, orgname, geomvals, params, merge);
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getdata (geomrefs text[] ,params json)
RETURNS TABLE(id text, data json) 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._obs_getdata(username, orgname, geomrefs, params);
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_client.obs_getmeta (geom_ref Geometry(Geometry, 4326) ,params json ,max_timespan_rank integer DEFAULT NULL ,max_score_rank integer DEFAULT NULL ,target_geoms integer DEFAULT NULL)
RETURNS json AS $$
DECLARE
ret json;
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_getmeta(username, orgname, geom_ref, params, max_timespan_rank, max_score_rank, target_geoms) INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getdata_exception_safe (geomvals geomval[] ,params json ,merge boolean DEFAULT true)
RETURNS TABLE(id int, data json) 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._obs_getdata(username, orgname, geomvals, params, merge);
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;
--
-- Exception-safe private DataServices API function
--
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getdata_exception_safe (geomrefs text[] ,params json)
RETURNS TABLE(id text, data json) 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._obs_getdata(username, orgname, geomrefs, params);
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;
--
-- Exception-safe private DataServices API function
--
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getmeta_exception_safe (geom_ref Geometry(Geometry, 4326) ,params json ,max_timespan_rank integer DEFAULT NULL ,max_score_rank integer DEFAULT NULL ,target_geoms integer DEFAULT NULL)
RETURNS json AS $$
DECLARE
ret json;
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._obs_getmeta(username, orgname, geom_ref, params, max_timespan_rank, max_score_rank, target_geoms) 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;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getdata (username text, organization_name text, geomvals geomval[], params json, merge boolean DEFAULT true)
RETURNS TABLE(id int, data json) AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT * FROM cdb_dataservices_server.obs_getdata (username, organization_name, geomvals, params, merge);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getdata (username text, organization_name text, geomrefs text[], params json)
RETURNS TABLE(id text, data json) AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT * FROM cdb_dataservices_server.obs_getdata (username, organization_name, geomrefs, params);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._obs_getmeta (username text, organization_name text, geom_ref Geometry(Geometry, 4326), params json, max_timespan_rank integer DEFAULT NULL, max_score_rank integer DEFAULT NULL, target_geoms integer DEFAULT NULL)
RETURNS json AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT cdb_dataservices_server.obs_getmeta (username, organization_name, geom_ref, params, max_timespan_rank, max_score_rank, target_geoms);
$$ LANGUAGE plproxy;

File diff suppressed because it is too large Load Diff

View File

@@ -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_client UPDATE TO '0.14.1'" 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._obs_getdata (text, text, geomval[], json, boolean);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getdata (text, text, text[], json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getmeta (text, text, Geometry(Geometry, 4326), json, integer, integer, integer);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getdata_exception_safe (geomval[], json, boolean);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getdata_exception_safe (text[], json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._obs_getmeta_exception_safe (Geometry(Geometry, 4326), json , integer, integer, integer);
DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getdata (geomval[], json, boolean);
DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getdata (text[], json);
DROP FUNCTION IF EXISTS cdb_dataservices_client.obs_getmeta (Geometry(Geometry, 4326), json, integer, integer, integer);

View File

@@ -0,0 +1,277 @@
--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.16.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;
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_service_get_rate_limit (service text)
RETURNS json AS $$
DECLARE
ret json;
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_service_get_rate_limit(username, orgname, service) INTO ret; RETURN ret;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
--
-- Public dataservices API function
--
-- These are the only ones with permissions to publicuser role
-- and should also be the only ones with SECURITY DEFINER
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_service_set_user_rate_limit (username text ,orgname text ,service text ,rate_limit json)
RETURNS void AS $$
DECLARE
BEGIN
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
RAISE EXCEPTION 'The api_key must be provided';
END IF;
-- 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;
PERFORM cdb_dataservices_client._cdb_service_set_user_rate_limit(username, orgname, service, rate_limit);
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
--
-- Public dataservices API function
--
-- These are the only ones with permissions to publicuser role
-- and should also be the only ones with SECURITY DEFINER
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_service_set_org_rate_limit (username text ,orgname text ,service text ,rate_limit json)
RETURNS void AS $$
DECLARE
BEGIN
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
RAISE EXCEPTION 'The api_key must be provided';
END IF;
-- 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;
PERFORM cdb_dataservices_client._cdb_service_set_org_rate_limit(username, orgname, service, rate_limit);
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
--
-- Public dataservices API function
--
-- These are the only ones with permissions to publicuser role
-- and should also be the only ones with SECURITY DEFINER
CREATE OR REPLACE FUNCTION cdb_dataservices_client.cdb_service_set_server_rate_limit (username text ,orgname text ,service text ,rate_limit json)
RETURNS void AS $$
DECLARE
BEGIN
IF session_user = 'publicuser' OR session_user ~ 'cartodb_publicuser_*' THEN
RAISE EXCEPTION 'The api_key must be provided';
END IF;
-- 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;
PERFORM cdb_dataservices_client._cdb_service_set_server_rate_limit(username, orgname, service, rate_limit);
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
--
-- Exception-safe private DataServices API function
--
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_get_rate_limit_exception_safe (service text)
RETURNS json AS $$
DECLARE
ret json;
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_service_get_rate_limit(username, orgname, service) 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;
--
-- Exception-safe private DataServices API function
--
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_set_user_rate_limit_exception_safe (username text ,orgname text ,service text ,rate_limit json)
RETURNS void AS $$
DECLARE
_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;
-- 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
PERFORM cdb_dataservices_client._cdb_service_set_user_rate_limit(username, orgname, service, rate_limit);
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;
--
-- Exception-safe private DataServices API function
--
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_set_org_rate_limit_exception_safe (username text ,orgname text ,service text ,rate_limit json)
RETURNS void AS $$
DECLARE
_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;
-- 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
PERFORM cdb_dataservices_client._cdb_service_set_org_rate_limit(username, orgname, service, rate_limit);
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;
--
-- Exception-safe private DataServices API function
--
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_set_server_rate_limit_exception_safe (username text ,orgname text ,service text ,rate_limit json)
RETURNS void AS $$
DECLARE
_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;
-- 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
PERFORM cdb_dataservices_client._cdb_service_set_server_rate_limit(username, orgname, service, rate_limit);
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;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_get_rate_limit (username text, orgname text, service text)
RETURNS json AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT cdb_dataservices_server.cdb_service_get_rate_limit (username, orgname, service);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_set_user_rate_limit (username text, orgname text, service text, rate_limit json)
RETURNS void AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT cdb_dataservices_server.cdb_service_set_user_rate_limit (username, orgname, service, rate_limit);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_set_org_rate_limit (username text, orgname text, service text, rate_limit json)
RETURNS void AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT cdb_dataservices_server.cdb_service_set_org_rate_limit (username, orgname, service, rate_limit);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_client._cdb_service_set_server_rate_limit (username text, orgname text, service text, rate_limit json)
RETURNS void AS $$
CONNECT cdb_dataservices_client._server_conn_str();
SELECT cdb_dataservices_server.cdb_service_set_server_rate_limit (username, orgname, service, rate_limit);
$$ LANGUAGE plproxy;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client.cdb_service_set_user_rate_limit (username text ,orgname text ,service text ,rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client.cdb_service_set_org_rate_limit (username text ,orgname text ,service text ,rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client.cdb_service_set_server_rate_limit (username text ,orgname text ,service text ,rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_set_user_rate_limit_exception_safe (username text ,orgname text ,service text ,rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_set_org_rate_limit_exception_safe (username text ,orgname text ,service text ,rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_set_server_rate_limit_exception_safe (username text ,orgname text ,service text ,rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_get_rate_limit (username text, orgname text, service text) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_set_user_rate_limit (username text, orgname text, service text, rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_set_org_rate_limit (username text, orgname text, service text, rate_limit json) FROM PUBLIC, publicuser;
REVOKE EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_set_server_rate_limit (username text, orgname text, service text, rate_limit json) FROM PUBLIC, publicuser;
GRANT EXECUTE ON FUNCTION cdb_dataservices_client.cdb_service_get_rate_limit(service text) TO publicuser;
GRANT EXECUTE ON FUNCTION cdb_dataservices_client._cdb_service_get_rate_limit_exception_safe(service text ) TO publicuser;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
--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.15.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;
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_service_get_rate_limit (text);
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_service_set_user_rate_limit (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_service_set_org_rate_limit (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client.cdb_service_set_server_rate_limit (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_get_rate_limit_exception_safe (text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_set_user_rate_limit_exception_safe (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_set_org_rate_limit_exception_safe (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_set_server_rate_limit_exception_safe (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_get_rate_limit (text, text, text);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_set_user_rate_limit (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_set_org_rate_limit (text, text, text, json);
DROP FUNCTION IF EXISTS cdb_dataservices_client._cdb_service_set_server_rate_limit (text, text, text, json);

File diff suppressed because it is too large Load Diff

View File

@@ -261,6 +261,38 @@
- { name: boundary_id, type: text}
- { name: time_span, type: text, default: 'NULL'}
- name: obs_getdata
return_type: TABLE(id int, data json)
multi_row: true
multi_field: true
table_fields:
- { name: id, type: integer }
- { name: data, type: json }
params:
- { name: geomvals, type: "geomval[]" }
- { name: params, type: json }
- { name: merge, type: boolean, default: true }
- name: obs_getdata
return_type: TABLE(id text, data json)
multi_row: true
multi_field: true
table_fields:
- { name: id, type: text }
- { name: data, type: json }
params:
- { name: geomrefs, type: "text[]" }
- { name: params, type: json }
- name: obs_getmeta
return_type: json
params:
- { name: geom_ref, type: "Geometry(Geometry, 4326)" }
- { name: params, type: json }
- { name: max_timespan_rank, type: integer, default: 'NULL' }
- { name: max_score_rank, type: integer, default: 'NULL' }
- { name: target_geoms, type: integer, default: 'NULL' }
- name: obs_getcategory
return_type: text
params:
@@ -388,4 +420,30 @@
return_type: BOOLEAN
params:
- { name: service, type: TEXT }
- { name: input_size, type: NUMERIC }
- { name: input_size, type: NUMERIC }
- name: cdb_service_get_rate_limit
return_type: json
params:
- { name: service, type: "text" }
- name: cdb_service_set_user_rate_limit
superuser: true
return_type: void
params:
- { name: service, type: "text" }
- { name: rate_limit, type: json }
- name: cdb_service_set_org_rate_limit
superuser: true
return_type: void
params:
- { name: service, type: "text" }
- { name: rate_limit, type: json }
- name: cdb_service_set_server_rate_limit
superuser: true
return_type: void
params:
- { name: service, type: "text" }
- { name: rate_limit, type: json }

View File

@@ -17,7 +17,7 @@ class SqlTemplateRenderer
end
def render
ERB.new(@template).result(binding)
ERB.new(@template, _save_level=nil, _trim_mode='-').result(binding)
end
def name
@@ -44,16 +44,29 @@ class SqlTemplateRenderer
@function_signature['geocoder_config_key']
end
def params
@function_signature['params'].reject(&:empty?).map { |p| "#{p['name']}"}
def parameters_info(with_user_org)
parameters = []
if with_user_org
parameters << { 'name' => 'username', 'type' => 'text' }
parameters << { 'name' => 'orgname', 'type' => 'text' }
end
parameters + @function_signature['params'].reject(&:empty?)
end
def params_with_type
@function_signature['params'].reject(&:empty?).map { |p| "#{p['name']} #{p['type']}" }
def user_org_declaration()
"username text;\n orgname text;" unless superuser_function?
end
def params_with_type_and_default
parameters = @function_signature['params'].reject(&:empty?).map do |p|
def params(with_user_org = superuser_function?)
parameters_info(with_user_org).map { |p| p['name'].to_s }
end
def params_with_type(with_user_org = superuser_function?)
parameters_info(with_user_org).map { |p| "#{p['name']} #{p['type']}" }
end
def params_with_type_and_default(with_user_org = superuser_function?)
parameters = parameters_info(with_user_org).map do |p|
if not p['default'].nil?
"#{p['name']} #{p['type']} DEFAULT #{p['default']}"
else
@@ -62,6 +75,49 @@ class SqlTemplateRenderer
end
return parameters
end
def superuser_function?
!!@function_signature['superuser']
end
def void_return_type?
return_type.downcase == 'void'
end
def return_declaration
"ret #{return_type};" unless void_return_type? || multi_row
end
def return_statement(&block)
if block
erb_out = block.binding.eval('_erbout')
if multi_row
erb_out << 'RETURN QUERY SELECT * FROM '
elsif multi_field
erb_out << 'SELECT * FROM '
elsif void_return_type?
erb_out << 'PERFORM '
else
erb_out << 'SELECT '
end
yield
if multi_row || void_return_type?
erb_out << ';'
else
erb_out << ' INTO ret;'
end
if !multi_row && !void_return_type?
erb_out << ' RETURN ret;'
end
else
if !multi_row && !void_return_type?
' RETURN ret;'
end
end
end
end

View File

@@ -7,27 +7,18 @@
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 %>
username text;
orgname text;
<%= return_declaration if not multi_row %>
<%= user_org_declaration %>
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 <%= DATASERVICES_CLIENT_SCHEMA %>._cdb_entity_config() AS (u text, o text);
<% unless superuser_function? -%>SELECT u, o INTO username, orgname FROM <%= DATASERVICES_CLIENT_SCHEMA %>._cdb_entity_config() AS (u text, o text);<% end %>
-- 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;
<% if multi_row %>
RETURN QUERY
SELECT * FROM <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= ['username', 'orgname'].concat(params).join(', ') %>);
<% elsif multi_field %>
SELECT * FROM <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= ['username', 'orgname'].concat(params).join(', ') %>) INTO ret;
RETURN ret;
<% else %>
SELECT <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= ['username', 'orgname'].concat(params).join(', ') %>) INTO ret;
RETURN ret;
<% end %>
<% return_statement do %><%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= params(_with_user_org=true).join(', ') %>)<% end %>
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;

View File

@@ -0,0 +1,35 @@
--
-- Exception-safe private DataServices API function
--
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>_exception_safe (<%= params_with_type_and_default.join(' ,') %>)
RETURNS <%= return_type %> AS $$
DECLARE
<%= return_declaration %>
<%= user_org_declaration %>
_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;
<% unless superuser_function? -%>SELECT u, o INTO username, orgname FROM <%= DATASERVICES_CLIENT_SCHEMA %>._cdb_entity_config() AS (u text, o text);<% end %>
-- 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_statement do %><%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>(<%= params(_with_user_org=true).join(', ') %>)<% end %>
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_statement %>
END;
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;

View File

@@ -1,9 +1,9 @@
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %> (<%= ['username text', 'organization_name text'].concat(params_with_type_and_default).join(', ') %>)
CREATE OR REPLACE FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %> (<%= params_with_type_and_default(_with_user_org=true).join(', ') %>)
RETURNS <%= return_type %> AS $$
CONNECT <%= DATASERVICES_CLIENT_SCHEMA %>._server_conn_str();
<% if multi_field %>
SELECT * FROM <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (<%= ['username', 'organization_name'].concat(params).join(', ') %>);
SELECT * FROM <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (<%= params(_with_user_org=true).join(', ') %>);
<% else %>
SELECT <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (<%= ['username', 'organization_name'].concat(params).join(', ') %>);
SELECT <%= DATASERVICES_SERVER_SCHEMA %>.<%= name %> (<%= params(_with_user_org=true).join(', ') %>);
<% end %>
$$ LANGUAGE plproxy;

View File

@@ -1 +1,4 @@
<% unless superuser_function? %>
GRANT EXECUTE ON FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>.<%= name %>(<%= params_with_type.join(', ') %>) TO publicuser;
GRANT EXECUTE ON FUNCTION <%= DATASERVICES_CLIENT_SCHEMA %>._<%= name %>_exception_safe(<%= params_with_type.join(', ') %> ) TO publicuser;
<% end %>

View File

@@ -1,3 +1,6 @@
--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 "CREATE EXTENSION cdb_dataservices_client" 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;

View File

@@ -15,9 +15,9 @@ 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, score numeric, numtiles bigint, notnull_percent numeric, numgeoms numeric, percentfill numeric, estnumgeoms numeric, meanmediansize numeric);
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, geom_type text, geom_extra jsonb, geom_tags jsonb);
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);
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, timespan_type text, timespan_extra jsonb, timespan_tags jsonb);
-- For quotas and services configuration

View File

@@ -0,0 +1,56 @@
SET client_min_messages TO warning;
SET search_path TO public,cartodb,cdb_dataservices_client;
-- Mock the server functions to raise exceptions
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 $$
BEGIN
RAISE EXCEPTION 'Not enough quota or any other exception whatsoever.';
RETURN NULL;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isodistance(username text, orgname text, source geometry, mode text, range integer[], options text[] DEFAULT ARRAY[]::text[])
RETURNS SETOF isoline AS $$
BEGIN
RAISE EXCEPTION 'Not enough quota or any other exception whatsoever.';
END;
$$ LANGUAGE 'plpgsql';
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_client.simple_route AS $$
DECLARE
ret cdb_dataservices_client.simple_route;
BEGIN
RAISE EXCEPTION 'Not enough quota or any other exception whatsoever.';
-- This code shall never be reached
SELECT NULL, 5.33, 100 INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql';
-- Use regular user role
SET ROLE test_regular_user;
-- Exercise the exception safe and the proxied functions
SELECT _cdb_geocode_street_point_exception_safe('One street, 1');
WARNING: cdb_dataservices_client._cdb_geocode_street_point(6): [contrib_regression] REMOTE ERROR: Not enough quota or any other exception whatsoever.
DETAIL: SQL statement "SELECT cdb_dataservices_client._cdb_geocode_street_point(username, orgname, searchtext, city, state_province, country)"
PL/pgSQL function _cdb_geocode_street_point_exception_safe(text,text,text,text) line 21 at SQL statement
_cdb_geocode_street_point_exception_safe
------------------------------------------
(1 row)
SELECT * FROM _cdb_isodistance_exception_safe('POINT(-3.70568 40.42028)'::geometry, 'walk', ARRAY[300]::integer[]);
WARNING: cdb_dataservices_client._cdb_isodistance(6): [contrib_regression] REMOTE ERROR: Not enough quota or any other exception whatsoever.
DETAIL: PL/pgSQL function _cdb_isodistance_exception_safe(geometry,text,integer[],text[]) line 21 at RETURN QUERY
center | data_range | the_geom
--------+------------+----------
(0 rows)
SELECT * FROM _cdb_route_point_to_point_exception_safe('POINT(-3.70237112 40.41706163)'::geometry,'POINT(-3.69909883 40.41236875)'::geometry, 'car', ARRAY['mode_type=shortest']::text[]);
WARNING: cdb_dataservices_client._cdb_route_point_to_point(7): [contrib_regression] REMOTE ERROR: Not enough quota or any other exception whatsoever.
DETAIL: SQL statement "SELECT * FROM cdb_dataservices_client._cdb_route_point_to_point(username, orgname, origin, destination, mode, options, units)"
PL/pgSQL function _cdb_route_point_to_point_exception_safe(geometry,geometry,text,text[],text) line 21 at SQL statement
shape | length | duration
-------+--------+----------
| |
(1 row)

View File

@@ -173,6 +173,27 @@ BEGIN
RETURN QUERY SELECT '0106000020E61000000100000001030000000100000019000000DD96C805677C52C0CBD8D0CDFE5A44407A19C5724B7C52C033BF9A03045B4440FF59F3E32F7C52C0CB290131095B4440247EC51A2E7C52C0548B8862F25A44401FF5D72B2C7C52C0CB811E6ADB5A444049F086342A7C52C09CC3B5DAC35A444044679945287C52C01F680586AC5A444012D90759167C52C09430D3F6AF5A44405698BED7107C52C04759BF99985A4440DEE522BE137C52C00664AF777F5A4440F92EA52E197C52C09BA73AE4665A4440C558A65F227C52C0D80DDB16655A4440373465A71F7C52C065A71FD4455A44404AED45B41D7C52C0785DBF60375A444083A3E4D5397C52C09946938B315A4440F2B4FCC0557C52C01FF5D72B2C5A444026C286A7577C52C02BDD5D67435A44405BCF108E597C52C0C651B9895A5A444030D461855B7C52C0D1393FC5715A444065E1EB6B5D7C52C078280AF4895A44403AE63C635F7C52C07D1F0E12A25A44403F6F2A52617C52C05983F755B95A44405C3AE63C637C52C04852D2C3D05A444049810530657C52C0FAEE5696E85A4440DD96C805677C52C0CBD8D0CDFE5A4440'::geometry as the_geom, '36047049300'::text as geom_refs;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getmeta(username text, orgname text, geom geometry(Geometry, 4326), params JSON, max_timespan_rank INTEGER DEFAULT NULL, max_score_rank INTEGER DEFAULT NULL, target_geoms INTEGER DEFAULT NULL)
RETURNS JSON AS $$
BEGIN
RAISE NOTICE 'cdb_dataservices_server.obs_getmeta invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, params, max_timespan_rank, max_score_rank, target_geoms;
RETURN '[{"id" : 1, "numer_id" : "us.census.acs.B01003001", "timespan_rank" : 1, "score_rank" : 1, "score" : 19.9580760018781868330120152747832081562684, "numer_aggregate" : "sum", "numer_colname" : "total_pop", "numer_geomref_colname" : "geoid", "numer_tablename" : "obs_209d3476ef8eaaa18e597cabcf1bdb627f37aa5e", "numer_type" : "Numeric", "denom_aggregate" : null, "denom_colname" : null, "denom_geomref_colname" : null, "denom_tablename" : null, "denom_type" : null, "geom_colname" : "the_geom", "geom_geomref_colname" : "geoid", "geom_tablename" : "obs_78fb6c1d6ff6505225175922c2c389ce48d7632c", "geom_type" : "Geometry", "geom_timespan" : "2015", "numer_timespan" : "2011 - 2015", "numer_name" : "Total Population", "denom_name" : null, "geom_name" : "US Census Block Groups", "normalization" : null, "denom_id" : null, "geom_id" : "us.census.tiger.block_group"}]'::JSON;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getdata(username text, orgname text, geomrefs text[], params json)
RETURNS TABLE (id TEXT, data JSON) AS $$
BEGIN
RAISE NOTICE 'cdb_dataservices_server.obs_getdata invoked with params (%, %, %, %)', username, orgname, geomrefs, params;
RETURN QUERY SELECT '36047'::TEXT AS id, '[{"value" : 10349.1547875017}]'::JSON AS data;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getdata(username text, orgname text, geomvals geomval[], params json, merge boolean default true)
RETURNS TABLE (id TEXT, data JSON) AS $$
BEGIN
RAISE NOTICE 'cdb_dataservices_server.obs_getdata invoked with params (%, %, %, %, %)', username, orgname, geomvals, params, merge;
RETURN QUERY SELECT '36047'::TEXT AS id, '[{"value" : 10349.1547875017}]'::JSON AS data;
END;
$$ LANGUAGE 'plpgsql';
-- Exercise the public and the proxied function
SELECT obs_get_demographic_snapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '2009 - 2013'::text, '"us.census.tiger".block_group'::text);
NOTICE: cdb_dataservices_client._obs_get_demographic_snapshot(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_get_demographic_snapshot invoked with params (test_user, <NULL>, 0101000020E6100000548B8862F27B52C0DDD1FF722D5A4440, 2009 - 2013, "us.census.tiger".block_group)
@@ -337,3 +358,34 @@ CONTEXT: PL/pgSQL function obs_getavailableboundaries(geometry,text) line 16 at
(us.census.tiger.place,"Incorporated places are those reported to the Census Bureau as legally in existence as of January 1, 2010, as reported in the latest Boundary and Annexation Survey (BAS), under the laws of their respective states.",2014,obs_7c9493c41fa8f4bd178ab993ea3d5891c1977667)
(1 row)
SELECT obs_getmeta(ST_SetSRID(ST_Point(-73.9, 40.7), 4326), '[{"numer_id": "us.census.acs.B01003001"}]', 1, 1, 1000);
NOTICE: cdb_dataservices_client._obs_getmeta(7): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getmeta invoked with params (test_user, <NULL>, 0101000020E61000009A999999997952C09A99999999594440, [{"numer_id": "us.census.acs.B01003001"}], 1, 1, 1000)
CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getmeta(username, orgname, geom_ref, params, max_timespan_rank, max_score_rank, target_geoms)"
PL/pgSQL function obs_getmeta(geometry,json,integer,integer,integer) line 16 at SQL statement
obs_getmeta
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"id" : 1, "numer_id" : "us.census.acs.B01003001", "timespan_rank" : 1, "score_rank" : 1, "score" : 19.9580760018781868330120152747832081562684, "numer_aggregate" : "sum", "numer_colname" : "total_pop", "numer_geomref_colname" : "geoid", "numer_tablename" : "obs_209d3476ef8eaaa18e597cabcf1bdb627f37aa5e", "numer_type" : "Numeric", "denom_aggregate" : null, "denom_colname" : null, "denom_geomref_colname" : null, "denom_tablename" : null, "denom_type" : null, "geom_colname" : "the_geom", "geom_geomref_colname" : "geoid", "geom_tablename" : "obs_78fb6c1d6ff6505225175922c2c389ce48d7632c", "geom_type" : "Geometry", "geom_timespan" : "2015", "numer_timespan" : "2011 - 2015", "numer_name" : "Total Population", "denom_name" : null, "geom_name" : "US Census Block Groups", "normalization" : null, "denom_id" : null, "geom_id" : "us.census.tiger.block_group"}]
(1 row)
SELECT obs_getdata(ARRAY['36047'], obs_getmeta(st_setsrid(st_point(-73.9, 40.7), 4326), '[{"numer_id": "us.census.acs.B01003001", "geom_id": "us.census.tiger.county"}]', 1, 1, 1000));
NOTICE: cdb_dataservices_client._obs_getmeta(7): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getmeta invoked with params (test_user, <NULL>, 0101000020E61000009A999999997952C09A99999999594440, [{"numer_id": "us.census.acs.B01003001", "geom_id": "us.census.tiger.county"}], 1, 1, 1000)
CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getmeta(username, orgname, geom_ref, params, max_timespan_rank, max_score_rank, target_geoms)"
PL/pgSQL function obs_getmeta(geometry,json,integer,integer,integer) line 16 at SQL statement
NOTICE: cdb_dataservices_client._obs_getdata(4): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getdata invoked with params (test_user, <NULL>, {36047}, [{"id" : 1, "numer_id" : "us.census.acs.B01003001", "timespan_rank" : 1, "score_rank" : 1, "score" : 19.9580760018781868330120152747832081562684, "numer_aggregate" : "sum", "numer_colname" : "total_pop", "numer_geomref_colname" : "geoid", "numer_tablename" : "obs_209d3476ef8eaaa18e597cabcf1bdb627f37aa5e", "numer_type" : "Numeric", "denom_aggregate" : null, "denom_colname" : null, "denom_geomref_colname" : null, "denom_tablename" : null, "denom_type" : null, "geom_colname" : "the_geom", "geom_geomref_colname" : "geoid", "geom_tablename" : "obs_78fb6c1d6ff6505225175922c2c389ce48d7632c", "geom_type" : "Geometry", "geom_timespan" : "2015", "numer_timespan" : "2011 - 2015", "numer_name" : "Total Population", "denom_name" : null, "geom_name" : "US Census Block Groups", "normalization" : null, "denom_id" : null, "geom_id" : "us.census.tiger.block_group"}])
CONTEXT: PL/pgSQL function obs_getdata(text[],json) line 16 at RETURN QUERY
obs_getdata
--------------------------------------------
(36047,"[{""value"" : 10349.1547875017}]")
(1 row)
SELECT obs_getdata(ARRAY[(ST_SetSRID(ST_Point(-73.9, 40.7), 4326), 1)::geomval], obs_getmeta(st_setsrid(st_point(-73.9, 40.7), 4326), '[{"numer_id": "us.census.acs.B01003001"}]'));
NOTICE: cdb_dataservices_client._obs_getmeta(7): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getmeta invoked with params (test_user, <NULL>, 0101000020E61000009A999999997952C09A99999999594440, [{"numer_id": "us.census.acs.B01003001"}], <NULL>, <NULL>, <NULL>)
CONTEXT: SQL statement "SELECT cdb_dataservices_client._obs_getmeta(username, orgname, geom_ref, params, max_timespan_rank, max_score_rank, target_geoms)"
PL/pgSQL function obs_getmeta(geometry,json,integer,integer,integer) line 16 at SQL statement
NOTICE: cdb_dataservices_client._obs_getdata(5): [contrib_regression] REMOTE NOTICE: cdb_dataservices_server.obs_getdata invoked with params (test_user, <NULL>, {"(0101000020E61000009A999999997952C09A99999999594440,1)"}, [{"id" : 1, "numer_id" : "us.census.acs.B01003001", "timespan_rank" : 1, "score_rank" : 1, "score" : 19.9580760018781868330120152747832081562684, "numer_aggregate" : "sum", "numer_colname" : "total_pop", "numer_geomref_colname" : "geoid", "numer_tablename" : "obs_209d3476ef8eaaa18e597cabcf1bdb627f37aa5e", "numer_type" : "Numeric", "denom_aggregate" : null, "denom_colname" : null, "denom_geomref_colname" : null, "denom_tablename" : null, "denom_type" : null, "geom_colname" : "the_geom", "geom_geomref_colname" : "geoid", "geom_tablename" : "obs_78fb6c1d6ff6505225175922c2c389ce48d7632c", "geom_type" : "Geometry", "geom_timespan" : "2015", "numer_timespan" : "2011 - 2015", "numer_name" : "Total Population", "denom_name" : null, "geom_name" : "US Census Block Groups", "normalization" : null, "denom_id" : null, "geom_id" : "us.census.tiger.block_group"}], t)
CONTEXT: PL/pgSQL function obs_getdata(geomval[],json,boolean) line 16 at RETURN QUERY
obs_getdata
--------------------------------------------
(36047,"[{""value"" : 10349.1547875017}]")
(1 row)

View File

@@ -0,0 +1,41 @@
SET client_min_messages TO warning;
SET search_path TO public,cartodb,cdb_dataservices_client;
-- Mock the server functions to raise exceptions
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 $$
BEGIN
RAISE EXCEPTION 'Not enough quota or any other exception whatsoever.';
RETURN NULL;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_isodistance(username text, orgname text, source geometry, mode text, range integer[], options text[] DEFAULT ARRAY[]::text[])
RETURNS SETOF isoline AS $$
BEGIN
RAISE EXCEPTION 'Not enough quota or any other exception whatsoever.';
END;
$$ LANGUAGE 'plpgsql';
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_client.simple_route AS $$
DECLARE
ret cdb_dataservices_client.simple_route;
BEGIN
RAISE EXCEPTION 'Not enough quota or any other exception whatsoever.';
-- This code shall never be reached
SELECT NULL, 5.33, 100 INTO ret;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql';
-- Use regular user role
SET ROLE test_regular_user;
-- Exercise the exception safe and the proxied functions
SELECT _cdb_geocode_street_point_exception_safe('One street, 1');
SELECT * FROM _cdb_isodistance_exception_safe('POINT(-3.70568 40.42028)'::geometry, 'walk', ARRAY[300]::integer[]);
SELECT * FROM _cdb_route_point_to_point_exception_safe('POINT(-3.70237112 40.41706163)'::geometry,'POINT(-3.69909883 40.41236875)'::geometry, 'car', ARRAY['mode_type=shortest']::text[]);

View File

@@ -194,6 +194,30 @@ BEGIN
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getmeta(username text, orgname text, geom geometry(Geometry, 4326), params JSON, max_timespan_rank INTEGER DEFAULT NULL, max_score_rank INTEGER DEFAULT NULL, target_geoms INTEGER DEFAULT NULL)
RETURNS JSON AS $$
BEGIN
RAISE NOTICE 'cdb_dataservices_server.obs_getmeta invoked with params (%, %, %, %, %, %, %)', username, orgname, geom, params, max_timespan_rank, max_score_rank, target_geoms;
RETURN '[{"id" : 1, "numer_id" : "us.census.acs.B01003001", "timespan_rank" : 1, "score_rank" : 1, "score" : 19.9580760018781868330120152747832081562684, "numer_aggregate" : "sum", "numer_colname" : "total_pop", "numer_geomref_colname" : "geoid", "numer_tablename" : "obs_209d3476ef8eaaa18e597cabcf1bdb627f37aa5e", "numer_type" : "Numeric", "denom_aggregate" : null, "denom_colname" : null, "denom_geomref_colname" : null, "denom_tablename" : null, "denom_type" : null, "geom_colname" : "the_geom", "geom_geomref_colname" : "geoid", "geom_tablename" : "obs_78fb6c1d6ff6505225175922c2c389ce48d7632c", "geom_type" : "Geometry", "geom_timespan" : "2015", "numer_timespan" : "2011 - 2015", "numer_name" : "Total Population", "denom_name" : null, "geom_name" : "US Census Block Groups", "normalization" : null, "denom_id" : null, "geom_id" : "us.census.tiger.block_group"}]'::JSON;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getdata(username text, orgname text, geomrefs text[], params json)
RETURNS TABLE (id TEXT, data JSON) AS $$
BEGIN
RAISE NOTICE 'cdb_dataservices_server.obs_getdata invoked with params (%, %, %, %)', username, orgname, geomrefs, params;
RETURN QUERY SELECT '36047'::TEXT AS id, '[{"value" : 10349.1547875017}]'::JSON AS data;
END;
$$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION cdb_dataservices_server.obs_getdata(username text, orgname text, geomvals geomval[], params json, merge boolean default true)
RETURNS TABLE (id TEXT, data JSON) AS $$
BEGIN
RAISE NOTICE 'cdb_dataservices_server.obs_getdata invoked with params (%, %, %, %, %)', username, orgname, geomvals, params, merge;
RETURN QUERY SELECT '36047'::TEXT AS id, '[{"value" : 10349.1547875017}]'::JSON AS data;
END;
$$ LANGUAGE 'plpgsql';
-- Exercise the public and the proxied function
SELECT obs_get_demographic_snapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '2009 - 2013'::text, '"us.census.tiger".block_group'::text);
SELECT obs_get_segment_snapshot(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326), '"us.census.tiger".block_group'::text);
@@ -214,3 +238,7 @@ SELECT obs_getuscensuscategory(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326
SELECT obs_getpopulation(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326));
SELECT obs_search('total_pop'::text);
SELECT obs_getavailableboundaries(ST_SetSRID(ST_Point(-73.936669 , 40.704512), 4326));
SELECT obs_getmeta(ST_SetSRID(ST_Point(-73.9, 40.7), 4326), '[{"numer_id": "us.census.acs.B01003001"}]', 1, 1, 1000);
SELECT obs_getdata(ARRAY['36047'], obs_getmeta(st_setsrid(st_point(-73.9, 40.7), 4326), '[{"numer_id": "us.census.acs.B01003001", "geom_id": "us.census.tiger.county"}]', 1, 1, 1000));
SELECT obs_getdata(ARRAY[(ST_SetSRID(ST_Point(-73.9, 40.7), 4326), 1)::geomval], obs_getmeta(st_setsrid(st_point(-73.9, 40.7), 4326), '[{"numer_id": "us.census.acs.B01003001"}]'));

View File

@@ -2,4 +2,7 @@
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION cdb_dataservices_client UPDATE TO '<%= version %>'" 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

View File

@@ -0,0 +1,36 @@
# Exception-Safe functions
The public API dataservices functions emit exceptions in general when an error occurs
or a limiting condition is met (e.g. quotas are exceeded).
For each public function `func` we have a internal function named `_func_exception_safe` which
acts as a wrapper to the public function, with the same signature, but captures
exceptions generated during its execution (except those due to incomplete configuration or
authentication issues) and returns NULL or empty set values in those cases.
Please note these functions are considered **not public** and therefore their API (including which exceptions are wrapped and which ones are not) may change.
Instead of raising an exception they raise warnings, hopefully containing the same information of the original exception.
## Intended Use
These functions are useful in cases when it is undesirable to rollback a transaction.
Fo example if a table is geocoded with:
```sql
UPDATE table SET the_geom=cdb_geocode_street_point(address,city,NULL,country);
```
In case of the user geocoding quota being exhausted mid-process, the user could
incur in external service expenses but any geocoded data would be lost due to the
transaction rollback.
We can avoid the problem using the corresponding exception-safe function:
```sql
UPDATE table SET the_geom=_cdb_geocode_street_point_exception_safe(address,city,NULL,country);
```
# Addition Information
See https://github.com/CartoDB/dataservices-api/issues/314 for more information.

View File

@@ -12,3 +12,124 @@ Quota consumption is calculated based on the number of request made for each fun
**Note:** Queries to the Data Services API, and any of its functions in your maps, may be forbidden in the future
* It is advised to store results of these queries into your datasets, and refresh them as needed. This ensure more control of quota credits for your account
## Quota Information Functions
There are several SQL functions that you can run to obtain quota information about your services.
## cdb_service_quota_info()
Returns information about per-service quotas (available and used) for the account.
#### Returns
This function returns a set of service quota information records, one per service.
Name | Type | Description
--------------- | --------- | ------------
`service` | `text` | Type of service.
`monthly_quota` | `numeric` | Quota available to the user (number of calls) per monthly period.
`used_quota` | `numeric` | Quota used by the user in the present period.
`soft_limit` | `boolean` | Set to `True`, if the user has *soft-limit* quota.
`provider` | `text` | Service provider for this type of service.
Service Types:
* `'isolines'` [Isoline/Isochrones (isochrone/isodistance lines) service](https://carto.com/docs/carto-engine/dataservices-api/isoline_functions/)
* `'hires_geocoder'` [Street level geocoding](https://carto.com/docs/carto-engine/dataservices-api/geocoding-functions#street-level-geocoder)
* `'routing'` [Routing functions](https://carto.com/docs/carto-engine/dataservices-api/routing_functions/)
* `'observatory'` Data Observatory services ([demographic](https://carto.com/docs/carto-engine/dataservices-api/demographic_functions/) and [segmentation](https://carto.com/docs/carto-engine/dataservices-api/segmentation_functions/) functions)
**Notes**
Users who have *soft-quota* activated never run out of quota, but they may incur extra
expenses when the regular quota is exceeded.
A zero value of `monthly_quota` indicates that the service has not been activated for the user.
#### Example
```sql
SELECT * FROM cdb_service_quota_info();
```
Result:
```sql
service | monthly_quota | used_quota | soft_limit | provider
----------------+---------------+------------+------------+------------------
isolines | 100 | 0 | f | mapzen
hires_geocoder | 100 | 0 | f | mapzen
routing | 50 | 0 | f | mapzen
observatory | 0 | 0 | f | data observatory
(4 rows)
```
In this case, notice that the user has no access to the observatory services. All quotas are *hard-limited* (no soft limits), and no quota has been used in the present period.
## cdb_enough_quota(service text ,input_size numeric)
This function is useful to check if enough quota is available for completing a job.
This is specifically relevant if a number of service calls are to be performed inside a transaction. If any of the calls fails (due to exceeded quota), the transaction will be rolled back; resulting in partial quota consumption, but no saved results from the services consumed.
**Tip:** If you are requesting repeating quota-consuming functions (e.g. to geocode a whole table), it is extremely important to check if enough quota is available to complete the job _before_ applying this function.
Note that some services consume more than one credit per row/call. For example, isolines (with more than one range/track) consume (N rows x M ranges) credits; indicating that the input size should be N x M.
#### Arguments
Name | Type | Description
------------ | --------- | -----------
`service` | `text` | Service to check; see the list of valid services above.
`input_size` | `numeric` | Number of service calls required, i.e. size of the input to be processed.
#### Returns
The result is a *boolean* value. A *true* value (`'t'`) indicates that the available quota
for the service is enough for the input size requested. A *false* value (`'f'`) indicates
insufficient quota.
#### Example
Suppose you want to geocode a whole table. In order to check that you have enough quota, and avoid a "quota exhausted" exception, first find out how many records you need to geocode:
```sql
SELECT COUNT(*) FROM {tablename} WHERE {street_name_column} IS NOT NULL;
```
Result: here's a sample result of 10000 records:
```sql
count
-------
10000
(1 row)
```
The result shows how much quota is needed to complete this job. In this case,
each call to `cdb_geocode_street_point` consumes one quota credit. This indicates that we need one credit per row to geocode the whole table.
```sql
SELECT cdb_enough_quota('hires_geocoder', {number_of_records});
```
The result is similar to the following:
```sql
cdb_enough_quota
------------------
t
```
If the result of this query is *true* (`'t'`), you can safely proceed. If a *false* value (`'f'`) is returned, you should avoid processing any more requests that consume quota. Apply the `cdb_service_quota_info` function to get more information about your services.
**Note:** Remember to apply any filtering conditions that you used to count the records (in this case, `{street_name_column} IS NOT NULL`):
```sql
UPDATE {tablename} SET the_geom = cdb_geocode_street_point({street_name_column})
WHERE {street_name_column} IS NOT NULL;
```

197
doc/rate_limits.md Normal file
View File

@@ -0,0 +1,197 @@
# Rate limits
Services can be rate-limited. (currently only gecoding is limited)
The rate limits configuration can be established at server, organization or user levels, the latter having precedence over the earlier.
The default configuration (a null or empty configuration) doesn't impose any limits.
The configuration consist of a JSON object with two attributes:
* `period`: the rate-limiting period, in seconds.
* `limit`: the maximum number of request in the established period.
If a service request exceeds the configured rate limits
(i.e. if more than `limit` calls are performe in a fixed interval of
duration `period` seconds) the call will fail with an "Rate limit exceeded" error.
## Server-side interface
There's a server-side SQL interface to query or change the configuration.
### cdb_dataservices_server.cdb_service_get_rate_limit(username, orgname, service)
This function returns the rate limit configuration for a given user and service.
#### Returns
The result is a JSON object with the configuration (`period` and `limit` attributes as explained above).
### cdb_dataservices_server.cdb_service_set_user_rate_limit(username, orgname, service, rate_limit)
This function sets the rate limit configuration for the user. This overrides any other configuration.
The configuration is provided as a JSON literal. To remove the user-level configuration `NULL` should be passed as the `rate_limit`.
#### Returns
This functions doesn't return any value.
### cdb_dataservices_server.cdb_service_set_org_rate_limit(username, orgname, service, rate_limit)
This function sets the rate limit configuration for the organization.
This overrides server level configuration and is overriden by user configuration if present.
The configuration is provided as a JSON literal. To remove the organization-level configuration `NULL` should be passed as the `rate_limit`.
#### Returns
This functions doesn't return any value.
### cdb_dataservices_server.cdb_service_set_server_rate_limit(username, orgname, service, rate_limit)
This function sets the default rate limit configuration for all users accesing the dataservices server. This is overriden by organization of user configuration.
The configuration is provided as a JSON literal. To remove the organization-level configuration `NULL` should be passed as the `rate_limit`.
#### Returns
This functions doesn't return any value.
## Client-side interface
For convenience there's also a client-side interface (in the client dataservices-api extension), consisting
of public functions to get the current configuration and privileged functions to change it.
### Public functions
These functions are accesible to non-privileged roles, and should only be executed
using the role corresponding to a CARTO user, since that will determine the
user and organization to which the rate limits configuration applies.
### cdb_dataservices_client.cdb_service_get_rate_limit(service)
This function returns the rate limit configuration in effect for the specified service
and the user corresponding to the role which makes the calls. The effective configuration
may come from any of the configuration levels (server/organization/user); only the
existing configuration with most precedence is returned.
#### Returns
The result is a JSON object with the configuration (`period` and `limit` attributes as explained above).
#### Example:
```
SELECT cdb_dataservices_client.cdb_service_get_rate_limit('geocoder');
cdb_service_get_rate_limit
---------------------------------
{"limit": 1000, "period": 86400}
(1 row)
```
### Privileged (superuser) functions
Thes functions are not accessible by regular user roles, and the user and organization names must be provided as parameters.
### cdb_dataservices_client.cdb_service_set_user_rate_limit(username, orgname, service, rate_limit)
This function sets the rate limit configuration for the user. This overrides any other configuration.
The configuration is provided as a JSON literal. To remove the user-level configuration `NULL` should be passed as the `rate_limit`.
#### Returns
This functions doesn't return any value.
#### Example
This will configure the geocoder service rate limit for user `myusername`, a non-organization user.
The limit will be set at 1000 requests per day. Since the user doesn't belong to any organization,
`NULL` will be passed to the organization argument; otherwise the name of the user's organization should
be provided.
Note that the name of the geocoding services is `geocoder` and not `geocoding`.
```
SELECT cdb_dataservices_client.cdb_service_set_user_rate_limit(
'myusername',
NULL,
'geocoder',
'{"limit":1000,"period":86400}'
);
cdb_service_set_user_rate_limit
---------------------------------
(1 row)
```
### cdb_dataservices_client.cdb_service_set_org_rate_limit(username, orgname, service, rate_limit)
This function sets the rate limit configuration for the organization.
This overrides server level configuration and is overriden by user configuration if present.
The configuration is provided as a JSON literal. To remove the organization-level configuration `NULL` should be passed as the `rate_limit`.
#### Returns
This functions doesn't return any value.
#### Example
This will configure the geocoder service rate limit for the `myorg` organization.
The limit will be set at 100 requests per hour.
Note that even we're setting the default configuration for the whole organization,
the name of a user of the organization must be provided for technical reasons.
```
SELECT cdb_dataservices_client.cdb_service_set_org_rate_limit(
'myorgadmin',
'myorg',
'geocoder',
'{"limit":100,"period":3600}'
);
cdb_service_set_org_rate_limit
---------------------------------
(1 row)
```
### cdb_dataservices_client.cdb_service_set_server_rate_limit(username, orgname, service, rate_limit)
This function sets the default rate limit configuration for all users accesing the dataservices server. This is overriden by organization of user configuration.
The configuration is provided as a JSON literal. To remove the organization-level configuration `NULL` should be passed as the `rate_limit`.
#### Returns
This functions doesn't return any value.
#### Example
This will configure the default geocoder service rate limit for all users
accesing the data-services server.
The limit will be set at 10000 requests per month.
Note that even we're setting the default configuration for the server,
the name of a user and the name of the corresponding organization (or NULL)
must be provided for technical reasons.
```
SELECT cdb_dataservices_client.cdb_service_set_server_rate_limit(
'myorgadmin',
'myorg',
'geocoder',
'{"limit":10000,"period":108000}'
);
cdb_service_set_server_rate_limit
---------------------------------
(1 row)
```

View File

@@ -38,7 +38,7 @@ all: $(DATA)
.PHONY: release
release: $(EXTENSION).control $(SOURCES_DATA)
test -n "$(NEW_VERSION)" # $$NEW_VERSION VARIABLE MISSING. Eg. make release NEW_VERSION=0.x.0
mv *.sql old_versions
git mv *.sql old_versions
$(SED) $(REPLACEMENTS) $(EXTENSION).control
cat $(SOURCES_DATA_DIR)/*.sql > $(EXTENSION)--$(NEW_VERSION).sql
$(ERB) version=$(NEW_VERSION) upgrade_downgrade_template.erb > $(EXTENSION)--$(EXTVERSION)--$(NEW_VERSION).sql

View File

@@ -0,0 +1,40 @@
--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.24.2'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
---- cdb_geocode_namedplace_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
RETURNS Geometry AS $$
import spiexceptions
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name])[0]['point']
$$ LANGUAGE plpythonu;
---- cdb_geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
RETURNS Geometry AS $$
import spiexceptions
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name, country_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, country_name])[0]['point']
$$ LANGUAGE plpythonu;
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$
import spiexceptions
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
except spiexceptions.ExternalRoutineException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
$$ LANGUAGE plpythonu;

View File

@@ -0,0 +1,36 @@
--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.24.1'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
RETURNS Geometry AS $$
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name])[0]['point']
except BaseException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name])[0]['point']
$$ LANGUAGE plpythonu;
---- cdb_geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
RETURNS Geometry AS $$
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name, country_name])[0]['point']
except BaseException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, country_name])[0]['point']
$$ LANGUAGE plpythonu;
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
except BaseException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
$$ LANGUAGE plpythonu;

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
comment = 'CartoDB dataservices server extension'
default_version = '0.20.0'
default_version = '0.24.2'
requires = 'plpythonu, plproxy, postgis, cdb_geocoder'
superuser = true
schema = cdb_dataservices_server

View File

@@ -0,0 +1,174 @@
--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.21.0'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData(
username TEXT,
orgname TEXT,
geomvals geomval[],
params JSON,
merge BOOLEAN DEFAULT True)
RETURNS TABLE (
id INT,
data JSON
) AS $$
CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname);
SELECT * FROM cdb_observatory.OBS_GetData(geomvals, params, merge);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomvals geomval[],
params JSON,
merge BOOLEAN DEFAULT True)
RETURNS TABLE (
id INT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4, $5);", ["text", "text", "geomval[]", "json", "boolean"])
result = plpy.execute(obs_plan, [username, orgname, geomvals, params, merge])
empty_results = len(geomvals) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomvals))
logger.error('Error trying to OBS_GetData', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomvals))
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData(
username TEXT,
orgname TEXT,
geomrefs TEXT[],
params JSON)
RETURNS TABLE (
id TEXT,
data JSON
) AS $$
CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname);
SELECT * FROM cdb_observatory.OBS_GetData(geomrefs, params);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomrefs TEXT[],
params JSON)
RETURNS TABLE (
id TEXT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4);", ["text", "text", "text[]", "json"])
result = plpy.execute(obs_plan, [username, orgname, geomrefs, params])
empty_results = len(geomrefs) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomrefs))
exc_info = sys.exc_info()
logger.error('%s, %s, %s' % (exc_info[0], exc_info[1], exc_info[2]))
logger.error('Error trying to OBS_GetData', exc_info, data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomrefs))
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeta(
username TEXT,
orgname TEXT,
geom Geometry(Geometry, 4326),
params JSON,
max_timespan_rank INTEGER DEFAULT NULL,
max_score_rank INTEGER DEFAULT NULL,
target_geoms INTEGER DEFAULT NULL)
RETURNS JSON AS $$
CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname);
SELECT cdb_observatory.OBS_GetMeta(geom, params, max_timespan_rank, max_score_rank, target_geoms);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetMeta(
username TEXT,
orgname TEXT,
geom Geometry(Geometry, 4326),
params JSON,
max_timespan_rank INTEGER DEFAULT NULL,
max_score_rank INTEGER DEFAULT NULL,
target_geoms INTEGER DEFAULT NULL)
RETURNS JSON 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_config_{0}".format(username)]
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
with metrics('obs_getmeta', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetMeta($1, $2, $3, $4, $5, $6, $7) as meta;", ["text", "text", "Geometry (Geometry, 4326)", "json", "integer", "integer", "integer"])
result = plpy.execute(obs_plan, [username, orgname, geom, params, max_timespan_rank, max_score_rank, target_geoms])
if result:
return result[0]['meta']
else:
return None
except BaseException as e:
import sys
logger.error('Error trying to OBS_GetMeta', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetMeta')
$$ LANGUAGE plpythonu;

View File

@@ -0,0 +1,11 @@
--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.OBS_GetData(TEXT, TEXT, geomval[], JSON, BOOLEAN);
DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetData(TEXT, TEXT, geomval[], JSON, BOOLEAN);
DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetData(TEXT, TEXT, TEXT[], JSON);
DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetData(TEXT, TEXT, TEXT[], JSON);
DROP FUNCTION IF EXISTS cdb_dataservices_server.OBS_GetMeta(TEXT, TEXT, Geometry(Geometry, 4326), JSON, INTEGER, INTEGER, INTEGER);
DROP FUNCTION IF EXISTS cdb_dataservices_server._OBS_GetMeta(TEXT, TEXT, Geometry(Geometry, 4326), JSON, INTEGER, INTEGER, INTEGER);

View File

@@ -0,0 +1,292 @@
--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.22.0'" to load this file. \quit
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_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 $$
import json
from cartodb_services.mapzen import MapzenRouting, MapzenRoutingResponse
from cartodb_services.mapzen.types import polyline_to_linestring
from cartodb_services.metrics import QuotaService
from cartodb_services.tools import Coordinate
from cartodb_services.tools import Logger,LoggerConfig
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
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)
quota_service = QuotaService(user_routing_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
try:
client = MapzenRouting(user_routing_config.mapzen_api_key, logger, user_routing_config.mapzen_service_params)
if not waypoints or len(waypoints) < 2:
logger.info("Empty origin or destination")
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))
resp = client.calculate_route_point_to_point(waypoint_coords, mode, options, units)
if resp and resp.shape:
shape_linestring = polyline_to_linestring(resp.shape)
if shape_linestring:
quota_service.increment_success_service_use()
return [shape_linestring, resp.length, resp.duration]
else:
quota_service.increment_empty_service_use()
return [None, None, None]
else:
quota_service.increment_empty_service_use()
return [None, None, None]
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to calculate mapzen routing', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to calculate mapzen routing')
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_here_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.here import HereMapsGeocoder
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_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)
# -- Check the quota
quota_service = QuotaService(user_geocoder_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
try:
geocoder = HereMapsGeocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code, logger, user_geocoder_config.heremaps_service_params)
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
if coordinates:
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:
quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode street point using here maps', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using here maps')
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_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 $$
import cartodb_services
cartodb_services.init(plpy, GD)
from cartodb_services.mapzen import MapzenGeocoder
from cartodb_services.mapzen.types import country_to_iso3
from cartodb_services.metrics import QuotaService
from cartodb_services.tools import Logger
from cartodb_services.refactor.tools.logger import LoggerConfigBuilder
from cartodb_services.refactor.service.mapzen_geocoder_config import MapzenGeocoderConfigBuilder
from cartodb_services.refactor.core.environment import ServerEnvironmentBuilder
from cartodb_services.refactor.backend.server_config import ServerConfigBackendFactory
from cartodb_services.refactor.backend.user_config import UserConfigBackendFactory
from cartodb_services.refactor.backend.org_config import OrgConfigBackendFactory
from cartodb_services.refactor.backend.redis_metrics_connection import RedisMetricsConnectionFactory
server_config_backend = ServerConfigBackendFactory().get()
environment = ServerEnvironmentBuilder(server_config_backend).get()
user_config_backend = UserConfigBackendFactory(username, environment, server_config_backend).get()
org_config_backend = OrgConfigBackendFactory(orgname, environment, server_config_backend).get()
logger_config = LoggerConfigBuilder(environment, server_config_backend).get()
logger = Logger(logger_config)
mapzen_geocoder_config = MapzenGeocoderConfigBuilder(server_config_backend, user_config_backend, org_config_backend, username, orgname).get()
redis_metrics_connection = RedisMetricsConnectionFactory(environment, server_config_backend).get()
quota_service = QuotaService(mapzen_geocoder_config, redis_metrics_connection)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
try:
geocoder = MapzenGeocoder(mapzen_geocoder_config.mapzen_api_key, logger, mapzen_geocoder_config.service_params)
country_iso3 = None
if country:
country_iso3 = country_to_iso3(country)
coordinates = geocoder.geocode(searchtext=searchtext, city=city,
state_province=state_province,
country=country_iso3, search_type='address')
if coordinates:
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:
quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode street point using mapzen', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using mapzen')
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
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, user_isolines_routing_config.mapzen_matrix_service_params)
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, user_isolines_routing_config.mapzen_isochrones_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 = {'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;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,292 @@
--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.21.0'" to load this file. \quit
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_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 $$
import json
from cartodb_services.mapzen import MapzenRouting, MapzenRoutingResponse
from cartodb_services.mapzen.types import polyline_to_linestring
from cartodb_services.metrics import QuotaService
from cartodb_services.tools import Coordinate
from cartodb_services.tools import Logger,LoggerConfig
redis_conn = GD["redis_connection_{0}".format(username)]['redis_metrics_connection']
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)
quota_service = QuotaService(user_routing_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
try:
client = MapzenRouting(user_routing_config.mapzen_api_key, logger)
if not waypoints or len(waypoints) < 2:
logger.info("Empty origin or destination")
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))
resp = client.calculate_route_point_to_point(waypoint_coords, mode, options, units)
if resp and resp.shape:
shape_linestring = polyline_to_linestring(resp.shape)
if shape_linestring:
quota_service.increment_success_service_use()
return [shape_linestring, resp.length, resp.duration]
else:
quota_service.increment_empty_service_use()
return [None, None, None]
else:
quota_service.increment_empty_service_use()
return [None, None, None]
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to calculate mapzen routing', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to calculate mapzen routing')
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_here_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.here import HereMapsGeocoder
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_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)
# -- Check the quota
quota_service = QuotaService(user_geocoder_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
try:
geocoder = HereMapsGeocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code, logger)
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
if coordinates:
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:
quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode street point using here maps', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using here maps')
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_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 $$
import cartodb_services
cartodb_services.init(plpy, GD)
from cartodb_services.mapzen import MapzenGeocoder
from cartodb_services.mapzen.types import country_to_iso3
from cartodb_services.metrics import QuotaService
from cartodb_services.tools import Logger
from cartodb_services.refactor.tools.logger import LoggerConfigBuilder
from cartodb_services.refactor.service.mapzen_geocoder_config import MapzenGeocoderConfigBuilder
from cartodb_services.refactor.core.environment import ServerEnvironmentBuilder
from cartodb_services.refactor.backend.server_config import ServerConfigBackendFactory
from cartodb_services.refactor.backend.user_config import UserConfigBackendFactory
from cartodb_services.refactor.backend.org_config import OrgConfigBackendFactory
from cartodb_services.refactor.backend.redis_metrics_connection import RedisMetricsConnectionFactory
server_config_backend = ServerConfigBackendFactory().get()
environment = ServerEnvironmentBuilder(server_config_backend).get()
user_config_backend = UserConfigBackendFactory(username, environment, server_config_backend).get()
org_config_backend = OrgConfigBackendFactory(orgname, environment, server_config_backend).get()
logger_config = LoggerConfigBuilder(environment, server_config_backend).get()
logger = Logger(logger_config)
mapzen_geocoder_config = MapzenGeocoderConfigBuilder(server_config_backend, user_config_backend, org_config_backend, username, orgname).get()
redis_metrics_connection = RedisMetricsConnectionFactory(environment, server_config_backend).get()
quota_service = QuotaService(mapzen_geocoder_config, redis_metrics_connection)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
try:
geocoder = MapzenGeocoder(mapzen_geocoder_config.mapzen_api_key, logger)
country_iso3 = None
if country:
country_iso3 = country_to_iso3(country)
coordinates = geocoder.geocode(searchtext=searchtext, city=city,
state_province=state_province,
country=country_iso3, search_type='address')
if coordinates:
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:
quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode street point using mapzen', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using mapzen')
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
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;

View File

@@ -0,0 +1,207 @@
--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.23.0'" to load this file. \quit
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_get_rate_limit(
username TEXT,
orgname TEXT,
service TEXT)
RETURNS JSON AS $$
import json
from cartodb_services.config import ServiceConfiguration, RateLimitsConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_config = ServiceConfiguration(service, username, orgname)
rate_limit_config = RateLimitsConfigBuilder(service_config.server, service_config.user, service_config.org, service=service, username=username, orgname=orgname).get()
if rate_limit_config.is_limited():
return json.dumps({'limit': rate_limit_config.limit, 'period': rate_limit_config.period})
else:
return None
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_user_rate_limit(
username TEXT,
orgname TEXT,
service TEXT,
rate_limit_json JSON)
RETURNS VOID AS $$
import json
from cartodb_services.config import RateLimitsConfig, RateLimitsConfigSetter
import cartodb_services
cartodb_services.init(plpy, GD)
config_setter = RateLimitsConfigSetter(service=service, username=username, orgname=orgname)
if rate_limit_json:
rate_limit = json.loads(rate_limit_json)
limit = rate_limit.get('limit', None)
period = rate_limit.get('period', None)
else:
limit = None
period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_user_rate_limits(config)
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_org_rate_limit(
username TEXT,
orgname TEXT,
service TEXT,
rate_limit_json JSON)
RETURNS VOID AS $$
import json
from cartodb_services.config import RateLimitsConfig, RateLimitsConfigSetter
import cartodb_services
cartodb_services.init(plpy, GD)
config_setter = RateLimitsConfigSetter(service=service, username=username, orgname=orgname)
if rate_limit_json:
rate_limit = json.loads(rate_limit_json)
limit = rate_limit.get('limit', None)
period = rate_limit.get('period', None)
else:
limit = None
period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_org_rate_limits(config)
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_server_rate_limit(
username TEXT,
orgname TEXT,
service TEXT,
rate_limit_json JSON)
RETURNS VOID AS $$
import json
from cartodb_services.config import RateLimitsConfig, RateLimitsConfigSetter
import cartodb_services
cartodb_services.init(plpy, GD)
config_setter = RateLimitsConfigSetter(service=service, username=username, orgname=orgname)
if rate_limit_json:
rate_limit = json.loads(rate_limit_json)
limit = rate_limit.get('limit', None)
period = rate_limit.get('period', None)
else:
limit = None
period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_server_rate_limits(config)
$$ LANGUAGE plpythonu;
CREATE OR REPLACE
FUNCTION cdb_dataservices_server.CDB_Conf_SetConf(key text, value JSON)
RETURNS void AS $$
BEGIN
PERFORM cdb_dataservices_server.CDB_Conf_RemoveConf(key);
EXECUTE 'INSERT INTO cartodb.CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value;
END
$$ LANGUAGE PLPGSQL VOLATILE SECURITY DEFINER;
CREATE OR REPLACE
FUNCTION cdb_dataservices_server.CDB_Conf_RemoveConf(key text)
RETURNS void AS $$
BEGIN
EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE KEY = $1;' USING key;
END
$$ LANGUAGE PLPGSQL VOLATILE SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_here_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.tools import LegacyServiceManager
from cartodb_services.here import HereMapsGeocoder
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
service_manager = LegacyServiceManager('geocoder', username, orgname, GD)
service_manager.assert_within_limits()
try:
geocoder = HereMapsGeocoder(service_manager.config.heremaps_app_id, service_manager.config.heremaps_app_code, service_manager.logger, service_manager.config.heremaps_service_params)
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
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 BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using here maps', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using here maps')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_google_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.tools import LegacyServiceManager
from cartodb_services.google import GoogleMapsGeocoder
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
service_manager = LegacyServiceManager('geocoder', username, orgname, GD)
service_manager.assert_within_limits(quota=False)
try:
geocoder = GoogleMapsGeocoder(service_manager.config.google_client_id, service_manager.config.google_api_key, service_manager.logger)
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
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 BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using google maps', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using google maps')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_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.tools import ServiceManager
from cartodb_services.mapzen import MapzenGeocoder
from cartodb_services.mapzen.types import country_to_iso3
from cartodb_services.refactor.service.mapzen_geocoder_config import MapzenGeocoderConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_manager = ServiceManager('geocoder', MapzenGeocoderConfigBuilder, username, orgname)
service_manager.assert_within_limits()
try:
geocoder = MapzenGeocoder(service_manager.config.mapzen_api_key, service_manager.logger, service_manager.config.service_params)
country_iso3 = None
if country:
country_iso3 = country_to_iso3(country)
coordinates = geocoder.geocode(searchtext=searchtext, city=city,
state_province=state_province,
country=country_iso3, search_type='address')
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 BaseException as e:
import sys
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using mapzen', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using mapzen')
finally:
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
--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.22.0'" to load this file. \quit
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_service_get_rate_limit(TEXT, TEXT, TEXT);
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_service_set_user_rate_limit(TEXT, TEXT, TEXT, JSON);
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_service_set_org_rate_limit(TEXT, TEXT, TEXT, JSON);
DROP FUNCTION IF EXISTS cdb_dataservices_server.cdb_service_set_server_rate_limit(TEXT, TEXT, TEXT, JSON);
DROP FUNCTION IF EXISTS cdb_dataservices_server.CDB_Conf_SetConf(text, JSON);
DROP FUNCTION IF EXISTS cdb_dataservices_server.CDB_Conf_RemoveConf(text);
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_here_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_google_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
DROP FUNCTION IF EXISTS cdb_dataservices_server._cdb_mapzen_geocode_street_point(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);

View File

@@ -0,0 +1,11 @@
--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.24.0'" to load this file. \quit
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE geom_type text;
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE geom_extra jsonb;
ALTER TYPE cdb_dataservices_server.obs_meta_geometry ADD ATTRIBUTE geom_tags jsonb;
ALTER TYPE cdb_dataservices_server.obs_meta_timespan ADD ATTRIBUTE timespan_type text;
ALTER TYPE cdb_dataservices_server.obs_meta_timespan ADD ATTRIBUTE timespan_extra jsonb;
ALTER TYPE cdb_dataservices_server.obs_meta_timespan ADD ATTRIBUTE timespan_tags jsonb;

File diff suppressed because it is too large Load Diff

View File

@@ -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.23.0'" to load this file. \quit
-- HERE goes your code to upgrade/downgrade
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE geom_type;
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE geom_extra;
ALTER TYPE cdb_dataservices_server.obs_meta_geometry DROP ATTRIBUTE geom_tags;
ALTER TYPE cdb_dataservices_server.obs_meta_timespan DROP ATTRIBUTE timespan_type;
ALTER TYPE cdb_dataservices_server.obs_meta_timespan DROP ATTRIBUTE timespan_extra;
ALTER TYPE cdb_dataservices_server.obs_meta_timespan DROP ATTRIBUTE timespan_tags;

View File

@@ -0,0 +1,100 @@
--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.24.1'" to load this file. \quit
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomvals geomval[],
params JSON,
merge BOOLEAN DEFAULT True)
RETURNS TABLE (
id INT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4, $5);", ["text", "text", "geomval[]", "json", "boolean"])
result = plpy.execute(obs_plan, [username, orgname, geomvals, params, merge])
empty_results = len(geomvals) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return []
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomvals))
logger.error('Error trying to OBS_GetData', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomvals))
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomrefs TEXT[],
params JSON)
RETURNS TABLE (
id TEXT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4);", ["text", "text", "text[]", "json"])
result = plpy.execute(obs_plan, [username, orgname, geomrefs, params])
empty_results = len(geomrefs) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return []
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomrefs))
exc_info = sys.exc_info()
logger.error('%s, %s, %s' % (exc_info[0], exc_info[1], exc_info[2]))
logger.error('Error trying to OBS_GetData', exc_info, data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomrefs))
$$ LANGUAGE plpythonu;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
--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.24.0'" to load this file. \quit
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomvals geomval[],
params JSON,
merge BOOLEAN DEFAULT True)
RETURNS TABLE (
id INT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4, $5);", ["text", "text", "geomval[]", "json", "boolean"])
result = plpy.execute(obs_plan, [username, orgname, geomvals, params, merge])
empty_results = len(geomvals) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomvals))
logger.error('Error trying to OBS_GetData', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomvals))
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomrefs TEXT[],
params JSON)
RETURNS TABLE (
id TEXT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4);", ["text", "text", "text[]", "json"])
result = plpy.execute(obs_plan, [username, orgname, geomrefs, params])
empty_results = len(geomrefs) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomrefs))
exc_info = sys.exc_info()
logger.error('%s, %s, %s' % (exc_info[0], exc_info[1], exc_info[2]))
logger.error('Error trying to OBS_GetData', exc_info, data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomrefs))
$$ LANGUAGE plpythonu;

File diff suppressed because it is too large Load Diff

View File

@@ -31,7 +31,7 @@ RETURNS cdb_dataservices_server.simple_route AS $$
raise Exception('You have reached the limit of your quota')
try:
client = MapzenRouting(user_routing_config.mapzen_api_key, logger)
client = MapzenRouting(user_routing_config.mapzen_api_key, logger, user_routing_config.mapzen_service_params)
if not waypoints or len(waypoints) < 2:
logger.info("Empty origin or destination")

View File

@@ -567,3 +567,173 @@ RETURNS NUMERIC AS $$
finally:
quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData(
username TEXT,
orgname TEXT,
geomvals geomval[],
params JSON,
merge BOOLEAN DEFAULT True)
RETURNS TABLE (
id INT,
data JSON
) AS $$
CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname);
SELECT * FROM cdb_observatory.OBS_GetData(geomvals, params, merge);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomvals geomval[],
params JSON,
merge BOOLEAN DEFAULT True)
RETURNS TABLE (
id INT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4, $5);", ["text", "text", "geomval[]", "json", "boolean"])
result = plpy.execute(obs_plan, [username, orgname, geomvals, params, merge])
empty_results = len(geomvals) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return []
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomvals))
logger.error('Error trying to OBS_GetData', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomvals))
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetData(
username TEXT,
orgname TEXT,
geomrefs TEXT[],
params JSON)
RETURNS TABLE (
id TEXT,
data JSON
) AS $$
CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname);
SELECT * FROM cdb_observatory.OBS_GetData(geomrefs, params);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetData(
username TEXT,
orgname TEXT,
geomrefs TEXT[],
params JSON)
RETURNS TABLE (
id TEXT,
data JSON
) AS $$
from cartodb_services.metrics import metrics
from cartodb_services.metrics import QuotaService
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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_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_obs_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
with metrics('obs_getdata', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT * FROM cdb_dataservices_server._OBS_GetData($1, $2, $3, $4);", ["text", "text", "text[]", "json"])
result = plpy.execute(obs_plan, [username, orgname, geomrefs, params])
empty_results = len(geomrefs) - len(result)
if empty_results > 0:
quota_service.increment_empty_service_use(empty_results)
if result:
quota_service.increment_success_service_use(len(result))
return result
else:
return []
except BaseException as e:
import sys
quota_service.increment_failed_service_use(len(geomrefs))
exc_info = sys.exc_info()
logger.error('%s, %s, %s' % (exc_info[0], exc_info[1], exc_info[2]))
logger.error('Error trying to OBS_GetData', exc_info, data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetData')
finally:
quota_service.increment_total_service_use(len(geomrefs))
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._OBS_GetMeta(
username TEXT,
orgname TEXT,
geom Geometry(Geometry, 4326),
params JSON,
max_timespan_rank INTEGER DEFAULT NULL,
max_score_rank INTEGER DEFAULT NULL,
target_geoms INTEGER DEFAULT NULL)
RETURNS JSON AS $$
CONNECT cdb_dataservices_server._obs_server_conn_str(username, orgname);
SELECT cdb_observatory.OBS_GetMeta(geom, params, max_timespan_rank, max_score_rank, target_geoms);
$$ LANGUAGE plproxy;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetMeta(
username TEXT,
orgname TEXT,
geom Geometry(Geometry, 4326),
params JSON,
max_timespan_rank INTEGER DEFAULT NULL,
max_score_rank INTEGER DEFAULT NULL,
target_geoms INTEGER DEFAULT NULL)
RETURNS JSON 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_obs_config({0}, {1})".format(plpy.quote_nullable(username), plpy.quote_nullable(orgname)))
user_obs_config = GD["user_obs_config_{0}".format(username)]
plpy.execute("SELECT cdb_dataservices_server._get_logger_config()")
logger_config = GD["logger_config"]
logger = Logger(logger_config)
with metrics('obs_getmeta', user_obs_config, logger):
try:
obs_plan = plpy.prepare("SELECT cdb_dataservices_server._OBS_GetMeta($1, $2, $3, $4, $5, $6, $7) as meta;", ["text", "text", "Geometry (Geometry, 4326)", "json", "integer", "integer", "integer"])
result = plpy.execute(obs_plan, [username, orgname, geom, params, max_timespan_rank, max_score_rank, target_geoms])
if result:
return result[0]['meta']
else:
return None
except BaseException as e:
import sys
logger.error('Error trying to OBS_GetMeta', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to OBS_GetMeta')
$$ LANGUAGE plpythonu;

View File

@@ -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, score numeric, numtiles bigint, notnull_percent numeric, numgeoms numeric, percentfill numeric, estnumgeoms numeric, meanmediansize numeric);
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, geom_type text, geom_extra jsonb, geom_tags jsonb);
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetAvailableGeometries(
username TEXT,
@@ -50,7 +50,7 @@ RETURNS SETOF cdb_dataservices_server.obs_meta_geometry AS $$
SELECT * FROM cdb_observatory.OBS_GetAvailableGeometries(bounds, filter_tags, numer_id, denom_id, timespan);
$$ LANGUAGE plproxy;
CREATE TYPE cdb_dataservices_server.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);
CREATE TYPE cdb_dataservices_server.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, timespan_type text, timespan_extra jsonb, timespan_tags jsonb);
CREATE OR REPLACE FUNCTION cdb_dataservices_server.OBS_GetAvailableTimespans(
username TEXT,

View File

@@ -16,6 +16,24 @@ RETURNS JSON AS $$
SELECT VALUE FROM cartodb.cdb_conf WHERE key = input_key;
$$ LANGUAGE SQL STABLE SECURITY DEFINER;
CREATE OR REPLACE
FUNCTION cdb_dataservices_server.CDB_Conf_SetConf(key text, value JSON)
RETURNS void AS $$
BEGIN
PERFORM cdb_dataservices_server.CDB_Conf_RemoveConf(key);
EXECUTE 'INSERT INTO cartodb.CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value;
END
$$ LANGUAGE PLPGSQL VOLATILE SECURITY DEFINER;
CREATE OR REPLACE
FUNCTION cdb_dataservices_server.CDB_Conf_RemoveConf(key text)
RETURNS void AS $$
BEGIN
EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE KEY = $1;' USING key;
END
$$ LANGUAGE PLPGSQL VOLATILE SECURITY DEFINER;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._get_geocoder_config(username text, orgname text, provider text DEFAULT NULL)
RETURNS boolean AS $$
cache_key = "user_geocoder_config_{0}".format(username)

View File

@@ -72,109 +72,77 @@ $$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_here_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.tools import LegacyServiceManager
from cartodb_services.here import HereMapsGeocoder
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_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)
# -- Check the quota
quota_service = QuotaService(user_geocoder_config, redis_conn)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
service_manager = LegacyServiceManager('geocoder', username, orgname, GD)
service_manager.assert_within_limits()
try:
geocoder = HereMapsGeocoder(user_geocoder_config.heremaps_app_id, user_geocoder_config.heremaps_app_code, logger)
geocoder = HereMapsGeocoder(service_manager.config.heremaps_app_id, service_manager.config.heremaps_app_code, service_manager.logger, service_manager.config.heremaps_service_params)
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
if coordinates:
quota_service.increment_success_service_use()
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:
quota_service.increment_empty_service_use()
service_manager.quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode street point using here maps', sys.exc_info(), data={"username": username, "orgname": orgname})
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using here maps', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using here maps')
finally:
quota_service.increment_total_service_use()
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_google_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.tools import LegacyServiceManager
from cartodb_services.google import GoogleMapsGeocoder
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_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)
quota_service = QuotaService(user_geocoder_config, redis_conn)
service_manager = LegacyServiceManager('geocoder', username, orgname, GD)
service_manager.assert_within_limits(quota=False)
try:
geocoder = GoogleMapsGeocoder(user_geocoder_config.google_client_id, user_geocoder_config.google_api_key, logger)
geocoder = GoogleMapsGeocoder(service_manager.config.google_client_id, service_manager.config.google_api_key, service_manager.logger)
coordinates = geocoder.geocode(searchtext=searchtext, city=city, state=state_province, country=country)
if coordinates:
quota_service.increment_success_service_use()
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:
quota_service.increment_empty_service_use()
service_manager.quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode street point using google maps', sys.exc_info(), data={"username": username, "orgname": orgname})
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using google maps', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using google maps')
finally:
quota_service.increment_total_service_use()
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server._cdb_mapzen_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 $$
import cartodb_services
cartodb_services.init(plpy, GD)
from cartodb_services.tools import ServiceManager
from cartodb_services.mapzen import MapzenGeocoder
from cartodb_services.mapzen.types import country_to_iso3
from cartodb_services.metrics import QuotaService
from cartodb_services.tools import Logger
from cartodb_services.refactor.tools.logger import LoggerConfigBuilder
from cartodb_services.refactor.service.mapzen_geocoder_config import MapzenGeocoderConfigBuilder
from cartodb_services.refactor.core.environment import ServerEnvironmentBuilder
from cartodb_services.refactor.backend.server_config import ServerConfigBackendFactory
from cartodb_services.refactor.backend.user_config import UserConfigBackendFactory
from cartodb_services.refactor.backend.org_config import OrgConfigBackendFactory
from cartodb_services.refactor.backend.redis_metrics_connection import RedisMetricsConnectionFactory
server_config_backend = ServerConfigBackendFactory().get()
environment = ServerEnvironmentBuilder(server_config_backend).get()
user_config_backend = UserConfigBackendFactory(username, environment, server_config_backend).get()
org_config_backend = OrgConfigBackendFactory(orgname, environment, server_config_backend).get()
import cartodb_services
cartodb_services.init(plpy, GD)
logger_config = LoggerConfigBuilder(environment, server_config_backend).get()
logger = Logger(logger_config)
mapzen_geocoder_config = MapzenGeocoderConfigBuilder(server_config_backend, user_config_backend, org_config_backend, username, orgname).get()
redis_metrics_connection = RedisMetricsConnectionFactory(environment, server_config_backend).get()
quota_service = QuotaService(mapzen_geocoder_config, redis_metrics_connection)
if not quota_service.check_user_quota():
raise Exception('You have reached the limit of your quota')
service_manager = ServiceManager('geocoder', MapzenGeocoderConfigBuilder, username, orgname)
service_manager.assert_within_limits()
try:
geocoder = MapzenGeocoder(mapzen_geocoder_config.mapzen_api_key, logger)
geocoder = MapzenGeocoder(service_manager.config.mapzen_api_key, service_manager.logger, service_manager.config.service_params)
country_iso3 = None
if country:
country_iso3 = country_to_iso3(country)
@@ -182,18 +150,18 @@ RETURNS Geometry AS $$
state_province=state_province,
country=country_iso3, search_type='address')
if coordinates:
quota_service.increment_success_service_use()
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:
quota_service.increment_empty_service_use()
service_manager.quota_service.increment_empty_service_use()
return None
except BaseException as e:
import sys
quota_service.increment_failed_service_use()
logger.error('Error trying to geocode street point using mapzen', sys.exc_info(), data={"username": username, "orgname": orgname})
service_manager.quota_service.increment_failed_service_use()
service_manager.logger.error('Error trying to geocode street point using mapzen', sys.exc_info(), data={"username": username, "orgname": orgname})
raise Exception('Error trying to geocode street point using mapzen')
finally:
quota_service.increment_total_service_use()
service_manager.quota_service.increment_total_service_use()
$$ LANGUAGE plpythonu;

View File

@@ -0,0 +1,91 @@
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_get_rate_limit(
username TEXT,
orgname TEXT,
service TEXT)
RETURNS JSON AS $$
import json
from cartodb_services.config import ServiceConfiguration, RateLimitsConfigBuilder
import cartodb_services
cartodb_services.init(plpy, GD)
service_config = ServiceConfiguration(service, username, orgname)
rate_limit_config = RateLimitsConfigBuilder(service_config.server, service_config.user, service_config.org, service=service, username=username, orgname=orgname).get()
if rate_limit_config.is_limited():
return json.dumps({'limit': rate_limit_config.limit, 'period': rate_limit_config.period})
else:
return None
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_user_rate_limit(
username TEXT,
orgname TEXT,
service TEXT,
rate_limit_json JSON)
RETURNS VOID AS $$
import json
from cartodb_services.config import RateLimitsConfig, RateLimitsConfigSetter
import cartodb_services
cartodb_services.init(plpy, GD)
config_setter = RateLimitsConfigSetter(service=service, username=username, orgname=orgname)
if rate_limit_json:
rate_limit = json.loads(rate_limit_json)
limit = rate_limit.get('limit', None)
period = rate_limit.get('period', None)
else:
limit = None
period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_user_rate_limits(config)
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_org_rate_limit(
username TEXT,
orgname TEXT,
service TEXT,
rate_limit_json JSON)
RETURNS VOID AS $$
import json
from cartodb_services.config import RateLimitsConfig, RateLimitsConfigSetter
import cartodb_services
cartodb_services.init(plpy, GD)
config_setter = RateLimitsConfigSetter(service=service, username=username, orgname=orgname)
if rate_limit_json:
rate_limit = json.loads(rate_limit_json)
limit = rate_limit.get('limit', None)
period = rate_limit.get('period', None)
else:
limit = None
period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_org_rate_limits(config)
$$ LANGUAGE plpythonu;
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_service_set_server_rate_limit(
username TEXT,
orgname TEXT,
service TEXT,
rate_limit_json JSON)
RETURNS VOID AS $$
import json
from cartodb_services.config import RateLimitsConfig, RateLimitsConfigSetter
import cartodb_services
cartodb_services.init(plpy, GD)
config_setter = RateLimitsConfigSetter(service=service, username=username, orgname=orgname)
if rate_limit_json:
rate_limit = json.loads(rate_limit_json)
limit = rate_limit.get('limit', None)
period = rate_limit.get('period', None)
else:
limit = None
period = None
config = RateLimitsConfig(service=service, username=username, limit=limit, period=period)
config_setter.set_server_rate_limits(config)
$$ LANGUAGE plpythonu;

View File

@@ -1,10 +1,11 @@
---- cdb_geocode_namedplace_point(city_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text)
RETURNS Geometry AS $$
import spiexceptions
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name])[0]['point']
except BaseException as e:
except spiexceptions.ExternalRoutineException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3) as point;", ["text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name])[0]['point']
$$ LANGUAGE plpythonu;
@@ -12,10 +13,11 @@ $$ LANGUAGE plpythonu;
---- cdb_geocode_namedplace_point(city_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, country_name text)
RETURNS Geometry AS $$
import spiexceptions
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name, country_name])[0]['point']
except BaseException as e:
except spiexceptions.ExternalRoutineException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, NULL, $4) as point;", ["text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, country_name])[0]['point']
$$ LANGUAGE plpythonu;
@@ -23,10 +25,11 @@ $$ LANGUAGE plpythonu;
---- cdb_geocode_namedplace_point(city_name text, admin1_name text, country_name text)
CREATE OR REPLACE FUNCTION cdb_dataservices_server.cdb_geocode_namedplace_point(username text, orgname text, city_name text, admin1_name text, country_name text)
RETURNS Geometry AS $$
import spiexceptions
try:
mapzen_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_mapzen_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(mapzen_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
except BaseException as e:
except spiexceptions.ExternalRoutineException as e:
internal_plan = plpy.prepare("SELECT cdb_dataservices_server._cdb_internal_geocode_namedplace($1, $2, $3, $4, $5) as point;", ["text", "text", "text", "text", "text"])
return plpy.execute(internal_plan, [username, orgname, city_name, admin1_name, country_name])[0]['point']
$$ LANGUAGE plpythonu;

View File

@@ -20,7 +20,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('You have reached the limit of your quota')
try:
client = HereMapsRoutingIsoline(user_isolines_routing_config.heremaps_app_id,
client = HereMapsRoutingIsoline(user_isolines_routing_config.heremaps_app_id,
user_isolines_routing_config.heremaps_app_code, logger)
if source:
@@ -81,7 +81,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
raise Exception('You have reached the limit of your quota')
try:
client = MatrixClient(user_isolines_routing_config.mapzen_matrix_api_key, logger)
client = MatrixClient(user_isolines_routing_config.mapzen_matrix_api_key, logger, user_isolines_routing_config.mapzen_matrix_service_params)
mapzen_isolines = MapzenIsolines(client, logger)
if source:
@@ -151,7 +151,7 @@ RETURNS SETOF cdb_dataservices_server.isoline AS $$
try:
mapzen_isochrones = MapzenIsochrones(user_isolines_routing_config.mapzen_matrix_api_key,
logger)
logger, user_isolines_routing_config.mapzen_isochrones_service_params)
if source:
lat = plpy.execute("SELECT ST_Y('%s') AS lat" % source)[0]['lat']

View File

@@ -37,7 +37,7 @@ SELECT cartodb.cdb_conf_setconf('logger_conf', '{"geocoder_log_path": "/dev/null
(1 row)
SELECT cartodb.cdb_conf_setconf('data_observatory_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"}, "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}');
cdb_conf_setconf
------------------

View File

@@ -141,6 +141,39 @@ SELECT exists(SELECT *
t
(1 row)
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'obs_getmeta'
AND oidvectortypes(p.proargtypes) = 'text, text, geometry, json, integer, integer, integer');
exists
--------
t
(1 row)
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'obs_getdata'
AND oidvectortypes(p.proargtypes) = 'text, text, geomval[], json, boolean');
exists
--------
t
(1 row)
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'obs_getdata'
AND oidvectortypes(p.proargtypes) = 'text, text, text[], json');
exists
--------
t
(1 row)
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)

View File

@@ -0,0 +1,44 @@
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_get_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text');
exists
--------
t
(1 row)
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_set_user_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text, json');
exists
--------
t
(1 row)
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_set_org_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text, json');
exists
--------
t
(1 row)
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_set_server_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text, json');
exists
--------
t
(1 row)

View File

@@ -0,0 +1,9 @@
\set ECHO none
id | data
----+------
(0 rows)
id | data
----+------
(0 rows)

View File

@@ -14,7 +14,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('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('logger_conf', '{"geocoder_log_path": "/dev/null"}');
SELECT cartodb.cdb_conf_setconf('data_observatory_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"}, "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}');
-- Mock the varnish invalidation function
-- (used by cdb_geocoder tests)

View File

@@ -89,6 +89,27 @@ SELECT exists(SELECT *
AND proname = 'obs_getboundarybyid'
AND oidvectortypes(p.proargtypes) = 'text, text, text, text, text');
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'obs_getmeta'
AND oidvectortypes(p.proargtypes) = 'text, text, geometry, json, integer, integer, integer');
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'obs_getdata'
AND oidvectortypes(p.proargtypes) = 'text, text, geomval[], json, boolean');
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'obs_getdata'
AND oidvectortypes(p.proargtypes) = 'text, text, text[], json');
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)

View File

@@ -0,0 +1,27 @@
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_get_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text');
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_set_user_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text, json');
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_set_org_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text, json');
SELECT exists(SELECT *
FROM pg_proc p
INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'cdb_dataservices_server'
AND proname = 'cdb_service_set_server_rate_limit'
AND oidvectortypes(p.proargtypes) = 'text, text, text, json');

View File

@@ -0,0 +1,65 @@
\set ECHO none
\set VERBOSITY verbose
SET client_min_messages TO error;
-- Set configuration for a user 'foo'
DO $$
import json
from cartodb_services.config import ServiceConfiguration
import cartodb_services
cartodb_services.init(plpy, GD)
service_config = ServiceConfiguration('observatory', 'foo', None)
service_config.user.set('soft_obs_general_limit', True)
service_config.user.set('period_end_date', '20170516')
$$ LANGUAGE plpythonu;
-- Mock Observatory backend function
CREATE SCHEMA cdb_observatory;
CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetData(geomvals geomval[], params JSON, merge BOOLEAN DEFAULT TRUE)
RETURNS TABLE (
id INT,
data JSON
) AS $$
BEGIN
-- this will return an empty set
RAISE NOTICE 'Mocked OBS_GetData()';
END;
$$ LANGUAGE plpgsql;
GRANT USAGE ON SCHEMA cdb_observatory TO geocoder_api;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_observatory TO geocoder_api;
-- Test it
SELECT * FROM cdb_dataservices_server.OBS_GetData(
'foo',
NULL,
'{"(0103000020E61000000100000005000000010000E0F67F52C096D88AE6B25F4440010000E0238052C0BF6D8A1A8D5D4440010000D0DA7E52C05F03F3CC265D444001000020F47E52C0F2DD78AB5D5F4440010000E0F67F52C096D88AE6B25F4440,1)"}'::public._geomval,
'[{"id": 1, "score": 52.7515548093083898758340051256007949661290516400338, "geom_id": "us.census.tiger.census_tract", "denom_id": "us.census.acs.B01003001", "numer_id": "us.census.acs.B03002003", "geom_name": "US Census Tracts", "geom_type": "Geometry", "num_geoms": 2.86483076549783307739486952736, "denom_name": "Total Population", "denom_type": "Numeric", "numer_name": "White Population", "numer_type": "Numeric", "score_rank": 1, "target_area": 0.000307374806576033, "geom_colname": "the_geom", "score_rownum": 1, "target_geoms": null, "denom_colname": "total_pop", "denom_reltype": '
'"denominator", "geom_timespan": "2015", "normalization": "prenormalized", "numer_colname": "white_pop", "timespan_rank": 1, "geom_tablename": "obs_87a814e485deabe3b12545a537f693d16ca702c2", "max_score_rank": null, "numer_timespan": "2010 - 2014", "suggested_name": "white_pop_2010_2014", "denom_aggregate": "sum", "denom_tablename": "obs_b393b5b88c6adda634b2071a8005b03c551b609a", "numer_aggregate": "sum", "numer_tablename": "obs_b393b5b88c6adda634b2071a8005b03c551b609a", "timespan_rownum": 1, "geom_description": "Census tracts are small, relatively permanent statistical subdivisions of a county or equivalent entity that are updated by local participants prior to each decennial census as part of the Census Bureaus Participant Statistical Areas Program. The Census Bureau delineates census tracts in situations where no local participant existed or where state, local, or tribal governments'
'declined to participate. The primary purpose of census tracts is to provide a stable set of geographic units for the presentation of statistical data.\r\n\r\nCensus tracts generally have a population size between 1,200 and 8,000 people, with an optimum size of 4,000 people. A census tract usually covers a contiguous area; however, the spatial size of census tracts varies widely depending on the density of settlement. Census tract boundaries are delineated with the intention of being maintained over a long time so that statistical comparisons can be made from census to census. Census tracts occasionally are split due to population growth or merged as a result of substantial population decline.\r\n\r\nCensus tract boundaries generally follow visible and identifiable features. They may follow nonvisible legal boundaries, such as minor civil division (MCD) or incorporated place boundaries'
'in some states and situations, to allow for census-tract-to-governmental-unit relationships where the governmental boundaries tend to remain unchanged between censuses. State and county boundaries always are census tract boundaries in the standard census geographic hierarchy. Tribal census tracts are a unique geographic entity defined within federally recognized American Indian reservations and off-reservation trust lands and can cross state and county boundaries. Tribal census tracts may be completely different from the census tracts and block groups defined by state and county (see “Tribal Census Tract”).", "denom_description": "The total number of all people living in a given geographic area. This is a very useful catch-all denominator when calculating rates.", "max_timespan_rank": null, "numer_description": "The number of people identifying as white, non-Hispanic in each'
'geography.", "geom_t_description": null, "denom_t_description": null, "numer_t_description": null, "geom_geomref_colname": "geoid", "denom_geomref_colname": "geoid", "numer_geomref_colname": "geoid"}]'::json,
true);
-- Mock another observatory backend function (overloaded, different params)
CREATE OR REPLACE FUNCTION cdb_observatory.OBS_GetData(geomrefs TEXT[], params JSON)
RETURNS TABLE (
id INT,
data JSON
) AS $$
BEGIN
-- this will return an empty set
RAISE NOTICE 'Mocked OBS_GetData()';
END;
$$ LANGUAGE plpgsql;
GRANT USAGE ON SCHEMA cdb_observatory TO geocoder_api;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA cdb_observatory TO geocoder_api;
-- Test it
SELECT * FROM cdb_dataservices_server.OBS_GetData('foo', NULL, '{bar, baz}'::TEXT[], '[]'::JSON);

View File

@@ -7,12 +7,7 @@ It is used from pl/python functions contained in the `cdb_dataservices_server` e
On the other hand, it is pretty independent from the client, as long as the signatures of the public pl/python functions match.
## Dependencies
See the [[`requirements.txt`]] or better the Basically:
- pip
- redis and hiredis
- dateutil
- googlemaps
- request
Take a look at [`requirements.txt`](requirements.txt) for details about the required dependencies.
## Installation
Install the requirements:
@@ -40,11 +35,13 @@ OK
```
## Running the integration tests
See the [[../../../../test/README.md]]. Basically, move to the `/test` directory at the top level of this repo and execute the `run_tests.py` script:
See this [`README`](../../../../test/README.md) in the `/test` directory for details. Basically, you have to move to the `/test` directory at the top level of this repo and execute the `run_tests.py` script:
```sh
cd $(git rev-parse --show-toplevel)/test
python run_tests.py --host=$YOUR_HOST $YOUR_USERNAME $YOUR_API_KEY
```
## TODO
- Move dependencies expressed in `requirements.txt` to `setup.py`
## Versioning
Once you're satisfied with your changes, it is time to bump the version number in the `setup.py`. A couple of rules:
- **Backwards compatibility**: in general all changes shall be backwards compatible. Do not remove any code used from the server public `pl/python` functions or you'll run into problems when deploying.
- **Semantic versioning**: we try to stick to [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html)

View File

@@ -0,0 +1,3 @@
from service_configuration import ServiceConfiguration
from rate_limits import RateLimitsConfig, RateLimitsConfigBuilder, RateLimitsConfigSetter
from legacy_rate_limits import RateLimitsConfigLegacyBuilder

View File

@@ -0,0 +1,46 @@
import json
from rate_limits import RateLimitsConfig
class RateLimitsConfigLegacyBuilder(object):
"""
Build a RateLimitsConfig object using the *legacy* configuration classes
"""
def __init__(self, redis_connection, db_conn, service, username, orgname):
self._service = service
self._username = username
self._orgname = orgname
self._redis_connection = redis_connection
self._db_conn = db_conn
def get(self):
rate_limit = self.__get_rate_limit()
return RateLimitsConfig(self._service,
self._username,
rate_limit.get('limit', None),
rate_limit.get('period', None))
def __get_rate_limit(self):
rate_limit = {}
rate_limit_key = "{0}_rate_limit".format(self._service)
user_key = "rails:users:{0}".format(self._username)
rate_limit_json = self.__get_redis_config(user_key, rate_limit_key)
if not rate_limit_json and self._orgname:
org_key = "rails:orgs:{0}".format(self._orgname)
rate_limit_json = self.__get_redis_config(org_key, rate_limit_key)
if rate_limit_json:
rate_limit = json.loads(rate_limit_json)
else:
conf_key = 'rate_limits'
sql = "SELECT cdb_dataservices_server.CDB_Conf_GetConf('{0}') as conf".format(conf_key)
try:
conf = self._db_conn.execute(sql, 1)[0]['conf']
except Exception:
conf = None
if conf:
rate_limit = json.loads(conf).get(self._service)
return rate_limit or {}
def __get_redis_config(self, basekey, param):
config = self._redis_connection.hgetall(basekey)
return config and config.get(param)

View File

@@ -0,0 +1,113 @@
import json
from service_configuration import ServiceConfiguration
class RateLimitsConfig(object):
"""
Value object that represents the configuration needed to rate-limit services
"""
def __init__(self,
service,
username,
limit,
period):
self._service = service
self._username = username
self._limit = limit and int(limit)
self._period = period and int(period)
def __eq__(self, other):
return self.__dict__ == other.__dict__
# service this limit applies to
@property
def service(self):
return self._service
# user this limit applies to
@property
def username(self):
return self._username
# rate period in seconds
@property
def period(self):
return self._period
# rate limit in seconds
@property
def limit(self):
return self._limit
def is_limited(self):
return self._limit and self._limit > 0 and self._period and self._period > 0
class RateLimitsConfigBuilder(object):
"""
Build a rate limits configuration obtaining the parameters
from the user/org/server configuration.
"""
def __init__(self, server_conf, user_conf, org_conf, service, username, orgname):
self._server_conf = server_conf
self._user_conf = user_conf
self._org_conf = org_conf
self._service = service
self._username = username
self._orgname = orgname
def get(self):
# Order of precedence is user_conf, org_conf, server_conf
rate_limit_key = "{0}_rate_limit".format(self._service)
rate_limit_json = self._user_conf.get(rate_limit_key, None) or self._org_conf.get(rate_limit_key, None)
if (rate_limit_json):
rate_limit = rate_limit_json and json.loads(rate_limit_json)
else:
rate_limit = self._server_conf.get('rate_limits', {}).get(self._service, {})
return RateLimitsConfig(self._service,
self._username,
rate_limit.get('limit', None),
rate_limit.get('period', None))
class RateLimitsConfigSetter(object):
def __init__(self, service, username, orgname=None):
self._service = service
self._service_config = ServiceConfiguration(service, username, orgname)
def set_user_rate_limits(self, rate_limits_config):
# Note we allow copying a config from another user/service, so we
# ignore rate_limits:config.service and rate_limits:config.username
rate_limit_key = "{0}_rate_limit".format(self._service)
if rate_limits_config.is_limited():
rate_limit = {'limit': rate_limits_config.limit, 'period': rate_limits_config.period}
rate_limit_json = json.dumps(rate_limit)
self._service_config.user.set(rate_limit_key, rate_limit_json)
else:
self._service_config.user.remove(rate_limit_key)
def set_org_rate_limits(self, rate_limits_config):
rate_limit_key = "{0}_rate_limit".format(self._service)
if rate_limits_config.is_limited():
rate_limit = {'limit': rate_limits_config.limit, 'period': rate_limits_config.period}
rate_limit_json = json.dumps(rate_limit)
self._service_config.org.set(rate_limit_key, rate_limit_json)
else:
self._service_config.org.remove(rate_limit_key)
def set_server_rate_limits(self, rate_limits_config):
rate_limits = self._service_config.server.get('rate_limits', {})
if rate_limits_config.is_limited():
rate_limits[self._service] = {'limit': rate_limits_config.limit, 'period': rate_limits_config.period}
else:
rate_limits.pop(self._service, None)
if rate_limits:
self._service_config.server.set('rate_limits', rate_limits)
else:
self._service_config.server.remove('rate_limits')

View File

@@ -0,0 +1,36 @@
from cartodb_services.refactor.core.environment import ServerEnvironmentBuilder
from cartodb_services.refactor.backend.server_config import ServerConfigBackendFactory
from cartodb_services.refactor.backend.user_config import UserConfigBackendFactory
from cartodb_services.refactor.backend.org_config import OrgConfigBackendFactory
class ServiceConfiguration(object):
"""
This class instantiates configuration backend objects for all the configuration levels of a service:
* environment
* server
* organization
* user
The configuration backends allow retrieval and modification of configuration parameters.
"""
def __init__(self, service, username, orgname):
self._server_config_backend = ServerConfigBackendFactory().get()
self._environment = ServerEnvironmentBuilder(self._server_config_backend ).get()
self._user_config_backend = UserConfigBackendFactory(username, self._environment, self._server_config_backend ).get()
self._org_config_backend = OrgConfigBackendFactory(orgname, self._environment, self._server_config_backend ).get()
@property
def environment(self):
return self._environment
@property
def server(self):
return self._server_config_backend
@property
def user(self):
return self._user_config_backend
@property
def org(self):
return self._org_config_backend

View File

@@ -2,6 +2,8 @@
# -*- coding: utf-8 -*-
import json
class InvalidGoogleCredentials(Exception):
pass
class BadGeocodingParams(Exception):
def __init__(self, value):

View File

@@ -1,15 +1,18 @@
#!/usr/local/bin/python
# -*- coding: utf-8 -*-
import base64
import googlemaps
from exceptions import MalformedResult
from exceptions import MalformedResult, InvalidGoogleCredentials
class GoogleMapsGeocoder:
"""A Google Maps Geocoder wrapper for python"""
def __init__(self, client_id, client_secret, logger):
if not self._valid_credentials(client_secret):
raise InvalidGoogleCredentials('Invalid google secret key')
self.client_id = self._clean_client_id(client_id)
self.client_secret = client_secret
self.geocoder = googlemaps.Client(
@@ -36,7 +39,7 @@ class GoogleMapsGeocoder:
return [longitude, latitude]
def _build_optional_parameters(self, city=None, state=None,
country=None):
country=None):
optional_params = {}
if city:
optional_params['locality'] = city
@@ -49,3 +52,13 @@ class GoogleMapsGeocoder:
def _clean_client_id(self, client_id):
# Consistency with how the client_id is saved in metadata
return client_id.replace('client=', '')
def _valid_credentials(self, private_key):
try:
# Only fails if the string dont have a correct padding for b64
# but this way we could provide a more clear error than
# TypeError: Incorrect padding
base64.b64decode(private_key)
return True
except TypeError:
return False

View File

@@ -18,7 +18,7 @@ class HereMapsGeocoder(Traceable):
DEFAULT_GEN = 9
READ_TIMEOUT = 60
CONNECT_TIMEOUT = 10
MAX_RETRIES=3
MAX_RETRIES=1
ADDRESS_PARAMS = [
'city',
@@ -52,14 +52,17 @@ class HereMapsGeocoder(Traceable):
'strictlanguagemode'
] + ADDRESS_PARAMS
def __init__(self, app_id, app_code, logger, maxresults=DEFAULT_MAXRESULTS,
gen=DEFAULT_GEN, host=PRODUCTION_GEOCODE_JSON_URL):
def __init__(self, app_id, app_code, logger, service_params=None, maxresults=DEFAULT_MAXRESULTS):
service_params = service_params or {}
self.app_id = app_id
self.app_code = app_code
self._logger = logger
self.maxresults = maxresults
self.gen = gen
self.host = host
self.gen = service_params.get('gen', self.DEFAULT_GEN)
self.host = service_params.get('json_url', self.PRODUCTION_GEOCODE_JSON_URL)
self.connect_timeout = service_params.get('connect_timeout', self.CONNECT_TIMEOUT)
self.read_timeout = service_params.get('read_timeout', self.READ_TIMEOUT)
self.max_retries = service_params.get('max_retries', self.MAX_RETRIES)
def geocode(self, **kwargs):
params = {}
@@ -92,9 +95,9 @@ class HereMapsGeocoder(Traceable):
request_params.update(params)
# TODO Extract HTTP client wrapper
session = requests.Session()
session.mount(self.host, HTTPAdapter(self.MAX_RETRIES))
session.mount(self.host, HTTPAdapter(max_retries=self.max_retries))
response = session.get(self.host, params=request_params,
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
timeout=(self.connect_timeout, self.read_timeout))
self.add_response_data(response, self._logger)
if response.status_code == requests.codes.ok:
return json.loads(response.text)

View File

@@ -14,7 +14,7 @@ class HereMapsRoutingIsoline(Traceable):
ISOLINE_PATH = '/routing/7.2/calculateisoline.json'
READ_TIMEOUT = 60
CONNECT_TIMEOUT = 10
MAX_RETRIES = 3
MAX_RETRIES = 1
ACCEPTED_MODES = {
"walk": "pedestrian",
@@ -30,12 +30,17 @@ class HereMapsRoutingIsoline(Traceable):
'quality'
]
def __init__(self, app_id, app_code, logger,
base_url=PRODUCTION_ROUTING_BASE_URL):
def __init__(self, app_id, app_code, logger, service_params=None):
service_params = service_params or {}
self._app_id = app_id
self._app_code = app_code
self._logger = logger
self._url = "{0}{1}".format(base_url, self.ISOLINE_PATH)
base_url = service_params.get('base_url', self.PRODUCTION_ROUTING_BASE_URL)
isoline_path = service_params.get('isoline_path', self.ISOLINE_PATH)
self.connect_timeout = service_params.get('connect_timeout', self.CONNECT_TIMEOUT)
self.read_timeout = service_params.get('read_timeout', self.READ_TIMEOUT)
self.max_retries = service_params.get('max_retries', self.MAX_RETRIES)
self._url = "{0}{1}".format(base_url, isoline_path)
def calculate_isodistance(self, source, mode, data_range, options=[]):
return self.__calculate_isolines(source, mode, data_range, 'distance',
@@ -57,9 +62,9 @@ class HereMapsRoutingIsoline(Traceable):
parsed_options)
# TODO Extract HTTP client wrapper
session = requests.Session()
session.mount(self._url, HTTPAdapter(self.MAX_RETRIES))
session.mount(self._url, HTTPAdapter(max_retries=self.max_retries))
response = requests.get(self._url, params=request_params,
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
timeout=(self.connect_timeout, self.read_timeout))
self.add_response_data(response, self._logger)
if response.status_code == requests.codes.ok:
return self.__parse_isolines_response(response.text)

View File

@@ -15,25 +15,34 @@ class MapzenGeocoder(Traceable):
BASE_URL = 'https://search.mapzen.com/v1/search'
READ_TIMEOUT = 60
CONNECT_TIMEOUT = 10
MAX_RETRIES = 3
MAX_RETRIES = 1
def __init__(self, app_key, logger, base_url=BASE_URL):
def __init__(self, app_key, logger, service_params=None):
service_params = service_params or {}
self._app_key = app_key
self._url = base_url
self._url = service_params.get('base_url', self.BASE_URL)
self._connect_timeout = service_params.get('connect_timeout', self.CONNECT_TIMEOUT)
self._read_timeout = service_params.get('read_timeout', self.READ_TIMEOUT)
self._max_retries = service_params.get('max_retries', self.MAX_RETRIES)
self._logger = logger
@qps_retry(qps=20)
def geocode(self, searchtext, city=None, state_province=None,
country=None, search_type=None):
# Remove the search_type if its address from the params sent to mapzen
if search_type and search_type.lower() == 'address':
search_type = None
request_params = self._build_requests_parameters(searchtext, city,
state_province,
country, search_type)
try:
# TODO Extract HTTP client wrapper
session = requests.Session()
session.mount(self._url, HTTPAdapter(self.MAX_RETRIES))
session.mount(self._url, HTTPAdapter(max_retries=self._max_retries))
response = session.get(self._url, params=request_params,
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
timeout=(self._connect_timeout, self._read_timeout))
self.add_response_data(response, self._logger)
if response.status_code == requests.codes.ok:
return self.__parse_response(response.text)

View File

@@ -13,29 +13,34 @@ class MapzenIsochrones:
BASE_URL = 'https://matrix.mapzen.com/isochrone'
READ_TIMEOUT = 60
CONNECT_TIMEOUT = 10
MAX_RETRIES = 3
MAX_RETRIES = 1
ACCEPTED_MODES = {
"walk": "pedestrian",
"car": "auto"
}
def __init__(self, app_key, logger, base_url=BASE_URL):
def __init__(self, app_key, logger, service_params=None):
service_params = service_params or {}
self._app_key = app_key
self._url = base_url
self._logger = logger
self._url = service_params.get('base_url', self.BASE_URL)
self._connect_timeout = service_params.get('connect_timeout', self.CONNECT_TIMEOUT)
self._read_timeout = service_params.get('read_timeout', self.READ_TIMEOUT)
self._max_retries = service_params.get('max_retries', self.MAX_RETRIES)
@qps_retry
@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))
session.mount(self._url, HTTPAdapter(max_retries=self._max_retries))
response = session.get(self._url, params=request_params,
timeout=(self.CONNECT_TIMEOUT,
self.READ_TIMEOUT))
timeout=(self._connect_timeout,
self._read_timeout))
if response.status_code is requests.codes.ok:
return self._parse_response(response)

View File

@@ -23,9 +23,14 @@ class MatrixClient(Traceable):
READ_TIMEOUT = 60
CONNECT_TIMEOUT = 10
def __init__(self, matrix_key, logger):
def __init__(self, matrix_key, logger, service_params=None):
service_params = service_params or {}
self._matrix_key = matrix_key
self._logger = logger
self._url = service_params.get('one_to_many_url', self.ONE_TO_MANY_URL)
self._connect_timeout = service_params.get('connect_timeout', self.CONNECT_TIMEOUT)
self._read_timeout = service_params.get('read_timeout', self.READ_TIMEOUT)
"""Get distances and times to a set of locations.
See https://mapzen.com/documentation/matrix/api-reference/
@@ -44,8 +49,8 @@ class MatrixClient(Traceable):
'costing': costing,
'api_key': self._matrix_key
}
response = requests.get(self.ONE_TO_MANY_URL, params=request_params,
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
response = requests.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:

View File

@@ -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.total_seconds() > self._retry_timeout:
raise TimeoutException()
# inverse qps * (1.5 ^ i) is an increased sleep time of 1.5x per

View File

@@ -15,7 +15,7 @@ class MapzenRouting(Traceable):
PRODUCTION_ROUTING_BASE_URL = 'https://valhalla.mapzen.com/route'
READ_TIMEOUT = 60
CONNECT_TIMEOUT = 10
MAX_RETRIES=3
MAX_RETRIES=1
ACCEPTED_MODES = {
"walk": "pedestrian",
@@ -33,10 +33,14 @@ class MapzenRouting(Traceable):
METRICS_UNITS = 'kilometers'
IMPERIAL_UNITS = 'miles'
def __init__(self, app_key, logger, base_url=PRODUCTION_ROUTING_BASE_URL):
def __init__(self, app_key, logger, service_params=None):
service_params = service_params or {}
self._app_key = app_key
self._url = base_url
self._logger = logger
self._url = service_params.get('base_url', self.PRODUCTION_ROUTING_BASE_URL)
self._connect_timeout = service_params.get('connect_timeout', self.CONNECT_TIMEOUT)
self._read_timeout = service_params.get('read_timeout', self.READ_TIMEOUT)
self._max_retries = service_params.get('max_retries', self.MAX_RETRIES)
@qps_retry
def calculate_route_point_to_point(self, waypoints, mode,
@@ -50,9 +54,9 @@ class MapzenRouting(Traceable):
request_params = self.__parse_request_parameters(json_request_params)
# TODO Extract HTTP client wrapper
session = requests.Session()
session.mount(self._url, HTTPAdapter(self.MAX_RETRIES))
session.mount(self._url, HTTPAdapter(max_retries=self._max_retries))
response = session.get(self._url, params=request_params,
timeout=(self.CONNECT_TIMEOUT, self.READ_TIMEOUT))
timeout=(self._connect_timeout, self._read_timeout))
self.add_response_data(response, self._logger)
if response.status_code == requests.codes.ok:
return self.__parse_routing_response(response.text)

View File

@@ -43,12 +43,20 @@ class ServiceConfig(object):
def metrics_log_path(self):
return self._metrics_log_path
def _get_effective_monthly_quota(self, quota_key, default=0):
quota_from_redis = self._redis_config.get(quota_key, None)
if quota_from_redis and quota_from_redis <> '':
return int(quota_from_redis)
else:
return default
def __get_metrics_log_path(self):
if self.METRICS_LOG_KEY:
return self._db_config.logger_config.get(self.METRICS_LOG_KEY, None)
else:
return None
class DataObservatoryConfig(ServiceConfig):
METRICS_LOG_KEY = 'do_log_path'
@@ -92,9 +100,7 @@ class ObservatorySnapshotConfig(DataObservatoryConfig):
self._soft_limit = True
else:
self._soft_limit = False
self._monthly_quota = 0
if self.QUOTA_KEY in self._redis_config:
self._monthly_quota = int(self._redis_config[self.QUOTA_KEY])
self._monthly_quota = self._get_effective_monthly_quota(self.QUOTA_KEY)
self._connection_str = self._db_config.data_observatory_connection_str
@property
@@ -116,9 +122,7 @@ class ObservatoryConfig(DataObservatoryConfig):
self._soft_limit = True
else:
self._soft_limit = False
self._monthly_quota = 0
if self.QUOTA_KEY in self._redis_config:
self._monthly_quota = int(self._redis_config[self.QUOTA_KEY])
self._monthly_quota = self._get_effective_monthly_quota(self.QUOTA_KEY)
self._connection_str = self._db_config.data_observatory_connection_str
@property
@@ -143,6 +147,7 @@ class RoutingConfig(ServiceConfig):
if not self._routing_provider:
self._routing_provider = self.DEFAULT_PROVIDER
self._mapzen_api_key = self._db_config.mapzen_routing_api_key
self._mapzen_service_params = self._db_config.mapzen_routing_service_params
self._set_monthly_quota()
self._set_soft_limit()
self._period_end_date = date_parse(self._redis_config[self.PERIOD_END_DATE])
@@ -160,6 +165,10 @@ class RoutingConfig(ServiceConfig):
def mapzen_api_key(self):
return self._mapzen_api_key
@property
def mapzen_service_params(self):
return self._mapzen_service_params
@property
def monthly_quota(self):
return self._monthly_quota
@@ -173,14 +182,7 @@ class RoutingConfig(ServiceConfig):
return self._soft_limit
def _set_monthly_quota(self):
self._monthly_quota = self._get_effective_monthly_quota()
def _get_effective_monthly_quota(self):
quota_from_redis = self._redis_config.get(self.QUOTA_KEY)
if quota_from_redis and quota_from_redis <> '':
return int(quota_from_redis)
else:
return self._db_config.mapzen_routing_monthly_quota
self._monthly_quota = self._get_effective_monthly_quota(self.QUOTA_KEY)
def _set_soft_limit(self):
if self.SOFT_LIMIT_KEY in self._redis_config and self._redis_config[self.SOFT_LIMIT_KEY].lower() == 'true':
@@ -202,7 +204,7 @@ class IsolinesRoutingConfig(ServiceConfig):
GEOCODER_PROVIDER_KEY = 'geocoder_provider'
MAPZEN_PROVIDER = 'mapzen'
HEREMAPS_PROVIDER = 'heremaps'
DEFAULT_PROVIDER = 'heremaps'
DEFAULT_PROVIDER = 'mapzen'
METRICS_LOG_KEY = 'isolines_log_path'
def __init__(self, redis_connection, db_conn, username, orgname=None):
@@ -217,18 +219,19 @@ class IsolinesRoutingConfig(ServiceConfig):
self._isolines_provider = self.DEFAULT_PROVIDER
self._geocoder_provider = filtered_config[self.GEOCODER_PROVIDER_KEY].lower()
self._period_end_date = date_parse(filtered_config[self.PERIOD_END_DATE])
self._isolines_quota = self._get_effective_monthly_quota(self.QUOTA_KEY)
if filtered_config[self.SOFT_LIMIT_KEY].lower() == 'true':
self._soft_isolines_limit = True
else:
self._soft_isolines_limit = False
if self._isolines_provider == self.HEREMAPS_PROVIDER:
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':
self._soft_isolines_limit = True
else:
self._soft_isolines_limit = False
self._heremaps_service_params = db_config.heremaps_isolines_service_params
elif self._isolines_provider == self.MAPZEN_PROVIDER:
self._mapzen_matrix_api_key = self._db_config.mapzen_matrix_api_key
self._isolines_quota = self._db_config.mapzen_matrix_monthly_quota
self._soft_isolines_limit = False
self._mapzen_matrix_service_params = db_config.mapzen_matrix_service_params
self._mapzen_isochrones_service_params = db_config.mapzen_isochrones_service_params
@property
def service_type(self):
@@ -261,10 +264,22 @@ class IsolinesRoutingConfig(ServiceConfig):
def heremaps_app_code(self):
return self._heremaps_app_code
@property
def heremaps_service_params(self):
return self._heremaps_service_params
@property
def mapzen_matrix_api_key(self):
return self._mapzen_matrix_api_key
@property
def mapzen_matrix_service_params(self):
return self._mapzen_matrix_service_params
@property
def mapzen_isochrones_service_params(self):
return self._mapzen_isochrones_service_params
@property
def mapzen_provider(self):
return self._isolines_provider == self.MAPZEN_PROVIDER
@@ -344,13 +359,13 @@ class GeocoderConfig(ServiceConfig):
if self._geocoder_provider == self.NOKIA_GEOCODER:
if not set(self.NOKIA_GEOCODER_REDIS_MANDATORY_KEYS).issubset(set(filtered_config.keys())) or \
not self.heremaps_app_id or not self.heremaps_app_code:
raise ConfigException("""Some mandatory parameter/s for Nokia geocoder are missing. Check it please""")
raise ConfigException("""Heremaps app id or app code is not set up""")
elif self._geocoder_provider == self.GOOGLE_GEOCODER:
if self.GOOGLE_GEOCODER_API_KEY not in filtered_config.keys():
raise ConfigException("""Google geocoder need the mandatory parameter 'google_maps_private_key'""")
raise ConfigException("""Google geocoder private key is not set up""")
elif self._geocoder_provider == self.MAPZEN_GEOCODER:
if not self.mapzen_api_key:
raise ConfigException("""Mapzen config is not setted up""")
raise ConfigException("""Mapzen config is not set up""")
return True
@@ -361,8 +376,10 @@ class GeocoderConfig(ServiceConfig):
self._geocoder_provider = filtered_config[self.GEOCODER_PROVIDER].lower()
else:
self._geocoder_provider = self.DEFAULT_PROVIDER
self._geocoding_quota = int(filtered_config[self.QUOTA_KEY])
self._geocoding_quota = self._get_effective_monthly_quota(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
else:
@@ -371,14 +388,15 @@ class GeocoderConfig(ServiceConfig):
self._heremaps_app_id = db_config.heremaps_geocoder_app_id
self._heremaps_app_code = db_config.heremaps_geocoder_app_code
self._cost_per_hit = db_config.heremaps_geocoder_cost_per_hit
self._heremaps_service_params = db_config.heremaps_geocoder_service_params
elif self._geocoder_provider == self.GOOGLE_GEOCODER:
self._google_maps_api_key = filtered_config[self.GOOGLE_GEOCODER_API_KEY]
self._google_maps_client_id = filtered_config[self.GOOGLE_GEOCODER_CLIENT_ID]
self._cost_per_hit = 0
elif self._geocoder_provider == self.MAPZEN_GEOCODER:
self._mapzen_api_key = db_config.mapzen_geocoder_api_key
self._geocoding_quota = db_config.mapzen_geocoder_monthly_quota
self._cost_per_hit = 0
self._mapzen_service_params = db_config.mapzen_geocoder_service_params
@property
def service_type(self):
@@ -432,10 +450,18 @@ class GeocoderConfig(ServiceConfig):
def heremaps_app_code(self):
return self._heremaps_app_code
@property
def heremaps_service_params(self):
return self._heremaps_service_params
@property
def mapzen_api_key(self):
return self._mapzen_api_key
@property
def mapzen_service_params(self):
return self._mapzen_service_params
@property
def is_high_resolution(self):
return True
@@ -448,6 +474,9 @@ class GeocoderConfig(ServiceConfig):
def provider(self):
return self._geocoder_provider
@property
def service(self):
return self._service
class ServicesDBConfig:
@@ -484,8 +513,10 @@ class ServicesDBConfig:
self._heremaps_geocoder_app_code = heremaps_conf['geocoder']['app_code']
self._heremaps_geocoder_cost_per_hit = heremaps_conf['geocoder'][
'geocoder_cost_per_hit']
self._heremaps_geocoder_service_params = heremaps_conf['geocoder'].get('service', {})
self._heremaps_isolines_app_id = heremaps_conf['isolines']['app_id']
self._heremaps_isolines_app_code = heremaps_conf['isolines']['app_code']
self._heremaps_isolines_service_params = heremaps_conf['isolines'].get('service', {})
def _get_mapzen_config(self):
mapzen_conf_json = self._get_conf('mapzen_conf')
@@ -495,10 +526,14 @@ class ServicesDBConfig:
mapzen_conf = json.loads(mapzen_conf_json)
self._mapzen_matrix_api_key = mapzen_conf['matrix']['api_key']
self._mapzen_matrix_quota = mapzen_conf['matrix']['monthly_quota']
self._mapzen_matrix_service_params = mapzen_conf['matrix'].get('service', {})
self._mapzen_isochrones_service_params = mapzen_conf.get('isochrones', {}).get('service', {})
self._mapzen_routing_api_key = mapzen_conf['routing']['api_key']
self._mapzen_routing_quota = mapzen_conf['routing']['monthly_quota']
self._mapzen_routing_service_params = mapzen_conf['routing'].get('service', {})
self._mapzen_geocoder_api_key = mapzen_conf['geocoder']['api_key']
self._mapzen_geocoder_quota = mapzen_conf['geocoder']['monthly_quota']
self._mapzen_geocoder_service_params = mapzen_conf['geocoder'].get('service', {})
def _get_data_observatory_config(self):
do_conf_json = self._get_conf('data_observatory_conf')
@@ -516,7 +551,7 @@ class ServicesDBConfig:
def _get_conf(self, key):
try:
sql = "SELECT cartodb.CDB_Conf_GetConf('{0}') as conf".format(key)
sql = "SELECT cdb_dataservices_server.CDB_Conf_GetConf('{0}') as conf".format(key)
conf = self._db_conn.execute(sql, 1)
return conf[0]['conf']
except Exception as e:
@@ -534,6 +569,10 @@ class ServicesDBConfig:
def heremaps_isolines_app_code(self):
return self._heremaps_isolines_app_code
@property
def heremaps_isolines_service_params(self):
return self._heremaps_isolines_service_params
@property
def heremaps_geocoder_app_id(self):
return self._heremaps_geocoder_app_id
@@ -546,6 +585,10 @@ class ServicesDBConfig:
def heremaps_geocoder_cost_per_hit(self):
return self._heremaps_geocoder_cost_per_hit
@property
def heremaps_geocoder_service_params(self):
return self._heremaps_geocoder_service_params
@property
def mapzen_matrix_api_key(self):
return self._mapzen_matrix_api_key
@@ -554,6 +597,14 @@ class ServicesDBConfig:
def mapzen_matrix_monthly_quota(self):
return self._mapzen_matrix_quota
@property
def mapzen_matrix_service_params(self):
return self._mapzen_matrix_service_params
@property
def mapzen_isochrones_service_params(self):
return self._mapzen_isochrones_service_params
@property
def mapzen_routing_api_key(self):
return self._mapzen_routing_api_key
@@ -562,6 +613,10 @@ class ServicesDBConfig:
def mapzen_routing_monthly_quota(self):
return self._mapzen_routing_quota
@property
def mapzen_routing_service_params(self):
return self._mapzen_routing_service_params
@property
def mapzen_geocoder_api_key(self):
return self._mapzen_geocoder_api_key
@@ -570,6 +625,10 @@ class ServicesDBConfig:
def mapzen_geocoder_monthly_quota(self):
return self._mapzen_geocoder_quota
@property
def mapzen_geocoder_service_params(self):
return self._mapzen_geocoder_service_params
@property
def data_observatory_connection_str(self):
return self._data_observatory_connection_str

View File

@@ -1,5 +1,17 @@
from datetime import date, timedelta
from dateutil.relativedelta import relativedelta
from calendar import monthrange
def last_day_of_month(year, month):
"""last valid day of a month"""
return monthrange(year, month)[1]
def latest_valid_date(year, month, day):
"""latest date not later than the day specified"""
valid_day = min(day, last_day_of_month(year, month))
return date(year, month, valid_day)
class UserMetricsService:
@@ -8,6 +20,7 @@ class UserMetricsService:
SERVICE_GEOCODER_NOKIA = 'geocoder_here'
SERVICE_GEOCODER_CACHE = 'geocoder_cache'
SERVICE_HERE_ISOLINES = 'here_isolines'
SERVICE_MAPZEN_ISOLINES = 'mapzen_isolines'
SERVICE_MAPZEN_ROUTING = 'routing_mapzen'
SERVICE_OBSERVATORY = 'obs_general'
DAY_OF_MONTH_ZERO_PADDED = '%d'
@@ -21,6 +34,8 @@ class UserMetricsService:
def used_quota(self, service_type, date):
if service_type == self.SERVICE_HERE_ISOLINES:
return self.__used_isolines_quota(service_type, date)
if service_type == self.SERVICE_MAPZEN_ISOLINES:
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:
@@ -103,12 +118,9 @@ class UserMetricsService:
for date in self.__generate_date_range(date_from, date_to):
redis_prefix = self.__parse_redis_prefix(key_prefix, entity_name,
service, metric, date)
score = self._redis_connection.zscore(redis_prefix, date.day)
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 += int(score) if score else 0
score = self._redis_connection.zscore(redis_prefix, zero_padded_day)
aggregated_metric += int(score) if score else 0
return aggregated_metric
@@ -143,9 +155,9 @@ class UserMetricsService:
today = date.today()
if end_period_day > today.day:
temp_date = today + relativedelta(months=-1)
date_from = date(temp_date.year, temp_date.month, end_period_day)
date_from = latest_valid_date(temp_date.year, temp_date.month, end_period_day)
else:
date_from = date(today.year, today.month, end_period_day)
date_from = latest_valid_date(today.year, today.month, end_period_day)
return date_from, today

View File

@@ -6,6 +6,6 @@ class ConfigBackendInterface(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def get(self, key):
def get(self, key, default=None):
"""Return a value based on the key supplied from some storage"""
pass

View File

@@ -13,7 +13,8 @@ class MapzenGeocoderConfig(object):
log_path,
mapzen_api_key,
username,
organization):
organization,
service_params):
self._geocoding_quota = geocoding_quota
self._soft_geocoding_limit = soft_geocoding_limit
self._period_end_date = period_end_date
@@ -22,6 +23,7 @@ class MapzenGeocoderConfig(object):
self._mapzen_api_key = mapzen_api_key
self._username = username
self._organization = organization
self._service_params = service_params
# Kind of generic properties. Note which ones are for actually running the
# service and which ones are needed for quota stuff.
@@ -67,10 +69,15 @@ class MapzenGeocoderConfig(object):
@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):
@@ -86,16 +93,14 @@ class MapzenGeocoderConfigBuilder(object):
self._username = username
self._orgname = orgname
def get(self):
mapzen_server_conf = self._server_conf.get('mapzen_conf')
geocoding_quota = mapzen_server_conf['geocoder']['monthly_quota']
mapzen_api_key = mapzen_server_conf['geocoder']['api_key']
mapzen_service_params = mapzen_server_conf['geocoder'].get('service', {})
geocoding_quota = self._get_quota(mapzen_server_conf)
soft_geocoding_limit = self._user_conf.get('soft_geocoding_limit').lower() == 'true'
cost_per_hit=0
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)
@@ -109,4 +114,12 @@ class MapzenGeocoderConfigBuilder(object):
log_path,
mapzen_api_key,
self._username,
self._orgname)
self._orgname,
mapzen_service_params)
def _get_quota(self, mapzen_server_conf):
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)

View File

@@ -5,8 +5,8 @@ class InMemoryConfigStorage(ConfigBackendInterface):
def __init__(self, config_hash={}):
self._config_hash = config_hash
def get(self, key):
def get(self, key, default=None):
try:
return self._config_hash[key]
except KeyError:
return None
return default

View File

@@ -2,5 +2,5 @@ from ..core.interfaces import ConfigBackendInterface
class NullConfigStorage(ConfigBackendInterface):
def get(self, key):
return None
def get(self, key, default=None):
return default

View File

@@ -9,11 +9,19 @@ class RedisConfigStorage(ConfigBackendInterface):
self._config_key = config_key
self._data = None
def get(self, key):
def get(self, key, default=KeyError):
if not self._data:
self._data = self._connection.hgetall(self._config_key)
return self._data[key]
if (default == KeyError):
return self._data[key]
else:
return self._data.get(key, default)
def set(self, key, value):
self._connection.hset(self._config_key, key, value)
def remove(self, key):
self._connection.hdel(self._config_key, key)
class RedisUserConfigStorageBuilder(object):
def __init__(self, redis_connection, username):

Some files were not shown because too many files have changed in this diff Show More