Compare commits

...

2504 Commits

Author SHA1 Message Date
Raul Ochoa
2143e87401 Release 2.53.2 2016-06-28 13:07:19 +02:00
Raul Ochoa
f0a536ee1e Upgrades camshaft to 0.22.2 2016-06-28 13:06:46 +02:00
Raul Ochoa
dde4b63c6b Stubs next version 2016-06-28 00:25:29 +02:00
Raul Ochoa
0e7bcc4b56 Release 2.53.1 2016-06-28 00:24:40 +02:00
Raul Ochoa
e4816b4322 Merge pull request #527 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.22.1
2016-06-28 00:21:33 +02:00
Raul Ochoa
af4f29c538 Upgrades camshaft to 0.22.1 2016-06-28 00:17:33 +02:00
Raul Ochoa
7cedccedcd Stubs next version 2016-06-24 14:59:23 +02:00
Raul Ochoa
a9c12d4534 Release 2.53.0 2016-06-24 14:58:44 +02:00
Raul Ochoa
77f71b1978 Merge pull request #523 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.22.0
2016-06-24 14:56:05 +02:00
Raul Ochoa
1c029fbc7b Upgrades camshaft to 0.22.0 2016-06-24 14:51:44 +02:00
Raul Ochoa
2bc0d8d145 Stubs next version 2016-06-23 19:09:16 +02:00
Raul Ochoa
4c2af88f92 Release 2.52.0 2016-06-23 19:08:36 +02:00
Raul Ochoa
ddd5d2a0b0 Bump version 2016-06-23 19:08:10 +02:00
Raul Ochoa
d5cb59dc84 Merge pull request #521 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.21.0
2016-06-23 19:06:25 +02:00
Raul Ochoa
f21581630a Upgrades camshaft to 0.21.0 2016-06-23 19:01:59 +02:00
Raul Ochoa
3fef37d06b Stubs next version 2016-06-22 17:23:04 +02:00
Raul Ochoa
a8b93896ed Release 2.51.0 2016-06-22 17:22:20 +02:00
Raul Ochoa
6c1e9bf0ca Bump version 2016-06-22 17:21:58 +02:00
Raul Ochoa
1d8947d404 Merge pull request #520 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.20.0
2016-06-22 15:13:17 +02:00
Raul Ochoa
834377b342 Upgrades camshaft to 0.20.0 2016-06-22 15:03:26 +02:00
Daniel García Aubert
c2e0eb05e5 Updated NEWS. #519 2016-06-21 18:43:27 +02:00
Daniel
256032ca4a Merge pull request #519 from CartoDB/fix-error-with-context
Now errors with context have the same schema.
2016-06-21 18:41:46 +02:00
Daniel García Aubert
d80f2b9566 Now errors with context have the same schema. 2016-06-21 18:26:10 +02:00
Raul Ochoa
9e2f0371ba Merge pull request #518 from CartoDB/better-analyses-errors
Improve error messages for missing analyses for layers and dataviews
2016-06-21 17:34:44 +02:00
Raul Ochoa
a2e74a3e1b Improve error messages for missing analyses for layers and dataviews 2016-06-21 17:25:28 +02:00
Raul Ochoa
f04a5a1ab9 Merge pull request #517 from CartoDB/turbo-carto-datasource-improvements
Split turbo-carto adapter substitutions tokens query
2016-06-21 15:48:07 +02:00
Raul Ochoa
7114311b75 Split turbo-carto adapter substitutions tokens query 2016-06-21 15:05:44 +02:00
Daniel García Aubert
1e9e092dc3 Stubs next version 2016-06-21 14:52:27 +02:00
Daniel García Aubert
98b3a5ba23 Release 2.50.0 2016-06-21 14:41:52 +02:00
Daniel García Aubert
200966e806 Merge branch 'upgrade-camshaft-0.19.0' 2016-06-21 14:34:28 +02:00
Daniel García Aubert
407430b81e Updated shrinkwrap 2016-06-21 14:20:54 +02:00
Raul Ochoa
c4b1fc039c Merge pull request #516 from CartoDB/turbo-carto-datasource-improvements
Pixel size query for turbo-carto adapter using radians and degrees
2016-06-21 14:12:41 +02:00
Raul Ochoa
d00379af6b Pixel size query for turbo-carto adapter using radians and degrees instead of meters 2016-06-21 14:01:43 +02:00
Raul Ochoa
7cee0f3ee3 Merge pull request #515 from CartoDB/turbo-carto-datasource-improvements
Use psql client instead of pg query runner to use proper params
2016-06-21 13:24:36 +02:00
Daniel García Aubert
2588346f1b Bumped camshaft version to 0.19.0 2016-06-21 13:19:01 +02:00
Raul Ochoa
863128013d Use psql client instead of pg query runner to use proper params 2016-06-21 12:08:40 +02:00
Raul Ochoa
51eb8eb67f Upgrades camshaft to 0.18.0 2016-06-20 17:09:55 +02:00
Raul Ochoa
28e01fd8ac Bump version 2016-06-20 16:47:38 +02:00
Raul Ochoa
726e153ad5 Merge pull request #514 from CartoDB/dataview-aggregation-operations
Add support for min, max, and avg operations in aggregation dataview
2016-06-20 16:40:55 +02:00
Raul Ochoa
e8df09c85b Add support for min, max, and avg operations in aggregation dataview 2016-06-20 16:26:24 +02:00
Raul Ochoa
2b4fb2971d Stubs next version 2016-06-20 13:44:24 +02:00
Raul Ochoa
933b36cca0 Release 2.49.1 2016-06-20 13:35:59 +02:00
Raul Ochoa
37a7cfb6ba Update news 2016-06-20 13:35:38 +02:00
Raul Ochoa
8a1cda159c Merge pull request #512 from CartoDB/turbo-carto-datasource-fixes
Use an empty array as default value for falsy ramps
2016-06-20 13:33:02 +02:00
Raul Ochoa
403dcbebcd Use an empty array as default value for falsy ramps
Fixes #507
2016-06-20 13:27:39 +02:00
Raul Ochoa
373ad69306 Merge branch 'master' into turbo-carto-datasource-fixes 2016-06-20 13:27:02 +02:00
Raul Ochoa
b2029e09f5 Add CDB_OverviewsSupport sql from extension to fix CDB_Overviews calls 2016-06-20 13:26:30 +02:00
Raul Ochoa
4f37d2d0c2 Empty results should keep working, going red 2016-06-20 13:09:01 +02:00
Raul Ochoa
a5b07bc2a8 Upgrades turbo-carto to 0.12.1 2016-06-20 13:07:51 +02:00
Raul Ochoa
1544a5622d Merge pull request #511 from CartoDB/dataview-the_geom-query
Dataview the geom query
2016-06-17 17:08:48 +02:00
Raul Ochoa
d49a877771 Fix reversed own filter option 2016-06-17 16:26:45 +02:00
Raul Ochoa
0f4747743c Merge branch 'master' into dataview-the_geom-query 2016-06-17 15:55:07 +02:00
Raul Ochoa
368e4522e7 Merge pull request #510 from CartoDB/updated-at-from-analyses-result
Pick last update time for layergroupid from analyses results
2016-06-17 15:44:11 +02:00
Raul Ochoa
cb1d1bb115 Pick last update time for layergroupid from analyses results 2016-06-17 14:46:22 +02:00
Raul Ochoa
612cc3dd41 Use the_geom for intermediate dataviews 2016-06-16 17:27:00 +02:00
Raul Ochoa
bff082e577 Stubs next version 2016-06-15 19:27:48 +02:00
Raul Ochoa
ea41750a14 Release 2.49.0 2016-06-15 19:26:25 +02:00
Raul Ochoa
458376a665 Merge pull request #506 from CartoDB/upgrade-camshaft
Upgrade camshaft to 0.17.1
2016-06-15 19:24:48 +02:00
Raul Ochoa
f0284907c4 Upgrade camshaft to 0.17.1 2016-06-15 19:13:37 +02:00
Raul Ochoa
ad0385ccf7 Merge pull request #505 from CartoDB/upgrade-camshaft
Upgrade camshaft to 0.17.0
2016-06-15 16:58:23 +02:00
Raul Ochoa
4350fc3c65 Upgrade camshaft to 0.17.0 2016-06-15 16:48:00 +02:00
Raul Ochoa
fc3422b9e5 Merge pull request #503 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.16.0
2016-06-15 11:13:50 +02:00
Raul Ochoa
9703c19fb4 Upgrades camshaft to 0.16.0 2016-06-15 11:01:11 +02:00
Daniel García Aubert
d36f2fb354 Stubs next version 2016-06-14 17:50:40 +02:00
Daniel García Aubert
c837785314 Release 2.48.0 2016-06-14 17:48:07 +02:00
Daniel
33014a9f45 Merge pull request #500 from CartoDB/478-error-context
Adds more error information when either analysis or turbo-carto is not well formed
2016-06-14 15:56:00 +02:00
Daniel García Aubert
c16d0b8605 Fixed broken tests 2016-06-14 10:50:50 +02:00
Daniel García Aubert
c88e4c5173 Merge branch 'master' into 478-error-context 2016-06-14 10:43:00 +02:00
Daniel García Aubert
0540696c3e Avoid to expose internal naming 2016-06-14 10:27:35 +02:00
Raul Ochoa
5f59a97a02 Merge pull request #502 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.15.1
2016-06-14 01:41:41 +02:00
Raul Ochoa
d3b815c3c7 Upgrades camshaft to 0.15.1 2016-06-14 01:36:15 +02:00
Raul Ochoa
d2a8dcbede Merge pull request #501 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.15.0
2016-06-13 22:14:47 +02:00
Daniel García Aubert
4854e879a6 Updated npm-shrinkwrap 2016-06-13 19:49:20 +02:00
Daniel García Aubert
ddc99cebff Upgrades turbo-carto to 0.12.0 2016-06-13 18:40:14 +02:00
Raul Ochoa
47470d4f2b Upgrades camshaft to 0.15.0 2016-06-13 18:04:48 +02:00
Daniel García Aubert
d9297d54de made error_with_context non optional and adapted test's assertion 2016-06-13 16:14:01 +02:00
Daniel García Aubert
2d821f957e Merge branch 'master' into 478-error-context 2016-06-13 12:29:00 +02:00
Daniel García Aubert
c0ce6e7a8a WIP fixes 478, adds more error information when either analysis or turbo-carto is not well formed. 2016-06-13 12:20:56 +02:00
Raul Ochoa
3f620c6cdd Stubs next version 2016-06-13 10:47:15 +02:00
Raul Ochoa
9160d8018d Release 2.47.1 2016-06-13 10:43:45 +02:00
Raul Ochoa
51307bcc69 Upgrades camshaft to 0.14.1 2016-06-10 18:38:49 +02:00
Raul Ochoa
d29651ee80 Stubs next version 2016-06-10 14:41:08 +02:00
Raul Ochoa
18640077aa Release 2.47.0 2016-06-10 14:40:28 +02:00
Raul Ochoa
59563c893b Merge pull request #499 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.14.0
2016-06-10 14:19:39 +02:00
Raul Ochoa
90fd1786e1 Upgrades camshaft to 0.14.0 2016-06-10 14:05:23 +02:00
Raul Ochoa
4a11115dd0 Improve errors for dataviews validation 2016-06-09 18:13:54 +02:00
Raul Ochoa
baf3e774c5 Stubs next version 2016-06-09 10:33:35 +02:00
Raul Ochoa
ac296411d5 Release 2.46.0 2016-06-09 10:15:26 +02:00
Raul Ochoa
09cea4d6d4 Merge pull request #498 from CartoDB/upgrade-windshaft
Upgrades windshaft to 2.3.0
2016-06-08 19:45:53 +02:00
Raul Ochoa
382ff2416f Upgrades windshaft to 2.3.0 2016-06-08 19:14:48 +02:00
Raul Ochoa
27036379dd Merge pull request #494 from CartoDB/upgrade-windshaft
Upgrades windshaft to 2.2.0
2016-06-07 19:34:35 +02:00
Raul Ochoa
f4e6e140e0 Upgrades windshaft to 2.2.0 2016-06-07 19:26:41 +02:00
Raul Ochoa
b4e5cb88d9 Merge pull request #491 from CartoDB/issue-375
Sort start and end override params to correct bins width
2016-06-06 17:22:28 +02:00
Raul Ochoa
3269fef845 Sort start and end override params
Fixes #375
2016-06-06 17:10:52 +02:00
Raul Ochoa
e797719b41 Append url params for widgets 2016-06-06 17:10:36 +02:00
Raul Ochoa
284a8f2465 Deduplicate and skip falsy column names for geojson queries
Although Windshaft is already removing duplicates and skipping falsy
columns it's better to provide it with good input.

Closes #476
2016-06-06 15:58:16 +02:00
Raul Ochoa
54ea656da2 Merge pull request #490 from CartoDB/geojson-substitution-tokens
Upgrades windshaft to 2.1.0
2016-06-06 15:36:38 +02:00
Raul Ochoa
b4aaadf40b Upgrades windshaft to 2.1.0
Adds support for substitution tokens in geojson tiles

Fixes #484.
2016-06-06 15:29:58 +02:00
Raul Ochoa
74d2e3ef75 Merge pull request #489 from CartoDB/warn-about-deps
Warn on application start about non-matching dependencies
2016-06-06 12:11:38 +02:00
Raul Ochoa
b10e4c11d9 Warn on application start about non-matching dependencies 2016-06-06 12:07:43 +02:00
Raul Ochoa
075e141a9c Merge pull request #488 from CartoDB/upgrade-deps
Upgrades turbo-carto and camshaft deps
2016-06-06 12:04:56 +02:00
Raul Ochoa
04acf895f0 Upgrades turbo-carto and camshaft deps 2016-06-06 11:59:56 +02:00
Raul Ochoa
21608bf2e2 Merge pull request #487 from CartoDB/dataviews-adapter-fixes
Dataviews adapter working with non sql, non source layers
2016-06-06 11:56:31 +02:00
Raul Ochoa
653beb1952 Dataviews/widgets adapter working with non sql, non source, and non widgets layers
Ref #480
2016-06-06 11:46:27 +02:00
Raul Ochoa
050d33ff14 Use the_geom_webmercator; srid=3857 for the bounding box filter 2016-06-02 20:39:15 +02:00
Raul Ochoa
1ae86e039b Dataviews adapter: skip layers not containing SQL or widgets 2016-06-02 20:17:39 +02:00
Raul Ochoa
f75cadf6ba Dataviews adapter should work when there is a mix of layers with and without widgets 2016-06-02 19:51:16 +02:00
Raul Ochoa
93d0fe9176 Stubs next version 2016-06-02 16:21:40 +02:00
Raul Ochoa
6a15cd0566 Release 2.45.0 2016-06-02 16:19:39 +02:00
Raul Ochoa
614fe3f703 Update news and bump version 2016-06-02 14:45:00 +02:00
Raul Ochoa
82d4bb3046 Merge pull request #485 from CartoDB/mapconfig-dataviews-adapter
Mapconfig dataviews adapter
2016-06-02 14:42:22 +02:00
Raul Ochoa
f49c13b1b3 Do not apply twice metadata in anonymous maps 2016-06-02 14:28:32 +02:00
Raul Ochoa
828b817aca Append widgets metadata from mapconfig 2016-06-02 14:14:11 +02:00
Raul Ochoa
7f26f01743 Upgrade windshaft to 2.0.1 2016-06-02 13:38:05 +02:00
Raul Ochoa
50da63fc63 Upgrades windshaft to 2.0.0 2016-06-02 13:02:50 +02:00
Raul Ochoa
f8f6508449 Merge branch 'master' into mapconfig-dataviews-adapter
Conflicts:
	NEWS.md
	npm-shrinkwrap.json
2016-06-02 10:57:43 +02:00
Raul Ochoa
7256eb0935 Upgrade camshaft to 0.12.1 2016-06-02 10:54:23 +02:00
Raul Ochoa
cb08b42e54 Merge pull request #486 from CartoDB/upgrade-turbo-carto
Upgrades turbo-carto to 0.10.1
2016-06-01 19:43:58 +02:00
Raul Ochoa
9e7caeff94 Upgrades turbo-carto to 0.10.1 2016-06-01 19:32:17 +02:00
Raul Ochoa
e72a1d73be Geojson + column selection tests 2016-06-01 19:06:01 +02:00
Raul Ochoa
aaacad81e7 Add bbox unit tests 2016-06-01 19:05:46 +02:00
Raul Ochoa
55ee5b3b01 Ported histogram tests from windshaft 2016-06-01 15:03:18 +02:00
Raul Ochoa
94bf2748be Ignore errors coming from overviews adapter 2016-06-01 15:03:02 +02:00
Raul Ochoa
9a4aa7c1fa Add params to url if present in override option 2016-06-01 15:00:30 +02:00
Raul Ochoa
3e71365a95 Update camshaft to 0.12.0 2016-06-01 15:00:00 +02:00
Raul Ochoa
018ffcea7c List widget tests ported from windshaft 2016-06-01 11:51:31 +02:00
Raul Ochoa
e24ba9f495 Ported formula widget tests from windshaft 2016-06-01 11:48:37 +02:00
Raul Ochoa
0e2e069503 Remove empty line 2016-06-01 11:48:28 +02:00
Raul Ochoa
c4bbff3802 Tests for aggregation dataview ported from windshaft 2016-06-01 11:44:24 +02:00
Raul Ochoa
290054ef5d Add widget search support in test client 2016-06-01 11:43:19 +02:00
Raul Ochoa
4c25828540 Fix sql signature in agg, formula, and list dataviews 2016-06-01 11:42:24 +02:00
Javier Goizueta
5eda4888ed Stub next version 2016-06-01 10:51:36 +02:00
Javier Goizueta
7c322d9411 Release 2.44.1 2016-06-01 10:47:46 +02:00
Javier Goizueta
bd35d4e78a Merge pull request #468 from CartoDB/466-overviews-dataviews
Implement overviews support for all dataview types
2016-06-01 10:35:07 +02:00
Raul Ochoa
6eb711e70b Merge remote-tracking branch 'origin/master' into mapconfig-dataviews-adapter 2016-05-31 18:51:13 +02:00
Raul Ochoa
81ff0152c0 Merge pull request #481 from CartoDB/plpython-query-statements
Use plpython version of CDB_QueryStatements
2016-05-31 18:50:39 +02:00
Raul Ochoa
8a07f9f57e Create plpythonu extension 2016-05-31 18:45:43 +02:00
Raul Ochoa
ca367d0fe7 Use plpython version of CDB_QueryStatements 2016-05-31 18:39:03 +02:00
Raul Ochoa
cd7adbd792 Return a dataview/widget from response body 2016-05-31 18:20:16 +02:00
Raul Ochoa
5b76ec9f68 Merge remote-tracking branch 'origin/master' into mapconfig-dataviews-adapter 2016-05-31 17:14:28 +02:00
Raul Ochoa
bb21270aab Merge pull request #479 from CartoDB/improve-prepare_db
Improve prepare db
2016-05-31 17:14:11 +02:00
Raul Ochoa
22f3a54fbf Option to skip sql files download 2016-05-31 16:57:28 +02:00
Raul Ochoa
6644711969 Use a variable instead of a tmp file 2016-05-31 16:46:57 +02:00
Raul Ochoa
989df4a8a4 curl over all remote files at the same time 2016-05-31 16:42:42 +02:00
Javier Goizueta
d5423c88ea Replace use of the name widget by dataview for consistency 2016-05-31 15:30:38 +02:00
Javier Goizueta
5838b7a455 Remove debugging messages 2016-05-31 15:19:33 +02:00
Raul Ochoa
86e8cedfab All remote sql files together 2016-05-31 15:17:41 +02:00
Raul Ochoa
93c31c5433 Stubs next version 2016-05-31 10:35:25 +02:00
Raul Ochoa
4ca8fddd50 Release 2.44.0 2016-05-31 10:29:15 +02:00
Raul Ochoa
8cc46fd2a3 Correct versions for updated packages 2016-05-31 10:08:06 +02:00
Raul Ochoa
b2d8f53a5c Merge branch 'master' into mapconfig-dataviews-adapter 2016-05-31 09:41:22 +02:00
Raul Ochoa
8e8e59addc Merge pull request #477 from CartoDB/update-camshaft
Upgrades camshaft to 0.11.0
2016-05-30 21:29:00 +02:00
Raul Ochoa
63e52878a1 Upgrades camshaft to 0.11.0 2016-05-30 19:23:56 +02:00
Javier Goizueta
ef276bd51e Merge branch 'master' into 466-overviews-dataviews 2016-05-30 17:26:06 +02:00
Javier Goizueta
7ac3784f32 Increase the ratio used to select an overview level from a bounding box
This value would ideally be adjusted to prevent the grid size of the
overview used being greater that one pixel. So, this should be the
larger dimension of the map window in pixels.
2016-05-30 17:21:56 +02:00
Raul Ochoa
e12133e24b Merge remote-tracking branch 'origin/master' into mapconfig-dataviews-adapter 2016-05-27 15:35:29 +02:00
Raul Ochoa
be01781373 Merge pull request #475 from CartoDB/update-camshaft
Upgrades camshaft to 0.10.0
2016-05-27 15:33:16 +02:00
Raul Ochoa
65523768f9 Upgrades camshaft to 0.10.0 2016-05-27 15:26:52 +02:00
Raul Ochoa
f602ea88e2 Convert widgets from layers into dataviews
It also converts filters so full dataviews backend is reusable, that removes
widgets backend dependency.
2016-05-26 19:32:58 +02:00
Raul Ochoa
da6870cf1e Adds new adapter to transform widgets into dataviews 2016-05-26 11:57:55 +02:00
Raul Ochoa
06e420aa70 Merge pull request #473 from CartoDB/analyses-mapconfig-extensions
Tests for generic MapConfig adapter
2016-05-26 11:45:17 +02:00
Raul Ochoa
c667e64d7f Simplify test as we just validate val value 2016-05-26 11:36:03 +02:00
Raul Ochoa
5c3dd8b09d validate execution order 2016-05-26 11:30:28 +02:00
Raul Ochoa
f7c528277b Add tests for generic MapConfig adapter 2016-05-26 11:23:19 +02:00
Raul Ochoa
2ff33b5010 Generic MapConfig adapter can receive an arbitrary number of adapters 2016-05-26 11:02:43 +02:00
Raul Ochoa
d2f4e3ee74 Merge pull request #472 from CartoDB/analyses-mapconfig-extensions
Analyses mapconfig extensions
2016-05-25 18:51:09 +02:00
Raul Ochoa
730486b27b Initial description of dataviews mapconfig extension 2016-05-25 18:36:59 +02:00
Raul Ochoa
c4b4a93a0d Add map config extension for analyses 2016-05-25 17:53:09 +02:00
Raul Ochoa
f34213a147 Reorder public/private functions 2016-05-25 17:24:28 +02:00
Raul Ochoa
862f8b4ce6 Merge pull request #471 from CartoDB/mapconfig-fix-adapters-order
Order of adapters: named maps should expand named layers as first step
2016-05-25 13:50:34 +02:00
Raul Ochoa
5a2afa9b89 Order of adapters: named maps should expand named layers as first step 2016-05-24 19:16:38 +02:00
Raul Ochoa
4759d178d3 No vars for adapters 2016-05-24 18:43:09 +02:00
Raul Ochoa
777fb78abc Merge pull request #469 from CartoDB/mapconfig-reorg
Unify getMapConfig signature in adapters
2016-05-24 18:32:47 +02:00
Raul Ochoa
faa24caf5b Use generic map config adapter 2016-05-23 23:35:42 +02:00
Raul Ochoa
5e6529363b Remove unused var 2016-05-23 23:29:41 +02:00
Raul Ochoa
a785ebef65 Use generic map config adapter 2016-05-23 23:29:06 +02:00
Raul Ochoa
4137de5adf Remove class members 2016-05-23 22:01:08 +02:00
Raul Ochoa
f012e6092f Remove unused var 2016-05-23 21:58:42 +02:00
Raul Ochoa
9ce4929d87 Use generic adapter in named maps 2016-05-23 21:56:38 +02:00
Raul Ochoa
8efe844474 Use generic adapter 2016-05-23 21:37:06 +02:00
Raul Ochoa
02cb80daa1 Use context for datasource 2/2 2016-05-23 19:14:03 +02:00
Raul Ochoa
e9d1951d48 Use context for datasource 1/2 2016-05-23 19:09:57 +02:00
Raul Ochoa
a11cc28dc7 Use context for analyses results 2016-05-23 18:59:23 +02:00
Raul Ochoa
a8fdd6726e Fix style 2016-05-23 18:36:03 +02:00
Raul Ochoa
7ad8a99373 Unify getMapConfig signature for overviews adapter 2016-05-23 18:35:16 +02:00
Javier Goizueta
c0a24108ba Implement overviews histogram dataviews 2016-05-23 18:11:10 +02:00
Javier Goizueta
ae9b8a0380 Remove comment 2016-05-23 18:10:46 +02:00
Raul Ochoa
31a0b01a27 Rename param 2016-05-23 18:08:42 +02:00
Raul Ochoa
efcb73e0d1 Named layers adapter with getMapConfig signature 2016-05-23 18:03:45 +02:00
Javier Goizueta
f008c74419 Specific aggregation dataview implementation for overviews 2016-05-23 17:42:26 +02:00
Javier Goizueta
4a646d4700 Refactor overviews formula dataview 2016-05-23 17:20:04 +02:00
Javier Goizueta
657b262d92 Override all dataview types for overviews
All are using now the default behaviour defined in the base
class.
2016-05-23 17:06:52 +02:00
Javier Goizueta
988412fc07 Define default overviews dataview behaviour in base class 2016-05-23 16:53:28 +02:00
Raul Ochoa
70750d2c43 Unify getMapConfig signature 2016-05-23 16:50:26 +02:00
Raul Ochoa
9c1db98f67 Unifiy getMapConfig signature 2016-05-23 16:44:14 +02:00
Raul Ochoa
12c44fda6f Unify getMapConfig interface 2016-05-23 16:20:42 +02:00
Raul Ochoa
a42756ba24 Merge pull request #467 from CartoDB/mapconfig-reorg
Adapter.getMapConfig interface
2016-05-23 15:59:55 +02:00
Raul Ochoa
6ccdb6cefd Overviews adapter with getMapConfig interface 2016-05-23 15:52:31 +02:00
Raul Ochoa
9f6ce64a31 Named maps adapter with getMapConfig interface 2016-05-23 15:39:11 +02:00
Raul Ochoa
3e35604df0 turbo-carto adapter with getMapConfig interface 2016-05-23 15:18:20 +02:00
Raul Ochoa
01a69ef15c Merge remote-tracking branch 'origin/master' into mapconfig-reorg 2016-05-23 15:14:25 +02:00
Raul Ochoa
5adbc98c2b Merge pull request #461 from CartoDB/turbo-carto-tokens
SubstitutionTokens based on origin data
2016-05-23 15:13:39 +02:00
Raul Ochoa
fb045f1836 Merge branch 'master' into turbo-carto-tokens 2016-05-23 15:06:55 +02:00
Raul Ochoa
ee49b8b2a2 Turbo-carto adapter into adapters package 2016-05-23 14:18:58 +02:00
Javier Goizueta
5ba72b4894 Create base class for overviews dataviews 2016-05-23 14:18:45 +02:00
Raul Ochoa
6975db6ecf Merge pull request #465 from CartoDB/mapconfig-reorg
Mapconfig providers and adapters re-org
2016-05-23 14:12:47 +02:00
Raul Ochoa
8134aca14d Named map provider into providers package 2016-05-23 13:32:28 +02:00
Raul Ochoa
215bbbd29c Store provider into providers package 2016-05-23 13:29:34 +02:00
Raul Ochoa
c4b6f65404 Create map provider into providers package 2016-05-23 13:28:11 +02:00
Raul Ochoa
69f40e6f6a Removed duplicated declaration 2016-05-23 13:26:34 +02:00
Raul Ochoa
20725900b6 Overviews adapter into adapters package 2016-05-23 13:25:11 +02:00
Raul Ochoa
ab984729f5 Named layers adapter into adapters package 2016-05-23 13:16:34 +02:00
Raul Ochoa
8553326c1b Merge remote-tracking branch 'origin/master' into mapconfig-reorg 2016-05-23 13:11:14 +02:00
Raul Ochoa
9f8551058d Analysis adapter into adapter package 2016-05-23 13:10:52 +02:00
Raul Ochoa
5895871fad Make tests running before checkstyle/lint 2016-05-23 13:03:56 +02:00
Raul Ochoa
c372d69e98 LayergroupToken only makes sense at testing environment 2016-05-23 13:01:23 +02:00
Javier Goizueta
bacaee138a Merge pull request #463 from CartoDB/camshaft-getfilters
Use Camshaft's API to get node filters
2016-05-19 19:19:02 +02:00
Javier Goizueta
3add61ec57 Use Camshaft's API to get node filters 2016-05-19 18:32:49 +02:00
Raul Ochoa
02ae50eef0 Merge pull request #462 from CartoDB/turbo-carto-category
Adds turbo-carto category quantification with exact strategy
2016-05-19 17:11:39 +02:00
Raul Ochoa
b308259e6f Merge branch 'master' into turbo-carto-category
Conflicts:
	lib/cartodb/utils/style/postgres-datasource.js
2016-05-19 16:58:31 +02:00
Raul Ochoa
14a0afc7c0 Merge branch 'master' into turbo-carto-tokens 2016-05-19 16:56:00 +02:00
Raul Ochoa
d74daf39c7 Upgrades turbo-carto to 0.10.0 2016-05-19 16:54:56 +02:00
Raul Ochoa
eb091caf4a Merge pull request #460 from CartoDB/turbo-carto-invalid-method
Fail on turbo-carto invalid quantification methods
2016-05-19 16:11:05 +02:00
Raul Ochoa
424cc6d93b Fail on turbo-carto invalid quantification methods 2016-05-19 15:54:58 +02:00
Raul Ochoa
3bacfecc49 Merge branch 'master' into turbo-carto-category 2016-05-19 13:43:35 +02:00
Raul Ochoa
64dd033c94 Merge branch 'master' into turbo-carto-tokens 2016-05-19 13:39:36 +02:00
Raul Ochoa
caec04f63b Merge pull request #459 from CartoDB/sql-wrap-adapter
Adds support for sql wrap in all layers
2016-05-19 13:38:59 +02:00
Raul Ochoa
2e79781711 Adds support for sql wrap in all layers
Previously it was only working for analyses ones.
2016-05-19 13:34:29 +02:00
Javier Goizueta
289ffbbedc Release 2.43.1 2016-05-19 12:33:41 +02:00
Javier Goizueta
e0f0751b28 Merge pull request #458 from CartoDB/457-bbox-queryrewrite
Fix dataview bbox bug when no query rewrite data exists
2016-05-19 12:29:17 +02:00
Raul Ochoa
f30be00eb9 Remove console 2016-05-19 12:14:46 +02:00
Raul Ochoa
ee94b8a587 Very raw implementation of SubstitutionTokens based on origin data 2016-05-19 12:13:49 +02:00
Raul Ochoa
fd3f928d81 Fix test table 2016-05-19 12:13:37 +02:00
Raul Ochoa
ba08745c23 Adds hasTokens method to SubstitutionTokens 2016-05-19 12:10:19 +02:00
Raul Ochoa
573932efba Simplify condition and use positive naming for parsing cartocss 2016-05-19 11:48:57 +02:00
Raul Ochoa
31344a1c75 Adds test case with analysis 2016-05-19 11:42:28 +02:00
Raul Ochoa
c7f37047b0 Save original query from analysis before wrapping it 2016-05-19 11:41:06 +02:00
Javier Goizueta
2a06405a58 Move definition to the scope where it's needed 2016-05-18 18:21:17 +02:00
Javier Goizueta
9206b1a1b5 Fix dataviews/overviews tests and add some new cases 2016-05-18 18:16:32 +02:00
Javier Goizueta
5989ab344d Add test to detect problem #457 2016-05-18 18:02:08 +02:00
Javier Goizueta
a1e024e228 Fix dataview problem for bbox with no query rewrite data
Fixes #457
2016-05-18 17:49:09 +02:00
Javier Goizueta
8628d3b671 Stub next version 2016-05-18 16:15:27 +02:00
Javier Goizueta
7ce4104d2f Release version 2.43.0 2016-05-18 16:11:30 +02:00
Javier Goizueta
a26a5d6f5a Merge pull request #449 from CartoDB/overviews-widgets-2
Use overviews for widgets (dataviews, filtered queries)
2016-05-18 16:08:17 +02:00
Javier Goizueta
e98a5aeff0 Small code clean-up 2016-05-18 15:48:30 +02:00
Javier Goizueta
4c375780c7 replace underscore functions by standard (ES5) equivalents
Note: _.find(a,...) is not replaced by a.find(...)
because it is not available for all the collections
we need it for.
2016-05-18 15:43:20 +02:00
Javier Goizueta
48415fb1f3 Merge branch 'master' into overviews-widgets-2 2016-05-18 13:58:55 +02:00
Javier Goizueta
8da7cf73c1 Remove comment 2016-05-18 13:55:09 +02:00
Javier Goizueta
ba30f460ee Remove comment
Overviews will not be used for dataview search
2016-05-18 13:42:58 +02:00
Javier Goizueta
e1aa0bc7ae Use JSON format for EXPLAIN 2016-05-18 13:09:55 +02:00
Javier Goizueta
3987e83b7a Add tests for query rewriter with filters 2016-05-18 12:34:51 +02:00
Javier Goizueta
858d976637 Add tests for query rewriter using specific zoom level 2016-05-18 11:53:30 +02:00
Javier Goizueta
48d2978997 Test filters query rewrite data 2016-05-18 11:45:14 +02:00
Javier Goizueta
1872fbd021 Add test cases for dataview formulae
Check the overriden (sum,avg,count) and non-overriden (min, max) cases.
2016-05-18 10:48:13 +02:00
Javier Goizueta
bbb1b4a7b9 Add tests missing file 2016-05-18 08:11:52 +02:00
Javier Goizueta
aa0ddaae95 Remove comment 2016-05-18 08:07:48 +02:00
Javier Goizueta
cb3706e5cf Update Query Rewriter comments 2016-05-18 08:04:11 +02:00
Javier Goizueta
3d8f6576aa Implement category and range filters 2016-05-18 07:48:11 +02:00
Javier Goizueta
24f7bc6596 Add tests for dataviews with overviews 2016-05-18 07:47:30 +02:00
Raul Ochoa
a1934c87d5 Adds turbo-carto category quantification with exact strategy 2016-05-17 19:45:37 +02:00
Javier Goizueta
7a6b1ec871 Fix tests for MapConfigOverviewsAdaptar changes 2016-05-17 16:01:10 +02:00
Raul Ochoa
cfdac1bcb0 Stubs next version 2016-05-17 15:46:21 +02:00
Javier Goizueta
42ef40282b 💄 shorten long lines 2016-05-17 15:46:13 +02:00
Raul Ochoa
25da6e779c Release 2.42.2 2016-05-17 15:45:21 +02:00
Javier Goizueta
7f7204df6c Add filter stats information to query rewriter data 2016-05-17 15:41:31 +02:00
Javier Goizueta
3c6d930434 Fix bug 2016-05-17 15:39:32 +02:00
Raul Ochoa
b5540fc63a Regenerate npm-shrinkwrap.json after a fresh npm --no-shrinkwrap 2016-05-17 15:24:55 +02:00
Raul Ochoa
f6f58a71b3 Merge remote-tracking branch 'origin/turbo-carto-substitution-tokens'
Conflicts:
	NEWS.md
2016-05-17 15:15:07 +02:00
Francisco Dans
3a7361a009 stubs next version 2016-05-17 15:05:16 +02:00
Raul Ochoa
420f4aacc9 Update news 2016-05-17 15:04:15 +02:00
Francisco Dans
163c10b66e upgrades turbo-carto 2016-05-17 15:03:48 +02:00
Raul Ochoa
8fb35571fe Adds support for mapnik substitution token at turbo-carto level
Goes green and fixes #455
2016-05-17 15:00:18 +02:00
Raul Ochoa
91f39abc69 Going red for #455 2016-05-17 14:59:21 +02:00
Javier Goizueta
df63fbbd04 Refactor filter application into own model
This also avoids storing an object in the overviews query rewriter
for the bbox filter (a plain data structure is used instead).
2016-05-17 13:55:00 +02:00
Raul Ochoa
5b96576227 Stubs next version 2016-05-16 20:08:39 +02:00
Raul Ochoa
9f18e2d27d Release 2.42.0 2016-05-16 19:58:22 +02:00
Raul Ochoa
1ac6ead4b2 Update news 2016-05-16 19:57:51 +02:00
Javier Goizueta
9d82e8c27c Use bounding box of dataviews to select overviews level 2016-05-13 20:47:36 +02:00
Javier Goizueta
224eb392ba Add overviews-dependent dataviews behaviour
Now QueryRewriter is used in dataview objects they can decide
whether overviews are applicable, have the oportunity to
adapt queries for overviews, etc.
This is done by having overviews-related behaviour in models/dataview/overviews
and falling back to the regular models/dataview.
2016-05-13 18:46:58 +02:00
Raul Ochoa
8f51418d84 Merge pull request #453 from CartoDB/issue-450
Fix named maps with analysis
2016-05-13 17:13:29 +02:00
Raul Ochoa
c12e5f7a27 Fix named maps with analysis
Named map provider was missing analysis backend dependency

Fixes #450
2016-05-13 16:57:27 +02:00
Raul Ochoa
1c2354dc49 Merge pull request #452 from CartoDB/turbo-carto-split-strategy
Use split strategy for head/tails turbo-carto quantification
2016-05-13 13:20:12 +02:00
Raul Ochoa
2e26e2e126 Use split strategy for head/tails turbo-carto quantification 2016-05-13 12:57:43 +02:00
Raul Ochoa
94639f7e0c Merge pull request #451 from CartoDB/turbo-carto-errors
Improve turbo-carto related errors
2016-05-13 12:54:17 +02:00
Raul Ochoa
f3957b4fce Fix test expectations for turbo-carto errors 2016-05-13 12:42:18 +02:00
Raul Ochoa
61765d20e1 Fail on turbo-carto specific errors
This will try to fallback on postcss errors so it still targets
carto parser in those cases.

Closes #434
2016-05-13 12:10:05 +02:00
Raul Ochoa
503636f9fb Upgrade to turbo-carto 0.9.0 2016-05-13 12:09:11 +02:00
Raul Ochoa
4abadec9c4 Use the more suitable getLayergroup to validate regression 2016-05-13 00:49:09 +02:00
Javier Goizueta
b574489950 Refactor to reduce cyclomatic complexity 2016-05-12 18:47:24 +02:00
Javier Goizueta
85788f42a6 Adapt QueryRewriter to new requirements 2016-05-12 18:30:10 +02:00
Javier Goizueta
5fb7f07498 Prevent problems with missing layers in mapconfig 2016-05-12 18:29:30 +02:00
Javier Goizueta
fd44b62f26 Fix tests for new MapConfigOverviewsAdapter interface 2016-05-12 17:52:39 +02:00
Javier Goizueta
3300c095ed Merge branch 'master' into overviews-widgets-2 2016-05-12 17:37:24 +02:00
Javier Goizueta
55cf0a8447 Fix typo 2016-05-12 16:43:09 +02:00
Javier Goizueta
64a87690ee 💄 Fix line lengths, etc. 2016-05-12 16:20:34 +02:00
Javier Goizueta
3890014250 Fix QueryRewriter use
QueryRewriter should be passed the query that would be used otherwise.
If QR cannot handle it, it will be returned unmodified.
So QR must be used when a query has been prepared and the result
of QR should be used to replace it.
2016-05-12 10:25:09 +02:00
Raul Ochoa
7c2924ae14 Merge pull request #448 from CartoDB/upgrade-turbo-carto
Upgrades turbo-carto to 0.8.0
2016-05-11 20:09:41 +02:00
Raul Ochoa
bfdaf67a9b Upgrades turbo-carto to 0.8.0 2016-05-11 19:57:05 +02:00
Javier Goizueta
65612f0109 Add filters information at map instantion time to the query rewriter data 2016-05-11 19:24:13 +02:00
Raul Ochoa
e0ade85565 Stubs next version 2016-05-11 18:53:17 +02:00
Raul Ochoa
c5afc0dc94 Release 2.41.1 2016-05-11 18:51:05 +02:00
Raul Ochoa
a7e00c5856 Merge pull request #447 from CartoDB/upgrade-camshaft
Upgrades camshaft to 0.8.0
2016-05-11 18:50:14 +02:00
Raul Ochoa
2482accb42 Upgrades camshaft to 0.8.0 2016-05-11 18:39:07 +02:00
Raul Ochoa
3e4f71d873 Nicer error message when missing sql from layer options
Fixes #446
2016-05-11 18:24:47 +02:00
Javier Goizueta
fa19f90a6a Apply overviews query rewriter to dataviews
This requires the QueryRewriter to handle a filters parametes in
its data (with Camshaft filter definitions) and a final
options parameters with a bounding_box parameter.
2016-05-11 18:18:22 +02:00
Raul Ochoa
bbadd46766 Stubs next version 2016-05-11 16:47:33 +02:00
Raul Ochoa
b1f618a98e Release 2.41.0 2016-05-11 16:46:57 +02:00
Raul Ochoa
cdf3fe3a25 Bumps version 2016-05-11 16:45:36 +02:00
Raul Ochoa
1440841ac8 Merge pull request #445 from CartoDB/upgrade-camshaft
Upgrade camshaft to 0.7.0
2016-05-11 16:44:07 +02:00
Raul Ochoa
fc57fd2638 Upgrade camshaft to 0.7.0 2016-05-11 16:25:42 +02:00
Raul Ochoa
776cb8d47a Stubs next version 2016-05-10 17:26:27 +02:00
Raul Ochoa
c36f52415e Release 2.40.0 2016-05-10 17:23:50 +02:00
Raul Ochoa
2ee2c5bb55 Update news and bump version 2016-05-10 17:22:51 +02:00
Raul Ochoa
dccb557cd7 Merge pull request #444 from CartoDB/optimize-source-type-query-usage
Use original query from source nodes
2016-05-10 17:19:04 +02:00
Raul Ochoa
4570d17ce1 Use original query from source nodes
Doing a st_transform doesn't make sense as we already should have
the_geom_webmercator column available
2016-05-10 17:09:36 +02:00
Raul Ochoa
b3b3abcdb8 Merge pull request #443 from CartoDB/override-static-previews-params
Allow override zoom+center or bbox for static named maps previews
2016-05-09 22:53:35 +02:00
Raul Ochoa
6639664b3f Allow override zoom+center or bbox for static named maps previews 2016-05-09 21:13:13 +02:00
Raul Ochoa
b99db7cb69 Merge pull request #441 from CartoDB/sql-wrap
Analysis layers can have a sql_wrap option to wrap node queries
2016-05-09 14:09:16 +02:00
Raul Ochoa
3e94e3288f Use sql as replacement variable 2016-05-06 17:09:41 +02:00
Raul Ochoa
1115f9fba2 Merge pull request #442 from CartoDB/remove-repeated-config
Added config parameter for ST_RemoveRepeatedPoints
2016-05-06 17:01:23 +02:00
Daniel García Aubert
24dde1e4d0 Added config parameter to windshaft in order to use postgres' function ST_RemoveRepeatedPoints (set false by the default)
Conflicts:
	lib/cartodb/server_options.js
2016-05-06 16:50:25 +02:00
Raul Ochoa
7d4caf6974 Analysis layers can have a sql_wrap option to wrap node queries 2016-05-06 16:37:52 +02:00
Raul Ochoa
e4ba68850c Stubs next version 2016-05-05 18:36:50 +02:00
csobier
e2154f6561 Merge pull request #435 from CartoDB/docs-add-named-map-torque-link
link to named map with a torque layer block page
2016-05-05 12:35:41 -04:00
Raul Ochoa
778860c81f Release 2.39.0 2016-05-05 18:09:44 +02:00
Raul Ochoa
ee3c56efba Update news 2016-05-05 18:09:15 +02:00
Raul Ochoa
5dc328724a Merge pull request #440 from CartoDB/node-status-cache-control-header
Use a more aggressive cache control header for node status endpoint
2016-05-05 18:07:16 +02:00
Raul Ochoa
c77ea49594 Use a more aggressive cache control header for node status endpoint 2016-05-05 17:52:37 +02:00
Raul Ochoa
73aa159b98 Upgrade istanbul 2016-05-05 16:06:52 +02:00
Raul Ochoa
b7d7cffb67 Reformat package.json with npm cli tool 2016-05-05 16:05:46 +02:00
Raul Ochoa
eba8db292c Merge pull request #439 from CartoDB/avoid-profiler-dots
Upgrades step-profiler to 0.3.0 to avoid dots in json keys
2016-05-05 15:41:30 +02:00
Raul Ochoa
d5391ef15b Merge remote-tracking branch 'origin/master' into avoid-profiler-dots
Conflicts:
	NEWS.md
2016-05-05 15:30:12 +02:00
Francisco Dans
685cbb1eec updates news 2016-05-05 14:34:19 +02:00
Francisco Dans
5842a239fd shrinkwrap 2016-05-05 14:32:57 +02:00
Francisco Dans
285363aa40 bumps current version and turbocarto's 2016-05-05 14:32:11 +02:00
Raul Ochoa
92e130d8de Upgrades step-profiler to 0.3.0 to avoid dots in json keys
Closes #438
2016-05-05 13:45:25 +02:00
Francisco Dans
f674f90eba Merge branch 'master' of github.com:CartoDB/Windshaft-cartodb 2016-05-05 12:28:01 +02:00
Francisco Dans
0542b65cbb shrinkwrap changes for 2.38.0 2016-05-05 12:26:12 +02:00
Francisco Dans
60fa94781e adds upgrade to NEWS 2016-05-05 12:25:12 +02:00
Raul Ochoa
38d57533c2 Discourage console usage, global.logger should be used when required 2016-05-05 12:18:22 +02:00
Raul Ochoa
e3d6da06a7 Remove console usage 2016-05-05 12:17:51 +02:00
Raul Ochoa
3af05bb734 Remove console usage 2016-05-05 12:17:33 +02:00
Francisco Dans
ffd58cc7ca bumps minor 2016-05-05 12:07:26 +02:00
Francisco Dans
e103c52d27 upgrades turbo carto 2016-05-05 12:04:14 +02:00
csobier
46a4defab7 added torque layer in named maps as a new section under the cartodb.js heading 2016-05-04 12:53:23 -04:00
Daniel García Aubert
00a71af95d Stubs next version 2016-05-03 17:58:47 +02:00
Daniel García Aubert
2fb8036740 Release 2.37.0 2016-05-03 17:53:08 +02:00
Daniel García Aubert
6902a8c9b3 Upgraded camashaft version to 0.6.0 2016-05-03 17:46:38 +02:00
csobier
fd8be0352f link to named map with a torque layer block page 2016-05-03 11:38:57 -04:00
Raul Ochoa
c19a345f6c Stubs next version 2016-04-29 12:54:47 +02:00
Raul Ochoa
bdc3ecff5a Release 2.36.1 2016-04-29 12:53:58 +02:00
Raul Ochoa
6c4ec29e18 Add test to validate new behaviour in camshaft 0.5.1 2016-04-29 12:51:48 +02:00
Raul Ochoa
412712e62e Upgrades camshaft to 0.5.1 2016-04-29 12:51:39 +02:00
Raul Ochoa
0edcb30f75 Stubs next version 2016-04-28 18:46:49 +02:00
Raul Ochoa
c0f49b3acb Release 2.36.0 2016-04-28 18:45:51 +02:00
Raul Ochoa
b926244085 Upgrades windshaft to 1.19.0 2016-04-28 17:30:57 +02:00
Raul Ochoa
d21136b475 Stubs next version 2016-04-27 18:44:47 +02:00
Raul Ochoa
8788aaaf25 Release 2.35.0 2016-04-27 18:43:50 +02:00
Raul Ochoa
120e800089 Bump version and update news 2016-04-27 18:42:56 +02:00
Raul Ochoa
92dc4b148c Merge pull request #432 from CartoDB/dataviews-columns
Append dataviews related columns to layers
2016-04-27 18:40:33 +02:00
Raul Ochoa
755dfe6822 Append dataviews related columns to layers 2016-04-27 18:30:05 +02:00
Daniel García Aubert
b787ee1033 Stubs next version 2016-04-27 15:12:13 +02:00
Daniel García Aubert
9ee3612da0 Release 2.34.1 2016-04-27 15:09:13 +02:00
Daniel García Aubert
fe0b0a9c50 Upgraded windshaft to 1.17.3 2016-04-27 15:05:45 +02:00
Raul Ochoa
dea19f20dd Stubs next version 2016-04-27 10:24:16 +02:00
Raul Ochoa
f9f70cc6e7 Release 2.34.0 2016-04-27 10:23:24 +02:00
Raul Ochoa
23ef1157cb Merge pull request #431 from CartoDB/dataviews-filters
Dataviews filters
2016-04-26 19:21:43 +02:00
Raul Ochoa
8ca4d537ce Update news 2016-04-26 19:18:04 +02:00
Raul Ochoa
98d5731555 Add test to validate latest windshaft uses dataviews filters
Windshaft is transforming dataview filters into widget filters
2016-04-26 19:13:30 +02:00
Raul Ochoa
5da8929a5d Upgrade windshaft 2016-04-26 19:13:10 +02:00
Raul Ochoa
e198bafac1 Merge pull request #429 from CartoDB/upgrade-turbo-carto
Starts using turbo-carto dependency
2016-04-26 16:56:11 +02:00
Raul Ochoa
dd731399dc Starts using turbo-carto dependency 2016-04-26 16:28:05 +02:00
csobier
66fd899ffb Merge pull request #426 from CartoDB/docs-801-misplaced-text
removed dup text from static api section
2016-04-24 14:16:40 -04:00
csobier
bca8a33417 removed dup text from static api section 2016-04-24 13:59:38 -04:00
Raul Ochoa
a11c8d882e Each error-case will have different expectations 2016-04-21 17:27:20 +02:00
Raul Ochoa
c5bed48d61 Handle missing analyses nodes for layers pointing to them
Fixes #422
2016-04-21 17:24:52 +02:00
Raul Ochoa
98b7d12796 Merge pull request #424 from CartoDB/analysis-named-metadata
Analysis named maps metadata
2016-04-21 17:10:36 +02:00
Raul Ochoa
93dd8a2213 Add analyses metadata for named maps excluding queries 2016-04-21 17:03:41 +02:00
Raul Ochoa
4e4a223f24 Better naming for analysis mapconfig adapter 2016-04-21 16:25:59 +02:00
Raul Ochoa
4a73f3874d Better naming 2016-04-21 16:18:17 +02:00
Raul Ochoa
bc845b2e8d Validate dataviews format before instantiating 2016-04-21 16:16:00 +02:00
Raul Ochoa
83eceb349c Merge pull request #423 from CartoDB/multierror-support
Adds support to return multiple errors in BaseController.sendError
2016-04-21 16:15:28 +02:00
Raul Ochoa
bb518f0744 Update news 2016-04-21 16:09:57 +02:00
Raul Ochoa
08ad961123 Adds support to return multiple errors in BaseController.sendError 2016-04-21 16:05:48 +02:00
Raul Ochoa
146d494cae Adds dataview example in named map 2016-04-21 15:35:45 +02:00
Javier Goizueta
bb40ecf7c2 Stub next version 2016-04-20 18:30:42 +02:00
Javier Goizueta
7de9f64f2a Release 2.33.1 2016-04-20 18:27:06 +02:00
Javier Goizueta
0bb6178d49 Merge pull request #421 from CartoDB/420-overviews-schema
Support unneeded schema names in overviews queries
2016-04-20 18:16:16 +02:00
Javier Goizueta
084b3e94a6 Remove unneeded variable 2016-04-20 18:01:34 +02:00
Javier Goizueta
a0445b5cdd 💄 Fix indentation
2 spaces were used instead of 4 in some places
2016-04-20 17:47:43 +02:00
Javier Goizueta
1d4ddd373b Remove unneeded callback from synchronous tests 2016-04-20 17:27:52 +02:00
Raul Ochoa
92795963ae Stubs next version 2016-04-20 17:26:30 +02:00
Raul Ochoa
e634ad6f7d Release 2.33.0 2016-04-20 17:24:17 +02:00
Javier Goizueta
ecbae52abe Refactor: use reduce for collecting overviews metadata 2016-04-20 17:24:16 +02:00
Raul Ochoa
e1c5af8602 Bump version and update news 2016-04-20 17:15:17 +02:00
Raul Ochoa
6704a94f36 Merge pull request #418 from CartoDB/analysis-layers
Analysis layers
2016-04-20 17:13:14 +02:00
Raul Ochoa
a35403cd91 Add option to modify host header template for camshaft batch client 2016-04-20 16:36:29 +02:00
Raul Ochoa
41ead9664b Upgrade camshaft to 0.5.0 2016-04-20 16:34:48 +02:00
Raul Ochoa
e04a9a2579 Append dataviews filters after checking if mapconfig must be adapted 2016-04-20 15:40:14 +02:00
Raul Ochoa
d70af7c9c1 Fix tests with typo in s/radio/radius/ 2016-04-20 15:33:17 +02:00
Raul Ochoa
d910f5ef3e Update camshaft to use 0.4.0 fixed version 2016-04-20 15:33:04 +02:00
Javier Goizueta
57cba3d511 Fix comment 2016-04-20 14:30:13 +02:00
Javier Goizueta
7902b276ad Support unneeded schema names in overviews queries
Fixes #420
Keep table schema of overviews base tables and use it
to support queries that use the schema name when not
strictly needed.
2016-04-19 22:50:05 +02:00
Raul Ochoa
f932862ce4 Improve configuration for batch queries 2016-04-18 15:13:00 +02:00
Raul Ochoa
ab55b083b4 Style 2016-04-18 14:48:14 +02:00
Raul Ochoa
263b3e3682 Rename file 2016-04-18 14:47:35 +02:00
Raul Ochoa
5baad96924 remove commented out code 2016-04-18 14:43:29 +02:00
Raul Ochoa
68b19c65fe newline at end of file 2016-04-18 14:40:34 +02:00
Raul Ochoa
3a81302699 Merge branch 'master' into analysis-layers
Conflicts:
	package.json
2016-04-18 14:36:43 +02:00
Raul Ochoa
6b942ecf0b Merge pull request #417 from CartoDB/update-cartodb-psql
Upgrades cartodb-psql to 0.6.1 version
2016-04-18 14:33:59 +02:00
Raul Ochoa
1ed0c73525 Upgrades cartodb-psql to 0.6.1 version. 2016-04-18 14:30:20 +02:00
Raul Ochoa
7175b2b05e Merge branch 'master' into analysis-layers 2016-04-18 14:09:57 +02:00
Raul Ochoa
61137610c7 Merge pull request #416 from CartoDB/update-windshaft
Upgrades windshaft to 1.17.1
2016-04-18 13:53:57 +02:00
Raul Ochoa
b53031972e Upgrades windshaft to 1.17.1 2016-04-18 13:18:54 +02:00
Raul Ochoa
da602eeda0 Use inline execution in camshaft instead of a database service stub 2016-04-14 17:25:08 +02:00
Raul Ochoa
a26025b259 Add analysis backend so it's possible to inject configuration 2016-04-14 17:09:07 +02:00
Raul Ochoa
25a61c8479 Remove console log 2016-04-14 17:08:23 +02:00
Raul Ochoa
e73b64bfed Merge branch 'master' into analysis-layers 2016-04-14 13:40:51 +02:00
Raul Ochoa
b5b8085444 Reformat for better indentation 2016-04-14 13:40:02 +02:00
Raul Ochoa
388f08a277 Remove unneeded comma 2016-04-14 13:39:19 +02:00
Raul Ochoa
aa36236ed2 Rename analysis to analysis status backend, making room for analysis backend 2016-04-14 13:25:56 +02:00
Raul Ochoa
a9ca453b17 Remove some JSON.stringify 2016-04-14 13:20:22 +02:00
Raul Ochoa
9ab4eb5801 Change error expectation 2016-04-14 12:56:20 +02:00
Raul Ochoa
26149e7755 cdb_analysis_catalog is already retrieved from camshaft 2016-04-14 11:53:48 +02:00
Raul Ochoa
2d4fd62acf Do not create triggers for tests 2016-04-14 11:44:17 +02:00
Raul Ochoa
e037c8c1b2 Do not use layer index as analysis node is are unique 2016-04-14 11:08:39 +02:00
Raul Ochoa
09687b3811 Proper endpoint to check node status from analysis 2016-04-14 10:59:51 +02:00
Raul Ochoa
28400f4544 Better naming 2016-04-13 19:15:06 +02:00
Raul Ochoa
7a87b8ebef Use node id instead of param id for endpoint
It will be easier to retrieve node status with that id
2016-04-13 18:04:49 +02:00
Raul Ochoa
9ff661480b Do not append root as it is already included in sorted nodes 2016-04-13 18:02:28 +02:00
Raul Ochoa
ca564bfaad Add fake analysis node status endpoint 2016-04-11 18:49:56 +02:00
Raul Ochoa
dd36877a20 Add per node status 2016-04-11 18:49:43 +02:00
Raul Ochoa
1d860fd202 Remove top level url for analysis 2016-04-11 18:49:22 +02:00
Raul Ochoa
e9111ec3bb Update routes document 2016-04-08 11:13:40 +02:00
Raul Ochoa
0981ccd0c4 Add metadata information about analyses 2016-04-07 17:58:12 +02:00
Raul Ochoa
077c4ab907 Adds analysis MapConfig adapter to named maps 2016-04-07 16:18:48 +02:00
Raul Ochoa
efacafaa0d Merge remote-tracking branch 'origin/master' into analysis-layers 2016-04-07 15:04:25 +02:00
Raul Ochoa
1c250bf243 Remove dependency 2016-04-07 14:30:49 +02:00
Daniel García Aubert
c974b91c6b Stubs next version 2016-04-06 19:32:16 +02:00
Daniel García Aubert
6aebe26cc9 Release 2.32.0 2016-04-06 19:29:07 +02:00
Daniel García Aubert
f93794717e Upgrades windshaft to 1.17.0 2016-04-06 19:26:55 +02:00
Raul Ochoa
0ebf482936 Merge pull request #410 from CartoDB/named-dynamic-styling
Overrided cartocss in the instantiation of named maps
2016-04-06 18:09:11 +02:00
Daniel García Aubert
b5b8083acd Overrided cartocss in the instantiation of named maps 2016-04-06 17:43:25 +02:00
Raul Ochoa
ab6bae6a7f Merge branch 'master' into analysis-layers 2016-04-04 16:24:31 +02:00
Javier Goizueta
219658761f Stub next version 2016-04-04 14:34:35 +02:00
Javier Goizueta
e3a68a6b4d Release 2.31.2
This fixes a couple of overviews-related bugs
2016-04-04 14:31:57 +02:00
Javier Goizueta
01218c6ea1 Merge pull request #409 from CartoDB/405-wrapped-overviews-queries
Support overviews for named layer wrapped queries
2016-04-04 14:18:57 +02:00
Javier Goizueta
83d27a8e29 Merge pull request #407 from CartoDB/400-named-layer-overviews
Fix overviews integration for named layers
2016-04-04 14:18:34 +02:00
Javier Goizueta
fa2e884605 Support overviews for named layer wrapped queries
Fix #405
2016-04-01 15:40:44 +02:00
Javier Goizueta
f4554f41d2 Add tests for named maps overviews 2016-03-31 18:36:50 +02:00
Javier Goizueta
b97a67b844 Fix overviews integration for named layers
Fixes #400
2016-03-31 18:33:41 +02:00
csobier
3b13fad5e7 Merge pull request #403 from CartoDB/docs-592-consistent-placeholder-examples
added tip about placeholder format and errors
2016-03-28 07:12:59 -04:00
Raul Ochoa
4d39d30f6e Merge branch 'master' into analysis-layers
Conflicts:
	npm-shrinkwrap.json
2016-03-23 16:09:28 +01:00
Raul Ochoa
9a8964bd39 Stubs next version 2016-03-23 15:14:52 +01:00
Raul Ochoa
aae251b178 Release 2.31.1 2016-03-23 15:09:38 +01:00
Raul Ochoa
2db7a3d110 Merge pull request #404 from CartoDB/upgrade-windshaft
Upgrade windshaft to 1.16.1
2016-03-23 15:08:23 +01:00
Raul Ochoa
5fe96a618d Upgrade windshaft to 1.16.1 2016-03-23 15:01:30 +01:00
Raul Ochoa
499178319d Add search endpoint/backend for dataviews 2016-03-23 12:14:17 +01:00
Raul Ochoa
7b7e9ffe59 Upgrade cartodb-psql module to get some bufixes 2016-03-23 12:13:26 +01:00
csobier
43d1e5c613 changed documentation variable to username throughout, and other clean-up 2016-03-22 11:23:04 -04:00
csobier
8547cb836f consistent placeholder examples with brackets 2016-03-22 09:19:50 -04:00
Raul Ochoa
2bd3e46a4d Build dataviews with factory to generalise them 2016-03-22 13:10:42 +01:00
Raul Ochoa
e44b5eaccd Fix test 2016-03-22 13:10:37 +01:00
Raul Ochoa
26512f6485 Remove unused function 2016-03-22 12:22:48 +01:00
Raul Ochoa
90b92f0180 Adds support for category filters 2016-03-22 12:22:04 +01:00
Raul Ochoa
ebe25761d2 Extract variable 2016-03-22 10:52:02 +01:00
Raul Ochoa
f928147559 Fix bbox template 2016-03-21 18:16:54 +01:00
Raul Ochoa
d5c5c7bdbb Do not remove analysis, camshaft takes care of source root nodes now 2016-03-21 18:02:19 +01:00
Raul Ochoa
ff147ca3bf Add dataviews to layergroup metadata 2016-03-18 18:09:17 +01:00
Raul Ochoa
f745e915d3 Own filter test for dataviews 2016-03-18 17:49:20 +01:00
Raul Ochoa
1e239658d8 Just remove analysis if there are analysis 2016-03-18 17:34:40 +01:00
Raul Ochoa
52f35d74b9 Allow a higher jshint maxcomplexity 2016-03-18 17:31:28 +01:00
Raul Ochoa
57e6e49749 Another workaround to not delete analyses if there are dataviews 2016-03-18 17:28:36 +01:00
Raul Ochoa
b3bbb9d97a Initial checkin for dataviews
It only supports histograms.
2016-03-18 17:22:02 +01:00
Raul Ochoa
697749b204 Add timer helper 2016-03-18 17:21:43 +01:00
Raul Ochoa
a769545e39 Rely on camshaft.reference for now 2016-03-18 17:16:51 +01:00
Raul Ochoa
df40302fd0 Add camshaft-reference 2016-03-18 13:04:00 +01:00
csobier
85e5a89298 added tip about placeholder format and errors 2016-03-17 17:42:57 -04:00
Raul Ochoa
5bd30b6b5f Analysis layers adapter skips analysis if there is only source nodes 2016-03-17 12:50:42 +01:00
Raul Ochoa
ed84ed8475 Test client detect png request based on regex 2016-03-17 12:45:05 +01:00
Raul Ochoa
a444b80c96 Fix typo 2016-03-17 12:44:51 +01:00
Daniel García Aubert
fc94f3ad94 Fixed stub next version 2016-03-16 18:07:28 +01:00
Daniel García Aubert
d43b766448 Merge branch 'master' of github.com:CartoDB/Windshaft-cartodb 2016-03-16 17:40:49 +01:00
Daniel García Aubert
6ceca348cb Stubs next version 2016-03-16 17:40:30 +01:00
Daniel García Aubert
bff6f056d0 Stubs next version 2016-03-16 17:33:26 +01:00
Daniel García Aubert
366a66b331 Release 2.31.0 2016-03-16 17:30:58 +01:00
Raul Ochoa
43c56af0fc Merge remote-tracking branch 'origin/master' into analysis-layers
Conflicts:
	npm-shrinkwrap.json
2016-03-16 16:13:44 +01:00
Daniel García Aubert
c0370c5703 Stubs next version 2016-03-15 17:45:50 +01:00
Daniel García Aubert
8d5551343b Release 2.30.0 2016-03-15 17:40:26 +01:00
Daniel García Aubert
4089e8537a Upgraded windshaft to version 1.15.0 2016-03-15 17:35:13 +01:00
csobier
cf06c6e974 Merge pull request #401 from CartoDB/docs-685-named-map-tiles-and-cleanup
moved fetch tiles section up one heading level
2016-03-15 09:16:40 -04:00
csobier
2ebab4c89e moved fetch tiles section up one heading level 2016-03-15 09:08:28 -04:00
csobier
8023fbae24 Merge pull request #379 from CartoDB/docs-685-named-map-tiles-and-cleanup
Docs 685 named map tiles and cleanup
2016-03-15 08:50:20 -04:00
csobier
35cb652c6c edited token placeholder for consistency 2016-03-14 13:01:10 -04:00
csobier
c6085779a4 use the layergroupid, not SRID, as the mapnik token 2016-03-14 12:25:59 -04:00
csobier
86232eb239 clarified mapnik description and removed unnecessary content, as instructed by Carla 2016-03-14 11:51:07 -04:00
Raul Ochoa
6db48a24b8 Adds test for analysis with no api key 2016-03-14 16:42:51 +01:00
csobier
5cc3e914fa added missing bracket, removed note about API key 2016-03-14 11:34:52 -04:00
Raul Ochoa
1da937d639 Add commented code to generate image output for validation 2016-03-14 16:19:55 +01:00
Raul Ochoa
4924bcc298 Validate image from analysis 2016-03-14 16:16:27 +01:00
Raul Ochoa
a05f3d6ee9 Add cdb_analysis_catalog table and first test using source:id 2016-03-14 16:06:25 +01:00
Daniel García Aubert
d52d3d909f Fixed double-check error in turbo-cartocss preprocesing. 2016-03-14 15:25:56 +01:00
Raul Ochoa
eec44dd62d Merge branch 'master' into analysis-layers
Conflicts:
	npm-shrinkwrap.json
	test/support/test-client.js
2016-03-14 15:13:19 +01:00
Daniel García Aubert
e7da9a151b Stubs next version 2016-03-14 14:47:02 +01:00
Daniel García Aubert
f75ba9d2c3 Release 2.29.0 2016-03-14 14:42:40 +01:00
Daniel García Aubert
be61d41f5e Stubs next version 2016-03-14 12:12:56 +01:00
Daniel García Aubert
f619a97f1a Release 2.28.0 2016-03-14 12:06:33 +01:00
Raul Ochoa
3f41f19ab9 Rename adapter 2016-03-14 11:50:52 +01:00
Daniel
e47449e357 Merge pull request #399 from CartoDB/move-turbo-cartocss
Move turbo cartocss
2016-03-14 11:35:06 +01:00
Daniel García Aubert
178345ab12 Fixed typo 2016-03-14 11:18:32 +01:00
Daniel García Aubert
a8340fef68 Bump image tolerance in turbo-cartocss test 2016-03-11 18:33:52 +01:00
Daniel García Aubert
052b58ab90 Moved turbo-cartocss integration from named maps admin to named map provider 2016-03-11 18:28:14 +01:00
Daniel García Aubert
cc5443152b Now turbo-cartocss is also parsed in template modification. 2016-03-11 11:06:51 +01:00
Daniel García Aubert
d937d8970d Fixed broken test in turbo-cartocss for named maps 2016-03-10 21:25:01 +01:00
Daniel García Aubert
dab4b6d56b Implemented integration of turbo-cartocss for named maps 2016-03-10 20:45:00 +01:00
Raul Ochoa
1535820d4f Regenerate npm-shrinkwrap.json 2016-03-10 11:32:43 +01:00
Raul Ochoa
b2378939c5 Merge branch 'master' of github.com:CartoDB/Windshaft-cartodb into analysis-layers 2016-03-10 11:14:10 +01:00
Daniel García Aubert
46b212b2cd Merge branch 'move-turbo-cartocss' of github.com:CartoDB/Windshaft-cartodb into move-turbo-cartocss 2016-03-09 20:14:06 +01:00
Daniel García Aubert
f47842c96d Integrated turbo-cartocss adapter for named maps 2016-03-09 20:12:51 +01:00
Raul Ochoa
050f90a07b Regenerate npm-shrinkwrap.json 2016-03-09 18:11:34 +01:00
Raul Ochoa
c1642dfa73 Merge branch 'master' into move-turbo-cartocss
Conflicts:
	lib/cartodb/controllers/map.js
2016-03-09 18:08:46 +01:00
Raul Ochoa
bbfcc640d1 Style 2016-03-09 18:08:06 +01:00
Raul Ochoa
e9b8c512c9 Re-indent 2016-03-09 18:07:11 +01:00
Raul Ochoa
15b54a2918 Re-indent 2016-03-09 18:05:17 +01:00
Alejandro Martínez
cf8ce42049 Release 2.27.0 2016-03-09 17:57:18 +01:00
Raul Ochoa
7fa8d1e0c9 Analyses are now an array and layers consume from their nodes
Layers now can define a `source: {id: 'a0'}` option to point to an
analysis node that will be used as the query for that layer.
2016-03-09 17:39:20 +01:00
Daniel García Aubert
eefa9f4222 Merge branch 'master' into move-turbo-cartocss 2016-03-09 12:03:29 +01:00
Daniel García Aubert
a0073da4b3 Added regression test for turbo-cartocss' integration 2016-03-09 11:48:07 +01:00
Daniel García Aubert
c6fbb08c8f Regenerated npm-shrinkwrap 2016-03-09 10:36:57 +01:00
Daniel García Aubert
affa254b9d Moved and adapted acceptance test for turbo-cartocss integration 2016-03-08 20:06:43 +01:00
Raul Ochoa
d5fbcfcecb Merge branch 'master' into analysis-layers
Conflicts:
	npm-shrinkwrap.json
2016-03-08 16:06:01 +01:00
Raul Ochoa
ecd33e5561 TestClient with method to retrieve tiles 2016-03-08 15:56:08 +01:00
Raul Ochoa
9d77aea6be Regenerate npm-shrinkwrap.json 2016-03-08 15:23:56 +01:00
Raul Ochoa
20609bc37e Merge pull request #397 from CartoDB/remove-deprecated-tools
Remove deprecated tools directory
2016-03-08 15:14:06 +01:00
Raul Ochoa
b56d110f50 Remove deprecated tools directory 2016-03-08 15:07:37 +01:00
Daniel García Aubert
3e0c19a669 Fixed typo 2016-03-08 14:41:10 +01:00
Daniel García Aubert
ab6004f21e Integrated turbo-cartocss for anonymous maps 2016-03-08 14:34:57 +01:00
Alejandro Martínez
34863765ed Freeze cartodb-query-tables version 2016-03-08 10:05:49 +00:00
csobier
32223baaef removed internal code, displayed somexyz examples 2016-03-07 10:53:51 -05:00
Raul Ochoa
3cb007d147 Merge pull request #388 from CartoDB/new_querytables_library
Use new querytables library
2016-03-07 16:42:25 +01:00
csobier
2f038f006b applied consistent terminology and applied rest of Carla's edits 2016-03-07 09:08:38 -05:00
Raul Ochoa
634a4c2a01 Debug option for internal nodes: it allows to display and customize cartocss 2016-03-04 16:20:23 +01:00
Raul Ochoa
f504807812 Regenerate npm-shrinkwrap.json 2016-03-04 12:12:12 +01:00
Raul Ochoa
c7bdabfc65 Merge branch 'new_querytables_library' into analysis-layers 2016-03-04 12:08:57 +01:00
Raul Ochoa
16a7c4fa3d Merge branch 'master' into new_querytables_library
Conflicts:
	test/support/prepare_db.sh
	test/support/sql/CDB_QueryStatements.sql
2016-03-04 00:39:14 +01:00
Raul Ochoa
3979cda8c2 Change comment about regex 2016-03-04 00:11:06 +01:00
Raul Ochoa
250d52f72c Merge pull request #395 from CartoDB/no-plpythonu-pg-dependency
No plpythonu pg dependency
2016-03-03 23:58:18 +01:00
Raul Ochoa
26e5b4f404 Do not install postgresql-plpython-9.3 in travis, so no more sudo:true 2016-03-03 20:51:53 +01:00
Raul Ochoa
f19c1a34ec Implement CDB_QueryStatements as SQL language function
Do not relies on cartodb-postgresql extension which relies on
plpythonu language. That avoid installing it in travis-ci.
2016-03-03 20:48:37 +01:00
Raul Ochoa
94c7bc41be Merge branch 'master' into new_querytables_library 2016-03-03 19:30:51 +01:00
Raul Ochoa
df0597f12a Rename suite 2016-03-03 19:29:42 +01:00
Raul Ochoa
52cb224225 Add integration test with QueryTables module
This tests should be better placed at cartodb-query-tables repo but
it's easier to do it here. Lazy dev.
2016-03-03 19:27:44 +01:00
Raul Ochoa
baf87e90d7 Just callback as result is handled internally 2016-03-03 19:25:32 +01:00
Javier Goizueta
6c3fde70e8 Stub next version 2016-03-03 19:05:06 +01:00
Raul Ochoa
d9f6df9815 Remove nested step call 2016-03-03 19:01:58 +01:00
Javier Goizueta
b2539f52b8 Release 2.26.3 2016-03-03 19:01:40 +01:00
Raul Ochoa
7c154dd405 Add notes about why we keep feeding the layergroupAffectedTables cache 2016-03-03 19:01:21 +01:00
Javier Goizueta
47dfdf964e Merge pull request #390 from CartoDB/overviews-optimization
Optimize overviews queries
2016-03-03 18:59:24 +01:00
Raul Ochoa
10a602a4f3 Merge remote-tracking branch 'origin/master' into analysis-layers 2016-03-03 17:52:05 +01:00
Raul Ochoa
e3a5c52ebf Merge branch 'master' into analysis-layers 2016-03-03 17:51:46 +01:00
Raul Ochoa
66aea5e10f Merge pull request #393 from CartoDB/travis-pg-93
Back to pg 9.3 and postgresql-plpython-9.3 using sudo=true build
2016-03-03 17:39:28 +01:00
Raul Ochoa
e0d18e3c20 Back to pg 9.3 and postgresql-plpython-9.3 using sudo=true build 2016-03-03 17:20:22 +01:00
Raul Ochoa
4b79d06ae3 Back to pg 9.3 and postgresql-plpython-9.3 using sudo=true build 2016-03-03 16:20:20 +01:00
Raul Ochoa
f9c0e29db0 Dataviews separated from analysis
They are just another consumer of the analysis as layers are.
2016-03-03 12:07:05 +01:00
Raul Ochoa
e53d823b5a Fix total population column name for widget 2016-03-03 12:04:03 +01:00
Raul Ochoa
31dede5d06 Notes to make clear the total-population analysis 2016-03-03 12:01:49 +01:00
Raul Ochoa
69142964c6 fix trade-area params 2016-03-03 11:54:50 +01:00
Raul Ochoa
2eac808e18 Change analysis name so it's easier to understand 2016-03-03 11:45:37 +01:00
Javier Goizueta
4e40a61795 Change form of overviews queries so they can be optimized
The PostgreSQL planner wasn't applying the spatial filtering of
tile bounds to the queries efficiently.
2016-03-02 19:25:08 +01:00
Raul Ochoa
011b60eeab Change ids 2016-03-02 13:27:53 +01:00
Raul Ochoa
16654c016a Style 2016-03-02 13:27:45 +01:00
Raul Ochoa
9b9e6b13b7 Fix query table 2016-03-02 13:27:28 +01:00
Raul Ochoa
3b11525cfb Add analysis use cases that we need to support 2016-03-02 12:43:14 +01:00
Raul Ochoa
6823fd8b03 Better datasets for analysis 2016-03-02 12:43:00 +01:00
Raul Ochoa
ce032fcc96 Improve styling in analysis layers 2016-03-02 12:42:42 +01:00
Raul Ochoa
a44477dddc TestClient with method to retrieve tiles 2016-03-02 12:40:53 +01:00
Javier Goizueta
2a789b5a5b Merge pull request #386 from CartoDB/384-overviews-error-message
Change error messages when getting overviews metadata fails
2016-02-26 19:10:09 +01:00
Raul Ochoa
3709d1f1d5 Merge branch 'master' into analysis-layers 2016-02-25 11:46:41 +01:00
Raul Ochoa
1789993467 Stubs next version 2016-02-25 11:43:36 +01:00
Raul Ochoa
604b50ffb5 Release 2.26.2 2016-02-25 11:42:53 +01:00
Raul Ochoa
2818413c5a Update windshaft to 1.13.2 2016-02-25 11:42:28 +01:00
Raul Ochoa
e958f925d3 Merge branch 'master' into analysis-layers 2016-02-24 17:28:03 +01:00
Raul Ochoa
06164af17f Stubs next version 2016-02-24 17:23:15 +01:00
Raul Ochoa
6131c4a66a Release 2.26.1 2016-02-24 17:22:04 +01:00
Raul Ochoa
465dde7a51 Merge pull request #389 from CartoDB/upgrade-windshaft
Upgrade windshaft to 1.13.1
2016-02-24 17:20:58 +01:00
Raul Ochoa
7894acf830 Upgrade windshaft to 1.13.1 2016-02-24 17:16:30 +01:00
Raul Ochoa
d923b343fc Merge branch 'master' into analysis-layers 2016-02-24 10:56:19 +01:00
Raul Ochoa
86c6f6040d Stubs next version 2016-02-24 10:51:12 +01:00
Raul Ochoa
b79b2d4e7e Release 2.26.0 2016-02-24 10:49:45 +01:00
Raul Ochoa
b9d2e297b6 Merge branch 'master' of github.com:CartoDB/Windshaft-cartodb into analysis-layers 2016-02-24 10:35:28 +01:00
Raul Ochoa
f2778a3292 Merge pull request #387 from CartoDB/upgrade-windshaft
Upgrade windshaft and regenerate npm-shrinkwrap.json
2016-02-24 02:25:49 +01:00
Raul Ochoa
f6f9f203d2 Update news and bump version 2016-02-24 02:21:37 +01:00
Raul Ochoa
f6c519a9e7 Upgrade windshaft to 1.13.0 2016-02-24 02:18:55 +01:00
Alejandro Martínez
0036056c07 Reopen PR 2016-02-23 19:31:38 +01:00
Alejandro Martínez
dcf156ba21 Merge remote-tracking branch 'origin/master' into new_querytables_library 2016-02-23 19:20:10 +01:00
Javier Goizueta
f0a1e7a0e0 Simplify error passing 2016-02-23 18:15:14 +01:00
Raul Ochoa
b931178e59 Upgrade windshaft and regenerate npm-shrinkwrap.json 2016-02-23 17:06:34 +01:00
Javier Goizueta
21f3c8a387 Change error messages when getting overviews metadata fails
Remove the detail that the error occurred trying to get overviews
metadata from the error message. This should be less confusing
to the user.
2016-02-23 11:45:26 +01:00
Alejandro Martínez
e491c0b825 Rename node-cartodb-query-tables to cartodb-query-tables 2016-02-22 19:11:54 +01:00
Raul Ochoa
2ac2974414 Stubs next version 2016-02-22 18:02:29 +01:00
Raul Ochoa
ce8c21261f Release 2.25.2 2016-02-22 18:00:58 +01:00
Raul Ochoa
dd8340b400 Do not leak redis connections
Reuse redis client in afterEach and quit client in function
2016-02-22 17:51:53 +01:00
csobier
14f58e12bb moved response info from template.json section to the related Response section, and left the name description as part of the template.json description 2016-02-22 11:41:06 -05:00
Raul Ochoa
b93d33e065 Merge pull request #385 from CartoDB/test-no-imagemagick
Tests without imagemagick dep
2016-02-22 16:51:54 +01:00
Raul Ochoa
4c06c9ade4 Remove imagemagick reference from install instructions 2016-02-22 16:43:43 +01:00
Raul Ochoa
2393a611a8 dry 2016-02-22 16:41:55 +01:00
Raul Ochoa
495fdaf8ec Rename assert.imageEqualsFile 2016-02-22 16:36:06 +01:00
Raul Ochoa
da680ec2a8 Code re-org 2016-02-22 16:08:16 +01:00
Raul Ochoa
3cadf7f2a2 Make imagesAreSimilar private 2016-02-22 16:07:26 +01:00
Raul Ochoa
7c7bec6f31 Remove imagemagick reference 2016-02-22 16:05:12 +01:00
Raul Ochoa
0683f638ce Do not take optional name hint 2016-02-22 16:04:31 +01:00
Raul Ochoa
ae9daed43f Better naming for imageBuffersAreSimilar 2016-02-22 16:02:15 +01:00
Raul Ochoa
5301e748de Do not create intermediate files when there is no need 2016-02-22 16:00:30 +01:00
Raul Ochoa
37ae6b4fa0 Rely on mapnik.Image instead of compare from imagemagick 2016-02-22 15:38:29 +01:00
Raul Ochoa
6695e1128c Merge pull request #382 from CartoDB/widgets-urls-in-namedmaps
Widgets urls in namedmaps
2016-02-22 15:37:30 +01:00
Alejandro Martínez
37fcfe69c7 Merge remote-tracking branch 'origin/master' into new_querytables_library 2016-02-22 15:35:36 +01:00
Raul Ochoa
fb146f164c Use before/after to not alter global configuration 2016-02-22 15:31:01 +01:00
Alejandro Martínez
850f1cb7f4 Remove stray spaces 2016-02-22 15:28:14 +01:00
Alejandro Martínez
e67f7b0d0e Drop old QueryTablesApi 2016-02-22 15:26:06 +01:00
Alejandro Martínez
ba8e3d419e Fix package.json 2016-02-22 15:09:09 +01:00
Raul Ochoa
877425267e Correct URLs for widgets in named maps
Fixes #381
2016-02-22 15:06:39 +01:00
csobier
adefa8b819 applied Carla's edits to date 2016-02-22 09:01:04 -05:00
Raul Ochoa
36b7377662 URLs for widgets are broken in named maps 2016-02-22 15:00:06 +01:00
Alejandro Martínez
2d6ee93448 Delete query_tables_api.js, wrap shrinkwrap 2016-02-22 13:40:20 +00:00
Raul Ochoa
f78c6fbc63 Stubs next version 2016-02-22 13:08:43 +01:00
Raul Ochoa
62e8868e4b Release 2.25.1 2016-02-22 12:58:51 +01:00
Raul Ochoa
aed0e03f7d Merge pull request #380 from CartoDB/upgrade-windshaft
Upgrade windshaft to 1.11.1
2016-02-22 12:55:29 +01:00
Raul Ochoa
3b67efeab1 Update news 2016-02-22 12:51:09 +01:00
Raul Ochoa
dcfa38e29c Upgrade windshaft to 1.11.1 2016-02-22 12:46:51 +01:00
Alejandro Martínez
cf06ff86c2 Use node-cartodb-query-tables library 2016-02-22 11:40:25 +01:00
Raul Ochoa
1c567ec455 Add tests with named maps + private dataset + widgets 2016-02-19 17:48:55 +01:00
Raul Ochoa
842fa4dfd2 Create populated places private table for named maps + widgets 2016-02-19 17:48:19 +01:00
csobier
cfa2714dbb added fetch tile in for Maps API 2016-02-19 11:45:06 -05:00
Raul Ochoa
30f8234bd0 Use analysis configuration as per new camshaft api 2016-02-19 17:13:28 +01:00
Raul Ochoa
ae8e3f2ef8 Merge branch 'master' into analysis-layers 2016-02-19 15:45:56 +01:00
csobier
4d6b4b1755 added xyz tile info-first draft 2016-02-18 16:58:28 -05:00
csobier
0994571895 clean-up portion of Named Maps doc-WIP 2016-02-18 13:15:28 -05:00
Raul Ochoa
3161939de9 Stubs next version 2016-02-18 15:15:09 +01:00
Raul Ochoa
4d8b341b6f Release 2.25.0 2016-02-18 15:14:18 +01:00
Raul Ochoa
b7fff960a2 Ignore CDB_ sql files downloaded for tests 2016-02-18 14:52:08 +01:00
Raul Ochoa
b6273cfef3 Merge pull request #377 from CartoDB/upgrade-windshaft
Upgrade windshaft
2016-02-18 14:49:18 +01:00
Raul Ochoa
b3f62e1631 Update news and bump version 2016-02-18 14:27:44 +01:00
Raul Ochoa
65e539d4c8 Upgrade windshaft 2016-02-18 13:49:10 +01:00
Raul Ochoa
6d91172630 Remove console.log 2016-02-18 13:43:39 +01:00
Alejandro Martínez
e1732076fc Merge branch 'new_querytables' of github.com:CartoDB/Windshaft-cartodb into new_querytables 2016-02-17 15:37:06 +01:00
Alejandro Martínez
587f66c23d Sort cache channels and keys alphabetically 2016-02-17 15:36:26 +01:00
Raul Ochoa
3d0c0f34ad Use a set to compare surrogate keys, avoiding key order errors 2016-02-17 12:18:57 +01:00
Raul Ochoa
8d4ebc171b Use a set to compare surrogate keys, avoiding key order errors 2016-02-17 12:15:43 +01:00
Raul Ochoa
4d3c21f1bc Merge remote-tracking branch 'origin/new_querytables' into analysis-layers 2016-02-17 11:48:09 +01:00
Raul Ochoa
6ece30fa2c Ignore CDB_ sql files downloaded for tests 2016-02-17 11:47:27 +01:00
Raul Ochoa
dfcb3b6dc1 Merge branch 'new_querytables' into analysis-layers 2016-02-17 11:31:55 +01:00
Raul Ochoa
87b4a37f3f Move camshaft dep to avoid future conflicts while updating windshaft 2016-02-17 11:29:40 +01:00
Raul Ochoa
4db2c715a0 Merge branch 'master' into analysis-layers
Conflicts:
	npm-shrinkwrap.json
	package.json
2016-02-17 11:29:11 +01:00
csobier
76653a4417 Merge pull request #368 from CartoDB/docs-setParam-torque-note
add note regarding setParams and torque
2016-02-16 10:36:40 -05:00
Raul Ochoa
cd81a59418 Adds some notes about how to npm link windshaft for development 2016-02-15 16:53:31 +01:00
Alejandro Martínez
19596245b8 Fix long line 2016-02-15 16:21:13 +01:00
Alejandro Martínez
0e83420e24 Fix long line 2016-02-15 16:15:43 +01:00
Alejandro Martínez
119846b56b Fix specs 2016-02-15 16:04:13 +01:00
Raul Ochoa
121c146ef9 Stubs next version 2016-02-15 14:47:36 +01:00
Raul Ochoa
3ab94c7c91 Release 2.24.0 2016-02-15 14:46:43 +01:00
Raul Ochoa
a44ed65a0b Merge pull request #376 from CartoDB/upgrade-windshaft
Upgrade windshaft to 1.10.0
2016-02-15 13:29:02 +01:00
Raul Ochoa
d0f84b2440 windshaft@1.10.1 2016-02-15 13:22:35 +01:00
Alejandro Martínez
33ba629c6d Add publicuser creation to Travis config 2016-02-15 13:00:21 +01:00
Alejandro Martínez
9e7b288f44 Merge remote-tracking branch 'origin/master' into new_querytables 2016-02-15 11:47:29 +00:00
Raul Ochoa
fe5c6faff1 Upgrade windshaft to 1.10.0 2016-02-15 12:16:56 +01:00
Raul Ochoa
2f51ad9c3f Regenerate npm-shrinkwrap.json to include camshaft dep 2016-02-12 18:49:01 +01:00
Raul Ochoa
ed1f753690 Fix style 2016-02-12 18:45:46 +01:00
Raul Ochoa
bcf3ce71ef Adds experimental adapter to use queries based on camshaft analysis 2016-02-12 18:38:06 +01:00
Alejandro Martínez
a656285001 Run tests against master cartodb-postgresql 2016-02-12 17:25:57 +01:00
Raul Ochoa
39cb463fbd Fix jsdoc 2016-02-12 16:13:40 +01:00
Raul Ochoa
354c982ea0 Fix jsdoc 2016-02-12 16:12:02 +01:00
Raul Ochoa
f71d38fb79 Stubs next version 2016-02-12 16:06:20 +01:00
Alejandro Martínez
b7ff554209 Use new _Updated_At function and new names 2016-02-11 11:45:09 +01:00
Javier Goizueta
ba0cf1eddf Release 2.23.0 2016-02-10 13:07:12 +01:00
Javier Goizueta
b381e8bad7 Release 2.23.0 2016-02-10 13:05:15 +01:00
Javier Goizueta
700335062e Merge pull request #365 from CartoDB/overviews-work
Version 2.23.0 with overviews support
2016-02-10 12:58:17 +01:00
Javier Goizueta
cd2bc319d8 Fix: bad error message 2016-02-10 12:27:39 +01:00
Javier Goizueta
4f8534afb3 Fix: accept empty layers in the MapConfigOverviewsAdapter 2016-02-10 12:16:37 +01:00
Javier Goizueta
c5b7d400f5 Merge branch 'master' into overviews-work 2016-02-10 11:56:54 +01:00
Raul Ochoa
ef58d7bcbd Add test for empty layers mapconfig 2016-02-10 11:49:56 +01:00
Alejandro Martínez
95ab99be4d Use new CDB_QueryTablesUpdatedAt function 2016-02-09 19:06:34 +01:00
Javier Goizueta
bbb8841f5a Upgrade Windshaft to 1.9.0
This version supports the current (provisional) QueryRewriter interface
2016-02-09 17:31:10 +01:00
Javier Goizueta
5b50e784cd Merge branch 'master' into overviews-work 2016-02-09 17:14:08 +01:00
Daniel García Aubert
f0af107ffa Stubs next version 2016-02-08 18:36:00 +01:00
Daniel García Aubert
0606fca484 Release 2.22.0 2016-02-08 18:31:28 +01:00
Daniel García Aubert
e6812ef6c1 Upgrade Windshaft version to 1.8.3 2016-02-08 18:26:26 +01:00
Daniel García Aubert
260e5ec25f tubs next version 2016-02-05 15:09:32 +01:00
Daniel García Aubert
097f68f98c Merge branch 'master' of github.com:CartoDB/Windshaft-cartodb 2016-02-05 15:05:15 +01:00
Daniel García Aubert
45d72b2bc6 Release 2.21.1 2016-02-05 15:03:34 +01:00
Raul Ochoa
82d4c20586 Merge pull request #371 from CartoDB/widgets-tests
Widgets tests
2016-02-05 14:58:07 +01:00
Raul Ochoa
03e3f7f13c Merge pull request #370 from CartoDB/fix-geojson-config
Fixed default geojson config
2016-02-05 14:53:43 +01:00
Raul Ochoa
b571b39b38 Aggregations in their own file 2016-02-05 13:32:38 +01:00
Raul Ochoa
f42d20f2c3 Histograms in their own file 2016-02-05 13:24:39 +01:00
Raul Ochoa
74cb876771 Move list to own file 2016-02-05 13:01:34 +01:00
Raul Ochoa
d78e01b7a4 Extract getWidget to TestClient 2016-02-05 12:59:33 +01:00
Raul Ochoa
73478ed0e9 Rename widgets tests file 2016-02-05 12:36:25 +01:00
Daniel García Aubert
887d71a9ad Fixed default geojson config 2016-02-05 12:35:03 +01:00
Javier Goizueta
56095926e0 Remove CartCSS handling from QueryRewriter
QueryRewriter doesn't require a style method anymore
2016-02-05 08:23:02 +01:00
Daniel García Aubert
13c3fbae70 Stubs next version 2016-02-04 19:35:23 +01:00
Daniel García Aubert
0b6845235a Release 2.21.0 2016-02-04 19:31:57 +01:00
Raul Ochoa
d2558197d2 Merge pull request #369 from CartoDB/geojson-renderer
Geojson renderer
2016-02-04 19:26:41 +01:00
Raul Ochoa
d005521aa4 Upgrade windshaft version 2016-02-04 19:06:54 +01:00
Daniel García Aubert
336aaa3840 Updated travis config in order to use npm@2 2016-02-04 17:24:02 +01:00
Daniel García Aubert
edbdd95f79 Upgrades npm version to 2.14.16 2016-02-04 17:09:30 +01:00
Daniel García Aubert
bb5a8fd0bf Merge branch 'geojson-renderer' of github.com:CartoDB/Windshaft-cartodb into geojson-renderer 2016-02-04 17:02:14 +01:00
Daniel García Aubert
3284e709c3 Regenerate npm-shrinkwrap 2016-02-04 17:00:44 +01:00
Raul Ochoa
d33ae29211 Revert "Fixed missing map key for named layers"
This reverts commit a4041524a3.
2016-02-04 16:26:32 +01:00
Daniel García Aubert
da51a173d7 Upgrades windshaft to 1.8.1 2016-02-04 15:46:13 +01:00
Raul Ochoa
425ec83209 Use a valid SPDX license expression 2016-02-04 15:22:08 +01:00
Daniel García Aubert
971b77451d Merge branch 'geojson-renderer' of github.com:CartoDB/Windshaft-cartodb into geojson-renderer 2016-02-04 12:46:52 +01:00
Daniel García Aubert
6407101709 Upgrade to Windshaft 1.8.0 2016-02-04 12:40:53 +01:00
Javier Goizueta
0a218da835 Implement an Overviews query rewriter
Use the Windshaft query-rewriter interface to adapt queries so
they use available overview tables.

This requires a version of Windshaft that implements the query-rewriter
interface (package.json/npm-shrinkwap.json have yet to be updated)
2016-02-04 10:26:31 +01:00
Daniel
89033d2cd4 Merge pull request #367 from CartoDB/metadata-refactor
Added property 'enableLayerMetadata' to config files
2016-02-03 15:37:05 +01:00
Javier Goizueta
870688309a Fix syntax 2016-02-02 19:29:10 +01:00
Javier Goizueta
a5070162c2 Merge branch 'overviews-work' of github.com:CartoDB/Windshaft-cartodb into overviews-work 2016-02-02 19:24:49 +01:00
Javier Goizueta
8348f74513 Provide OverviewsHandler configuration to Windshaft
A parameter has been added to Windshaft Mapnik renderer configuration
to define how queries will be adapted to use overviews.

Here we're using the default OverviewHandler providen in Windshaft,
with a parameter to define how the zoom level is determined.
2016-02-02 19:23:07 +01:00
csobier
e1babd05c1 add note regarding setParams and torque 2016-02-02 13:14:00 -05:00
Daniel García Aubert
08d43a8620 Added property 'enableLayerMetadata' to config files 2016-02-02 16:34:58 +01:00
Daniel García Aubert
8601a67e97 Improved assertions for multilayer tests 2016-02-01 18:39:34 +01:00
Daniel García Aubert
640500a0e3 Updated config to use Windshaft's geojson renderer 2016-02-01 17:12:50 +01:00
Daniel García Aubert
6ee1f1a8bf Fixed bad assertion in multilayer tests 2016-02-01 16:31:03 +01:00
Daniel García Aubert
a4041524a3 Fixed missing map key for named layers 2016-02-01 16:29:36 +01:00
Carlos Matallín
c3b17df3e7 Merge pull request #366 from CartoDB/docs-minor-clarification-added
Docs minor clarification added
2016-02-01 14:47:20 +01:00
csobier
5e77c50102 changed relative links to absolute links 2016-01-29 16:46:42 -05:00
csobier
1620cbc8df modified title 2016-01-29 12:11:21 -05:00
csobier
912b8f6ff4 fixed title of named maps 2016-01-29 12:07:47 -05:00
csobier
486a55ed7f edited intro text and fixed typo 2016-01-29 11:52:17 -05:00
csobier
af50af325d added links to new mapconfig, updated named map intro, and added cartodbjs named map examples 2016-01-29 11:46:03 -05:00
Daniel García Aubert
feef31d1bf Merge branch 'geojson-renderer' of github.com:CartoDB/Windshaft-cartodb into geojson-renderer 2016-01-29 15:36:47 +01:00
Raul Ochoa
f5b12d81ed Fix indent 2016-01-28 19:49:16 +01:00
Raul Ochoa
81200b72b4 Merge branch 'master' into overviews-work
Conflicts:
	test/acceptance/multilayer.js
2016-01-28 19:48:11 +01:00
Raul Ochoa
d6ecb8c793 Remove trailing whitespace 2016-01-28 19:44:25 +01:00
Javier Goizueta
5038ae6b1b Fix data for overviews integration tests 2016-01-27 17:40:12 +01:00
Javier Goizueta
37a4aaeeb4 Refactor findStatusCode for legibility
...disregarding jshint opinion
2016-01-27 17:39:24 +01:00
Javier Goizueta
6dbb0cb1c1 Emulate new overview table naming schme in the tests 2016-01-26 15:08:55 +01:00
Javier Goizueta
3b6abb5c9f Refactor construction of OverviewsApi 2016-01-26 11:49:41 +01:00
Javier Goizueta
ef9e9f8c78 Adapt to changes in CDB_Overviews SQL function
Now data for multiple tables is obtained in one call, simplifying the
use of this function. Also base table is returned as an oid, so we
now have the overview base table names with schema only when needed.
2016-01-26 11:38:21 +01:00
Javier Goizueta
2a819e559b Remove commented code 2016-01-22 11:15:25 +01:00
Javier Goizueta
8d691b2048 Refactor OverviewsApi
Separate metadata processing into collecting each layer's information (map)
and then organizing metadata per tables/zoom levels (reduce).
2016-01-22 11:03:01 +01:00
Javier Goizueta
1f6d5cfd6d Fix signature of CDB_Overviews 2016-01-21 18:39:31 +01:00
Javier Goizueta
81cb75f821 Refactor statusFromErrorMessage
...to make jshint happy
2016-01-21 18:24:49 +01:00
Javier Goizueta
8592136683 Change status code assigned to some errors
Errors without an explicit status code with the error message
containing 'does not exist' were assigned codes 404 or 403.
Now if the error message is 'function X does not exist'
(originated in SQL) the error code assigned is 400.
2016-01-21 18:02:21 +01:00
Javier Goizueta
18246418a0 Adapt test to new behaviour
Now an error occurs before craeeteLayergroup when checking affected
tables for overviews information. This prevents the creation of the
map configuration, so the corresponding redis keys need not be deleted.

The error message changes also because now the error originates in
a different function call, QueryTablesApi.prototype.getAffectedTablesInQuery
vs getAffectedTablesAndLastUpdatedTime.
2016-01-21 17:49:51 +01:00
Javier Goizueta
a6e3b07439 Reformat long lines 2016-01-21 17:42:52 +01:00
Javier Goizueta
c8033700c3 Fix equality operator use 2016-01-21 17:40:57 +01:00
Javier Goizueta
77f529d519 Add acceptance test for overviews 2016-01-21 17:36:25 +01:00
Javier Goizueta
6532024330 Add tests for MapConfigOverviewsAdapter 2016-01-21 15:44:22 +01:00
Javier Goizueta
62cc53228c OverviewApi: skip tables with no overlays in result 2016-01-21 13:35:56 +01:00
Javier Goizueta
532654eea8 Add tests for the OverviewsApi 2016-01-21 13:33:45 +01:00
Javier Goizueta
87bffb9657 Fix: overviews entry should be inside options 2016-01-21 12:06:01 +01:00
Javier Goizueta
094c9076be Fix: only mapnik layers can have overviews 2016-01-21 12:04:40 +01:00
Javier Goizueta
cc0385d614 Fix class name 2016-01-21 12:03:50 +01:00
Javier Goizueta
ed9b3e1230 Bring in code commented out for tests 2016-01-21 10:58:50 +01:00
Javier Goizueta
ffd89edaa7 Add overviews metadata to MapController instantiateTemplate
As in MapController create.
2016-01-20 18:36:06 +01:00
Javier Goizueta
5543fcb736 Fix: handle error properly when augmented layers with overviews 2016-01-20 18:09:00 +01:00
Javier Goizueta
7c897a40bf Fix bug in tests
The invalid SQL in this test (missing comma) was unnoticed because
the test was provoking a failed before the SQL was parsed, but new
features may cause the SQL to be evaluated (to get affected tables)
before the CartoCSS validity is checked.
2016-01-20 18:07:35 +01:00
Javier Goizueta
528574c550 Add dummy CDB_Overviews SQL function for tests 2016-01-20 17:10:12 +01:00
Javier Goizueta
b9f8812c98 Update comments 2016-01-20 17:09:15 +01:00
Javier Goizueta
09568050d6 Fix for changes in pgQueryRunner 2016-01-20 13:13:02 +01:00
Javier Goizueta
3dad225568 Fix bug 2016-01-20 13:12:45 +01:00
Javier Goizueta
4ca8ecf64c Refactor/fix potential problems 2016-01-20 12:44:00 +01:00
Javier Goizueta
2f2f6114e8 Refactor coding style
Hide the fact that we define functions in a loop from jshint!
2016-01-20 12:42:43 +01:00
Raul Ochoa
e4e7d6c840 Stubs next version 2016-01-20 12:26:16 +01:00
Raul Ochoa
d266d9a590 Release 2.20.0 2016-01-20 12:25:12 +01:00
Raul Ochoa
1e8525162a Bump version 2016-01-20 12:22:56 +01:00
Raul Ochoa
5fed5afe1f Update news 2016-01-20 12:22:24 +01:00
Javier Goizueta
8a49e46626 Accept minor jshint suggestions 2016-01-20 11:51:46 +01:00
Javier Goizueta
9feae66173 Bugfixes 2016-01-20 11:49:17 +01:00
Raul Ochoa
f8e4deb4b9 Merge pull request #364 from CartoDB/upgrade-windshaft
Upgrade windshaft to 1.7.0
2016-01-20 11:45:03 +01:00
Raul Ochoa
9c2fe9eac4 Upgrade windshaft to 1.7.0 2016-01-20 11:39:53 +01:00
Javier Goizueta
6aa9515fd1 Merge branch 'master' into overviews-work 2016-01-20 10:19:27 +01:00
Javier Goizueta
54854f0984 Avoid wrapper-functions to capture looping variable values
Use async-queue defer additional parameters
2016-01-20 10:07:19 +01:00
Javier Goizueta
89590d32df Sketch of vector overviews support 2016-01-19 19:31:43 +01:00
Raul Ochoa
d53a293f28 Merge pull request #363 from CartoDB/fix-statsd-key
Change redis pool name to report with a valid statsd key
2016-01-19 13:26:48 +01:00
Raul Ochoa
1dea84f9bf Change redis pool name to report with a valid statsd key 2016-01-19 13:00:02 +01:00
Raul Ochoa
e72bd77265 Merge branch 'master' into geojson-renderer
Conflicts:
	npm-shrinkwrap.json
	package.json
2016-01-18 14:52:01 +01:00
Raul Ochoa
8b50097a12 Merge pull request #361 from CartoDB/mapconfig-extension
Mapconfig widgets extension
2016-01-18 14:39:35 +01:00
Raul Ochoa
fbc1bccb48 Merge branch 'master' into mapconfig-extension
Conflicts:
	npm-shrinkwrap.json
2016-01-18 14:32:33 +01:00
Raul Ochoa
b5b881e662 Regenerate npm-shrinkwrap.json 2016-01-18 14:24:23 +01:00
Raul Ochoa
30e479094f Fix tests for windshaft master 2016-01-18 14:08:01 +01:00
Raul Ochoa
2b3244440f Merge remote-tracking branch 'origin/master' into mapconfig-extension 2016-01-15 18:31:30 +01:00
Raul Ochoa
ba4db870e4 Merge pull request #362 from CartoDB/prepare-tests-for-next-windshaft
Prepare tests for next windshaft
2016-01-15 18:30:50 +01:00
Raul Ochoa
d3f5b03f13 Validate current torque metadata keys 2016-01-15 17:25:09 +01:00
Raul Ochoa
e00661aa34 Remove substitution tokens in attributes service test 2016-01-15 17:17:20 +01:00
Raul Ochoa
3afb7a0eb3 Adds some notes about unsupported endpoints 2016-01-15 17:02:09 +01:00
Raul Ochoa
1eb69ae3d1 Remove make target to update windshaft 2016-01-15 16:02:02 +01:00
Raul Ochoa
5eeaa0272c Use master branch from windshaft and regenerate npm-shrinkwrap.json 2016-01-15 16:01:01 +01:00
Raul Ochoa
3e601cc2e6 Use geojson renderer branch from windshaft 2016-01-15 15:53:40 +01:00
Raul Ochoa
3e9f2a1319 Merge branch 'master' into mapconfig-extension 2016-01-14 18:45:30 +01:00
Raul Ochoa
45acdd9f39 fix json, 2nd attempt 2016-01-14 18:16:31 +01:00
Raul Ochoa
62b1df970a fix json 2016-01-14 18:16:12 +01:00
Raul Ochoa
1aac4316ab Merge pull request #360 from CartoDB/travis-container-based
Travis container based
2016-01-13 20:40:00 +01:00
Raul Ochoa
97d3bed1d2 test with pg 9.4 2016-01-13 20:33:12 +01:00
Raul Ochoa
19216eaa88 Use create language instead of extension 2016-01-13 20:21:54 +01:00
Raul Ochoa
3780aed1b7 Check with no postgresql-plpython-9.3 at all 2016-01-13 20:14:04 +01:00
Raul Ochoa
04a2d1d33c Remove postgresql-plpython-9.3 2016-01-13 20:11:24 +01:00
Raul Ochoa
18278da4bb Create language instead of extension 2016-01-13 19:36:01 +01:00
Raul Ochoa
553c64bd8b Create extension for plpython 2016-01-13 19:32:50 +01:00
Raul Ochoa
74abee2700 Use apt addon instead of apt-get install 2016-01-13 19:23:30 +01:00
Raul Ochoa
8ea159e0a1 Remove sudo calls 2016-01-13 19:14:58 +01:00
Raul Ochoa
353919239d Attempt to use travis' container based builds 2016-01-13 18:59:33 +01:00
Raul Ochoa
9e74e8633a Merge pull request #359 from CartoDB/query-runner-improvements
Query runner improvements
2016-01-13 18:56:26 +01:00
Raul Ochoa
98611be544 Merge pull request #351 from CartoDB/install_instructions
Install instructions
2016-01-12 16:39:58 +01:00
Raul Ochoa
3b7ff2285c Merge pull request #356 from CartoDB/http-409-status-on-template-limit-reached
Send 409 error code when maximum number of templates limit is reached
2016-01-12 16:14:37 +01:00
Raul Ochoa
8203c878f4 Send 409 error code when maximum number of templates limit is reached
Closes #346
2016-01-12 15:53:16 +01:00
Javier Goizueta
216e7b7f1d Use attributes-substitution-tokens of Windshaft
Intended for installation in a staging server
2016-01-08 12:07:51 +01:00
Carlos Matallín
4f4480dc9b Merge pull request #339 from CartoDB/newdocs
docs: split Map-API.md in different files
2016-01-07 15:38:31 +01:00
Carlos Matallín
16e1abe376 replicate #355 2016-01-07 15:33:16 +01:00
Carlos Matallín
2d0ebc821f Merge pull request #355 from CartoDB/353-named-maps-limit
added limit amount regarding named maps
2016-01-07 10:41:22 +01:00
csobier
67e921017c added limit amount regarding named maps 2016-01-06 08:44:53 -05:00
Paul Norman
7ed96ef0bb Add a list of packages and postgres instructions 2015-12-30 23:37:12 -08:00
Paul Norman
6f7bbe4ff5 Move install instructions to their own file 2015-12-30 17:29:19 -08:00
Raul Ochoa
74898e4261 Integration tests for QueryTablesApi
Again this is more about how it would be possible to use it isolated.
2015-12-30 17:48:24 +01:00
Raul Ochoa
c664d5392c Adds some tests about how to use PgQueryRunner isolated 2015-12-30 17:48:00 +01:00
Raul Ochoa
76cbc2f863 Improve PgQueryRunner public run method
Last param is callback function, receiving err + result, no need to
keep passing two functions, the query handler and the final callback.

It should be easier to understand now as query handler was in a position
where it had to know about receiving a callback, that was exposing an
implementation detail of PgQueryRunner.
2015-12-30 17:44:49 +01:00
Raul Ochoa
69fdaca41f Merge pull request #350 from CartoDB/fix-tests
Do not test `all` layers in blend suite
2015-12-30 16:04:58 +01:00
Raul Ochoa
5ac327272f Do not test all layers. Test is also present in windshaft suite. 2015-12-30 15:52:52 +01:00
Raul Ochoa
53a2d52523 Merge pull request #349 from CartoDB/pnorman-patch-1
Fix readme typo
2015-12-29 12:55:06 +01:00
Paul Norman
cd847adfb3 Fix readme typo
[no ci]
2015-12-28 11:53:54 -08:00
Raul Ochoa
e65dc2d790 Merge branch 'master' into mapconfig-extension 2015-12-22 12:59:39 +01:00
Raul Ochoa
e0d8f5afac Tests for named maps + torque layers with params instantiation 2015-12-21 20:01:44 +01:00
Raul Ochoa
7d2f543284 Allow column_type query string param 2015-12-02 18:50:11 +01:00
Raul Ochoa
ad566d8ff0 Merge branch 'master' into mapconfig-extension
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-11-24 13:36:39 +01:00
Raul Ochoa
67ba517a0e Stubs next version 2015-11-23 16:08:32 +01:00
Raul Ochoa
9a01c8b26e Release 2.19.1 2015-11-23 16:07:37 +01:00
Raul Ochoa
b40fd29228 Merge pull request #344 from CartoDB/upgrade-windshaft
Upgrade windshaft
2015-11-23 16:03:16 +01:00
Raul Ochoa
152440e611 Upgrade windshaft to 1.6.1
Regenerates npm-shrinkwrap.json, including bump in torque.js@2.11.4
2015-11-23 15:51:57 +01:00
Raul Ochoa
ea2a94be88 Fix news formatting 2015-11-23 15:51:00 +01:00
Raul Ochoa
0a38549c55 Regenerate npm-shrinkwrap.json 2015-11-23 11:00:55 +01:00
Raul Ochoa
e3b25f3080 Dependencies installation example 2015-11-19 12:50:34 +01:00
Raul Ochoa
1de4753daa fix tests 2015-11-16 18:34:36 +01:00
Raul Ochoa
d9614cc1c5 Add search endpoint 2015-11-16 13:15:01 +01:00
Raul Ochoa
37ff13493c Use mapconfig-extension from windshaft 2015-11-16 12:23:05 +01:00
Raul Ochoa
9264f4a668 Re-adds npm-shrinkwrap.json 2015-11-16 12:13:54 +01:00
Raul Ochoa
e254379244 Use windshaft's histogram branch 2015-11-13 10:35:52 +01:00
Raul Ochoa
4c851a0d09 Remove npm-shrinkwrap.json to ease development 2015-11-13 10:35:30 +01:00
Raul Ochoa
a84dd7cd29 Add more url params 2015-11-12 19:45:49 +01:00
Raul Ochoa
86abc392a1 Merge branch 'master' into mapconfig-extension
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-11-12 11:38:42 +01:00
Raul Ochoa
9e00cb3309 Stubs next version 2015-11-12 11:30:58 +01:00
Raul Ochoa
6d55544d70 Release 2.19.0 2015-11-12 11:29:50 +01:00
Raul Ochoa
d8e38e7e81 Merge pull request #343 from CartoDB/upgrade-mapnik
Upgrade windshaft/mapnik
2015-11-11 16:34:10 +01:00
Raul Ochoa
3dbcf5f293 Upgrade windshaft/mapnik 2015-11-11 16:28:21 +01:00
Raul Ochoa
7d230cc15d Widgets returning two results 2015-11-04 17:21:33 +01:00
Raul Ochoa
2320b0b852 Reference Windshaft's notes on Installing Mapnik 2015-11-03 16:56:37 +01:00
Raul Ochoa
837f99f31c Restrict npm supported versions to >=1.2.1 <2.0.0 2015-11-03 16:55:42 +01:00
Raul Ochoa
663703abae Merge branch 'master' into mapconfig-extension
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-11-02 11:13:34 +01:00
Raul Ochoa
5844c031c9 Stubs next version 2015-11-02 10:55:57 +01:00
Raul Ochoa
c9e95ccc9d Release 2.18.0 2015-11-02 10:38:50 +01:00
Raul Ochoa
98b14de02e Merge pull request #342 from CartoDB/upgrade-mapnik
Upgrade mapnik
2015-11-02 10:31:49 +01:00
Carlos Matallín
4bc8c57729 docs: remove code-title 2015-10-30 11:25:42 +01:00
Raul Ochoa
479861e612 Update news 2015-10-29 18:31:15 +01:00
Raul Ochoa
a746445b88 Upgrade windshaft to 1.5.0 2015-10-29 18:30:02 +01:00
Raul Ochoa
2c4cb6d42e Adds some tests for per widget bbox filters 2015-10-29 17:18:14 +01:00
Carlos Matallín
b2cd421e2e docs: rearrange overview 2015-10-29 16:59:51 +01:00
Raul Ochoa
8a81828a3d Enable bbox query string param 2015-10-29 16:25:56 +01:00
Raul Ochoa
8e568d0f20 Adapt tests to new widgets format 2015-10-29 13:19:49 +01:00
Raul Ochoa
3b9759d5e4 Merge branch 'master' into mapconfig-extension
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-10-28 19:41:44 +01:00
Raul Ochoa
a20a1f692b Stubs next version 2015-10-28 19:27:53 +01:00
Raul Ochoa
628b1921b4 Release 2.17.0 2015-10-28 19:27:03 +01:00
Raul Ochoa
fd8131201d Merge pull request #341 from CartoDB/upgrade-mapnik
Upgrades windshaft to 1.4.0
2015-10-28 19:26:11 +01:00
Raul Ochoa
ee39450864 Regenerate npm-shrinkwrap.json 2015-10-28 19:21:22 +01:00
Raul Ochoa
34e866007e Use windshaft 1.4.0 2015-10-28 19:15:26 +01:00
Carlos Matallín
277c0ee818 docs: fixes 2015-10-28 17:38:46 +01:00
Carlos Matallín
a3c7b3fc35 docs: fixes 2015-10-28 17:31:20 +01:00
Carlos Matallín
034b492788 docs: static maps 2015-10-28 17:02:16 +01:00
Carlos Matallín
cd00680c80 docs: static maps 2015-10-28 17:00:22 +01:00
Carlos Matallín
cc0ebf70a7 docs: static maps 2015-10-28 16:55:11 +01:00
Carlos Matallín
8087f838ef docs: named maps 2015-10-28 16:46:50 +01:00
Raul Ochoa
3fa4f8573e Upgrades windshaft to 1.3.0 2015-10-28 16:31:11 +01:00
Carlos Matallín
3eda1750cc docs: named maps 2015-10-28 16:26:33 +01:00
Carlos Matallín
2c35e27095 docs: anonymous_maps 2015-10-28 16:07:04 +01:00
Carlos Matallín
90487819bf docs: anonymous_maps 2015-10-28 16:02:23 +01:00
Carlos Matallín
50a943c131 docs: quickstart 2015-10-28 15:53:39 +01:00
Carlos Matallín
36b91180e4 docs: quickstart 2015-10-28 15:51:31 +01:00
Carlos Matallín
df44a84bfc Merge branch 'master' into newdocs 2015-10-28 15:31:35 +01:00
Raul Ochoa
e5afdb1e04 Adds test combining two widgets + filters 2015-10-28 12:21:43 +01:00
Raul Ochoa
cf2774c852 Fix test description 2015-10-28 12:06:06 +01:00
Raul Ochoa
36369068e1 Use match instead of full url 2015-10-27 19:11:29 +01:00
Raul Ochoa
af0812e990 Fix jshint 2015-10-27 19:08:46 +01:00
Raul Ochoa
0285f015e2 Pass filters within params 2015-10-27 13:26:11 +01:00
Raul Ochoa
473b20596a Adds helper function to retrieve widgets 2015-10-27 13:26:11 +01:00
Raul Ochoa
fda405f35d Unify widgets tests 2015-10-27 13:20:15 +01:00
Raul Ochoa
4047cb82b9 Merge pull request #340 from CartoDB/fix-widget-urls
Adds trailing slash to API endpoint in widget URLs
2015-10-26 17:52:55 +01:00
Pablo Alonso Garcia
7b57d22444 Added trailing slash to API endpoint in widget URLs 2015-10-26 17:50:50 +01:00
Raul Ochoa
50e63bf83d Merge branch 'master' into mapconfig-extension
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-10-26 17:06:13 +01:00
Raul Ochoa
8a9e257cdb Adds target to Makefile to just remove and re-install windshaft dep 2015-10-26 16:51:21 +01:00
Raul Ochoa
3a05d8c2e8 Widgets inside layer options 2015-10-26 16:40:39 +01:00
Raul Ochoa
8b222914c5 Add URL to widgets with their endpoints 2015-10-26 14:35:51 +01:00
Raul Ochoa
6d9182aba8 Rename widgets endpoint to honour its name 2015-10-26 13:42:06 +01:00
Raul Ochoa
f9d3e419a0 Renames list -> histogram 2015-10-26 11:12:26 +01:00
Raul Ochoa
4b0ecb1251 Adds histogram support, a bit of code duplication 2015-10-26 11:10:59 +01:00
Raul Ochoa
36a6af3266 Replaces List with Widget backend and changes list access to be layer based 2015-10-26 10:23:56 +01:00
Raul Ochoa
2f592e6f62 Stubs next version 2015-10-22 16:28:49 +02:00
Raul Ochoa
860d4bb475 Release 2.16.0 2015-10-22 16:27:52 +02:00
Raul Ochoa
c7b5fb9187 Be more clear about how to upgrade shrinkwrap file 2015-10-22 16:26:37 +02:00
Carlos Matallín
5e0c9377f2 newdocs: fix titles 2015-10-22 15:02:01 +02:00
Carlos Matallín
8db1ad6f19 newdocs: split files 2015-10-22 13:28:08 +02:00
Raul Ochoa
f513db837d Merge pull request #338 from CartoDB/upgrade-windshaft
Upgrades windshaft to 1.2.0
2015-10-21 18:56:45 +02:00
Raul Ochoa
d7181ec6c2 Upgrades windshaft to 1.2.0 2015-10-21 18:38:19 +02:00
Raul Ochoa
7761f56d36 Stubs next version 2015-10-21 13:58:26 +02:00
Raul Ochoa
f136b9f6e7 Release 2.15.1 2015-10-21 13:56:53 +02:00
Raul Ochoa
12175f10a6 Upgrades windshaft to 1.1.1 2015-10-21 13:55:36 +02:00
Raul Ochoa
52dbe14af2 Merge branch 'master' into mapconfig-extension
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-10-13 16:06:04 +02:00
Raul Ochoa
01bd09040e Stubs next version 2015-10-13 12:44:29 +02:00
Raul Ochoa
ab38e7069a Release 2.15.0 2015-10-13 12:36:25 +02:00
Raul Ochoa
9449642773 Remove soft-purge option when purging fastly 2015-10-09 16:37:17 +02:00
Raul Ochoa
1f489a4537 Fix broken test due fastly-purge upgrade 2015-10-09 16:02:11 +02:00
Raul Ochoa
6effcfb62e Upgrades windshaft to 1.1.0 and fastly-purge to 1.0.1 2015-10-09 15:50:39 +02:00
Raul Ochoa
9bc95a6071 List endpoint for layergroups 2015-10-06 19:47:44 +02:00
Raul Ochoa
b80e80bd61 Do not pass MapStore as it is no longer needed in Attributes backend 2015-10-06 19:46:52 +02:00
Raul Ochoa
59fb1dea54 Start using mapconfig-extension branch from windshaft 2015-10-06 18:55:27 +02:00
Raul Ochoa
2cc4cc5deb Stubs next version 2015-09-30 19:26:33 +02:00
Raul Ochoa
4c5630ac43 Release 2.14.1 2015-09-30 18:52:08 +02:00
Raul Ochoa
3181bcc63e Remove app dependency from controllers 2015-09-30 18:00:54 +02:00
Raul Ochoa
bf9cb33d63 Fix tests after upgrading windshaft, which includes a fix for layergroupid 2015-09-30 17:55:17 +02:00
Raul Ochoa
e7aa6bbdf9 Upgrade windshaft 2015-09-30 17:44:40 +02:00
Raul Ochoa
550b73ce23 Update news 2015-09-30 17:41:37 +02:00
Raul Ochoa
ffaa756637 Merge pull request #337 from CartoDB/safe-user-extraction
Safe user extraction
2015-09-30 17:25:12 +02:00
Raul Ochoa
9cd67f06c1 User extraction from request middleware
Used only where potentially a user is required.

It doesn't make sense to extract a user for request that don't need
a user in the context.
2015-09-30 17:17:01 +02:00
Raul Ochoa
79375616d5 Default host to empty string when header is not found
A String object is required to not fail on `.match` interface.
2015-09-30 16:31:56 +02:00
Raul Ochoa
ba6b8fbff1 Stubs next version 2015-09-30 11:28:38 +02:00
Raul Ochoa
6c37901824 Release 2.14.0 2015-09-30 11:26:03 +02:00
Raul Ochoa
0cf8661432 Be more specific about windshaft version upgrade 2015-09-30 11:25:07 +02:00
Raul Ochoa
ff561157ac Use Windshaft from registry 2015-09-30 11:21:25 +02:00
Raul Ochoa
a7cf9fd74f Regenerate npm-shrinkwrap.json 2015-09-30 11:04:40 +02:00
Raul Ochoa
788d24a455 Merge pull request #335 from CartoDB/standalone-server
Standalone server using Windshaft as library
2015-09-30 01:13:16 +02:00
Raul Ochoa
f9e3870941 Update news with all changes related to use Windshaft as library 2015-09-30 00:59:42 +02:00
Raul Ochoa
3a92fdd0f3 Remove sql api related configuration from configure script 2015-09-29 20:00:39 +02:00
Raul Ochoa
6a38defac5 Use Windshaft master branch 2015-09-29 19:42:13 +02:00
Raul Ochoa
3dfa7a8427 Name functions 2015-09-29 19:39:08 +02:00
Raul Ochoa
8dca835a8e Regenerate npm-shrinkwrap.json 2015-09-29 12:58:48 +02:00
Raul Ochoa
f2278d47a5 Increment map views on static preview images 2015-09-29 12:21:11 +02:00
Raul Ochoa
de3f195187 Merge pull request #333 from CartoDB/remove-outdated-docs
Remove outdated docs
2015-09-28 22:15:13 +02:00
Raul Ochoa
f33c3ce21a rmdirRecursiveSync DRY 2015-09-25 19:56:28 +02:00
Raul Ochoa
67ba424a19 Check style 2015-09-25 19:47:09 +02:00
Raul Ochoa
3376a08eb8 Remove unneeded resources server 2015-09-25 19:45:05 +02:00
Raul Ochoa
1ae15fe209 Remove unneeded resources server 2015-09-25 19:44:11 +02:00
Raul Ochoa
3c2820a5e1 Remove unneeded resources server 2015-09-25 19:43:20 +02:00
Raul Ochoa
8da6088f10 Remove outdated benchmark client 2015-09-25 19:39:49 +02:00
Raul Ochoa
8961a266b3 Remove redis key with test helper 2015-09-25 19:37:53 +02:00
Raul Ochoa
db8ab80bef Remove redis client 2015-09-25 19:32:30 +02:00
Raul Ochoa
36efc359f7 Remove redis client 2015-09-25 19:30:01 +02:00
Raul Ochoa
4f4dab143e Make tests to fail if unexpected keys are found in redis
Make test fail if they try to remove unexistent redis key
2015-09-25 19:23:33 +02:00
Raul Ochoa
af1e31fb29 Remove console 2015-09-25 19:22:34 +02:00
Raul Ochoa
1f757a7378 check style 2015-09-25 19:21:20 +02:00
Raul Ochoa
6028172018 Delegates redis keys deletion to test client[A 2015-09-25 19:18:28 +02:00
Raul Ochoa
2d374160a1 Delegates redis keys deletion to test client 2015-09-25 19:18:03 +02:00
Raul Ochoa
587fbfb4ff Delegates redis keys deletion to test client 2015-09-25 19:17:33 +02:00
Raul Ochoa
84820a87c8 Ask for specific redis key removal 2015-09-25 19:16:57 +02:00
Raul Ochoa
937d417e80 Delegates redis keys deletion to test client 2015-09-25 19:14:42 +02:00
Raul Ochoa
5b76cfd4dd Delegates redis keys deletion to test client 2015-09-25 19:13:46 +02:00
Raul Ochoa
957ed22b95 Delegates redis keys deletion to test client 2015-09-25 19:13:13 +02:00
Raul Ochoa
ebbe89cfb8 Ask for specific redis key removal 2015-09-25 19:11:48 +02:00
Raul Ochoa
c8eb6f275f Ask for specific redis key removal 2015-09-25 19:07:57 +02:00
Raul Ochoa
5f1213415b Ask for specific redis key removal 2015-09-25 19:06:04 +02:00
Raul Ochoa
d36ccb2602 Adapts tests to after test client changes 2015-09-25 19:05:37 +02:00
Raul Ochoa
486b803856 Delete redis keys using test helper 2015-09-25 19:04:59 +02:00
Raul Ochoa
d35630329f Ask for specific redis key removal 2015-09-25 18:41:44 +02:00
Raul Ochoa
aa9f742852 Ask for specific redis key removal 2015-09-25 18:37:21 +02:00
Raul Ochoa
960906e00c Ask for specific redis key removal 2015-09-25 18:22:45 +02:00
Raul Ochoa
432acd2b0e Ask for specific redis key removal 2015-09-25 18:20:30 +02:00
Raul Ochoa
84a03a81a0 Ask for specific redis key removal 2015-09-25 18:17:58 +02:00
Raul Ochoa
f64791eadd Ask for specific redis key removal 2015-09-25 18:04:45 +02:00
Raul Ochoa
51db76ac41 Ask for specific redis key removal 2015-09-25 17:59:00 +02:00
Raul Ochoa
1ec7f71b6c Ask for specific redis key removal 2015-09-25 17:51:19 +02:00
Raul Ochoa
bb3abdcc48 Remove redis keys after each test 2015-09-25 17:08:38 +02:00
Raul Ochoa
4d3ce038bc Remove redis keys after each test 2015-09-25 17:04:08 +02:00
Raul Ochoa
d66db547cb Remove redis keys after each test 2015-09-25 16:25:26 +02:00
Raul Ochoa
ebf1627753 Remove redis keys after each test 2015-09-25 16:23:14 +02:00
Raul Ochoa
bc818ca9cf Remove redis keys after each test 2015-09-25 16:23:08 +02:00
Raul Ochoa
0827124492 Remove redis keys after each test 2015-09-25 16:16:51 +02:00
Raul Ochoa
fea970f434 Remove redis keys after each test 2015-09-25 16:16:37 +02:00
Raul Ochoa
61cc14939b Remove redis keys after each test 2015-09-25 16:10:50 +02:00
Raul Ochoa
835d8c867e Remove redis keys after each test 2015-09-25 16:09:41 +02:00
Raul Ochoa
62601e4252 Remove redis keys after each test 2015-09-25 16:06:19 +02:00
Raul Ochoa
cc0b482c7a Remove redis keys after each test 2015-09-25 16:05:01 +02:00
Raul Ochoa
ff94f9ca0c Remove redis keys after each test 2015-09-25 16:03:20 +02:00
Raul Ochoa
8cd25dbd4f Remove redis keys after each test 2015-09-25 14:51:21 +02:00
Raul Ochoa
8ecf2e10c8 style 2015-09-25 14:50:09 +02:00
Raul Ochoa
5fb13bb545 Remove redis keys after each test 2015-09-25 14:49:59 +02:00
Raul Ochoa
a24b745f5c Remove redis keys after each test 2015-09-25 14:46:46 +02:00
Raul Ochoa
a127ff8d89 Remove redis keys after each test 2015-09-25 14:44:17 +02:00
Raul Ochoa
d3aa27533a Remove redis keys after each test 2015-09-25 14:42:40 +02:00
Raul Ochoa
35ec9e0063 Remove redis keys after each test 2015-09-25 14:42:30 +02:00
Raul Ochoa
1bac98d086 Remove redis keys after each test 2015-09-25 14:40:12 +02:00
Raul Ochoa
fc2f759dd3 Remove redis keys after each test 2015-09-25 14:39:39 +02:00
Raul Ochoa
f337a13577 Remove redis keys after each test 2015-09-25 14:39:15 +02:00
Raul Ochoa
eebd89aedb Remove redis keys after each test 2015-09-25 14:35:58 +02:00
Raul Ochoa
a9573987ec Remove redis keys after each test 2015-09-25 14:23:13 +02:00
Raul Ochoa
be8c82870f Add database id for found keys 2015-09-25 14:21:04 +02:00
Raul Ochoa
e667da8453 Remove redis keys being used in tests 2015-09-25 14:20:21 +02:00
Raul Ochoa
1258466529 Remove redis keys used in tests after each test 2015-09-25 14:09:35 +02:00
Raul Ochoa
8495b223c6 Early return when no keys to delete 2015-09-25 14:09:14 +02:00
Raul Ochoa
8339e4a4cb Remove redis keys used in tests after each test 2015-09-25 14:08:59 +02:00
Raul Ochoa
fa7288e03e Remove redis keys used in tests after each test 2015-09-25 14:08:35 +02:00
Raul Ochoa
763b6fce6e Remove redis keys used in each test 2015-09-25 14:07:12 +02:00
Raul Ochoa
7224acca84 Clean all redis keys after each test 2015-09-25 14:06:53 +02:00
Raul Ochoa
e12e7c4170 Don't allow to use suite related functions anymore 2015-09-25 13:37:32 +02:00
Raul Ochoa
0060d751b6 Use describe instead of suite 2015-09-25 13:37:10 +02:00
Raul Ochoa
b368463670 Use describe instead of suite 2015-09-25 13:31:51 +02:00
Raul Ochoa
21eb931701 Remove specific template maps doc as it's redundant info from Map-API.md 2015-09-25 11:21:03 +02:00
Raul Ochoa
e12b44ab2b Removes internal doc as it's mostly a duplication of Map-API.md
It also contains outdated terms and features.
2015-09-25 11:19:07 +02:00
Raul Ochoa
723dc59490 Show some redis stats after running tests
By commenting out you can monitor to a file
2015-09-25 09:52:14 +02:00
Raul Ochoa
5e1bc3e199 Named map updates does not emit update event if template didn't change
closes #323
2015-09-23 19:59:39 +02:00
Raul Ochoa
857548bbe4 Adds support for named layers in named tiles/static maps 2015-09-23 18:44:11 +02:00
Raul Ochoa
56070f3017 Show some redis stats after running tests
By commenting out you can monitor to a file
2015-09-23 17:18:58 +02:00
Raul Ochoa
f553efa69e Named map mapconfig provider takes care of template modifications
If a template changes it will flush the provider so it recreates the mapconfig
2015-09-23 16:45:20 +02:00
Raul Ochoa
84bf375f72 Makes cache async 2015-09-23 14:32:26 +02:00
Raul Ochoa
807455eb3d Force VACUUM ANALYZE in test table to stabilize test 2015-09-23 14:07:51 +02:00
Raul Ochoa
57284a9398 style 2015-09-23 13:05:35 +02:00
Raul Ochoa
c8705a8022 Use provider to get affected tables in static maps 2015-09-23 13:04:46 +02:00
Raul Ochoa
bbdc4591df Adds methods to assert mapnik images 2015-09-23 13:04:08 +02:00
Raul Ochoa
0a13e7943b Split tiles/static 2015-09-22 19:59:27 +02:00
Raul Ochoa
1e0bc57d32 Rename test file 2015-09-22 19:49:01 +02:00
Raul Ochoa
14e6cb05b3 Adds tests for named maps authentication for tiles 2015-09-22 19:48:08 +02:00
Raul Ochoa
b617bb0277 Health check will always return error if file is found even if empty 2015-09-22 15:15:57 +02:00
Raul Ochoa
ac7b02a434 Adds test for corner case in health check 2015-09-22 14:55:50 +02:00
Raul Ochoa
17458f3f4e Use windshaft's backend-foundations branch as it already has mvt support 2015-09-22 14:13:09 +02:00
Raul Ochoa
e87fc8a839 Merge branch 'standalone-server' into standalone-server-mvt 2015-09-22 12:28:16 +02:00
Raul Ochoa
6cf4d53b7c Merge branch 'master' into standalone-server
Conflicts:
	lib/cartodb/controllers/named_static_maps.js
2015-09-21 23:55:17 +02:00
Raul Ochoa
619545b993 Stubs next version 2015-09-21 22:49:06 +02:00
Raul Ochoa
e75d17f0e1 Release 2.13.0 2015-09-21 22:45:50 +02:00
Raul Ochoa
77a5b70576 Update news and bump version 2015-09-21 22:43:33 +02:00
Raul Ochoa
59b0a00c6f Merge pull request #332 from CartoDB/static-namedmaps-x-cache
Keep x-cache-channel in named map static maps
2015-09-21 22:40:42 +02:00
Raul Ochoa
5d24da4f2b Keep x-cache-channel in named map static maps 2015-09-21 22:36:13 +02:00
Raul Ochoa
0d3e96ee9f Merge branch 'standalone-server' into standalone-server-mvt 2015-09-18 17:23:58 +02:00
Raul Ochoa
16480a6c44 log as warn 2015-09-18 17:23:37 +02:00
Raul Ochoa
813a59a36e Removes function from control flow 2015-09-18 17:16:30 +02:00
Raul Ochoa
23fd33030d remove console.log 2015-09-18 17:13:37 +02:00
Raul Ochoa
2bdce4baa7 Replaces console.log with global logger 2015-09-18 17:13:22 +02:00
Raul Ochoa
d2df0b7c84 Configure log4js in test environment so it doesn't output by default 2015-09-18 16:59:45 +02:00
Raul Ochoa
16468b1216 remove console.log 2015-09-18 16:45:35 +02:00
Raul Ochoa
3abdee5e87 use debug for corner case 2015-09-18 16:40:55 +02:00
Raul Ochoa
d69a69da94 remove console.log 2015-09-18 16:39:52 +02:00
Raul Ochoa
bc806bba34 remove console.log 2015-09-18 16:39:30 +02:00
Raul Ochoa
81081ba2d4 Remove console.log from test 2015-09-18 16:26:54 +02:00
Raul Ochoa
5ad567803d Set backlog on server listen 2015-09-18 16:25:10 +02:00
Raul Ochoa
486cafba9d re-generate npm-shrinkwrap.json 2015-09-18 03:06:26 +02:00
Raul Ochoa
c0a1119d1d Merge branch 'standalone-server' into standalone-server-mvt 2015-09-18 02:58:39 +02:00
Raul Ochoa
bd4894ebd3 Starts modifying readme 2015-09-18 02:58:16 +02:00
Raul Ochoa
e9e95eda0a Merge branch 'standalone-server' into standalone-server-mvt 2015-09-18 02:31:38 +02:00
Raul Ochoa
1b3f1ba2e8 Merge pull request #331 from CartoDB/standalone-server-express-4
Upgrade express to 4.x
2015-09-18 02:09:23 +02:00
Raul Ochoa
5e27f981de Regenerate npm-shrinkwrap.json 2015-09-18 01:58:47 +02:00
Raul Ochoa
c97f78bb39 Merge branch 'standalone-server' into standalone-server-mvt
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-09-18 01:34:14 +02:00
Raul Ochoa
f7b1032b7a Do not fail for now if there are pending keys in redis 2015-09-17 18:24:12 +02:00
Raul Ochoa
7ee2649feb Remove redis keys having in mind last updated time 2015-09-17 18:12:45 +02:00
Raul Ochoa
281320f2c4 use 127.0.0.1 instead of localhost 2015-09-17 17:51:34 +02:00
Raul Ochoa
30f7c74aee Reenable external resources tests using 127.0.0.1 2015-09-17 17:36:23 +02:00
Raul Ochoa
2dfd7257dd Try to run in travis with external resources disabled 2015-09-17 17:19:31 +02:00
Raul Ochoa
1f9dd5fd8c re-enable nock after every suite 2015-09-17 17:14:32 +02:00
Raul Ochoa
dd83c05a89 restore nock globally after each suite 2015-09-17 15:10:23 +02:00
Raul Ochoa
30cba053da Check there is no unexepcted keys on redis after tests 2015-09-17 15:07:54 +02:00
Raul Ochoa
5428d3f0b0 Remove __dirname 2015-09-17 13:58:45 +02:00
Raul Ochoa
95398354e3 require test helper 2015-09-17 13:58:22 +02:00
Raul Ochoa
7e73216539 Remove unused variables 2015-09-17 13:44:37 +02:00
Raul Ochoa
bbac1df463 Moves acceptance test about statsd uncaugth exception to integration 2015-09-17 13:40:01 +02:00
Raul Ochoa
208dd209a4 Merge branch 'standalone-server' into standalone-server-express-4
Conflicts:
	lib/cartodb/controllers/base.js
2015-09-17 12:57:33 +02:00
Raul Ochoa
9139feaa30 Move error message handling test to unit 2015-09-17 12:48:29 +02:00
Raul Ochoa
f9f6c8b700 Use debug instead of console 2015-09-17 12:03:58 +02:00
Raul Ochoa
db8457af60 status + send on syntax error handler 2015-09-17 11:07:02 +02:00
Raul Ochoa
361dd00e9d Use debug instead of console 2015-09-17 11:06:46 +02:00
Raul Ochoa
7fd870cfd2 Rewrite assert.response using request module 2015-09-17 02:06:46 +02:00
Raul Ochoa
967ef99277 Fix jsonp tests 2015-09-17 02:06:32 +02:00
Raul Ochoa
d93abe8e7d Change to delete 2015-09-17 02:05:47 +02:00
Raul Ochoa
a4ba21f9db Call send with correct params 2015-09-17 02:05:25 +02:00
Raul Ochoa
feabb20748 Send depending on body type 2015-09-17 02:04:30 +02:00
Raul Ochoa
31fe06e3ce Use listener and remove etag 2015-09-17 02:04:10 +02:00
Raul Ochoa
ef86bacf7f Set headers with set method 2015-09-17 02:03:09 +02:00
Raul Ochoa
beabe48aec Upgrade express, adds body-parser
- basic changes in server
- basic changes in unit tests
2015-09-17 00:19:00 +02:00
Raul Ochoa
e335f51dbc Makefile getting tests with find command 2015-09-16 23:18:38 +02:00
Raul Ochoa
38e422e84c Moves sendError and sendResponse to Base controller
Test for findStatusCode moved to controller
2015-09-16 21:54:56 +02:00
Raul Ochoa
1d6d11171d Fix test to not rely on network 2015-09-16 19:53:14 +02:00
Raul Ochoa
e32ced107e Fix all ported tests related to req2params 2015-09-16 18:09:39 +02:00
Raul Ochoa
99d78ce9b8 Remove unused variables 2015-09-16 17:02:35 +02:00
Raul Ochoa
066aff16f1 Use global for req2params number of request assert 2015-09-16 16:58:08 +02:00
Raul Ochoa
352dc6b311 BaseController to encapsulate req2params method
All controllers now extending BaseController
- Most of the acceptance ported tests will be broken
2015-09-16 16:18:26 +02:00
Raul Ochoa
a176ddbf3f Regenerate npm-shrinkwrap.json 2015-09-16 13:25:57 +02:00
Raul Ochoa
1c6571d1db Upgrade dependencies and regenerate npm-shrinkwrap.json
Surrogate keys tests sleeping :-(
2015-09-16 13:17:03 +02:00
Raul Ochoa
bf7b35230f Regenerate npm-shrinkwrap.json 2015-09-16 11:44:12 +02:00
Raul Ochoa
46d901ada7 Merge branch 'standalone-server' into standalone-server-mvt 2015-09-16 11:09:27 +02:00
Raul Ochoa
66f94d9452 Fix test 2015-09-16 02:49:18 +02:00
Raul Ochoa
62f428f434 Remove app dependency 2015-09-16 01:48:54 +02:00
Raul Ochoa
713ad03c3b No need to expose findStatusCode at app level 2015-09-16 01:44:30 +02:00
Raul Ochoa
ad2ebc11dd Remove unused require 2015-09-16 01:39:15 +02:00
Raul Ochoa
72a0c4a487 New sendResponse and sendError methods
- fixes response for static named map error cases
2015-09-16 01:36:51 +02:00
Raul Ochoa
fba5a35514 Move sendResponse and sendError to response object 2015-09-15 19:28:02 +02:00
Raul Ochoa
e2e5e40ea9 Fix maxcomplexity 2015-09-15 19:01:34 +02:00
Raul Ochoa
f5660667c8 Move req.profiler call to req2params itself 2015-09-15 18:16:50 +02:00
Raul Ochoa
64e225c4aa Merge branch 'master' into standalone-server 2015-09-15 11:48:33 +02:00
Raul Ochoa
126491fc93 Remove unused xml file that was used in health check 2015-09-15 11:46:19 +02:00
Raul Ochoa
ea872d96f8 Listen to renderer cache events and log stats 2015-09-14 19:24:24 +02:00
Raul Ochoa
3f7202d89c Port tests for stats 2015-09-14 19:07:53 +02:00
Raul Ochoa
2d3088ba27 Port everything related to stats from windshaft 2015-09-14 18:47:01 +02:00
Raul Ochoa
469b602484 Attributes backend using mapconfig provider to access attributes 2015-09-14 18:46:22 +02:00
Raul Ochoa
aa6f00f927 Merge branch 'standalone-server' into standalone-server-mvt 2015-09-10 12:06:21 +02:00
Raul Ochoa
67afd8738b Remove renderer cache param from attributes backend 2015-09-10 00:47:32 +02:00
Raul Ochoa
98d6170870 Adds notes about contributing 2015-09-08 16:44:44 +02:00
Raul Ochoa
b2e1e5361f Merge branch 'standalone-server' into standalone-server-mvt
Conflicts:
	npm-shrinkwrap.json
2015-09-08 15:46:23 +02:00
Raul Ochoa
f96c80d7a1 Merge branch 'master' into standalone-server
Conflicts:
	lib/cartodb/cartodb_windshaft.js
2015-09-08 15:42:30 +02:00
Raul Ochoa
7ae034d746 Remove no longer needed health check params 2015-09-07 18:40:20 +02:00
Raul Ochoa
c409c146bf Upgrade CDB_QueryTables to use latest version 2015-09-07 17:17:40 +02:00
Raul Ochoa
e0a7eb01cc Use torque renderer config
Adds some notes about db pool params in torque
2015-09-04 16:33:40 +02:00
Raul Ochoa
3af2136770 Merge branch 'master' into standalone-server
Conflicts:
	lib/cartodb/cartodb_windshaft.js
	lib/cartodb/monitoring/health_check.js
2015-09-04 13:21:54 +02:00
Raul Ochoa
13a2001a2b Merge pull request #329 from CartoDB/health-check-no-results
Do not return results from health check
2015-08-28 18:50:00 +02:00
Raul Ochoa
d6102284a4 Do not return results from health check
It also removed old dependencies and takes disabled file path in ctor.
2015-08-28 17:41:40 +02:00
Raul Ochoa
c56ef8e0da Merge branch 'master' into standalone-server
Conflicts:
	app.js
	npm-shrinkwrap.json
	package.json
2015-08-28 13:54:56 +02:00
Raul Ochoa
bb17609ea3 Stubs next version 2015-08-27 17:48:06 +02:00
Raul Ochoa
f2f342e14c Release 2.12.0 2015-08-27 17:46:29 +02:00
Raul Ochoa
11bd07ee6b Merge pull request #328 from CartoDB/upgrade-windshaft
Upgrades windshaft to 0.51.0
2015-08-27 17:39:14 +02:00
Raul Ochoa
fa85dcbc4c Upgrades windshaft to 0.51.0 2015-08-27 17:24:38 +02:00
Raul Ochoa
473ae13a03 Merge pull request #327 from CartoDB/http-agent-configuration
Make http and https globalAgent options configurable
2015-08-27 16:44:55 +02:00
Raul Ochoa
0561a28a4d Make http and https globalAgent options configurable 2015-08-27 16:28:16 +02:00
Raul Ochoa
b3467116fe Stubs next version 2015-08-26 09:55:15 +02:00
Raul Ochoa
e667d10eb8 Release 2.11.0 2015-08-26 09:52:53 +02:00
Raul Ochoa
a5bda00cdd Merge pull request #326 from CartoDB/upgrade-windshaft
Upgrades windshaft to 0.50.0
2015-08-25 19:32:28 +02:00
Raul Ochoa
627bc672bc Upgrades windshaft to 0.50.0 2015-08-25 19:27:00 +02:00
Raul Ochoa
9ef96080a6 Log PID on start 2015-08-24 12:45:21 +02:00
Raul Ochoa
bf4844e664 Stubs next version 2015-08-18 16:35:02 +02:00
Raul Ochoa
06f454abcf Release 2.10.0 2015-08-18 16:33:44 +02:00
Raul Ochoa
9d4e4a99bc Merge pull request #325 from CartoDB/upgrade-windshaft-tilelive-cache
Upgrades windshaft
2015-08-18 16:29:22 +02:00
Raul Ochoa
b77be76f51 Bump version and add news 2015-08-18 15:22:27 +02:00
Raul Ochoa
3121ed9a95 Config samples for metatileCache with default behaviour 2015-08-18 15:18:58 +02:00
Raul Ochoa
37dfd8fc12 Upgrade windshaft 2015-08-18 15:18:44 +02:00
Raul Ochoa
de2719b0c5 Stubs next version 2015-08-06 18:03:00 +02:00
Raul Ochoa
e3d5abc9a2 Release 2.9.0 2015-08-06 18:02:09 +02:00
Raul Ochoa
ea7a5da1c1 Merge pull request #324 from CartoDB/memory-stats
Send memory usage stats
2015-08-06 16:12:18 +02:00
Raul Ochoa
2e063cc2d2 Send memory usage stats 2015-08-06 16:06:42 +02:00
Raul Ochoa
943509864d Improve uniqueness of named map map config provider 2015-07-31 12:24:34 +02:00
Raul Ochoa
2ac228359f Fallback to image/png header 2015-07-31 12:23:36 +02:00
Raul Ochoa
909f8da2ff Adds lru cache for layergroups and named maps mapconfig provider 2015-07-15 16:51:26 +02:00
Raul Ochoa
5a5832394a Remove console.log 2015-07-15 16:10:59 +02:00
Raul Ochoa
52b60a22fd Makes all tests to run together 2015-07-15 16:09:43 +02:00
Raul Ochoa
116da64e5c More strict cyclomatic complexity check 2015-07-15 15:10:59 +02:00
Raul Ochoa
9c6c63c167 More strict jshint 2015-07-15 15:03:28 +02:00
Raul Ochoa
e7284262e4 Merge branch 'master' into standalone-server
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-07-15 12:20:12 +02:00
Raul Ochoa
decd9077e4 Stubs next version 2015-07-15 11:44:59 +02:00
Raul Ochoa
f6c47bf85e Release 2.8.0 2015-07-15 11:43:54 +02:00
Raul Ochoa
423191c13b Merge pull request #319 from CartoDB/upgrade-windshaft
Upgrades windshaft to 0.48.0
2015-07-15 11:43:09 +02:00
Raul Ochoa
7a5928d957 Upgrades windshaft to 0.48.0 2015-07-15 11:31:26 +02:00
Raul Ochoa
bbec3ae7da Subscribes to named map changes to invalidate cache 2015-07-14 21:18:10 +02:00
Raul Ochoa
1f7daab677 Caching named map providers by template name and config/auth token
Named Map provider cache buster changes on creation
2015-07-14 21:17:58 +02:00
Raul Ochoa
91ab64dda9 Fix cached result in getAffectedTablesAndLastUpdatedTime 2015-07-14 21:00:27 +02:00
Raul Ochoa
722705468f Not adding surrogate keys for empty affected tables 2015-07-14 20:53:26 +02:00
Raul Ochoa
07c920bad5 Use named map provider cache to retrieve providers 2015-07-14 20:53:06 +02:00
Raul Ochoa
6d3ef11a7c Fix cache usage in layergroup affected tables 2015-07-14 20:11:49 +02:00
Raul Ochoa
4aabe9d946 Named maps controller adding cache headers
This requires a cache for affected tables as it is hitting db for
every request right now
2015-07-14 20:10:55 +02:00
Raul Ochoa
7247b20686 Unify sendResponse in named maps controller 2015-07-14 17:34:05 +02:00
Raul Ochoa
8e8f618a22 assert instead of ifs 2015-07-14 17:33:42 +02:00
Raul Ochoa
a50af0ee64 Merge branch 'master' into standalone-server 2015-07-14 16:36:26 +02:00
Raul Ochoa
436c334f5a Stubs next version 2015-07-14 16:33:12 +02:00
Raul Ochoa
4f84138ade Release 2.7.2 2015-07-14 16:32:04 +02:00
Raul Ochoa
a0d86ac5dc Update news 2015-07-14 16:28:51 +02:00
Raul Ochoa
d426702213 Merge branch 'master' into standalone-server 2015-07-14 16:24:39 +02:00
Raul Ochoa
e2be4f1275 Merge pull request #314 from CartoDB/use-cdb-query-tables-text
Use CDB_QueryTablesText instead of CDB_QueryTables
2015-07-14 16:20:23 +02:00
Raul Ochoa
c97610ad59 style 2015-07-14 14:30:37 +02:00
Raul Ochoa
e8b5845174 Shared cache for affected tables in layergroup and map controllers 2015-07-14 13:40:41 +02:00
Raul Ochoa
c295584864 Cache channel now in layergroup controller
Internal cache channel dbname+layergroupid cache must be unified in layergroup
and map controllers
Removes sendWithHeaders
2015-07-14 11:55:49 +02:00
Raul Ochoa
36257f73b9 Better format 2015-07-13 17:18:50 +02:00
Raul Ochoa
9355a5ca24 Tests for surrogate keys in layergroup anonymous instantiation 2015-07-13 16:54:08 +02:00
Raul Ochoa
d6447ef311 Fix tests related to surrogate keys, includes tables 2015-07-13 16:36:41 +02:00
Raul Ochoa
5e2a20fbe0 Tags layergroup instantiation with surrogate keys per affected tables 2015-07-13 16:15:34 +02:00
Raul Ochoa
76823f7529 No need to pass a reference to itself 2015-07-13 15:06:22 +02:00
Raul Ochoa
96a6a0d980 Using MapStore, no need to attach it to app 2015-07-13 15:05:45 +02:00
Raul Ochoa
b05701be61 Authentication/Authorization moves to its own entity 2015-07-13 15:05:03 +02:00
Raul Ochoa
962ac97433 regenerate npm-shrinkwrap.json 2015-07-13 12:52:12 +02:00
Raul Ochoa
9491b81d0c Standalone server with MVT support 2015-07-13 12:34:52 +02:00
Raul Ochoa
316f08df08 named maps tiles sending tile headers 2015-07-13 11:53:23 +02:00
Raul Ochoa
f9554ec761 Re-enable render limits 2015-07-10 19:10:55 +02:00
Raul Ochoa
e128b1d750 remove unused method 2015-07-10 12:33:01 +02:00
Raul Ochoa
e45efbcfb0 New map config provider to allow injecting limits in context 2015-07-10 12:31:56 +02:00
Raul Ochoa
847ab96a48 RendererFactory changes for new signature 2015-07-10 12:30:52 +02:00
Raul Ochoa
1e52f790ad One pass for prepare request and response objects 2015-07-10 11:25:20 +02:00
Raul Ochoa
9bece712a9 Splits controllers and supports after layergroup creation actions 2015-07-10 11:24:32 +02:00
Raul Ochoa
6e0678e084 better style 2015-07-10 01:31:06 +02:00
Raul Ochoa
579cabdc1a Initial refactor of layergroup creation 2015-07-10 01:30:38 +02:00
Raul Ochoa
9f252dfac4 Improve named map config format for cache key 2015-07-09 19:49:11 +02:00
Raul Ochoa
5aad624346 NamedMaps controller using NamedMapMapConfigProvider
PreviewBackend with format param
2015-07-09 18:47:21 +02:00
Raul Ochoa
23d1109910 Adds named maps mapconfig provider
starts using it in named map instantiation
2015-07-09 14:39:25 +02:00
Raul Ochoa
ae2a72a810 Fix named maps controller using MapStoreMapConfig 2015-07-09 13:37:00 +02:00
Raul Ochoa
ed096c3a1a disable tests, time to work on a named map provider before fixing 'em 2015-07-08 20:51:55 +02:00
Raul Ochoa
123346ebdb Refactor controllers to use map store map config provider 2015-07-08 20:51:36 +02:00
Raul Ochoa
8540965696 fix health check tests 2015-07-08 20:50:34 +02:00
Raul Ochoa
c8568b175b Move server info to its own controller 2015-07-08 16:08:38 +02:00
Raul Ochoa
1737cbe1a5 Unifies named map instantiation so it's easy to work on it 2015-07-08 15:50:59 +02:00
Raul Ochoa
c81048312d Context with user 2015-07-08 15:34:46 +02:00
Raul Ochoa
ac3afd5695 Fix jshint 2015-07-08 13:28:07 +02:00
Raul Ochoa
fa84813a37 Manage cors with a middleware 2015-07-08 13:27:56 +02:00
Raul Ochoa
8cd3807100 Split named maps administration from instantiation/usage 2015-07-08 13:11:57 +02:00
Raul Ochoa
7aeb54d53d Enables multilayer ported tests 2015-07-08 12:59:49 +02:00
Raul Ochoa
725ff41fb1 Ports tile stats tests from windshaft 2015-07-08 00:19:11 +02:00
Raul Ochoa
d071fe6d0c Ports windshaft server unit tests 2015-07-08 00:12:32 +02:00
Raul Ochoa
2234a763cb Uses model through model namespace 2015-07-07 23:52:39 +02:00
Raul Ochoa
d52b65470e Ports acceptance tests from windshaft 2015-07-07 23:46:58 +02:00
Raul Ochoa
b63e697934 Handle no layers case 2015-07-07 23:45:56 +02:00
Raul Ochoa
8a036c79c7 Merge branch 'master' into standalone-server
Conflicts:
	app.js
2015-07-07 12:36:39 +02:00
Raul Ochoa
9a393fa793 Adds some notes about uv_threadpool_size and mapnik renderer pool size 2015-07-07 12:27:09 +02:00
Raul Ochoa
7614f72df6 Stubs next version 2015-07-06 11:58:08 +02:00
Raul Ochoa
ef2db78567 Release 2.7.1 2015-07-06 11:56:30 +02:00
Raul Ochoa
8708468444 fix 2.7.0 release date 2015-07-06 11:56:18 +02:00
Raul Ochoa
cd28a4fbcc redis-mpool noReadyCheck and unwatchOnRelease options from config
do not extend them as it disallows to pick from config
2015-07-06 11:52:34 +02:00
Raul Ochoa
e49881d1ed Improve authorizedBySigner 2015-07-06 03:23:51 +02:00
Raul Ochoa
aa266f9b61 Improve authorizedByAPIKey 2015-07-06 03:19:56 +02:00
Raul Ochoa
ccd3d0a3bf Merge branch 'named-maps-tiles' into standalone-server
Conflicts:
	app.js
2015-07-06 02:55:13 +02:00
Raul Ochoa
69fc367f69 Empty results/png directory 2015-07-06 02:32:13 +02:00
Raul Ochoa
a9f24542d5 regenerate npm-shrinkwrap.json 2015-07-06 02:09:06 +02:00
Raul Ochoa
8e4e458a2a fix jshint 2015-07-06 02:08:56 +02:00
Raul Ochoa
feec7805af Merge branch 'master' into named-maps-tiles
Conflicts:
	npm-shrinkwrap.json
	package.json
2015-07-06 01:32:33 +02:00
Raul Ochoa
19f488095b Stubs next version 2015-07-06 01:07:30 +02:00
Raul Ochoa
cd65c6dd0e Release 2.7.0 2015-07-06 01:05:28 +02:00
Raul Ochoa
0c670cfdfd Merge pull request #318 from CartoDB/upgrade-windshaft
Upgrades windshaft to 0.47.0
2015-07-05 21:51:34 +02:00
Raul Ochoa
27ff1ac4f6 Upgrades windshaft to 0.47.0 2015-07-05 21:16:12 +02:00
Raul Ochoa
3f06de93f7 Merge pull request #317 from CartoDB/improve-redis
Improve redis
2015-07-05 21:11:34 +02:00
Raul Ochoa
0da6495330 Fixes unwatchOnRelease redis config 2015-07-05 21:00:25 +02:00
Raul Ochoa
bf24347328 Exposes redis noReadyCheck config 2015-07-05 20:59:52 +02:00
Raul Ochoa
7a5d73f9df Upgrades redis-mpool 2015-07-05 20:58:39 +02:00
Raul Ochoa
7fc403425d metadata backend 2015-07-04 23:44:39 +02:00
Raul Ochoa
ef171bf2af reverts map store changes 2015-07-04 23:38:15 +02:00
Raul Ochoa
b74a6624e3 remove redundant code 2015-07-04 23:32:26 +02:00
Raul Ochoa
19bf1fe56b note about token format 2015-07-04 23:32:19 +02:00
Raul Ochoa
ea6bb8dca3 fix jsdoc 2015-07-04 23:20:12 +02:00
Raul Ochoa
9d6d3f96b2 Unify mapstore 2015-07-04 23:18:09 +02:00
Raul Ochoa
5967c5d1d5 Reorg app.js 2015-07-04 23:09:00 +02:00
Raul Ochoa
a6017c6ade Reorg requires 2015-07-04 21:33:31 +02:00
Raul Ochoa
2d3f2667ca Standalone server initial implementation
- no dependency over Windshaft.Server
2015-07-04 20:41:22 +02:00
Raul Ochoa
ed90cadd75 fix jshint 2015-07-02 16:35:13 +02:00
Raul Ochoa
0d9f34fd48 Stubs next version 2015-07-02 15:48:58 +02:00
Raul Ochoa
da55a3bdd2 Release 2.6.1 2015-07-02 15:47:40 +02:00
Raul Ochoa
333334e598 Upgrades windshaft 2015-07-02 15:41:48 +02:00
Raul Ochoa
7168e4410c Stubs next version 2015-07-02 14:12:41 +02:00
Raul Ochoa
3ff8571f4a Release 2.6.0 2015-07-02 14:11:39 +02:00
Raul Ochoa
75ddcbbd01 Updates windshaft to 0.46.0 and documents new config formatMetatile 2015-07-02 13:28:37 +02:00
Raul Ochoa
91a44980f3 Skips limits tests until beforeRendererCreate is available 2015-07-02 02:03:03 +02:00
Raul Ochoa
034f3c77ce modifies controllers to use new mapbackend signatures 2015-07-02 02:02:22 +02:00
Raul Ochoa
9b3e18f333 Merge pull request #315 from CartoDB/readme_update
Update instructions
2015-07-01 09:37:57 +02:00
Juan Ignacio Sánchez Lara
fcb0a4a7e6 Less specific upgrade help 2015-07-01 07:22:37 +02:00
Raul Ochoa
5a003a7cbe Initial/dummy implementation for named maps tiles
Issues:
 - creates a layergroup per tile:
   - trigges a mapview
   - extracts each time affected tables and last update
 - duplicates a lot of code from NamedStaticMapsController
 - keeps relying on fake request concept
2015-06-30 15:41:57 +02:00
Juan Ignacio Sánchez Lara
94e38cef9d Update instructions 2015-06-30 11:00:32 +02:00
Raul Ochoa
d13d107aea Adds names to functions 2015-06-29 19:18:52 +02:00
Raul Ochoa
4f87796e9c Uses backend-foundations branch to use createLayergroup from backend 2015-06-29 18:58:58 +02:00
Raul Ochoa
837da45f4f Merge branch 'master' into named-maps-tiles 2015-06-29 18:37:11 +02:00
Raul Ochoa
9e30f05e7d Reverts to use cdb branch as is already published 2015-06-29 16:46:07 +02:00
Raul Ochoa
0df725112b Update CDB_QueryTables function 2015-06-29 16:42:55 +02:00
Raul Ochoa
098ed6b203 New endpoint for named maps tiles 2015-06-29 16:39:35 +02:00
Raul Ochoa
c6f9152efe Moves template maps to backends directory 2015-06-29 16:38:13 +02:00
Raul Ochoa
9ea2029f81 Deprecating scripts from tools directory 2015-06-25 18:07:48 +02:00
Raul Ochoa
2715f47a22 Points CDB_QueryTables script to the branch with CDB_QueryTablesText 2015-06-24 19:07:41 +02:00
Rafa de la Torre
90d0b23441 Use CDB_QueryTablesText instead of CDB_QueryTables
This avoids trouble with len(schema.table_name) > 63
See https://github.com/CartoDB/cartodb-postgresql/issues/86
2015-06-24 15:43:04 +02:00
Raul Ochoa
b59e0a00a0 Merge pull request #313 from CartoDB/cartodb-layer-docs
Update Map-API docs
2015-06-23 15:04:16 +02:00
Andrew Thompson
790571fd2c Update Map-API docs
It was not clear to me what the difference was between a mapnik layer and a cartodb layer until I read the comments in the Mapconfig spec! Let's save some users the extra step :)
2015-06-22 11:14:57 -04:00
Raul Ochoa
6ecebae110 Adds test to validate (once it is fixed) long table names do not fail 2015-06-18 16:29:59 +02:00
Raul Ochoa
849470a3c0 Stubs next version 2015-06-18 12:55:38 +02:00
Raul Ochoa
74d0a6f183 Release 2.5.0 2015-06-18 12:53:45 +02:00
Raul Ochoa
61c134215a Bumps version and regenerates npm-shrinkwrap.json 2015-06-18 12:29:02 +02:00
Raul Ochoa
b7218d8832 Fix list style 2015-06-18 12:19:03 +02:00
Raul Ochoa
63e19427af Fix documentation error examples to match 'General Concepts' guidelines 2015-06-18 12:17:17 +02:00
Raul Ochoa
d4f8578fd6 Merge pull request #312 from CartoDB/issue-311
Adds layergroupid header
2015-06-18 11:21:03 +02:00
Raul Ochoa
eaccd062d3 Adds layergroupid header
Closes #311
2015-06-18 01:13:33 +02:00
Raul Ochoa
5f2d5931f4 Regenerate npm-shrinkwrap.json using master branch 2015-06-12 15:48:03 +02:00
Raul Ochoa
ce40fa608e Clarify bounds meaning in template view 2015-06-08 14:31:04 -04:00
Raul Ochoa
0979c75852 Merge pull request #308 from CartoDB/issue-305
Named maps error responses with valid format
2015-06-08 10:49:22 -04:00
Raul Ochoa
f01e8e0866 Merge pull request #304 from CartoDB/docs-revamp
Documentation for named maps static images + view option in templates
2015-06-08 10:49:08 -04:00
Raul Ochoa
a4e303ab63 Remove console.log from tests 2015-06-08 10:37:56 -04:00
Raul Ochoa
c5137c9c29 Update news 2015-06-05 13:41:46 -04:00
Raul Ochoa
9bce88f9b1 Fix tests 2015-06-05 13:39:25 -04:00
Raul Ochoa
68c70effec Named maps returning errors=>Array instead of error=>String 2015-06-05 13:38:38 -04:00
Raul Ochoa
ebae218219 Use windshaft branch with unified error reponses format 2015-06-05 13:37:49 -04:00
Raul Ochoa
6685b759b2 Remove duplicated module.exports 2015-06-04 20:14:36 -04:00
Raul Ochoa
539b0496bf Update news 2015-06-04 12:53:59 -04:00
Raul Ochoa
3c33fac8f4 Merge pull request #307 from CartoDB/template-names
Changes rules for names in templates
2015-06-04 12:52:30 -04:00
Raul Ochoa
9613f76ef5 Keep placeholder key validation independent from name validation 2015-06-04 11:58:24 -04:00
Raul Ochoa
3f0d344313 Changes rules for names in templates
Now valid names can start with numbers and can contain dashes (-).
Closes #306
2015-06-04 10:41:40 -04:00
Raul Ochoa
823ee63c25 Merge branch 'master' into docs-revamp
Conflicts:
	docs/Map-API.md
2015-06-03 17:11:01 -04:00
Raul Ochoa
d5d76f9c63 Adds information about named map static images endpoint 2015-06-03 17:09:10 -04:00
Raul Ochoa
dfc9a6fbb4 Documentation about view in named maps' templates
Closes #287
2015-06-03 17:00:42 -04:00
Raul Ochoa
2bd9aece35 Add header for zoom + center in static maps 2015-06-03 17:00:05 -04:00
Raul Ochoa
21870c9fa2 Merge branch 'master' into docs-revamp 2015-06-03 16:57:24 -04:00
Raul Ochoa
7c315b3afd Merge pull request #303 from CartoDB/links-to-map-config
Updated links to MapConfig 1.3.0
2015-06-03 16:37:24 -04:00
Pablo Alonso Garcia
da0cdb081d Updated links to MapConfig 1.3.0 2015-06-03 10:48:42 +02:00
Carlos Matallín
9bd0a3f1c9 Update Map-API.md 2015-06-01 17:00:53 +02:00
Raul Ochoa
83992895e4 Merge pull request #301 from CartoDB/layers-documentation
Documentation about layers metadata and layer selection/filtering
2015-06-01 16:48:14 +02:00
Raul Ochoa
aa3b336e46 Stubs next version 2015-06-01 15:50:53 +02:00
Raul Ochoa
e17b374fde Release 2.4.1 2015-06-01 15:49:30 +02:00
Raul Ochoa
61158b62f1 Update news 2015-06-01 15:46:32 +02:00
Raul Ochoa
88ed43a92e Merge pull request #302 from CartoDB/upgrade-windshaft
Upgrade windshaft
2015-06-01 14:28:28 +02:00
Raul Ochoa
e5fff6b452 Merge branch 'master' into upgrade-windshaft 2015-06-01 14:19:49 +02:00
Raul Ochoa
044d49c53a Uses windshaft 0.44.1 from registry 2015-06-01 12:20:44 +02:00
Raul Ochoa
69abf8d9b1 uses windshaft's master branch 2015-06-01 11:35:57 +02:00
Andy Eschbacher
14e13899a6 made minor changes 2015-05-28 11:02:34 -04:00
Raul Ochoa
488c246222 Documentation about layers metadata and layer selection 2015-05-28 15:10:55 +02:00
Raul Ochoa
654905a79c Stubs next version 2015-05-26 15:53:07 +02:00
Raul Ochoa
12cb199803 Release 2.4.0 2015-05-26 15:52:28 +02:00
Raul Ochoa
8759cf726b Merge pull request #300 from CartoDB/upgrade-windshaft
Bumps windshaft version to 0.44.0
2015-05-26 15:50:19 +02:00
Raul Ochoa
7a45c9e434 Bumps windshaft version to 0.44.0
- adds a test to validate metadata is returned for unrolled named layers
2015-05-26 15:39:21 +02:00
Raul Ochoa
9ee69dea55 Stubs next version 2015-05-18 18:11:48 +02:00
Raul Ochoa
ebe38e977f Release 2.3.0 2015-05-18 18:10:47 +02:00
Raul Ochoa
40ad143c3e Merge pull request #299 from CartoDB/upgrade-cartodb-redis
Upgrades cartodb-redis for `global` map stats
2015-05-18 18:08:06 +02:00
Raul Ochoa
875159fa5f Upgrades cartodb-redis for global map stats 2015-05-18 17:40:41 +02:00
Raul Ochoa
c97c65de34 Fixes multilayer link 2015-05-18 11:24:06 +02:00
Raul Ochoa
25ae09b2c5 Update patch to generate routes document 2015-04-29 17:18:36 +02:00
Raul Ochoa
853c2b4b85 Adds new route for named maps static previews 2015-04-29 17:17:46 +02:00
Raul Ochoa
682db1ca75 Stubs next version 2015-04-29 15:26:56 +02:00
Raul Ochoa
d56bd8de72 Release 2.2.0 2015-04-29 15:18:47 +02:00
Raul Ochoa
1df91aee6f Merge pull request #293 from CartoDB/named-static-maps
Named static maps
2015-04-29 12:48:02 +02:00
Raul Ochoa
b64eaed7ed Enables any URL in HTTP renderer whitelist in example configurations 2015-04-29 12:15:26 +02:00
Raul Ochoa
03dae8a93a changes about tests 2015-04-29 10:35:11 +02:00
Raul Ochoa
6b93fa0575 Update news 2015-04-29 10:31:47 +02:00
Raul Ochoa
5a9a2d7449 Use windshaft's registry version 2015-04-29 10:21:23 +02:00
Raul Ochoa
8d200686fd regenerate npm-shrinkwrap.json 2015-04-29 09:59:36 +02:00
Raul Ochoa
1c2f84b0cb Rely on windshaft master branch 2015-04-29 00:20:41 +02:00
Raul Ochoa
513fa2af01 Log all named map invalidation with context 2015-04-28 17:25:07 +02:00
Raul Ochoa
7580081a64 Append stats to profiler 2015-04-28 16:14:30 +02:00
Raul Ochoa
1a66f96379 Adds custom cache control header for named map static images 2015-04-28 16:14:19 +02:00
Raul Ochoa
fde680450f Do not use headers from abaculus in combination with sendWithHeaders 2015-04-28 16:14:03 +02:00
Raul Ochoa
6843692f01 Pick format from user params 2015-04-28 16:10:50 +02:00
Raul Ochoa
1f3a073f21 Use headers from fake request 2015-04-28 16:10:30 +02:00
Raul Ochoa
7b4d41464f tests for static named maps 2015-04-27 19:15:06 +02:00
Raul Ochoa
7ae2910061 adds tests as part of the jshint target 2015-04-27 18:08:55 +02:00
Raul Ochoa
ed3517e733 fix jshint 2015-04-27 18:08:40 +02:00
Raul Ochoa
6ac3b4c005 fix jshint 2015-04-27 18:05:39 +02:00
Raul Ochoa
26545af9ae fix jshint 2015-04-27 18:03:15 +02:00
Raul Ochoa
1ee96f14ce fix jshint 2015-04-27 18:02:15 +02:00
Raul Ochoa
2250e6d608 fix jshint 2015-04-27 18:00:47 +02:00
Raul Ochoa
5ad27e4bf5 fix jshint 2015-04-27 17:58:56 +02:00
Raul Ochoa
5f765712b4 fix jshint 2015-04-27 17:54:07 +02:00
Raul Ochoa
cb2e330e0b Uses describe/it instead of suite/test 2015-04-27 17:49:15 +02:00
Raul Ochoa
6de911e5bb Adds fastly invalidation expectations in surrogate key invalidation tests 2015-04-27 17:43:46 +02:00
Raul Ochoa
9edec8ef3f Adds Fastly cache backend 2015-04-27 16:31:47 +02:00
Raul Ochoa
8e8ab09bec Clarify fastly configuration is optional 2015-04-27 16:28:28 +02:00
Raul Ochoa
c06cba81f4 SurrogateKeysCache now accepts several cache backends
- uses queue-async to parallelize the call to invalidate
2015-04-27 16:22:37 +02:00
Raul Ochoa
ad5514dd02 Pick fastly config for server options 2015-04-27 16:20:55 +02:00
Raul Ochoa
a5b9ca706c Adds new fastly cache backend 2015-04-27 16:18:50 +02:00
Raul Ochoa
5a476f9354 Adds fastly-purge dependency 2015-04-27 16:18:03 +02:00
Raul Ochoa
403039b695 Adds new configuration examples for fastly surrogate keys invalidation 2015-04-27 16:17:13 +02:00
Raul Ochoa
5ee19cc2ed Rename template maps controller to named maps to be more clear 2015-04-27 15:01:49 +02:00
Raul Ochoa
8c3f9c7ba0 Inject server options to use setDBParams 2015-04-27 14:59:41 +02:00
Raul Ochoa
b95a001e0b New static maps controller/endpoint for named maps
- loads a template
 - creates a layergroup on the fly
 - checks for view center+zoom or bounds
 - if not found it tries to estimate them
 - if fails it falls to default bounds value
 - returns an static image tagged with a surrogate key
2015-04-27 14:56:38 +02:00
Raul Ochoa
d180305e8b Exposes pgQueryRunner in server options 2015-04-27 14:54:14 +02:00
Raul Ochoa
ef8fcf7e93 Do not inject NamedMapsCacheEntry as template controller knows about them
Also do not inject pgConnection
2015-04-27 14:52:36 +02:00
Raul Ochoa
e7bd5dd644 Moves setDBParams to serverOptions so it can be reused 2015-04-27 14:47:58 +02:00
Raul Ochoa
8503a5c7c9 Tables extent API: returns estimated bounds for a list of tables 2015-04-27 12:55:20 +02:00
Raul Ochoa
2de0e5d52b Extracts psql query run to its own class to be reusable 2015-04-27 12:48:34 +02:00
Raul Ochoa
b9e4b0a90c Removes alpha version from example 2015-04-27 11:56:54 +02:00
Raul Ochoa
8fb3dc7529 Move templateName function to template maps model 2015-04-27 11:55:05 +02:00
Raul Ochoa
a897e36b91 Merge pull request #290 from CartoDB/simplify-template-names
Simplify template names
2015-04-23 12:19:21 +02:00
Raul Ochoa
446c432484 dry content type validation 2015-04-23 12:05:52 +02:00
Raul Ochoa
c49f3aaba5 DRY ifUnauthenticated method 2015-04-23 12:01:53 +02:00
Raul Ochoa
fed29b3b50 Extract finish function 2015-04-23 11:47:01 +02:00
Raul Ochoa
e7d134d70c No more {username}@{template_name} template id
It's still backwards compatible
2015-04-23 11:29:55 +02:00
Raul Ochoa
62dbce4311 Merge pull request #289 from CartoDB/issue-267
Call callback on invalid map store token for named maps
2015-04-22 18:38:58 +02:00
Raul Ochoa
5b5f7fc700 Merge pull request #288 from CartoDB/clean-templates-suite
cleans templates suite: uses describe+it instead of suite+test
2015-04-21 23:58:13 +02:00
Raul Ochoa
026a0750e3 Call callback on invalid map store token for named maps
fixes #267
2015-04-21 18:59:52 +02:00
Raul Ochoa
7045f41252 cleans templates suite: uses describe+it instead of suite+test 2015-04-21 18:28:31 +02:00
Raul Ochoa
eaf6775d9d Stubs next version 2015-04-16 18:06:55 +02:00
Raul Ochoa
ba2a9b81e9 Release 2.1.3 2015-04-16 18:02:36 +02:00
Raul Ochoa
5577600903 Upgrade windshaft and regenerate npm-shrinkwrap.json 2015-04-16 17:48:59 +02:00
Raul Ochoa
a0a455b225 Stubs next version 2015-04-15 16:13:40 +02:00
Raul Ochoa
0019ab495b Release 2.1.2 2015-04-15 16:12:42 +02:00
Raul Ochoa
cbebac1cb1 Merge pull request #286 from CartoDB/profiler-metrics
Profiler metrics improvements
2015-04-15 15:41:12 +02:00
Raul Ochoa
e2fd4aca60 Upgrade windshaft 2015-04-15 15:32:10 +02:00
Raul Ochoa
0c578a193c Remove stack for debug environment option 2015-04-14 16:44:03 +02:00
Raul Ochoa
84f579f0ec Do not add x-profiler header as it's already added by sendResponse 2015-04-14 16:41:04 +02:00
Raul Ochoa
1bf2809355 Do not check statsd_client in profiler 2015-04-14 16:40:15 +02:00
Raul Ochoa
e91bc91057 Adds test suite for x-cache-channel 2015-04-10 13:39:20 +02:00
Raul Ochoa
4f9b6be45b Update routes documentation 2015-04-10 12:00:25 +02:00
Raul Ochoa
95aa74ee34 Stubs next version 2015-04-10 10:57:31 +02:00
Raul Ochoa
e516300825 Release 2.1.1 2015-04-10 10:56:10 +02:00
Raul Ochoa
2d84d38b90 Do not add x-cache-channel header for GET template routes 2015-04-10 10:55:46 +02:00
Raul Ochoa
7cd78be094 Stubs next version 2015-04-09 15:26:21 +02:00
Raul Ochoa
c7a10b048a Release 2.1.0 2015-04-09 15:24:10 +02:00
Raul Ochoa
d143b0235b Upgrades windshaft to 0.42.0 2015-04-09 15:23:42 +02:00
Raul Ochoa
a876c82660 Fixes tests for subdomainless example config change 2015-04-08 16:09:36 +02:00
Raul Ochoa
a6c1aefecc Fixes in example configuration files:
- Puts back the still supported /tiles/template and /tiles/layergroup
 - Changes from /u/:user to /user/:user for subdomainless users
2015-04-08 16:05:33 +02:00
Raul Ochoa
9b122280e1 Stubs next version 2015-04-08 12:27:40 +02:00
Raul Ochoa
4777d1e93c Release 2.0.0 2015-04-08 12:26:07 +02:00
Raul Ochoa
97e8b54b8c Replaces render timeout fallback asset on behalf of @saleiva, thx! 2015-04-08 12:21:57 +02:00
Raul Ochoa
136f68765a Merge pull request #284 from CartoDB/issue-280
Add user from params to fakereq object
2015-04-08 11:37:14 +02:00
Raul Ochoa
0062ec99f1 Merge pull request #283 from CartoDB/render-limits
Render limits
2015-04-08 11:32:14 +02:00
Raul Ochoa
98bc95bc58 Add user from params to fakereq object so it's propagated
fixes #280
2015-04-08 11:11:48 +02:00
Raul Ochoa
47cc1de89b Uses windshaft@0.41.0 registry version 2015-04-07 17:57:21 +02:00
Raul Ochoa
69c623b5b2 Regenerate npm-shrinkwrap.json 2015-04-07 14:36:43 +02:00
Raul Ochoa
ab9ae60958 Merge branch 'master' into render-limits 2015-04-07 14:18:34 +02:00
Raul Ochoa
907ed478cf Tidy app.js 2015-04-07 13:00:20 +02:00
Raul Ochoa
2eb7529efb Pick cacheOnTimeout and render limit from mapnik config
- adds default mapnik configuration values
 - removes old top-level mapnik config, rely on renderer one
2015-04-07 12:52:33 +02:00
Raul Ochoa
1782f240ce Upgrade cartodb-redis package 2015-04-07 11:38:00 +02:00
Raul Ochoa
2ea880ce2c cacheOnTimeout only for mapnik renderer
it does not make sense to have that as a general feature
2015-04-07 11:09:35 +02:00
Raul Ochoa
775b2b75a6 Fix typo 2015-04-07 10:41:19 +02:00
Raul Ochoa
2d050eb43c Merge pull request #282 from CartoDB/remove_per_user_check
Disable per-user healthchecks
2015-04-07 10:07:25 +02:00
Luis Bosque
7934d659fb Removed more unused code from healthcheck 2015-04-06 20:49:29 +02:00
Luis Bosque
21b5ed9c8a Fixed healthcheck for jshint 2015-04-06 20:35:22 +02:00
Luis Bosque
da70839f78 Disable per-user healthchecks 2015-04-06 20:15:26 +02:00
Raul Ochoa
2e1f08d764 Adds a feature flag to cache timed out tile requests: cacheOnTimeout 2015-04-06 18:52:54 +02:00
Raul Ochoa
21072645a4 Tests for both: onTileErrorStrategy enabled and disabled 2015-04-06 18:44:57 +02:00
Raul Ochoa
e3c6569302 Adds an onTileErrorStrategy that intercepts error timeout
- returns an fallback image without error
2015-04-06 18:43:40 +02:00
Raul Ochoa
091352e75b Fix typo 2015-04-06 18:00:46 +02:00
Raul Ochoa
bf7044d723 Adds tests to test new per user limit 2015-04-01 19:36:43 +02:00
Raul Ochoa
38e4812b43 Restore previous beforeLayergroupCreate hook behaviour
Adds new rendercache's beforeRendererCreate hook
2015-04-01 19:35:55 +02:00
Raul Ochoa
b8395010a3 Adds some tests for limits based on user limits 2015-04-01 17:39:02 +02:00
Raul Ochoa
f0eeb393d6 Use windshaft render-limits branch
Bump cartodb-redis version
Regenerate npm-shrinkwrap.json as I accidentaly deleted it
2015-04-01 15:49:01 +02:00
Raul Ochoa
a9ab9f8b5c Pick render limit and add it to request context
- Extends the problematic fake request in templates
 - Picks the value in waterfall, this must be improved because:
   1. It does not make sense if there is no layers with limits
   2. If we want to include it always without considering the layer type
      we can do the operation in parallel
2015-04-01 15:11:58 +02:00
Raul Ochoa
f019f34601 Mapnik renderer configuration not part of the renderer root configuration
- All configuration must be moved into `renderer.mapnik`
 - see `config/environments/*.js.example` for reference
2015-04-01 15:04:56 +02:00
Raul Ochoa
400e51f13a Removes rollbar as optional logger 2015-03-31 11:36:29 +02:00
Raul Ochoa
3234c37d62 Merge pull request #278 from CartoDB/257-remove-old-api
Remove old API
2015-03-30 19:04:27 +02:00
Raul Ochoa
e0413c3302 Prepared next release 2015-03-30 18:44:44 +02:00
Raul Ochoa
cd79fc606b Regenerate npm-shrinkwrap.json 2015-03-30 17:57:27 +02:00
Raul Ochoa
a2ac1c23f1 Tests for surrogate keys invalidation
- uses nock to mock request
 - a bit hacky because tests keep environment inconsistent
   * for intance I had to mock cartocdn to not fail in other suite
2015-03-30 17:51:17 +02:00
Raul Ochoa
69f99daa60 Mock better query tables api 2015-03-30 16:28:58 +02:00
Raul Ochoa
f1e8c9a709 Tests for cdb request 2015-03-30 16:28:37 +02:00
Raul Ochoa
1fc0545b5a Replace affected tables tests with multilayer ones 2015-03-30 15:57:53 +02:00
Raul Ochoa
b599e67c35 Replaces affected tables test with multilayer one 2015-03-30 15:27:40 +02:00
Raul Ochoa
85804f9854 Fixes jshint 2015-03-30 15:07:49 +02:00
Raul Ochoa
7df3658d41 Invalid json lzma test 2015-03-30 15:06:00 +02:00
Raul Ochoa
c92e786a5f Replace lzma test with multilayer 2015-03-30 15:01:17 +02:00
Raul Ochoa
d6ef0b7457 Replaces server tests for user db connection with multilayer 2015-03-30 14:39:26 +02:00
Raul Ochoa
434d6d4110 Extract request function 2015-03-30 13:42:59 +02:00
Raul Ochoa
55a78899a4 Removes sql api specific test 2015-03-30 13:39:47 +02:00
Raul Ochoa
124133ceca Replace zoom test with multilayer one 2015-03-30 13:38:34 +02:00
Raul Ochoa
2b9f2ee66c Removes tests as they are covered in multilayer suite 2015-03-30 13:35:20 +02:00
Raul Ochoa
70d1a30c64 style 2015-03-30 13:30:57 +02:00
Raul Ochoa
2161bbf8e9 Remove comments 2015-03-30 13:30:44 +02:00
Raul Ochoa
41521b6776 No need to test style deletion 2015-03-30 12:42:57 +02:00
Raul Ochoa
ec2fcad2e0 No need to test good style cases 2015-03-30 12:42:15 +02:00
Raul Ochoa
ecc67b1d0f Replace test for multiple cartocss errors 2015-03-30 12:41:34 +02:00
Raul Ochoa
4ea1199014 it instead of test 2015-03-30 12:32:48 +02:00
Raul Ochoa
e7544e84c2 Replace server test with multilayer one 2015-03-30 12:32:09 +02:00
Raul Ochoa
ada616ee6a jshint adds mocha globals 2015-03-30 12:31:44 +02:00
Raul Ochoa
000a248ab4 Removes test as is covered in "layergroup creation fails if CartoCSS is bogus" 2015-03-30 12:24:40 +02:00
Raul Ochoa
ff515f8c12 No need to have a test for empty cartocss 2015-03-30 12:20:04 +02:00
Raul Ochoa
848bfacc2d no need to check it used post for long queries 2015-03-30 12:15:26 +02:00
Raul Ochoa
da4b1d5a0f jshint 2015-03-30 12:13:59 +02:00
Raul Ochoa
b2d9e5e822 Merge branch 'master' into 257-remove-old-api 2015-03-30 11:57:03 +02:00
Raul Ochoa
d0313a4228 Remove gc_prob as it is no longer used in grainstore 2015-03-27 17:59:55 +01:00
Raul Ochoa
1f53884722 Remove metrics for authorizedBy* 2015-03-27 17:57:46 +01:00
Raul Ochoa
a664a1c550 Merge pull request #276 from CartoDB/disable_health_check
Return failed health checks with disabled file
2015-03-27 17:27:31 +01:00
Raul Ochoa
d210643d63 Only required query params 2015-03-26 17:19:16 +01:00
Raul Ochoa
4be0a70362 Do not append interactivity to params, it is no longer
it will be used from mapconfig layer definition
2015-03-26 13:05:35 +01:00
Luis Bosque
09e0f86936 jshint fixes 2015-03-25 18:41:27 +01:00
Luis Bosque
e3b7027b24 Remove unnecesary variable in health check 2015-03-25 18:23:03 +01:00
Luis Bosque
0f30b7d7ef Return failed health checks with disabled file 2015-03-25 18:19:40 +01:00
Raul Ochoa
3012b99e15 Remove varnish emu 2015-03-24 10:39:23 +01:00
Raul Ochoa
f683e39aea Remove api sql emulator 2015-03-24 10:38:14 +01:00
Raul Ochoa
985973dfda Split old api and basic endpoints 2015-03-23 19:28:34 +01:00
Raul Ochoa
07bc281e25 Remove check table privacy 2015-03-23 19:19:46 +01:00
Raul Ochoa
1d433bf5b2 Remove table param from generateCacheChannel 2015-03-23 18:58:57 +01:00
Raul Ochoa
d5e20ef558 Remove cache_policy query param 2015-03-23 18:40:59 +01:00
Raul Ochoa
36ea58e750 no longer possible to set cache_buster request param 2015-03-23 18:03:19 +01:00
Raul Ochoa
e1e5f87123 No longer possible to set sql param 2015-03-23 18:02:41 +01:00
Raul Ochoa
ea3d2124dc No sql param in generateCacheChannel 2015-03-23 17:56:51 +01:00
Raul Ochoa
415d0c42d5 jshint 2015-03-23 17:56:18 +01:00
Raul Ochoa
c19f652ff3 Remove some old accepted query params 2015-03-23 17:54:37 +01:00
Raul Ochoa
f5f7be627f Move userByReq to its own model 2015-03-23 17:35:09 +01:00
Raul Ochoa
09b3f0a862 Skip server suite for now until we decide what tests we should port 2015-03-23 17:27:24 +01:00
Raul Ochoa
d9ab1e8810 Deprecates old config URLs: /tiles/template and /tiles/layergroup
Moves all tests to run on new URLs
Deprecated base_url_legacy in config, it will keep working tho
2015-03-23 15:54:45 +01:00
Raul Ochoa
23f5be6c33 Remove config and sql api backend 2015-03-23 15:00:33 +01:00
Raul Ochoa
07297f6bda Remove cdbQueryTablesFromPostgres option, now uses it by default 2015-03-23 14:44:42 +01:00
Raul Ochoa
02bc7b9fbf Remove per-table varnish invalidation 2015-03-23 14:27:41 +01:00
Raul Ochoa
0e3f72ce0b PHONY coverage 2015-03-23 14:21:08 +01:00
Raul Ochoa
f311f6d4df Merge branch 'master' into 257-remove-old-api 2015-03-23 14:13:11 +01:00
Raul Ochoa
65c6559b1a Merge pull request #275 from CartoDB/coverage
Add option to generate coverage metrics using istanbul module
2015-03-23 14:12:47 +01:00
Raul Ochoa
53d92fe70e Add option to generate coverage metrics using istanbul module 2015-03-23 14:05:29 +01:00
Raul Ochoa
6d32199c53 Remove get style tests 2015-03-23 12:42:39 +01:00
Raul Ochoa
25e4e3bd33 jshint 2015-03-23 12:40:24 +01:00
Raul Ochoa
0321884795 Re-generate npm-shrinkwrap.json to use windshaft/master.
A lot of tests from acceptance/server.js will fail
2015-03-23 12:29:42 +01:00
Raul Ochoa
5f6185dd51 Merge branch 'master' into 257-remove-old-api
Conflicts:
	lib/cartodb/cartodb_windshaft.js
	lib/cartodb/server_options.js
	package.json
2015-03-23 12:24:10 +01:00
Raul Ochoa
63ba75f703 Merge pull request #274 from CartoDB/url_rewrite
allow urls like /u/:user/
2015-03-20 12:21:41 +01:00
Raul Ochoa
9b4acf99d5 Adds example configuration to accept user param in /tiles/layergroup
That is used in testing. Tests should start moving to /api/v1/map.
2015-03-20 00:34:30 +01:00
Raul Ochoa
9ba53dc4cf Adds user param to params whitelist and uses localhost user for tests 2015-03-20 00:30:56 +01:00
javi
2f44dfe1da updated test config 2015-03-18 18:36:44 +01:00
javi
b891ae19f4 adding a bunch of test for layer group url 2015-03-18 18:15:26 +01:00
javi
00cf83dc45 try to fix test, take 3 2015-03-18 17:53:49 +01:00
javi
72294fbd25 refined tests 2015-03-18 17:26:33 +01:00
javi
5af09fc2bf small refactor in tests 2015-03-18 17:04:25 +01:00
javi
c1c6d493b7 allow urls like /u/:user/ 2015-03-18 15:54:05 +01:00
Raul Ochoa
a30ed5ce04 Merge pull request #271 from CartoDB/iri/https-change
Switching to HTTPS
2015-03-16 12:33:32 +01:00
Carla
7c35d5cd32 Switching to HTTPS
https://github.com/CartoDB/docs/issues/182
2015-03-16 12:26:28 +01:00
Raul Ochoa
2e67633ca8 Merge pull request #270 from CartoDB/jshint
Enable jshint
2015-03-16 00:48:15 +01:00
Raul Ochoa
87782b400d jshint to be tested by default 2015-03-16 00:38:29 +01:00
Raul Ochoa
b6d3785599 Fix Max cyclomatic complexity value 2015-03-16 00:36:38 +01:00
Raul Ochoa
645a2cd442 120 chars lines 2015-03-16 00:27:14 +01:00
Raul Ochoa
8c09dfd230 No capitalize step 2015-03-16 00:21:55 +01:00
Raul Ochoa
336491b54c Remove unused vars 2015-03-16 00:16:36 +01:00
Raul Ochoa
4365c1dbc2 Define mapnikXmlParams variable 2015-03-16 00:07:05 +01:00
Raul Ochoa
3c56c1fab3 Adds next param 2015-03-16 00:05:01 +01:00
Raul Ochoa
0a331cee37 do not redefine vars 2015-03-16 00:03:59 +01:00
Raul Ochoa
d7f5c40645 Triple === 2015-03-16 00:00:02 +01:00
Raul Ochoa
5df24e7f27 Remove Unreachable 'break' after 'return' 2015-03-15 23:58:38 +01:00
Raul Ochoa
406a1ffb0b no global replaceVars func 2015-03-15 23:58:12 +01:00
Raul Ochoa
438ecd5598 jshint: fix Function declarations should not be placed in blocks 2015-03-15 23:56:14 +01:00
Raul Ochoa
bd1c24ee1c jshint: Remove Confusing use of '!' 2015-03-15 23:52:46 +01:00
Raul Ochoa
e561f77d4d jshint: fix Dot notation 2015-03-15 23:49:32 +01:00
Raul Ochoa
d03a2c64a6 jshint: fix Missing semicolon 2015-03-15 23:46:59 +01:00
Raul Ochoa
fda8afdaf2 jshint: fix Bad line breaking 2015-03-15 23:44:45 +01:00
Raul Ochoa
e4da13189d Adds jshint
- dependency
 - makefile target
 - relax some rules
Work in progress
2015-03-15 23:37:03 +01:00
Raul Ochoa
f35d328dbf Update Routes.md 2015-03-12 12:58:46 +01:00
Raul Ochoa
d09998cce1 Extra notes about optional but deprecated endpoints
- /tiles/layergroup
- /tiles/template
2015-03-12 12:57:29 +01:00
Raul Ochoa
7a01d75cd8 Attributes route 2015-03-12 12:42:13 +01:00
Raul Ochoa
83e5d889a7 Some notes about routes 2015-03-12 12:38:06 +01:00
Raul Ochoa
f1eed600d5 Adds routes document (WIP) 2015-03-12 12:20:42 +01:00
Raul Ochoa
75a980ff1d Stubs next version 2015-03-11 17:15:44 +01:00
Raul Ochoa
9d9aafbcb3 Release 1.30.0 2015-03-11 17:14:41 +01:00
Raul Ochoa
8e9d9113d7 Upgrades windshaft to 0.40.0 2015-03-11 16:19:07 +01:00
Raul Ochoa
62661c633c Adds script/tool to go from lzma base64 encoded string to mapconfig 2015-03-11 15:16:24 +01:00
Raul Ochoa
38e35a6d61 Specific dependencies for building node-canvas 2015-03-11 14:25:36 +01:00
Raul Ochoa
0d5242d12b Add enabledFeatures configuration to the example configuration files
- Enables querytables from postgres as default
2015-03-09 14:42:47 +01:00
Raul Ochoa
edde869a68 Update CDB_QueryTables 2015-03-09 14:42:30 +01:00
Raul Ochoa
6d4eb23696 Improve readme
- Requirements bumped
 - Delete URLs documentation and point to docs directory.
2015-03-09 14:37:26 +01:00
Raul Ochoa
1979697551 Stubs next version 2015-03-09 14:08:38 +01:00
Raul Ochoa
661df294e1 Release 1.29.0 2015-03-09 14:07:47 +01:00
Raul Ochoa
39dc9a316d Merge pull request #268 from CartoDB/upgrade-windshaft
Upgrade windshaft
2015-03-09 14:03:31 +01:00
Raul Ochoa
cfe434c8ed Use published version 2015-03-09 13:52:47 +01:00
Raul Ochoa
53d7276136 Force bash 2015-03-08 11:36:31 +01:00
Raul Ochoa
e95167a049 Force bash 2015-03-08 11:36:17 +01:00
Raul Ochoa
e82131f4e8 Upgrades windshaft@0.39.0 2015-03-06 10:45:01 +01:00
Raul Ochoa
cbd44192c9 Use bash in Makefile targets 2015-02-26 17:00:50 +01:00
Raul Ochoa
f006d09f31 Update windshaft to version 0.38.2 2015-02-26 12:08:48 +01:00
Raul Ochoa
620160c44e Ignore npm-debug.log 2015-02-26 12:05:17 +01:00
Raul Ochoa
6ae2c2630a Upgrade windshaft to 0.38.1 2015-02-25 19:15:55 +01:00
Raul Ochoa
a287c84500 Upgrades windshaft to 0.38.0 2015-02-23 12:59:00 +01:00
Raul Ochoa
62e435fd9e Improve installation feedback as we did in Windshaft 2015-02-23 12:08:08 +01:00
Raul Ochoa
65702de64d Update to latest test/support/sql/CDB_QueryTables.sql 2015-02-23 12:06:47 +01:00
Raul Ochoa
ef2b45621b Merge branch 'master' into 257-remove-old-api
Conflicts:
	package.json
2015-02-20 15:24:13 +01:00
Raul Ochoa
1771313bea Stubs next version 2015-02-20 10:32:12 +01:00
Raul Ochoa
b0624582d9 Release 1.28.5 2015-02-20 10:30:27 +01:00
Raul Ochoa
10acdc4615 Upgrades windshaft to 0.37.5 2015-02-20 10:30:11 +01:00
Raul Ochoa
d96ed3511e Merge pull request #266 from namessanti/patch-1
Corrected DPI limits and jpeg quality
2015-02-19 19:26:02 +01:00
Santiago Giraldo Anduaga
e0dba85f67 Corrected DPI limits and jpeg quality
Corrected DPI limits and JPEG quality

@andrewxhill
2015-02-19 13:05:39 -05:00
Raul Ochoa
989e752959 Display master build status
it doesn't make sense to display errors from other branches/pr
2015-02-18 15:12:43 +01:00
Raul Ochoa
71efe2109c Merge branch 'master' into 257-remove-old-api
Conflicts:
	lib/cartodb/cartodb_windshaft.js
	package.json
2015-02-18 14:51:21 +01:00
Raul Ochoa
5da239a2eb Stubs next version 2015-02-18 11:55:35 +01:00
Raul Ochoa
5c2e5c0d05 Release 1.28.4 2015-02-18 11:54:40 +01:00
Raul Ochoa
27d6d636cf Upgrades to windshaft 0.37.4 2015-02-18 11:53:56 +01:00
Raul Ochoa
5db7f002e6 Stubs next version 2015-02-17 19:44:23 +01:00
Raul Ochoa
ac1f8f8497 Release 1.28.3 2015-02-17 19:43:17 +01:00
Raul Ochoa
ee6bd8c561 Merge pull request #265 from CartoDB/263-fix-403-errors-with-named-layers
Test for named layers and interactivity
2015-02-17 19:41:34 +01:00
Raul Ochoa
7f20e296a3 Upgrades windshaft to 0.37.3 and adds a test for named layers and interactivity
Closes #263
2015-02-17 19:28:05 +01:00
Raul Ochoa
2e577343d2 Update to latest CDB_QueryTables 2015-02-17 18:55:34 +01:00
Raul Ochoa
dc14248de2 Stubs next version 2015-02-17 16:17:32 +01:00
Raul Ochoa
9536669053 Release 1.28.2 2015-02-17 16:16:19 +01:00
Raul Ochoa
11db363bfb Upgrades windshaft to 0.37.2 2015-02-17 16:07:49 +01:00
Raul Ochoa
d2961430f3 Stubs next version 2015-02-17 12:20:51 +01:00
Raul Ochoa
2b7bd58fd5 Release 1.28.1 2015-02-17 12:20:07 +01:00
Raul Ochoa
055932d38e Upgrades windshaft to 0.37.1 2015-02-17 12:19:16 +01:00
Raul Ochoa
c65a29acf4 Stubs next version 2015-02-17 11:04:41 +01:00
Raul Ochoa
27cda49fd8 Release 1.28.0 2015-02-17 11:02:29 +01:00
Raul Ochoa
2d7b706507 Merge pull request #217 from strk/master-tolerant-configure
Have ./configure tolerate unknown options
2015-02-16 18:55:45 +01:00
Raul Ochoa
3ea3638fe9 Merge pull request #218 from strk/master-own-testuser
Use a windshaft-specific name for the test user
2015-02-16 18:55:34 +01:00
Raul Ochoa
1f9387bb68 Rely on published versions 2015-02-16 15:02:39 +01:00
Raul Ochoa
00542bbc57 Upgrades windshaft to 0.37.0 2015-02-16 14:57:03 +01:00
Raul Ochoa
5be8afbbeb Merge pull request #261 from CartoDB/private-cdb_tablemetadata
Authenticated query to retrieve last update
2015-02-16 14:29:10 +01:00
Raul Ochoa
9f7dcc2354 Update news 2015-02-16 14:21:56 +01:00
Raul Ochoa
21b3f44441 Merge branch 'master' into private-cdb_tablemetadata 2015-02-16 14:18:56 +01:00
Raul Ochoa
f295f847d1 Stubs next version 2015-02-16 12:15:08 +01:00
Raul Ochoa
0478905689 Release 1.27.0 2015-02-16 12:14:24 +01:00
Raul Ochoa
d311dd4245 Use PgConnection to set db auth
No need to use request context anymore
X-Cache-Channel will be set now even for private tables: fixes #253
2015-02-16 11:57:53 +01:00
Raul Ochoa
b25bb03cdf Merge branch 'master' into private-cdb_tablemetadata
Conflicts:
	lib/cartodb/server_options.js
	test/support/sql/windshaft.test.sql
2015-02-16 11:41:45 +01:00
Raul Ochoa
afa625e3d2 Merge pull request #260 from CartoDB/medusa-improvements
Medusa improvements
2015-02-16 11:34:23 +01:00
Raul Ochoa
e08b1ea1a0 Update news with changes in branch 2015-02-16 11:21:22 +01:00
Raul Ochoa
c6d328ee07 Upgrades to windshaft 0.36.0 2015-02-16 10:55:38 +01:00
Raul Ochoa
8d10d0f760 Remove draft 2015-02-16 10:54:53 +01:00
Raul Ochoa
a2a09979e4 Remove dump render cache stats 2015-02-11 18:47:11 +01:00
Raul Ochoa
597cb5286d No more before/after state change actions as there is no longer
a style change
2015-02-11 18:44:09 +01:00
Raul Ochoa
a0243e0bf7 Rely on windshaft's remove old api branch 2015-02-11 18:43:47 +01:00
Raul Ochoa
0f668aabf1 Rely on windshaft's master branch as everything for medusa is already there 2015-02-11 14:48:06 +01:00
Raul Ochoa
59dfd11e5b Remove geom_type retrieval 2015-02-10 16:57:43 +01:00
Raul Ochoa
b1b57d6f24 Regenerate npm-shrinkwrap.json 2015-02-10 11:41:22 +01:00
Raul Ochoa
636591ecbb Removes flush_cache endpoint 2015-02-10 00:13:50 +01:00
Raul Ochoa
a4eade31a2 Removes map_metadata endpoint 2015-02-10 00:08:08 +01:00
Raul Ochoa
ba0f394a48 Remove infowindow endpoint 2015-02-10 00:03:44 +01:00
Raul Ochoa
75c4153f9b No need to retrieve api key externally, QueryTablesApi takes care 2015-02-09 19:41:38 +01:00
Raul Ochoa
8e038b0323 Merge pull request #259 from CartoDB/empty-flush_cache-endpoint
Empty flush cache endpoint
2015-02-09 19:40:50 +01:00
Raul Ochoa
0a994c731c Merge branch 'master' into empty-flush_cache-endpoint 2015-02-09 19:05:25 +01:00
Raul Ochoa
13ae1b4067 Remove flush_cache tool as it doesn't make sense anymore 2015-02-09 19:04:38 +01:00
Raul Ochoa
742a9744ea Remove select permission for publicuser 2015-02-09 18:56:01 +01:00
Raul Ochoa
8ed864ad18 apt-get update before apt-get install 2015-02-09 18:49:58 +01:00
Raul Ochoa
87638168ff apt-get update before apt-get install 2015-02-09 18:39:24 +01:00
Raul Ochoa
8364da683a Merge branch 'master' into medusa-improvements 2015-02-09 18:39:14 +01:00
Raul Ochoa
6eec5822f0 Create CREATE EXTENSION plpythonu for tests 2015-02-09 18:36:47 +01:00
Raul Ochoa
d667dbcc2f Merge branch 'master' into private-cdb_tablemetadata 2015-02-09 18:36:19 +01:00
Raul Ochoa
40de1a8f86 Create CREATE EXTENSION plpythonu for tests 2015-02-09 18:34:28 +01:00
Raul Ochoa
b53c25e514 Merge pull request #258 from CartoDB/stop-testing-node-0.8
Don't test against node 0.8
2015-02-09 15:09:57 +01:00
Raul Ochoa
81919706ea Adds default image placeholder for http renderer to use as fallback 2015-02-09 15:08:36 +01:00
Raul Ochoa
d38fc16b57 Don't test against node 0.8 2015-02-09 14:49:01 +01:00
Raul Ochoa
90b22b2718 QueryTables and last updated_at retrieved with user
Move setDBAuth and setDBConn to PgConnection entity
 - It uses cartodb-redis to retrieve datasource configuration
Start using it in ServerOptions, TemplateMaps and QueryTablesApi
QueryTablesApi don't receive anymore the connection/credentials
 - It will always use an authenticated query to retrieve last update
 - That will allow to query affected private tables last update
2015-02-09 14:46:52 +01:00
Raul Ochoa
04af57cab9 Add some entries to cdb_tablemetadata for tables being used in tests 2015-02-09 14:38:59 +01:00
Raul Ochoa
d40b15454b Run some tests only if they are using the SQL API 2015-02-09 14:38:29 +01:00
Raul Ochoa
e1e925bd9e Run postgresql/sql-api dependant tests against two implementations
This time for real.
2015-02-09 14:33:17 +01:00
Raul Ochoa
151968ae13 Merge branch 'master' into private-cdb_tablemetadata 2015-02-06 18:42:18 +01:00
Raul Ochoa
547782eea5 Use windshaft's plain-renderer-plus-http-default-plus-per-layer-datasource
branch to pick latest developments for medusa
2015-02-06 12:03:17 +01:00
Raul Ochoa
6bd967e9fb Merge branch 'master' into medusa-improvements
Conflicts:
	lib/cartodb/server_options.js
2015-02-06 12:01:28 +01:00
Raul Ochoa
13f5fda1b8 Merge pull request #255 from CartoDB/empty-flush_cache-endpoint
Remove per table flush cache endpoint
2015-02-05 17:37:56 +01:00
Raul Ochoa
673bd4f3f2 Add querytables and cdb_tablemetadata for proper testing its integration 2015-02-05 17:21:38 +01:00
Raul Ochoa
d56affae2d Merge pull request #256 from CartoDB/private-cdb_tablemetadata
Remove no longer needed method from query_tables_api
2015-02-05 17:21:21 +01:00
Raul Ochoa
09527b6808 Remove no longer needed method from query_tables_api 2015-02-05 17:08:20 +01:00
Raul Ochoa
d065ace036 Remove per table flush cache endpoint 2015-02-05 17:05:50 +01:00
Raul Ochoa
2736b93c69 test to validate it's not possible to override authorization
with a crafted layergroup
2015-02-05 16:47:37 +01:00
Raul Ochoa
10b7ab307e Merge pull request #254 from CartoDB/add_cdbjs_layer
Added layer source info for cartodb.js
2015-02-05 15:23:53 +01:00
Andy Eschbacher
56c24a738a Added layer source info for cartodb.js 2015-02-04 16:23:34 -05:00
Raul Ochoa
fa8b27231c Removed unused/old template lock functionality 2015-02-04 19:36:16 +01:00
Raul Ochoa
c17af23a40 A non empty datasource from MapConfigNamedLayersAdapter.getLayers
means the affected tables can have private tables involved.
That implies QueryTablesApi will need the proper user to use
CDB_QueryTables. So we store it in a request context to use it in
the afterLayergroupCreate call.

Tiles for these layergroups will fail to add a X-Cache-Channel
header because it won't be possible to use the proper user within
those tiles. Ok, they will fail if they are not requested through
the same tiler instance because if they are they most likely will
reuse the in memory cache.

See https://github.com/CartoDB/Windshaft-cartodb/issues/253
2015-02-04 19:31:20 +01:00
Raul Ochoa
fbecc11aa5 Do not use the SQL API Emulator for testing named layers as it hides
an integration issue with cdb_querytables
2015-02-04 19:01:14 +01:00
Raul Ochoa
8cacc3bb9e Merge branch 'master' into 239-mapconfig-named-maps-extension 2015-02-04 18:59:07 +01:00
Raul Ochoa
a82af16347 Adds a template test with http layer 2015-02-04 18:57:46 +01:00
Raul Ochoa
5018d32af6 Add querytables and cdb_tablemetadata for proper testing its integration 2015-02-04 18:52:37 +01:00
Raul Ochoa
2c7bc6adde Datasource to give per-layer authentication in named layers
Make beforeLayergroupCreate to return a datasource with different
 authentication for the different layers.
 - Named layers will get access to private tables in case it's needed

Changes in MapConfigNamedLayersAdapter:
  - It will retrieve the dbAuth params only if named layers are present so
  there is no extra overhead for normal layers
  - Rename queue function signature from `callback` to `done` so it is easier
  to follow the code

Add several tests to validate `named` layers authentication
2015-02-04 11:30:36 +01:00
Raul Ochoa
58f9f5f7a8 Remove unused object, rename suite 2015-02-03 14:16:55 +01:00
Raul Ochoa
e4e633cf86 Fix next reference 2015-02-02 17:44:15 +01:00
Raul Ochoa
4ca5c5fa3c Merge pull request #252 from namessanti/api-test-doc
Static Maps API
2015-02-02 15:50:44 +01:00
Raul Ochoa
1bb0d8738e Add test case for layers with private tables 2015-02-02 14:38:26 +01:00
Raul Ochoa
4949616c4e Some acceptance tests, http_status = 403 should not happen in adapter,
needs improvement
2015-01-30 19:29:45 +01:00
Raul Ochoa
12c5d835c5 Fix integration tests as I messed with the filename 2015-01-30 19:11:54 +01:00
Raul Ochoa
87eaeb0074 Some integration tests for different cases in named layers type 2015-01-30 18:57:01 +01:00
Raul Ochoa
8b07156a2d Make templateMaps available in cartodb windshaft 2015-01-30 16:51:09 +01:00
Raul Ochoa
358b296750 Remove beforeEach and afterEach, in combination with suite they are
triggered for every single test even outside of the suite they were
invoked in.
2015-01-30 16:50:06 +01:00
Raul Ochoa
d0ef87b0cf Add a before layergroup creation action to allow first level named
maps layer type to be extended as other layers
2015-01-30 15:31:49 +01:00
Raul Ochoa
e28fe1fdc0 Initialize template maps in server options 2015-01-30 15:30:13 +01:00
Raul Ochoa
aecb07b008 Create redis pool in server options when not supplied 2015-01-30 15:28:55 +01:00
Raul Ochoa
5573dfda84 Add queue-async dependency 2015-01-30 15:26:27 +01:00
Raul Ochoa
7a22973258 Use windshaft's before-layergroup-step branch 2015-01-30 12:59:26 +01:00
Raul Ochoa
f099a69df3 Add limitations for named maps of the user account 2015-01-30 11:27:16 +01:00
Raul Ochoa
938b6579c0 MapConfig named maps extension specification (draft) 2015-01-30 11:17:29 +01:00
Raul Ochoa
e445d0de01 Stubs next version 2015-01-28 17:37:38 +01:00
Raul Ochoa
7a35b9695f Release 1.26.2 2015-01-28 17:36:44 +01:00
Raul Ochoa
9523d40937 Merge pull request #250 from CartoDB/accept-open-string-as-valid-auth
Accept open string as valid auth
2015-01-28 17:35:38 +01:00
Raul Ochoa
697323dbbc Fix typo 2015-01-28 17:31:22 +01:00
Raul Ochoa
efe090f5b0 Accept 'open' string in templated auth as authorized 2015-01-28 17:29:50 +01:00
Raul Ochoa
ee1454d91c Stubs next version 2015-01-28 13:16:57 +01:00
Raul Ochoa
38242813be Release 1.26.1 2015-01-28 13:15:42 +01:00
Raul Ochoa
f9373dd8d0 Fix typos 2015-01-28 13:15:18 +01:00
Raul Ochoa
0e4e56f333 Fix version number 2015-01-28 13:14:32 +01:00
Raul Ochoa
c1d4da870f Upgrades windshaft to 0.35.1, see https://github.com/CartoDB/Windshaft/pull/254 2015-01-28 13:09:53 +01:00
Raul Ochoa
3c26f1f986 Stubs next version 2015-01-27 17:51:04 +01:00
Raul Ochoa
e9195967a4 Release 1.26.0 2015-01-27 17:50:13 +01:00
Raul Ochoa
30c6a390ac Upgrades windshaft to 0.35.0, supports mapconfig version 1.3.0 2015-01-27 17:49:08 +01:00
Raul Ochoa
3a97af767f Stubs next version 2015-01-26 17:33:22 +01:00
Raul Ochoa
57dd36a476 Release 1.25.0 2015-01-26 17:30:51 +01:00
Raul Ochoa
6ab6fd91e4 Merge pull request #248 from CartoDB/196-validate-layergroup-in-named-maps
Basic layergroup validation on named map creation/update
2015-01-26 17:04:48 +01:00
Raul Ochoa
c41c223b84 Merge pull request #249 from CartoDB/247-add-named-maps-surrogate-keys
Add named maps surrogate keys and call invalidation on template modification/deletion
2015-01-26 17:04:25 +01:00
Raul Ochoa
7e2be7b30f Document varnish configuration 2015-01-26 16:27:59 +01:00
Raul Ochoa
e690170689 More exhaustive layergroup validation:
- layers is an array and it's not empty
- layers has at least options
2015-01-26 15:51:10 +01:00
Raul Ochoa
81f1b0dcf8 Adds tests for named maps surrogate keys and for invalidation 2015-01-26 15:02:28 +01:00
Raul Ochoa
146a2b2606 Merge branch 'master' into 247-add-named-maps-surrogate-keys 2015-01-26 13:19:03 +01:00
Raul Ochoa
ff811ac1b5 Merge pull request #246 from CartoDB/238-drop-signed-maps
Drop signed maps
2015-01-26 13:13:27 +01:00
Santiago Giraldo
6a39893e20 Brittany reviewed text and markdown, added basemap and limit information 2015-01-23 16:15:30 -05:00
Raul Ochoa
11d9f5dd76 Basic layergroup validation on named map creation/update 2015-01-23 18:24:25 +01:00
Raul Ochoa
571a635fed Old style, avoid merge conflicts, missing history 2015-01-23 17:46:58 +01:00
Raul Ochoa
6e70518146 Split between old cache_enabled and new purge_enabled configuration 2015-01-23 17:46:16 +01:00
Raul Ochoa
fabb438cf0 Escape \b for the regex 2015-01-23 17:22:49 +01:00
Raul Ochoa
0abd6a2293 Adds check for surrogate key headers in template instances
p.s. it fixes instantiate template with params test
2015-01-23 17:02:13 +01:00
Raul Ochoa
272e8cd221 Adds Surrogate Keys to named maps 2015-01-23 16:37:38 +01:00
Raul Ochoa
885accdadf Adds varnish http port to the default configurations 2015-01-23 16:36:45 +01:00
Raul Ochoa
f5a3b77737 Make TemplateMaps to emit messages when adding/updating/deleting templates 2015-01-23 16:35:47 +01:00
Raul Ochoa
56abcfd2f4 Update documentation to remove references to signed maps 2015-01-23 11:33:58 +01:00
Santiago Giraldo
2e84d18c3c Updated Maps API v2 2015-01-22 13:44:13 -05:00
Raul Ochoa
ecd570323b Merge branch 'master' into 238-drop-signed-maps 2015-01-22 19:37:03 +01:00
Raul Ochoa
20eb92a3b1 Remove signedmaps and locks functionality as it is no longer needed 2015-01-22 19:28:59 +01:00
Raul Ochoa
8d22ed7594 Tests to validate template instantiation returns new instances with
default values if they are missing.
2015-01-22 18:38:42 +01:00
Santiago Giraldo
b26fe87430 added-static-api-doc 2015-01-22 12:07:34 -05:00
Raul Ochoa
3321987c33 Merge pull request #245 from CartoDB/apiUpdate
API doc update
2015-01-22 18:00:02 +01:00
Raul Ochoa
981be0edd5 Replace signed maps auth tests with template maps tests 2015-01-22 17:55:47 +01:00
Raul Ochoa
e8ab3a48c6 Removes TemplateMaps dependency on SignedMaps
- Token validation is done against the template
 - Template is always extended with default values for auth and placeholders
 - MapConfig is extended, in order to validate auth_toknes, with template info:
    - template name
    - template auth
 - No more locks to create, update or delete templates
    - Trusting in redis' hash semantics
    - Some tradeoffs:
        * A client having more templates than allowed by a race condition
        between limit (HLEN) check and creation (HSET)
        * Updating a template could happen while the deleting it, resulting in
        in a new template
        * Templates already instantiated will be accessible thrught their
        layergroup so it is possible to continue requesting tiles/grids/etc.
 - Authorization is now handled by template maps
2015-01-22 15:40:40 +01:00
Andy Eschbacher
58a54de5a6 Added section on CartoDB.js use 2015-01-21 09:29:57 -05:00
Andy Eschbacher
21b1cea5e8 updates 2015-01-21 09:19:50 -05:00
Raul Ochoa
64b5a64e1b Add templateMaps to serveroptions for the time being 2015-01-21 11:44:06 +01:00
Raul Ochoa
f1b6be1ecb Merge branch 'master' into 238-drop-signed-maps 2015-01-21 11:42:42 +01:00
Raul Ochoa
ac84fc569f Merge pull request #244 from CartoDB/docs-anonymous-maps-jsonp-example
Add jsonp example for anonymous maps
2015-01-21 11:25:37 +01:00
Raul Ochoa
4bdc43ff7c Put back curl command 2015-01-21 11:21:16 +01:00
Raul Ochoa
3afbbccfa2 Add jsonp example for anonymous maps 2015-01-21 11:08:34 +01:00
Raul Ochoa
8bc08d75b7 Separate signed maps instantiation 2015-01-20 18:40:56 +01:00
Raul Ochoa
c14157acc2 Moves template routing 2015-01-20 18:16:09 +01:00
Raul Ochoa
595dac57a0 Moves setDBParams into controller 2015-01-20 18:14:10 +01:00
Raul Ochoa
5632b19e16 Remove unused functionality from app 2015-01-20 18:13:36 +01:00
Raul Ochoa
007196555d Use userByReq from serverOptions 2015-01-20 18:12:24 +01:00
Raul Ochoa
62ffc05ef4 Move template map instantiation into controller 2015-01-20 17:57:53 +01:00
Raul Ochoa
5962141114 Moves template options to controller 2015-01-20 17:45:47 +01:00
Raul Ochoa
7901a05b55 List templates moved into controller 2015-01-20 17:39:33 +01:00
Raul Ochoa
4c2a0ca048 Delete moved to controller 2015-01-20 17:34:23 +01:00
Raul Ochoa
b40c8e6624 Retrieve template moved to controller 2015-01-20 17:17:06 +01:00
Raul Ochoa
97d3b1a03b Move update template to controller 2015-01-20 17:07:55 +01:00
Raul Ochoa
fcea0c9b83 Move template creation to controller 2015-01-20 16:58:12 +01:00
Raul Ochoa
7ce8737e75 Initial split template maps endpoint into its own controller 2015-01-20 16:56:06 +01:00
Raul Ochoa
1d91f0fca9 Stubs next version 2015-01-15 17:37:51 +01:00
Raul Ochoa
23fe7fb0f7 Release 1.24.0 2015-01-15 17:36:48 +01:00
Raul Ochoa
1880b5d261 Merge pull request #243 from CartoDB/retina-support
Retina support for mapnik layers
2015-01-15 17:33:54 +01:00
Raul Ochoa
cf004322fd Upgrades windshaft to 0.34.0 for retina support 2015-01-15 17:21:24 +01:00
Raul Ochoa
30d8f28221 Use retina branch from windshaft 2015-01-14 18:26:28 +01:00
Raul Ochoa
caa05e779a Add scale_factor param as valid one 2015-01-14 18:11:13 +01:00
Raul Ochoa
f13fec13b8 Stubs next version 2015-01-14 16:42:41 +01:00
Raul Ochoa
a93f346948 Release 1.23.1 2015-01-14 16:41:46 +01:00
Raul Ochoa
48d44bada1 Regenerate npm-shrinkwrap.json 2015-01-14 16:18:31 +01:00
Raul Ochoa
a20d08ddc8 Stubs next version 2015-01-14 15:52:20 +01:00
Raul Ochoa
4f18e31af5 Release 1.23.0 2015-01-14 15:50:59 +01:00
Raul Ochoa
41f6a172ee Merge pull request #242 from CartoDB/static-controllers
Upgrade windshaft for static previews
2015-01-14 15:45:22 +01:00
Raul Ochoa
1776d31ba4 Upgrades windshaft to 0.33.0 2015-01-14 15:32:59 +01:00
Raul Ochoa
845ebcac15 Merge branch 'master' into static-controllers
Conflicts:
	npm-shrinkwrap.json
2015-01-13 12:45:37 +01:00
Raul Ochoa
45f73d4be8 Stubs next version 2015-01-13 12:19:28 +01:00
Raul Ochoa
ebdd71f342 Release 1.22.0 2015-01-13 12:18:10 +01:00
Raul Ochoa
597f8a7bab Merge pull request #240 from CartoDB/health-check
Add healthcheck endpoint
2015-01-13 12:12:34 +01:00
Raul Ochoa
3f1aa9955b Remove query tables api dependency from health check 2015-01-13 12:09:02 +01:00
Raul Ochoa
aad2a1e098 Regenerate npm-shrinkwrap.json 2015-01-13 12:01:34 +01:00
Alejandro Martínez
07fd7619bc Merge remote-tracking branch 'origin/master' into health-check
Conflicts:
	NEWS.md
	npm-shrinkwrap.json
	package.json
2015-01-13 11:55:54 +01:00
Alejandro Martínez
96bcd14bb8 Remove PostgreSQL from health checks
This way the health checks will only check for Redis and Mapnik
initialization.
An empty tile without layers or datasources is generated.
2015-01-13 11:29:19 +01:00
Alejandro Martínez
db9d350cae Add healthcheck configuration examples 2015-01-12 16:00:39 +01:00
Raul Ochoa
5914498027 Add canvas dependencies for travis 2015-01-02 17:26:30 +01:00
Raul Ochoa
180109e3aa Update npm-shrinkwrap.json 2015-01-02 15:36:19 +01:00
Raul Ochoa
929dac0df0 Merge branch 'master' into static-controllers 2014-12-23 14:16:33 +01:00
Raul Ochoa
6cd9a53aa5 Merge pull request #237 from CartoDB/templateid_typo
Update Map-API.md
2014-12-23 14:15:51 +01:00
Carlos Matallín
cd585dd657 Update Map-API.md 2014-12-23 14:06:02 +01:00
javi santana
2a150a6e7e Merge pull request #236 from CartoDB/typoFixes
Fixed typos, etc.
2014-12-18 10:17:32 +01:00
Andy Eschbacher
902b7339d1 Fixed typos, etc. 2014-12-17 15:31:18 -05:00
Raul Ochoa
f84b907dc8 Merge branch 'master' into static-controllers
Conflicts:
	npm-shrinkwrap.json
	package.json
2014-12-16 19:05:39 +01:00
Raul Ochoa
72cf5f8b04 Stubs next version 2014-12-15 16:08:18 +01:00
Raul Ochoa
e1d7852877 Release 1.21.2 2014-12-15 16:07:00 +01:00
Raul Ochoa
3f66c20616 Upgrades windshaft to 0.32.4 2014-12-15 16:05:58 +01:00
Raul Ochoa
a5f908d70e Merge branch 'master' into static-controllers
Conflicts:
	npm-shrinkwrap.json
	package.json
2014-12-12 16:53:38 +01:00
Raul Ochoa
e9383a2f0c Stubs next version 2014-12-11 10:24:22 +01:00
Raul Ochoa
0453166326 Release 1.21.1 2014-12-11 10:22:56 +01:00
Raul Ochoa
670478e9ca Merge pull request #234 from CartoDB/upgrade-windshaft
Upgrade windshaft
2014-12-11 10:21:27 +01:00
Raul Ochoa
1a9bc5550c Make windshaft version visible in news 2014-12-11 10:17:12 +01:00
Raul Ochoa
25f7e58b3a Re-generate npm-shrinkwrap.json 2014-12-11 10:16:05 +01:00
Raul Ochoa
839f8b062b Changes to windshaft tagged version 2014-12-11 10:12:40 +01:00
Raul Ochoa
eae1fbff8a Upgrades windshaft 2014-12-10 20:25:27 +01:00
Raul Ochoa
d628b2de27 Merge branch 'master' into static-controllers
Conflicts:
	npm-shrinkwrap.json
2014-12-02 18:24:41 +01:00
Raul Ochoa
56e4cb765f Merge pull request #231 from CartoDB/230-close-logfile-fd-on-kill-hup
Closes fd for log files on `kill -HUP`
2014-12-02 17:27:10 +01:00
Raul Ochoa
21179c56d4 Merge branch 'master' into static-controllers
Conflicts:
	npm-shrinkwrap.json
	package.json
2014-12-02 17:14:42 +01:00
Raul Ochoa
3da2830cfa Merge branch 'master' into 230-close-logfile-fd-on-kill-hup
Conflicts:
	npm-shrinkwrap.json
2014-12-02 17:09:50 +01:00
Raul Ochoa
873d6287c4 Merge pull request #232 from CartoDB/upgrade-windshaft
Upgrades windshaft to 0.32.1
2014-12-02 17:05:42 +01:00
Raul Ochoa
ea7eed4ad0 Upgrades windshaft to 0.32.1 2014-12-02 16:37:41 +01:00
Raul Ochoa
3b4b5ab298 Closes fd for log files on kill -HUP. Fixes #230 2014-12-02 15:05:28 +01:00
Raul Ochoa
2711c9b78c Fix typo 2014-12-02 11:00:36 +01:00
Raul Ochoa
48d60821a7 Exposes http renderer config 2014-12-01 18:43:40 +01:00
Raul Ochoa
076f4b441f Regenerates npm-shrinkwrap.json, will work on 0.8.x issues later 2014-11-27 12:16:52 +01:00
Raul Ochoa
e9eca83cd1 Fixes windshaft version 2014-11-27 12:07:29 +01:00
Raul Ochoa
f6aa20b96d Regenerate npm-shrinkwrap.json using millstone 0.6.14 2014-11-27 11:51:23 +01:00
Raul Ochoa
c15a384622 Regenerate npm-shrinkwrap.json as it seems to be different now 2014-11-27 03:18:22 +01:00
Raul Ochoa
46c3bedd15 Regenerate npm-shrinkwrap.json 2014-11-27 03:06:25 +01:00
Raul Ochoa
bc587f17de Adds proj4 in npm-shrinkwrap.json 2014-11-27 02:16:00 +01:00
Raul Ochoa
5905971178 Fix url for stats wiki 2014-11-25 14:39:18 +01:00
Raul Ochoa
afc7a7c956 Merge branch 'master' into static-controllers 2014-11-25 13:20:30 +01:00
Raul Ochoa
bf970803ec Defaults logging to stdout in development config example 2014-11-25 13:19:04 +01:00
Raul Ochoa
3de473662f Use static-controller branch from windshaft 2014-11-25 12:53:35 +01:00
Raul Ochoa
4bad92e3dd Improve named maps 2014-11-21 15:19:41 +01:00
Raul Ochoa
2089a299f1 Fix json 2014-11-18 11:33:33 +01:00
Raul Ochoa
10b1081960 Change highlighting to ``` 2014-11-14 17:23:15 +01:00
Raul Ochoa
c636a820d5 Fix named maps instantiation example 2014-11-13 14:14:24 +01:00
Raul Ochoa
6c4bb59f06 First tests, not all ready. WIP 2014-11-05 15:42:28 +01:00
Raul Ochoa
97c55c1187 Removes console.log 2014-11-05 15:42:16 +01:00
Raul Ochoa
2c5db229c6 Merge pull request #229 from CartoDB/pgraster
Add default configuration for raster overviews
2014-11-05 15:06:18 +01:00
Raul Ochoa
7c389a8010 Health check endpoint 2014-11-05 15:06:01 +01:00
Raul Ochoa
c84ed0a4b4 Merge branch 'master' into pgraster
Conflicts:
	npm-shrinkwrap.json
	package.json
2014-11-05 14:54:59 +01:00
Raul Ochoa
1c638aa661 Upgrades windshaft to 0.32.0 2014-11-05 14:48:59 +01:00
Raul Ochoa
6325a23bb4 Adds default value for raster overviews configuration 2014-11-05 12:48:26 +01:00
Raul Ochoa
07abae30ba Stubs next version 2014-10-24 17:08:27 +02:00
Raul Ochoa
494e2f48d5 Release 1.21.0 2014-10-24 17:07:36 +02:00
Raul Ochoa
c7875b3f53 Merge pull request #226 from CartoDB/layergroup-ttl
Allow a different cache-control max-age for layergroup responses
2014-10-24 16:55:30 +02:00
Raul Ochoa
c88330f5f2 Allow a different cache-control max-age for layergroup responses 2014-10-24 16:05:41 +02:00
Raul Ochoa
ff4ec19fff Fix documentation typos, endpoints and replace all /tiles with /api/v1/map 2014-10-21 19:18:34 +02:00
Raul Ochoa
697f3473f6 Use pgraster branch from windshaft 2014-10-21 14:46:53 +02:00
Raul Ochoa
439cd65050 Stubs next version 2014-10-20 17:52:47 +02:00
Raul Ochoa
79c7a559ad Release 1.20.2 2014-10-20 17:51:16 +02:00
Raul Ochoa
18d5315c2f Regenerate npm-shrinkwrap.json 2014-10-20 17:26:33 +02:00
Raul Ochoa
06693aeac7 Upgrades windshaft to 0.31.0 2014-10-20 17:24:23 +02:00
Raul Ochoa
d5e6f9906c Stubs next version 2014-10-17 14:23:19 +02:00
Raul Ochoa
fac4de21de Release 1.20.1 2014-10-17 14:21:51 +02:00
Raul Ochoa
e3d0f0ec8f Adds default value for redis returnToHead configuration 2014-10-17 14:18:14 +02:00
Raul Ochoa
81c86019ab Upgrades redis-mpool to 0.3.0 2014-10-17 14:15:59 +02:00
Raul Ochoa
95c4a25bd2 Stubs next version 2014-10-15 17:30:49 +02:00
Raul Ochoa
d2f801c7d6 Release 1.20.0 2014-10-15 17:29:56 +02:00
Raul Ochoa
f72c4f28da Prepend also the app name 2014-10-15 17:16:29 +02:00
Raul Ochoa
a248fe5c4b Prepend redis-pool in statsd key for redis-mpool status 2014-10-15 17:08:56 +02:00
Raul Ochoa
e9495ccd84 Merge pull request #225 from CartoDB/upgrade-windshaft
Upgrades Windshaft to report redis/renderers/mapnik pool metrics
2014-10-15 16:55:40 +02:00
Raul Ochoa
cf5e34eae6 Upgrades Windshaft to start reporting redis/renderers/mapnik pool metrics 2014-10-15 16:45:49 +02:00
Raul Ochoa
e52f583e20 Merge pull request #224 from CartoDB/one-redis-mpool
Use only one redis-mpool across the whole app
2014-10-15 16:31:02 +02:00
Raul Ochoa
98967cdf88 Be more clear about the effect of the statusInterval number 2014-10-15 16:25:35 +02:00
Raul Ochoa
ceb1bb7f50 Document what emitter.statusInterval is. 2014-10-15 16:20:51 +02:00
Raul Ochoa
94c61cb959 Update to release versions 2014-10-15 12:31:40 +02:00
Raul Ochoa
20cb559714 Merge branch 'master' into one-redis-mpool 2014-10-15 11:44:38 +02:00
Raul Ochoa
2a49770fc0 Merge pull request #223 from CartoDB/remove-travis-mapnik
Remove self-signed certificates workaround
2014-10-15 11:44:19 +02:00
Raul Ochoa
4a71a9f7b5 Remove self-signed certificates workaround 2014-10-15 11:06:16 +02:00
Raul Ochoa
b4b596ad8b Merge pull request #222 from CartoDB/remove-travis-mapnik
Let's use travis postgresql addon instead of manually installed one
2014-10-15 10:53:27 +02:00
Raul Ochoa
a865bcfa1d Let's use travis postgresql addon instead of manually installed one 2014-10-15 10:48:00 +02:00
Raul Ochoa
3587cf5154 Merge pull request #221 from CartoDB/remove-travis-mapnik
Reduces travis dependencies installation
2014-10-15 00:41:15 +02:00
Raul Ochoa
12b1d6e53b Reduces travis dependencies installation 2014-10-14 23:03:08 +02:00
Raul Ochoa
f4cb87f493 Adds default values for slow queries in redis 2014-10-14 22:14:34 +02:00
Raul Ochoa
804088009e Report to statsd the status of redis pools 2014-10-14 22:12:35 +02:00
Raul Ochoa
9f5faf7cf8 Server options to instantiate cartodb-redis with redis configuration if pool is not provided 2014-10-14 21:19:44 +02:00
Raul Ochoa
711c1a89ee Merge branch 'master' into one-redis-mpool 2014-10-14 18:23:17 +02:00
Raul Ochoa
30dd0604ca Stubs next version 2014-10-14 15:44:58 +02:00
Raul Ochoa
0b67eed92f Release 1.19.0 2014-10-14 15:12:17 +02:00
Raul Ochoa
9782cbae35 Merge pull request #220 from CartoDB/upgrade-npm-shrinkwrap
Generates npm-shrinkwrap.json with npm >1.2.0
2014-10-14 14:50:54 +02:00
Raul Ochoa
6ca4c0b23f Generates npm-shrinkwrap.json with npm >1.2.0 2014-10-14 14:17:54 +02:00
Raul Ochoa
a672ac66ae Upgrades windshaft to 0.28.2 2014-10-14 14:05:50 +02:00
Raul Ochoa
65c4ca01d0 Stubs next version 2014-10-13 16:29:31 +02:00
Raul Ochoa
6c3e2513d5 Release 1.18.2 2014-10-13 16:28:15 +02:00
Raul Ochoa
cc50364453 Upgrades windshaft to 0.28.1 2014-10-13 16:19:32 +02:00
Raul Ochoa
774104b34e Defaults resultSet to object if undefined in QueryTablesApi 2014-10-13 15:24:14 +02:00
Raul Ochoa
5a3e427249 Stubs next version 2014-10-13 11:50:21 +02:00
Raul Ochoa
a9e2f95fdb Release 1.18.1 2014-10-13 11:48:57 +02:00
Raul Ochoa
d89b2986fd Allow to add more node.js' threadpool workers via process.env.UV_THREADPOOL_SIZE 2014-10-08 16:50:35 +02:00
Raul Ochoa
91229dd1e1 Merge pull request #219 from strk/master-ignores
Ignore files produced by "make check"
2014-10-08 10:41:06 +02:00
Sandro Santilli
f52c65ea25 Ignore files produced by "make check" 2014-10-08 10:33:19 +02:00
Sandro Santilli
e9f5c60719 Use a windshaft-specific name for the test user
Avoids problems with running cartodb-sql-api tests after
windshaft-cartodb tests (as the test database is not cleaned up)
2014-10-08 10:31:32 +02:00
Sandro Santilli
9b06ac833a Have ./configure tolerate unknown options 2014-10-08 10:10:58 +02:00
Raul Ochoa
3dad6e96e3 Merge branch 'master' into one-redis-mpool 2014-10-07 12:47:10 +02:00
Raul Ochoa
8fd6e22dc4 Stubs next version 2014-10-03 17:05:20 +02:00
Raul Ochoa
474198b4e1 Release 1.18.0 2014-10-03 17:03:50 +02:00
Raul Ochoa
fbdafcb7b7 Comes back to use mapnik 2.3.x based on cartodb/node-mapnik@1.4.15-cdb from windshaft@0.28.0 2014-10-03 16:57:04 +02:00
Raul Ochoa
9b0232c48d Stubs next version 2014-10-01 20:28:47 +02:00
Raul Ochoa
723a184086 Release 1.17.2 2014-10-01 20:27:11 +02:00
Raul Ochoa
db34a4ffff Stubs next version 2014-09-30 15:09:56 +02:00
Raul Ochoa
0b896fb935 Release 1.17.1 2014-09-30 15:08:26 +02:00
Raul Ochoa
e0331ec022 Upgrades mocha 2014-09-30 15:03:14 +02:00
Raul Ochoa
e31ef916f0 Upgrades windshaft to 0.27.1 which downgrades node-mapnik to 1.4.10 2014-09-30 15:02:24 +02:00
Raul Ochoa
55669f88ff Updates news 2014-09-26 11:21:28 +02:00
Raul Ochoa
c13dbc9a57 Merge pull request #214 from CartoDB/CDB-4008
TTL for template locks so they are not kept forever
2014-09-26 11:16:05 +02:00
Raul Ochoa
e8e03585ff Adds dot.js dependency 2014-09-25 19:17:02 +02:00
Raul Ochoa
b4bee864d2 Lock now considers the creation time and compares against a ttl so
a lock is not keep forever in case of failure.

Pending: lazy removal of expired locks.
2014-09-25 19:00:35 +02:00
Raul Ochoa
b41d1e84da Stubs next version 2014-09-25 16:17:10 +02:00
Raul Ochoa
b5d5d7c2b0 Release 1.17.0 2014-09-25 16:15:51 +02:00
Raul Ochoa
3e571b4ce8 Use object.keys to iterate over objects 2014-09-25 12:17:32 +02:00
Raul Ochoa
fb8fd5121e Do not expose internal implementation 2014-09-25 12:16:34 +02:00
Raul Ochoa
ac2a3243b5 Don't cache regexes and avoid the _re hack 2014-09-25 12:04:52 +02:00
Raul Ochoa
1c10b8193b Adds dot to compile templates 2014-09-24 19:17:51 +02:00
Raul Ochoa
abf0fa1b32 Remove unused var 2014-09-24 19:12:43 +02:00
Raul Ochoa
4c5bc13c7f Check style fixes 2014-09-24 19:11:53 +02:00
Raul Ochoa
c33b81e3ad Merge pull request #213 from CartoDB/mapnik-2.3.x
Starts using mapnik 2.3.x by upgrading windshaft dependency
2014-09-24 16:26:21 +02:00
Raul Ochoa
f88f0b5019 Modify travis configuration to be able to compile node-mapnik with mapnik 2.3.x 2014-09-24 16:02:31 +02:00
Raul Ochoa
3b96f0d535 Starts using mapnik 2.3.x via windshaft upgrade 2014-09-24 15:54:13 +02:00
Raul Ochoa
243672ead5 Merge branch 'master' into mapnik-2.3.x 2014-09-24 15:27:41 +02:00
Raul Ochoa
7009eb20f8 Check style fixes 2014-09-24 11:42:53 +02:00
Raul Ochoa
24cbd192aa Share one redis-mpool across the application 2014-09-24 11:42:36 +02:00
Raul Ochoa
9d36ae293c Run check before any assert so server is stopped 2014-09-18 19:07:15 +02:00
Raul Ochoa
9496d83d1c Adds poolSize configuration for mapnik 2014-09-18 19:06:45 +02:00
Raul Ochoa
18233e9ea1 Upgrades windshaft and cartodb-redis 2014-09-18 19:05:20 +02:00
Raul Ochoa
6523c4bbbb Fixes template.json in documentation to be a valid JSON 2014-09-03 12:34:28 +02:00
Raul Ochoa
5bafbdfaa0 Changes mapnik dependency in windshaft module to use node-mapnik 1.4.13
which is based on mapnik-2.3.x
2014-08-29 17:03:31 +02:00
Raul Ochoa
7afa869833 Use double quote to be consistent 2014-08-29 16:48:28 +02:00
Raul Ochoa
0d32036523 Merge pull request #211 from CartoDB/CDB-3659
Remove some metrics
2014-08-26 13:44:21 +02:00
Raul Ochoa
a084ec19ff Update news 2014-08-26 12:23:56 +02:00
Raul Ochoa
7faff8f887 Removes cors metric 2014-08-26 11:53:59 +02:00
Raul Ochoa
f406001315 Removes get_infowindow and get_map_metadata metrics 2014-08-25 19:15:31 +02:00
Raul Ochoa
2b2020b43b Removes getTableGeometryType metric 2014-08-25 19:09:54 +02:00
Raul Ochoa
4886e4b34a Merge pull request #210 from CartoDB/improve-query-tables-api
Removes duplicated code in query_tables_api
2014-08-22 13:17:02 +02:00
Raul Ochoa
65e0364d37 Removes duplicated code in query_tables_api 2014-08-22 12:52:05 +02:00
Raul Ochoa
13e16e0a26 Merge pull request #209 from CartoDB/scale_denominator-support
Supports `!scale_denominator!` dynamic param in SQL queries
2014-08-22 10:30:14 +02:00
Raul Ochoa
965e1cd0c4 Supports !scale_denominator! dynamic param in SQL queries 2014-08-22 10:16:39 +02:00
Raul Ochoa
3750b67110 Merge pull request #208 from CartoDB/CDB-1843
Upgrades windshaft
2014-08-19 19:06:25 +02:00
Raul Ochoa
7e1f48f212 CDB-1843 upgrades windshaft 2014-08-19 18:42:48 +02:00
Raul Ochoa
42457df2c1 Stubs next version 2014-08-19 14:28:24 +02:00
Raul Ochoa
56d8f1acfe Release 1.16.1 2014-08-19 14:26:19 +02:00
Raul Ochoa
56ac4acc9f Upgrades cartodb-redis 2014-08-19 14:25:45 +02:00
javi santana
d91b0f1af5 fixed missing comma 2014-08-19 09:25:45 +02:00
Raul Ochoa
f986516379 Stubs next version 2014-08-18 15:29:47 +02:00
Raul Ochoa
fa59255556 Release 1.16.0 2014-08-18 15:28:38 +02:00
Raul Ochoa
ab1c11faf2 Merge pull request #207 from CartoDB/upgrade-windshaft
Upgrade windshaft
2014-08-18 15:26:58 +02:00
Raul Ochoa
307f220de4 Updates news 2014-08-18 15:14:01 +02:00
Raul Ochoa
50c8a2dc69 Defaults mapnik version for test 2014-08-18 14:48:45 +02:00
Raul Ochoa
3f726dc4c5 Upgrades windshaft 2014-08-18 14:41:29 +02:00
Raul Ochoa
105d50f1f4 Merge pull request #206 from CartoDB/upgrade-dependencies
Upgrades dependencies
2014-08-15 01:51:16 +02:00
Raul Ochoa
a3a5964926 Upgrades dependencies 2014-08-14 19:54:45 +02:00
Raul Ochoa
6a8cff6fcd Merge branch 'remove-mapnik-dependency'
Conflicts:
	NEWS.md
2014-08-14 19:26:52 +02:00
Raul Ochoa
b42e9c80f7 Adds windshaft's mapnik dependency to npm-shrinkwrap.json 2014-08-14 18:56:33 +02:00
Raul Ochoa
23a7684208 Removes mapnik dependency as it now relies on Windshaft to check mapnik version 2014-08-14 18:27:54 +02:00
Raul Ochoa
c52c245b9d Merge pull request #204 from CartoDB/CDB-3686
Configurable QueryTablesAPI to call directly postgresql
2014-08-14 13:44:07 +02:00
Raul Ochoa
4555b2107a Updates news 2014-08-14 13:32:22 +02:00
Raul Ochoa
49b0120c6d Formats NEWS 2014-08-14 13:32:04 +02:00
Raul Ochoa
f2541d8cae Merge branch 'master' into CDB-3686
Conflicts:
	package.json
2014-08-13 15:31:22 +02:00
Raul Ochoa
d1fb792709 Stubs next version 2014-08-13 15:27:16 +02:00
Raul Ochoa
86fb58155a Release 1.15.0 2014-08-13 15:26:25 +02:00
Raul Ochoa
d3c656893c Merge pull request #202 from CartoDB/CDB-3135
Upgrades dependencies to get redis-mpool improvements
2014-08-13 15:24:59 +02:00
Raul Ochoa
713e394e7b Slow pool configuration in example configurations 2014-08-13 15:15:30 +02:00
Raul Ochoa
40acf533ae Specifies name in the redis pool 2014-08-13 15:12:46 +02:00
Raul Ochoa
13fdfc602e Upgrades dependencies 2014-08-13 15:10:58 +02:00
Raul Ochoa
8255f3eb51 Upgrades cartodb-psql dependency 2014-08-11 20:18:27 +02:00
Raul Ochoa
e7ab71c606 Merge branch 'master' into CDB-3686 2014-08-11 12:19:11 +02:00
Raul Ochoa
3eab0d6349 Stubs next version 2014-08-07 12:35:38 +02:00
Raul Ochoa
58047fac17 Release 1.14.0 2014-08-07 12:34:49 +02:00
Raul Ochoa
6e4144d015 Prepares next release 2014-08-07 12:33:53 +02:00
Raul Ochoa
8b0fda8d89 Merge pull request #201 from CartoDB/CDB-3664
Upgrades windshaft (and grainstore) to be able to specify the tile format
2014-08-07 12:20:01 +02:00
Raul Ochoa
2ed656ca0d Upgrades windshaft (and grainstore) to be able to specify the tile
format, see: https://github.com/mapnik/mapnik/wiki/OutputFormats
2014-08-07 01:57:21 +02:00
Raul Ochoa
5cf79c82bb Configurable QueryTablesAPI to call directly postgresql using cartodb-psql
or to keep using a request to the SQL API
2014-08-06 21:48:08 +02:00
Raul Ochoa
d1373bec66 Improves SQL query for affected tables and last updated time 2014-08-04 17:48:59 +02:00
Raul Ochoa
325a0503cb Merge branch 'master' into cdb 2014-08-04 14:14:53 +02:00
Raul Ochoa
fa72f52ad4 Merge pull request #200 from CartoDB/CDB-3686
Affected tables and last updated time for a query into a single SQL API request
2014-08-04 14:14:00 +02:00
Raul Ochoa
528815a564 Updates news 2014-08-04 13:24:44 +02:00
Raul Ochoa
dabcba9f5f Merge branch 'master' into CDB-3686 2014-08-04 13:11:40 +02:00
Raul Ochoa
5d9afc18f5 Merge tag '1.13.1' into cdb 2014-08-04 13:11:01 +02:00
Raul Ochoa
995dabc9b7 Stubs next version 2014-08-04 13:05:08 +02:00
Raul Ochoa
36145542af Release 1.13.1 2014-08-04 13:04:13 +02:00
Raul Ochoa
06eca6525a Merge pull request #199 from CartoDB/CDB-3657
CDB-3657 Adds profiler as JSON to the header
2014-08-04 13:02:27 +02:00
Raul Ochoa
414673b347 CDB-3657 Adds profiler as JSON to the header 2014-08-04 12:53:15 +02:00
Raul Ochoa
a9767c049f CDB-3686 Adds support for per mil tolerance when comparing images as in Mac OS X some results from ImageMagick are a bit odd 2014-08-04 12:35:54 +02:00
Raul Ochoa
507a6a8979 CDB-3686 Style changes 2014-08-04 01:32:49 +02:00
Raul Ochoa
73d1db3bd2 CDB-3686 Adds support for per mil tolerance when comparing images as in Mac OS X some results from ImageMagick are a bit odd 2014-08-04 01:30:24 +02:00
Raul Ochoa
9b5921e8e1 CDB-3686 Fixes expected queries based on changes to request table names and last updated time in one request 2014-08-04 01:29:23 +02:00
Raul Ochoa
799a999148 CDB-3686 Makes SQL API emulator to handle new query with both names and updated time for affected tables. 2014-08-04 01:28:30 +02:00
Raul Ochoa
eafe3af13e Fixes reference to redis-mpool 2014-08-01 18:27:55 +02:00
Raul Ochoa
4e420c2f33 Merge tag '1.13.0' into CDB-3686 2014-07-30 18:25:10 +02:00
Raul Ochoa
654b3ad6d3 Fixes reference to redis-mpool 2014-07-30 18:23:45 +02:00
Raul Ochoa
9f8d73a1df Removes duplicated file 2014-07-30 18:17:14 +02:00
Raul Ochoa
f6e0b4ca9f Merge branch 'master' of https://github.com/cartodb/windshaft-cartodb into CDB-3686 2014-07-30 18:13:47 +02:00
Raul Ochoa
1dbad1f0b8 Stubs next version 2014-07-30 18:11:32 +02:00
Raul Ochoa
8f9e19e3e2 Fix date in NEWS 2014-07-30 18:10:28 +02:00
Raul Ochoa
b1a0b5e235 Release 1.13.0 2014-07-30 18:08:07 +02:00
Raul Ochoa
bce13944c3 Merge pull request #198 from CartoDB/multiuser
Support for multiple schemas, multiple auth tokens and public user from redis
2014-07-30 17:56:05 +02:00
Raul Ochoa
c8fc3d1e7a Updates to correct version of step profiler 2014-07-30 16:23:03 +02:00
Raul Ochoa
e6f7b9c1f9 Adds news about changes in multiuser branch 2014-07-30 16:08:45 +02:00
Raul Ochoa
552ebaaaac Upgrades Windshaft to version 0.22.0 2014-07-30 15:25:15 +02:00
Raul Ochoa
6019fb2ca3 Merge pull request #197 from CartoDB/CDB-3678
[CDB-3678] Creates api_hostname global variable
2014-07-30 15:09:58 +02:00
Raul Ochoa
3af45e1a32 Moves calls to SQL API to its own entity.
Groups affected tables and last updated time for affected tables into one request.
2014-07-30 13:46:46 +02:00
Raul Ochoa
75088c89d3 Style fixes 2014-07-30 13:45:53 +02:00
Luis Bosque
2c1d46f159 [CDB-3678] Creates api_hostname global variable 2014-07-29 14:54:35 +02:00
javi santana
15b9a1f34b fixed documentation 2014-07-24 13:01:35 +02:00
Carlos Matallín
5c70dd0557 run tests 2014-07-21 11:11:21 +02:00
Carlos Matallín
dc0acdbee1 Update Map-API.md 2014-07-21 10:18:15 +02:00
Carlos Matallín
ae01047e8c Merge pull request #195 from matallo/master
move maps api doc
2014-07-09 14:24:27 +02:00
Carlos Matallín
1b7c2a0208 move maps api doc 2014-07-09 14:23:53 +02:00
Carlos Matallín
a8b01f523a Merge pull request #194 from matallo/master
update doc
2014-07-09 14:20:43 +02:00
Carlos Matallín
23cbad8ba6 update doc 2014-07-09 14:19:25 +02:00
Carlos Matallín
984e0f6e83 Rename Map-API.md to Map-API-internal.md 2014-07-09 13:13:21 +02:00
Raul Ochoa
67df6a4d73 Adds support for several auth tokens 2014-07-08 10:35:45 +02:00
Raul Ochoa
f756b9d77f Removes search_path param 2014-07-04 12:18:35 +02:00
Raul Ochoa
0dfd51f81a Adds host to redis setup as it does not make sense to continue if there is no host in redis. 2014-07-04 11:47:44 +02:00
Raul Ochoa
bfdcee3772 Retrieving db public user from redis. It uses a new multiget method from cartodb-redis 2014-07-03 21:39:47 +02:00
Raul Ochoa
470aea22d9 Sets full search_path 2014-07-03 10:24:37 +02:00
Raul Ochoa
32e4c26c95 Sets origin for grainstore in shrinkwrap 2014-07-02 19:34:28 +02:00
Raul Ochoa
6a34568935 Forcing grainstore version in shrinkwrap 2014-07-02 19:16:06 +02:00
javi
3548106a6c changed branch for windshaft 2014-06-27 23:42:03 +02:00
javi
3806ad8843 Merge remote-tracking branch 'origin/CDB-2891-search_path' into multiuser 2014-06-27 09:10:39 +02:00
Raul Ochoa
037ce2dc12 CDB-2891 Exposes username as search_path in params 2014-06-27 00:48:48 +01:00
javi
338c0bcdbe use regclass instead table name to look for last_updated in CDB_tablemetadata 2014-06-26 15:00:55 +02:00
Raul Ochoa
bc3baf3094 CDB-3256 Prepares 1.12.1 release 2014-06-24 16:26:57 +02:00
Raul Ochoa
8a91b5cfb5 CDB-3256 Fixes test related to cache in templated layergroup creation 2014-06-24 16:05:54 +02:00
Raul Ochoa
4cf1ddd6fc CDB-3256 Adds response and method references to fake request object 2014-06-24 15:52:47 +02:00
Raul Ochoa
cb781aeb00 CDB-3256 Prepares 1.12.0 Release 2014-06-24 14:24:14 +02:00
Raul Ochoa
2dd03e21e1 CDB-3256 fix test and adds a couple more of tests for testing the no-cache scenarios 2014-06-24 13:13:00 +02:00
Raul Ochoa
055bacbad7 Sets PGUSER environment variable 2014-06-24 12:39:57 +02:00
Raul Ochoa
46ae6d1fe4 Changes travis configuration to be similar to windshaft one 2014-06-24 12:39:46 +02:00
Raul Ochoa
5e73b12cf5 CDB-3256 adds headers based on affected tables when creating a layergroup via HTTP GET 2014-06-24 12:16:30 +02:00
Sandro Santilli
86c6f3eeac Wrap all json strings and string values in double-quotes 2014-06-09 12:19:16 +02:00
Raul Ochoa
8922ae3a45 adds document about metrics being tracked 2014-05-29 13:10:46 +02:00
Raul Ochoa
318e22e9fa Merge commit '4738b880a6c29a6d10dda3ad178f35a54bd576d3'
Conflicts:
	NEWS.md
	package.json
2014-05-07 19:07:20 +02:00
Raul Ochoa
4738b880a6 Prepares release 1.10.3 2014-05-07 18:28:10 +02:00
Sandro Santilli
49829f8935 Set default PostgreSQL application name to "cartodb_tiler" 2014-05-07 16:19:22 +02:00
Sandro Santilli
8e9d72982a Refuse to start if log_filename points to a non-existing directory
Closes #189
2014-05-07 11:03:25 +02:00
Raul Ochoa
d2f0180475 Merge remote-tracking branch 'rochoa/master' 2014-04-22 11:40:48 +02:00
Raul Ochoa
4da0b1e07c CDB-2096 Configures the CWD for log4js logger. 2014-04-22 10:52:59 +02:00
Sandro Santilli
5a4a35b665 Fix documentation for redis.max setting
Closes #192
2014-04-16 17:53:42 +02:00
Raul Ochoa
248cb4bd76 Removes unused dependency. 2014-04-11 15:14:59 +02:00
Sandro Santilli
140001f036 Update release document 2014-04-09 09:14:20 +02:00
Sandro Santilli
3917cac800 Add 1.10.2 section 2014-04-08 10:00:41 +02:00
Sandro Santilli
ee37da5b35 Prepare for 1.10.3 2014-04-08 10:00:10 +02:00
Sandro Santilli
6f8f3d2057 Release 1.10.2 2014-04-08 09:57:49 +02:00
Sandro Santilli
882ec65ba0 Use signer's map_key when contacting sql-api
Includes testcase.
Fixes #188
2014-04-08 09:44:49 +02:00
Sandro Santilli
7e1aba3368 Use signer's map_key when contacting sql-api
Includes testcase.
Fixes #188
2014-04-08 09:44:00 +02:00
Sandro Santilli
8aeadd1960 Fix show_style tool broken since 1.8.1 2014-03-31 12:55:30 +02:00
Sandro Santilli
a5b091eec8 Prepare for 1.10.2 2014-03-31 12:55:04 +02:00
Sandro Santilli
bbd4db6ddb Fix show_style tool broken since 1.8.1 2014-03-31 12:53:48 +02:00
Sandro Santilli
312194228a Stop duplicating global.environment as global.settings 2014-03-28 18:47:59 +01:00
Sandro Santilli
5c1125900b Add support for log_filename directive, reopen logfile on SIGHUP 2014-03-28 18:05:18 +01:00
Sandro Santilli
08b8741282 Reload log files on SIGUSR2
This is an attempt to play more nicely with logrotate
2014-03-28 17:06:44 +01:00
Sandro Santilli
e8367b765a Add persist_connection setting in .example configs 2014-03-24 17:40:43 +01:00
Sandro Santilli
91cd0df7b3 Typo in comment 2014-03-24 17:03:32 +01:00
Sandro Santilli
dff0a2aa1f Merge branch 'b1.10'
Fixes bogus caching of failing jsonp responses
2014-03-21 15:17:43 +01:00
Sandro Santilli
1bf7bf66b3 Release 1.10.1 2014-03-21 15:16:19 +01:00
Sandro Santilli
9e495b42ee Do not cache non-success jsonp responses
Closes #186
Includes testcase
2014-03-21 13:58:20 +01:00
Sandro Santilli
5f30b9e798 Add an example of a slow mapconfig (using lots of data) 2014-03-20 18:19:30 +01:00
Sandro Santilli
7c892de7b1 Prepare for 1.11.0 2014-03-20 17:11:06 +01:00
Sandro Santilli
898f717254 Prepare for 1.10.1 2014-03-20 17:10:39 +01:00
Sandro Santilli
800ef32959 Release 1.10.0 2014-03-20 17:08:35 +01:00
Sandro Santilli
609d69c4c9 Upgrade of windshaft fixed connection details to client
Closes #183.
2014-03-20 10:21:28 +01:00
Sandro Santilli
9e1be39774 Switch to 3-clause BSD license
Closes #184
2014-03-20 10:20:51 +01:00
Sandro Santilli
87ac44a1f1 Upgrade windshaft to 0.20.0
Reduces noise on the "error" channel (now optionally writing to rollbar)
and avoids caching bogus mapnik renderers.
Details: http://github.com/CartoDB/Windshaft/blob/0.20.0/NEWS
2014-03-20 10:18:33 +01:00
Sandro Santilli
9c4feac19b Ensure make check fails if database preparation fails 2014-03-19 17:04:06 +01:00
Sandro Santilli
471edabe4d Reword uncaught exception error, and log full stack 2014-03-13 11:58:29 +01:00
Sandro Santilli
86841f80ca Use version of node-mapnik with temptative fix for glibc detected corruptions 2014-03-13 10:26:11 +01:00
Sandro Santilli
79348178a7 Upgrade node-varnish to 0.3.0 2014-03-12 18:11:19 +01:00
Sandro Santilli
60b552027b Add optional support for rollbar
Re-targets to 1.10.0
Also installs an uncaught exception handler

Closes #150
2014-03-12 17:21:35 +01:00
Sandro Santilli
62cbb15089 Include tiler version in startup log 2014-03-11 12:21:00 +01:00
Sandro Santilli
667b911023 Prepare for 1.9.1 2014-03-10 17:41:44 +01:00
Sandro Santilli
071e86799b Release 1.9.0 2014-03-10 17:40:55 +01:00
Sandro Santilli
4164cf7adb Set release date for 1.8.5 2014-03-10 17:37:19 +01:00
Sandro Santilli
b61aee36e7 More format changes 2014-03-06 16:29:26 +01:00
Sandro Santilli
7b16676f63 Retarget to 1.9.0 2014-03-06 16:28:13 +01:00
javi
ff4f46abcc Merge branch 'server_metadata' 2014-03-06 16:27:01 +01:00
javi santana
09c1bd96df fix formating 2014-03-06 16:22:25 +01:00
javi santana
40a190c29c added cdn_url option 2014-03-06 16:22:04 +01:00
javi
5bfc360856 added serverMetadata option for layer group, close #182 CDB-1940 2014-03-06 15:19:12 +01:00
Sandro Santilli
7eb26a7326 Upgrade windshaft to 0.19.3, fixing crash on dns error
Closes #180
2014-03-05 18:16:42 +01:00
Sandro Santilli
0afc9c154b Cleanly catch exceptions from sendResponse
Closes #178
2014-03-04 18:04:58 +01:00
Sandro Santilli
97e00fb47d Do not send duplicated stats on template instanciation
Closes #179
2014-03-04 17:51:50 +01:00
Sandro Santilli
dbae0eeb31 It is "cacheDns", not "dnsCache"
See https://github.com/sivy/node-statsd/issues/38
2014-03-04 17:37:19 +01:00
Sandro Santilli
bd9a21b805 Add "dnsCache" statsd setting in the example configs 2014-03-04 16:52:16 +01:00
Sandro Santilli
033f8df500 Include API docs, moved from wiki
Closes #164
2014-03-04 15:39:21 +01:00
Sandro Santilli
ffda103d61 Do not UNWATCH on every redis client release
Closes #161
2014-03-04 15:36:08 +01:00
Sandro Santilli
ecc9ea1226 Use 403 for forbidden, not 401
Includes upgrade of windshaft to 0.19.3
Includes upgrade of redis-mpool to 0.0.4
2014-03-04 15:32:31 +01:00
Sandro Santilli
93345a19b2 Do not log an error on GET /
Closes #177
2014-03-04 14:26:41 +01:00
Sandro Santilli
1741a20575 Do not cache map creation responses
Closes #176
CDB-1908 #resolve
CDB-1901 #resolve

Includes testcase
2014-03-04 10:46:15 +01:00
Sandro Santilli
30eb939dc7 Fix error message on missing requested signature
We don't really distinguish between missing or non-authorizing
signature. And that's fine. See #170
2014-03-03 18:14:17 +01:00
Sandro Santilli
40a254922a Raise 403 forbidden on missing requested signature
Closes #170
Includes testcase
2014-03-03 18:06:39 +01:00
Sandro Santilli
7bc5bab432 Properly prefix statsd labels for all endpoints
CDB-1861 #resolve
Will be 100% complete with update of Windshaft to 0.19.3+
2014-03-03 16:24:20 +01:00
Sandro Santilli
6034f49f40 Prepare for 1.8.5 2014-03-03 11:45:23 +01:00
Sandro Santilli
087eff4734 Release 1.8.4 2014-03-03 11:26:16 +01:00
Sandro Santilli
ed5b045a15 Allow using NODE_ENV env variable to determine app configuration
Default to "development" environment.
Forward NODE_ENV variable to childrens (for example, to hush
millstone).
2014-02-28 16:22:24 +01:00
Sandro Santilli
c1a3cbc28c Hush millstone during testsuite 2014-02-28 16:14:44 +01:00
Sandro Santilli
bddc65a504 Forbid instanciating templates of foreign users
Closes #173
Includes testcase
2014-02-28 16:05:46 +01:00
Sandro Santilli
ddd2628c19 Fix database connection settings on template instanciation
Closes #174
Enhances testsuite to ensure test.js settings are read
2014-02-28 15:56:31 +01:00
Sandro Santilli
cf0c33a85d Oops, previous commit closed #172, not #173
Closes #172
Reopens #173
2014-02-28 13:25:28 +01:00
Sandro Santilli
f46dc90035 Forbid using map signatures of foreign users
Closes #173
Includes testcase
2014-02-28 13:24:38 +01:00
Sandro Santilli
73276b1003 Upgrade windshaft to 0.19.2
Fixes obscure "ECONNREFUSED" error message (closes #171)
Change some http status responses to be more appropriate to the case
2014-02-28 10:54:18 +01:00
Sandro Santilli
16e67387c9 Tell npm to use known registrars
See http://blog.npmjs.org/post/78085451721/npms-self-signed-certificate-is-no-more
2014-02-28 10:50:45 +01:00
Sandro Santilli
ca1b31bd9c Add example MapConfig using a torque layer 2014-02-27 17:20:23 +01:00
Sandro Santilli
55f333c0b7 Call userByReq() only once in req2params 2014-02-27 16:40:59 +01:00
Sandro Santilli
f24e4f8a0a Really skip CDB_TableMetadata lookup for sql affected by no tables
Closes #169
2014-02-27 15:34:09 +01:00
Sandro Santilli
eec9933fb8 Accept a slightly different error message on timeout
Node 0.10 uses ESOCKETTIMEDOUT while 0.8 uses ETIMEDOUT
See http://travis-ci.org/CartoDB/Windshaft-cartodb/builds/19722727
2014-02-27 13:37:44 +01:00
Sandro Santilli
238e8f39f2 Fix ticket referenc ein NEWS entry of 1.8.3 2014-02-27 12:46:56 +01:00
Sandro Santilli
919bcb6888 Prepare for 1.8.4 2014-02-27 12:46:43 +01:00
Sandro Santilli
50ebb25205 Release 1.8.3 2014-02-27 12:45:02 +01:00
Sandro Santilli
625642ca33 Oops, previous commit closed #168, not #16
Closes #168
2014-02-27 12:43:15 +01:00
Sandro Santilli
36632c762e Do not query CDB_TableMetadata for queries affected by no tables
Closes #16
2014-02-27 12:32:34 +01:00
Sandro Santilli
f284362988 Reduce sql-api communication timeout, and allow overriding it
Introduces new sqlapi.timeout directive, defaults to 100 ms
Includes testcase.
Closes #167
2014-02-27 10:33:32 +01:00
Sandro Santilli
cf01f01bc9 Upgrades windshaft to 0.19.1 with many performance improvements
Among others:

- Improve speed of instanciating a map
- Give meaningful error on attempts to use map tokens with
  attribute service

Closes #156 -- CDB-1796 #resolve
Closes #147
Closes #159
Closes #165
2014-02-26 17:26:17 +01:00
Sandro Santilli
5d0c71d292 Prepare for 1.8.3 2014-02-25 11:10:56 +01:00
Sandro Santilli
b3d3269d3d Release 1.8.2 2014-02-25 10:52:55 +01:00
Sandro Santilli
a13c1f61af Do not log an error for a legit request requiring no X-Cache-Channel 2014-02-24 17:34:00 +01:00
Sandro Santilli
4064b8f254 Add test for lack of X-Cache-Channel in response to root request 2014-02-24 16:24:01 +01:00
Sandro Santilli
5c466c51a8 Revert order of hostname components for statsd.prefix 2014-02-21 17:25:10 +01:00
Sandro Santilli
36628ce78e Also enable the profiler in the example test config
This is again for #157 without closing it
2014-02-21 17:06:29 +01:00
Sandro Santilli
d2d7bba357 Add statsd prefix in test example config
Still doesn't add automated testing (#157) but makes manual
testing easier.
2014-02-21 16:57:02 +01:00
Sandro Santilli
8e68716d16 Give more info on failure 2014-02-21 16:56:50 +01:00
Sandro Santilli
6824c09916 Change example test user and database names
This is to avoid a clash with cartodb test databases
2014-02-20 18:03:43 +01:00
Sandro Santilli
09ea924eb2 Allow using GET with sql-api for queries shorter than configured len
Introduces new sqlapi.max_get_sql_length directive, defaults to 2048.
Closes #155
Includes testcases.
2014-02-20 10:17:48 +01:00
Sandro Santilli
c8a042abdd Expand "addCacheChannel" stats 2014-02-19 18:10:33 +01:00
Sandro Santilli
019540e622 Set example statsd prefix with :host placeholder 2014-02-19 16:16:39 +01:00
Sandro Santilli
9a5243ade3 Fix munin plugin after log format changes
Closes #154
2014-02-19 15:38:14 +01:00
Sandro Santilli
b4fc8ec4a5 Allow using ":host" as part of statsd.prefix
It'll be replaced with hostname.
Closes #153
2014-02-19 15:31:12 +01:00
Sandro Santilli
30a2d85e92 Prepare for 1.8.2 2014-02-19 15:26:43 +01:00
Sandro Santilli
98603594b1 Release 1.8.1 2014-02-19 12:24:43 +01:00
Sandro Santilli
7410d98d56 Require windsahft 0.19.0 final 2014-02-19 11:25:42 +01:00
Sandro Santilli
1f552a9e24 Do not duplicate date in logs (already injected by logger) 2014-02-19 11:16:37 +01:00
Sandro Santilli
6c6f3d02f6 Always generate X-Cache-Channel for token-based tile responses
Closes #152
2014-02-19 10:09:54 +01:00
Sandro Santilli
36a135f02b Refactor addCacheChannel using Step 2014-02-19 07:19:41 +01:00
Sandro Santilli
1c3734fde7 Make server_option a callable function, to reduce globals
Updates acceptance test for #152 to not mess wit internals
2014-02-19 06:45:29 +01:00
Sandro Santilli
3c09be64ce Add pending test for X-Cache-Channel on tiler restart (#152) 2014-02-18 18:33:00 +01:00
Sandro Santilli
719346a472 Use log4js logger
Closes #138.
The logger will be automatically used by Windshaft on upgrade
to 0.18.1, see https://github.com/CartoDB/Windshaft/issues/140
2014-02-18 15:12:08 +01:00
Sandro Santilli
69693acea0 Add statsd prefix in example configs 2014-02-18 10:38:15 +01:00
Sandro Santilli
3873fdf5db Prepare for 1.8.1 2014-02-18 10:38:01 +01:00
Sandro Santilli
c3a05e5041 Set 1.8.0 release date 2014-02-18 10:09:17 +01:00
Sandro Santilli
4c0ab92771 Default to installed mapnik_version during testing
See https://github.com/CartoDB/Windshaft/issues/117
2014-02-18 09:55:00 +01:00
Sandro Santilli
c14378ca5d Avoid checking for table privacy when not using table maps
See #147
2014-02-17 18:20:18 +01:00
Sandro Santilli
26b9c8123d Set maxSocket to allow more than 5 concurrent connections to sql-api 2014-02-17 18:03:11 +01:00
Sandro Santilli
5a504ac1dc Require Windshaft-0.18.2 for statsd-profiler integration 2014-02-17 16:56:44 +01:00
Sandro Santilli
8401dcf6d7 Use /api/v1/map route for unified map api in the examples
Closes #146
2014-02-17 16:29:23 +01:00
Sandro Santilli
1f2e4edd35 Comments cleanup 2014-02-17 11:10:08 +01:00
Sandro Santilli
212eec2ca6 Pass profiler back to windshaft on createLayergroup 2014-02-17 08:50:12 +01:00
Sandro Santilli
935826ed1a Integrate statsd in template instanciation endpoint
NOTE: stats are only enabled using windshaft 0.18.2+
2014-02-15 08:23:43 +01:00
Sandro Santilli
8f3c6c3c87 Add profiler calls in template instanciation endpoint 2014-02-15 08:06:57 +01:00
Sandro Santilli
cd3f8dcf89 Only print layergroupid on template instanciation 2014-02-14 17:33:20 +01:00
Sandro Santilli
9ff192366a Add example mapconfig 2014-02-14 17:24:18 +01:00
Sandro Santilli
63401ca3df Use a single redis client in SignedMap.isAuthorized 2014-02-14 17:07:52 +01:00
Sandro Santilli
8e323a6c07 Remove more commas (see previous commit) 2014-02-14 16:08:32 +01:00
xavijam
d50c6c6dc3 close #144 - removed unnecessary comma 2014-02-14 13:12:52 +01:00
Sandro Santilli
def474c611 Skip getting geometry type if request has no table 2014-02-14 12:26:34 +01:00
Sandro Santilli
c1b2d16119 rename tablePrivacy_getUserDBName profile label 2014-02-14 11:47:43 +01:00
Sandro Santilli
678d653ee9 Allow configuring TTL of mapConfigs via "mapConfigTTL" 2014-02-13 15:44:54 +01:00
Sandro Santilli
4a6af108b4 Fix use of maxUserTemplate configuration variable 2014-02-13 15:01:58 +01:00
Sandro Santilli
e4cd37647e Allow limiting number of allowed user templates
Adds maxUserTemplates directive.
Closes #136
2014-02-13 14:55:31 +01:00
Sandro Santilli
4254f56093 Fix output from list_template to be more readable 2014-02-13 12:56:44 +01:00
Sandro Santilli
f7cef9dcd8 Fix bogus reference in SignedMaps when globals.environment is not set 2014-02-13 10:57:41 +01:00
Sandro Santilli
1c69eb1ae4 Add example template to use with the commandline tools 2014-02-13 10:31:28 +01:00
Sandro Santilli
b673cb2a1f Add more detailed profile info about the "authorize" step
Closes #142
2014-02-13 10:25:28 +01:00
Sandro Santilli
e88e49001a Do not retrive user's api key if no api key was provided
Reduces redis interaction, see #142
2014-02-13 10:16:11 +01:00
Sandro Santilli
6a599ccb5d Add script to list templates 2014-02-13 09:19:19 +01:00
Sandro Santilli
a90bf2e87b Require windshaft 0.18.1 for improve garbage collection 2014-02-13 08:54:47 +01:00
Sandro Santilli
115b1a5267 Add reference to node-0.10 ticket 2014-02-13 08:46:16 +01:00
Sandro Santilli
84e346057e Have travis also build with node-0.10
Closes #141
2014-02-13 08:15:43 +01:00
Sandro Santilli
333de67ed5 Require Windshaft 0.18.0 2014-02-12 22:51:52 +01:00
Sandro Santilli
e4dd215808 Tested with node-0.10.25, works fine 2014-02-12 22:45:00 +01:00
javi
c214e269e9 added statsd to npm-shrinkwrap.json 2014-02-12 16:48:48 +01:00
Sandro Santilli
466eac18a7 Recommend setting "from" for other packages too 2014-02-12 16:23:52 +01:00
Sandro Santilli
6e5d8b2d30 Loosen node-varnish dep 2014-02-12 16:23:12 +01:00
Sandro Santilli
bf45bbea56 Do not send multiple equal commands to Varnish on connect
Closes #135
Also accept varnish "secret" in config
2014-02-12 16:14:27 +01:00
Sandro Santilli
cdbcc7dc18 Put statsd config in all example configs 2014-02-12 16:01:50 +01:00
Sandro Santilli
66e57606d2 Retarget to 1.8.0 for the statsd addition 2014-02-12 16:00:15 +01:00
Sandro Santilli
c7f3bb5722 Target 1.7.2 2014-02-12 15:54:21 +01:00
Sandro Santilli
0e2f921b7e Add flush_cache script. Closes #140 2014-02-12 15:54:21 +01:00
javi
c421ea6bfc added basic statsd cnfiguration options in sample file #139 2014-02-12 15:33:41 +01:00
javi
01feeae6f4 include state configuration for windshaft fixes #139 2014-02-12 15:27:42 +01:00
Sandro Santilli
1ff52fcd00 Add windshaft.from tweak for npm-shrinkwrap.json 2014-02-12 10:51:47 +01:00
Sandro Santilli
6db25c3b6a Release 1.7.1 2014-02-12 10:42:51 +01:00
Sandro Santilli
88deded0fe Workaround npm registry bug by downloading windshaft from github
See the problem here:
https://travis-ci.org/CartoDB/Windshaft-cartodb/builds/18663972
2014-02-11 19:33:05 +01:00
Sandro Santilli
fc0f2b5952 Require windshaft 0.17.2 for further reducing log noise
Closes #137
2014-02-11 17:31:21 +01:00
Sandro Santilli
e211e944e5 Set target version to 1.7.1 2014-02-11 16:37:22 +01:00
Sandro Santilli
a948038ff4 Disable debug logging unless "debug" config param evaluates to true
Closes #137
2014-02-11 16:34:43 +01:00
Sandro Santilli
c70d192987 Release 1.7.0 2014-02-11 15:19:36 +01:00
Sandro Santilli
3fc8630634 Require newer windshaft, regenerated shrinkwrap 2014-02-11 15:19:13 +01:00
Sandro Santilli
8c013ed2d1 Rename Step function in setDBConn 2014-02-11 13:42:44 +01:00
Sandro Santilli
7a749631e8 Fix profiler labels 2014-02-11 13:40:17 +01:00
Sandro Santilli
e3a5f398e4 Add test for instace token changing on template change 2014-02-10 15:48:35 +01:00
Sandro Santilli
747f4803ba Include hash of template in the maptoken returned from instanciation
Doing so basically removes the need to include the template identifier
in the surrogate keys of the responses for resources fetched via
the instance whenever template is updated. See #105
2014-02-10 15:30:35 +01:00
Sandro Santilli
24709e8341 Add acceptance test for use of attributes service from template
Closes #120
2014-02-10 12:31:36 +01:00
Sandro Santilli
53861ad327 Populate test private table 2014-02-10 12:31:00 +01:00
Sandro Santilli
399bed34ad Do not try to replace template variables in undefined elements
See #133
2014-02-10 11:26:21 +01:00
Sandro Santilli
6b41fef96c Fix sendError calls to receive the full Error instance 2014-02-10 11:11:35 +01:00
Sandro Santilli
031e2a2e0c Add test for missing cartocss from mapnik layer on layergroup post
See #133
2014-02-10 11:05:02 +01:00
Sandro Santilli
9b4787c4b7 Reword in bug fixes NEWS entries 2014-02-07 18:10:45 +01:00
Sandro Santilli
fe6e915c0d Always set database access parameters from req2params
Fixes privileged database access from unauthorized users while
fetching torque tiles or feature attributes (unreleased feature).
Closes #132.

Includes testcase, which closes #119
2014-02-07 18:08:41 +01:00
javi
b5d67ec6c0 updated news for #130 2014-02-06 17:46:39 +01:00
javi
f5e0d06e2f fixed when default value in a template attribute is a number and type = number checking fails fixed #130 2014-02-06 17:45:48 +01:00
javi
78f69d5236 template variables with spaces are not replaced correctly fixed #129 2014-02-06 17:33:26 +01:00
Sandro Santilli
ab7d603171 Drop unified.js acceptance test.
Does not really make sense now that endpoints are configurable.
See #126 and #127
2014-02-06 12:58:10 +01:00
Sandro Santilli
b4936ffafa Do not allow creating template with auth='token' and no valid tokens
Closes #128
Includes acceptance test for both creation and update
2014-02-06 12:24:14 +01:00
Sandro Santilli
752e9ec655 Add checkInvalidCertificate method for SignedMap class
Includes unit test
2014-02-06 12:05:01 +01:00
Sandro Santilli
9018e39762 Make endpoints configurable
Closes #127
Uses /api/v1/maps* in the production and staging example configs,
keeps /maps* for development and test (they are examples...)
2014-02-05 15:14:47 +01:00
Sandro Santilli
a964ed5fe6 Implement Unified Map API
Closes #126
2014-02-04 19:04:59 +01:00
Sandro Santilli
b862904506 Be explicit about the map output srid configuration 2014-02-04 16:26:26 +01:00
javi
7197cc2d62 added stack to response in development mode 2014-02-04 14:58:21 +01:00
Sandro Santilli
b01570924d Add support for torque tiles and attributes fetching
Retargets self to 1.7.0
Upgrades Windshaft to 0.16.0

Closes #118 -- CDB-1525 #resolve
Closes #112 -- CDB-1329 #resolve
2014-02-04 13:30:59 +01:00
Sandro Santilli
db478579c5 Fix example development configuration to avoid use of empty sqlapi.domain
This is because as of CartoDB-SQL-API-1.8.2 the "user_from_host"
default configuration for "development" environment is:

  '^(.*)\\.localhost'

Which would not match a domain-less hostname

Closes #117 for real now.
2014-01-30 16:56:23 +01:00
Sandro Santilli
978ea9cd04 Fix sqlapi request header to be "Host", not "Hostname"
Closes (better) #117 -- automated test included
2014-01-30 16:46:26 +01:00
Sandro Santilli
ca4f3d2025 Re-introduce sqlapi.host directive, allowing DNS lookups drop
For backward compatibility, sqlapi.host is only used if domain
is also defined and has a different value (empty string allowed).

Closes #117
2014-01-30 16:12:37 +01:00
Sandro Santilli
c0020fd75a Release 1.6.3 2014-01-30 12:44:25 +01:00
Sandro Santilli
add4255bdc Update windshaft to 0.15.1, fixing maxzoom in layergroup
Regenerates shrinkwrap, which includes other minor updates
in dependency modules.
2014-01-30 12:42:11 +01:00
Sandro Santilli
1f0faba71c Stop processing XML on renderer creation
Not needed anymore since 1.6.1 introduced on-demand XML generation.
2014-01-30 11:14:52 +01:00
Sandro Santilli
e3f2658d53 Port show_style to node (really needed now) 2014-01-29 16:01:27 +01:00
Sandro Santilli
f7cdb5f0b7 Typo 2014-01-29 15:14:47 +01:00
Sandro Santilli
d32278b227 Rename template instanciation function 2014-01-29 14:30:27 +01:00
Sandro Santilli
76acc5af99 Indent and other minor tweaks 2014-01-29 13:34:22 +01:00
javi
5755e382fb Merge branch 'master' of github.com:Vizzuality/Windshaft-cartodb 2014-01-29 13:12:40 +01:00
javi
95c450fe99 update NEWS for #116 2014-01-29 13:12:19 +01:00
javi
ad0b2ffc8e added support for template instanciation with jsonp closes #116 2014-01-29 13:11:37 +01:00
Sandro Santilli
1b1b6b975e Add test for malformed CartoCSS error (#115)
The test is disabled for it's failing, it isn't yet decided if
the regression has to be fixed or not.
2014-01-29 10:40:35 +01:00
Sandro Santilli
67e4e7e99b Set api_key to signer's when instanciating a template map
Closes #114
2014-01-28 12:37:41 +01:00
javi
ac31c69c80 added spec to test instanciation of open templated maps without api_key 2014-01-28 12:12:33 +01:00
javi
92ca447c06 fixed #91 2014-01-28 12:05:01 +01:00
javi
bdea9f10fc fixed sqlemu to return forbidden when table name contains "private" in its name 2014-01-28 12:04:10 +01:00
Sandro Santilli
dc3d36e0a5 Prepare for 1.6.3 2014-01-23 12:27:39 +01:00
Sandro Santilli
99ef396aeb Release 1.6.2 2014-01-23 12:25:34 +01:00
javi
69d7fb0344 fixed news #113 2014-01-22 19:12:17 +01:00
javi
e4e08db0b4 Merge branch 'master' of github.com:Vizzuality/Windshaft-cartodb 2014-01-22 19:10:37 +01:00
javi
164d952e56 support CORS in template instanciation endpoint, fixes #113 2014-01-22 19:10:09 +01:00
Sandro Santilli
c711dc328e Fix XML print from in show_style for token styles (#110) 2014-01-17 17:47:37 +01:00
Sandro Santilli
8b80ad8ba1 Restore XML print from the show_style tool
Closes #110
2014-01-16 18:51:02 +01:00
Sandro Santilli
5772c81590 Fix support for long (>64k chars) queries in layergroup creation
Closes #111. Includes testcase.
2014-01-16 17:20:30 +01:00
Sandro Santilli
09d4467e22 Prepare for 1.6.2 2014-01-16 17:19:55 +01:00
Sandro Santilli
d22f399f18 Release 1.6.1 2014-01-15 19:23:20 +01:00
Sandro Santilli
f89fd98ed7 Expect malformed response objects (#109)
Include test for sql errors on layergroup creation
Closes #109
2014-01-15 11:53:19 +01:00
Sandro Santilli
b01ce9d4cc Regenerate shrinkwrap for 1.6.1 2014-01-14 18:09:36 +01:00
Sandro Santilli
18ccd3cbaf Localize external CartoCSS resources at renderer creation time
Closes #108. JIRA CDB-1422 #resolve
2014-01-14 16:20:06 +01:00
Sandro Santilli
d6fe5339cf Do not choke on headers cleanup when response headers are not set
Raise a WARNING instead.
See #107 (github) and CDB-1438 (JIRA)
2014-01-13 18:56:09 +01:00
Sandro Santilli
2690ef3f05 Drop cache headers from error responses.
Closes #107 (github), #resolve CDB-1423 (JIRA)
2014-01-13 11:20:02 +01:00
Sandro Santilli
ae82d0ab47 Expect overrides of mapnik_version to be honoured
Reported on http://gis.stackexchange.com/questions/81450/cartodb-windshaft-error
2014-01-10 13:20:26 +01:00
Sandro Santilli
90e0a5dc30 Prepare for 1.6.1 2014-01-10 11:32:03 +01:00
Sandro Santilli
c1b6b865a7 Release 1.6.0 2014-01-10 11:30:10 +01:00
Sandro Santilli
d849ae216d Keep build status line within 80 cols (and use http) 2014-01-09 18:01:22 +01:00
Sandro Santilli
4ee4492490 Yet another username extraction fix. Thanks again @demimismo.
Closes #100 (yet again)
2014-01-09 16:46:47 +01:00
Sandro Santilli
fcd17692ee Fix username extraction in another two places. Thanks @demimismo.
Closes #100 (again)
2014-01-09 15:36:16 +01:00
Sandro Santilli
36159a7697 Change stresstester to always create a different template 2013-12-20 13:47:28 +01:00
Sandro Santilli
7886189bce Add script to stress-test templates API 2013-12-20 13:14:52 +01:00
Sandro Santilli
3a681b6670 Exit with error if template creation response text contains a space
Should really check for response code, but dunno how to do that
right away
2013-12-20 13:11:32 +01:00
Sandro Santilli
3e4c141913 Add command-line script to delete a template 2013-12-20 12:55:01 +01:00
Sandro Santilli
ef3733aebe Improve error on attempt to delete missing template 2013-12-20 12:54:38 +01:00
Sandro Santilli
b5f54ff534 Rename script to create multilayer 2013-12-20 10:44:11 +01:00
Sandro Santilli
ba494374d0 Add command-line script to instanciate a template 2013-12-20 10:43:48 +01:00
Sandro Santilli
c7465479a2 Improve error on a signature certificate with no or broken auth 2013-12-20 10:41:27 +01:00
Sandro Santilli
b14830e4e3 Add command-line script to update a template 2013-12-20 10:17:31 +01:00
Sandro Santilli
288f23eea2 Add script for command-line template creation 2013-12-20 10:15:18 +01:00
Sandro Santilli
50a902a90b Fix english of error message for sql-api connection problems 2013-12-18 12:59:26 +01:00
Sandro Santilli
277c00c7f8 Advertise `infowindow and map_metadata` as deprecated APIs 2013-12-18 12:54:40 +01:00
Sandro Santilli
4a09ac5b8f Add reference to template maps API extention 2013-12-18 12:54:09 +01:00
Sandro Santilli
d5e9e0559b Add info about Imagemagick requirement for running tests 2013-12-18 12:53:22 +01:00
Sandro Santilli
0dffb0fe85 We don't use Windshaft directly, no need to require it 2013-12-17 17:48:36 +01:00
Sandro Santilli
0f90d687c7 Implement signed teplate maps
Closes #98

Raises minimum required redis version to 2.4.0+ (Debian stable has 2.4.14)
2013-12-17 17:39:21 +01:00
Sandro Santilli
84b7d78ea4 Add an utility authorizedByAPIKey method for reuse 2013-12-17 17:17:17 +01:00
Sandro Santilli
241480bb23 cartodb-redis is upgraded to 0.3.0 2013-12-17 17:17:17 +01:00
Sandro Santilli
73a065c1cc Make sure user from domain is always computed locally
Involved upgrade of cartodb-redis to 0.3.0
Really closes #100
2013-12-17 17:17:17 +01:00
Sandro Santilli
1f693c6c78 Add 'user_from_host' directive to generalize username extraction
Closes #100
Default extractor is backward compatible
2013-12-17 17:17:17 +01:00
Sandro Santilli
e9db535dd8 Drop the idea that we can distinguish a "dbowner" from the domain
We only recognize "users"
2013-12-17 17:17:17 +01:00
Sandro Santilli
7b7408dab7 Revert "Drop /map_metadata API entry point"
This reverts commit b37b07a06a1dd3cf05d60f4aa613ab5c48b90700.

This was too light of a decision...
2013-12-17 17:17:17 +01:00
Sandro Santilli
9c897a91a9 Drop /map_metadata API entry point
Closes #101
2013-12-17 17:17:17 +01:00
Sandro Santilli
4189f8187f Simplify redis test setup using HMSET
See http://redis.io/commands/hmset
2013-12-17 17:17:16 +01:00
Sandro Santilli
98565b0c6b Shrinkwrap cartodb-redis dependency to "~0.2.0"
npm-shrinkwrap takes precedence over package.json...
See https://travis-ci.org/CartoDB/Windshaft-cartodb/builds/15036101
2013-12-17 17:17:16 +01:00
Sandro Santilli
38342a7f5f Refactor req2params to make setting db credential easier 2013-12-17 17:17:16 +01:00
Sandro Santilli
6f689745c0 Fix lzma testcase 2013-12-17 17:17:16 +01:00
Sandro Santilli
63fd660eb1 Fix error handling in testcase 2013-12-17 17:17:16 +01:00
Sandro Santilli
fa14b6045d Retarget to 1.6.0 2013-12-17 17:17:16 +01:00
Sandro Santilli
f2528fb462 Release 1.5.2 2013-12-17 17:17:16 +01:00
Sandro Santilli
0db0809146 Fix use of old layergroups on mapnik upgrade (#97) 2013-12-17 17:17:16 +01:00
Sandro Santilli
276422f4be Set grainstore's GC run probability, for documentation purpose
It sets it to the current grainstore default, so nothing changes.
2013-12-17 17:17:16 +01:00
Sandro Santilli
e6b55ac034 Allow requesting run_test.sh to prepare redis but not postgresql
Adds --nocreate-pg, --nocreate-redis, --nodrop-pg, --nodrop-redis
NOTE that dropping pg is still unimplemented
2013-12-17 17:17:16 +01:00
Sandro Santilli
58af35fdea Add backward-compatibility fix item in NEWS (#96) 2013-12-17 17:17:16 +01:00
Sandro Santilli
763989bc87 Prepare for 1.5.2 2013-12-17 17:17:16 +01:00
Sandro Santilli
385022de80 Revert "fixed #91" -- the fix was for an unconfirmed bug
This reverts commit 9155724082.
See #38 for further action
2013-12-17 17:17:16 +01:00
Sandro Santilli
6c104e2aca Enable test for fetcing tiles of private tables using api_key
See #39 and #91
2013-12-17 17:17:16 +01:00
Sandro Santilli
363c0d28f4 Add test for fetching tile of private table showing api_key
See #38 and #91
2013-12-17 17:17:16 +01:00
javi
a378fc4e68 fixed #91 2013-12-17 17:17:16 +01:00
javi
01de288c35 fixed #96 2013-12-17 17:17:15 +01:00
Sandro Santilli
f1a68e4451 Release 1.5.1 2013-12-17 17:17:15 +01:00
Sandro Santilli
f429b86f48 Accept unused CartoCSS directives
Closes #93

An example unused CartoCSS directive is
"point-transform" without "point-file"
or "point-url". Unused means it has no effect.

It used to be accepted but regressed in release 1.5.0
2013-12-17 17:17:15 +01:00
Sandro Santilli
ccfdacff5b Fix test for invalid font usage after Windshaft update (#90)
NOTE: the error is less friendly now, see
      http://github.com/mapbox/carto/issues/242
2013-12-17 17:17:15 +01:00
Sandro Santilli
a9d9b765e8 Survive presence of malformed CartoCSS in redis
Closes #94, enable relative testcase
2013-12-17 17:17:15 +01:00
Sandro Santilli
5298f4b517 Add package keywords 2013-12-17 17:17:15 +01:00
Sandro Santilli
53d03e82ab Set test redis port to 6335 2013-12-17 17:17:15 +01:00
Sandro Santilli
2fa288fc4d Add (pending) test for getting unrenderable stored styles (#94)
Required upgrading mocha tester to ~0.14.0
2013-12-17 17:17:15 +01:00
Sandro Santilli
73819579f3 Notify travis builds on #cartodb @ freenode.irc 2013-12-17 17:17:15 +01:00
Sandro Santilli
271ff4faeb Use a variable to hold the name of test database 2013-12-17 17:17:15 +01:00
Sandro Santilli
c04ac4fc7e Reduce ppa and explicit package usage
Should fix travis builds despite package compatibilit bugs
(https://travis-ci.org/CartoDB/Windshaft-cartodb/builds/14314805)
2013-12-17 17:17:15 +01:00
Sandro Santilli
5a87a16311 Add note about new directives in the 1.5.0 section 2013-12-17 17:17:15 +01:00
Sandro Santilli
dd48aa73e2 Improve documentation for postgres_auth_* configuration directives 2013-12-17 17:17:15 +01:00
Sandro Santilli
6dd046a1a4 Prepare for 1.5.1 2013-12-17 17:17:15 +01:00
Sandro Santilli
baaacbed31 Release 1.5.0 2013-12-17 17:17:15 +01:00
Sandro Santilli
0b3fdb07f6 Drop unneeded include from outermost app 2013-12-17 17:17:15 +01:00
Sandro Santilli
cc09a8b66f Update to cartodb-redis 0.1.0 2013-12-17 17:17:15 +01:00
Sandro Santilli
a60a3adc12 CartoDB redis interaction delegated to "cartodb-redis" module 2013-12-17 17:17:14 +01:00
Sandro Santilli
e412a0f4b6 Require windshaft-0.14.3 to get 3 new bugfixes:
- Return CORS headers when creating layergroups via GET
 - Fix http status on database authentication error
 - Ensure bogus text-face-name error raises at layergroup creation
2013-12-17 17:17:14 +01:00
Sandro Santilli
ed23d10364 Remember per-environment ./configure parameters
This is to avoid breaking test.js configuration while switching
between branches.
2013-12-17 17:17:14 +01:00
Sandro Santilli
4c95af2c69 Fix ticket reference 2013-12-17 17:17:14 +01:00
Sandro Santilli
baa95a62d1 Add support for reading user-specific database_password from redis
This commits adds support for CartoDB-2.5.0 model.
Closes #89.
Change is backward compatible.
2013-12-17 17:17:14 +01:00
Sandro Santilli
c7494c3c73 Avoid caches during test for user-specific database_host 2013-12-17 17:17:14 +01:00
Sandro Santilli
12f0826d32 Do not force ending dot in SQL-API hostname, for easier testing 2013-12-17 17:17:14 +01:00
Sandro Santilli
428e8631e2 Improve tests robustness on failure 2013-12-17 17:17:14 +01:00
Sandro Santilli
d3e3cfa385 Add NEWS item about CartoDB-2.5.0+ user-specific database_host (#88) 2013-12-17 17:17:14 +01:00
Sandro Santilli
3120d56e80 Add test for redis-specifid database_host. Closes #88 2013-12-17 17:17:14 +01:00
Sandro Santilli
07cb36ebc7 Read user's database_host from redis, when available (#88)
Still lacks a testcase
2013-12-17 17:17:14 +01:00
Sandro Santilli
d7c82e7a51 Indent fixes 2013-12-17 17:17:14 +01:00
Sandro Santilli
bf340e684a Tweak error messages on missing redis variables, update tests 2013-12-17 17:17:14 +01:00
Luis Bosque
8d1b394df1 Add function to read database host from redis 2013-12-17 17:17:14 +01:00
Sandro Santilli
d305dbd468 Style only change 2013-12-17 17:17:13 +01:00
Sandro Santilli
eb51d18012 Add support for specifying database connection passwords 2013-12-17 17:17:13 +01:00
Sandro Santilli
4f3f87fc13 Release 1.14.1 2013-12-17 17:17:12 +01:00
Sandro Santilli
3e6070bd9b Fix support for exponential notation in CartoCSS filter values
Closes #87.
Includes testcase
2013-12-17 17:17:12 +01:00
Sandro Santilli
0daba348fe Prepare for 1.4.1 2013-12-17 17:17:12 +01:00
Sandro Santilli
f874e8844c Add Support for Mapnik-2.2.0. Closes #78. 2013-12-17 17:17:12 +01:00
Sandro Santilli
a8fef04455 Prepare for mapnik-2.2.0 support (#78)
- Tolerate change in CartoCSS error message between 0.9.3 and 0.9.5
- Expect default style to be different for mapnik-2.2.0+ target
2013-12-17 17:17:12 +01:00
Sandro Santilli
2f74a080ee Prepare for 1.3.7 2013-12-17 17:17:12 +01:00
Sandro Santilli
198748feea Release 1.3.6, fixing support for node-0.8.9 2013-12-17 17:17:12 +01:00
Sandro Santilli
9f73be0d5c Prepare for 1.3.6 2013-12-17 17:17:12 +01:00
Sandro Santilli
8aea5041c7 Release 1.3.5 2013-12-17 17:17:12 +01:00
Sandro Santilli
1856b824cb Fix support for apostrophes in CartoCSS
Requires windshaft 0.13.7
Jira ref CDB-414
2013-12-17 17:17:12 +01:00
Sandro Santilli
a27cf1b41c Do not let anonymous requests use authorized renderer caches
Puts dbuser in params, for correct use by Windshaft renderer cache.
Before this fix, and after commit 1c9f63c9, the renderer cache key
did not contain the db user.
2013-12-17 17:17:12 +01:00
Sandro Santilli
b610b9aca2 tweak test description 2013-12-17 17:17:12 +01:00
Sandro Santilli
f5c24cf252 Add more profile slots 2013-12-17 17:17:11 +01:00
Sandro Santilli
8303068310 Remove spaces from configuration input, to make editing easier :) 2013-12-17 17:17:11 +01:00
Sandro Santilli
c17fd3b254 Make testsuite accept an installed mapnik version 2.1.0
See https://travis-ci.org/CartoDB/Windshaft-cartodb/builds/11286823
2013-12-17 17:17:11 +01:00
Sandro Santilli
d82838a137 Add travis widget, fix documented node dependency 2013-12-17 17:17:11 +01:00
Sandro Santilli
4506a9e905 Add travis configuration 2013-12-17 17:17:11 +01:00
Sandro Santilli
b4580943e8 Read test redis port configuration from test.js env 2013-12-17 17:17:11 +01:00
Sandro Santilli
730f9534dc Clean handling of redis connection failures in testcase 2013-12-17 17:17:11 +01:00
Sandro Santilli
a7cc7ceeb8 Fix error for invalid text-name in CartoCSS. Closes #81. 2013-12-17 17:17:11 +01:00
Sandro Santilli
7861852078 Add backward compatibility sqlapi configuration item in NEWS 2013-12-17 17:17:11 +01:00
Sandro Santilli
dbf6bb5fca Only use sqlapi configuration "host" if "domain" is undefined
We'll consider an empty string domain as valid (it's actually used
for testsuite).
2013-12-17 17:17:11 +01:00
Javier Arce
d4d5272bf2 Sets the sqlapi domain. Fixes #82 2013-12-17 17:17:11 +01:00
Sandro Santilli
0c4bcca7c9 Read redis port from test.js environment when running tests 2013-12-17 17:17:11 +01:00
Sandro Santilli
0414307679 Fix use of blank-prefixed "zoom" variable in CartoCSS 2013-12-17 17:17:11 +01:00
Luis Bosque
0f3a5501d4 Target v1.3.5 2013-12-17 17:17:11 +01:00
Luis Bosque
9d4ce3f070 Merge branch 'release/staging' 2013-09-06 13:54:04 +02:00
Sandro Santilli
17fc934aa3 Fix check-submodules rule not to fail if a submodule is missing 2013-09-04 18:19:09 +02:00
Sandro Santilli
27eaad932a Fix race condition in localization of external resources 2013-09-04 17:56:17 +02:00
Sandro Santilli
602b255ce5 Upgrade to latest windshaft for more stable test results 2013-09-03 18:15:37 +02:00
Sandro Santilli
efc6d5c857 Fix config/environments/test.js Makefile rule 2013-08-21 10:50:49 +02:00
Sandro Santilli
633e8d164b Rename sqlapi.host configuration to sqlapi.domain. Closes #79.
Support for "host" is retained for backward compatibility.
2013-08-21 10:11:30 +02:00
Sandro Santilli
db951234aa Add note about cache dir need to be writable by server user
As per
https://groups.google.com/d/msg/cartodb/z06r9SwaoOM/b34In4TTdd0J
2013-08-21 10:04:43 +02:00
Sandro Santilli
60617e7641 Upgrade windshaft to improve CSS error messages 2013-08-13 13:03:24 +02:00
Luis Bosque
7b43a0f0bd Merge branch 'release/staging' 2013-07-24 13:33:22 +02:00
Luis Bosque
06e68c1518 Target v1.3.4 2013-07-23 19:43:32 +02:00
Sandro Santilli
b4045353ea Fix contributors, use short form for author 2013-07-19 12:34:20 +02:00
Sandro Santilli
22130f37df Fix URLS and repository, add contributors, change author
Author became Vizzuality and contributors are the actual committers
2013-07-19 12:28:03 +02:00
Sandro Santilli
bce024961f Add note about layergroup logging at creation
The change is due to Windshaft upgrade.
Closes #76
2013-07-18 11:51:00 +02:00
Sandro Santilli
3819d0d47b Upgrade windshaft to improve profiling 2013-07-18 11:13:41 +02:00
Sandro Santilli
7cb69d1db9 Add example of including profile in response log line 2013-07-18 09:53:59 +02:00
Sandro Santilli
ec97381820 Add more timing in the profile, add useProfiler config variable
Default to useProfiler:true in staging and development
2013-07-16 16:33:03 +02:00
Sandro Santilli
25c46962cb Add --environment switch to restrict output to given env 2013-07-15 13:59:55 +02:00
Sandro Santilli
23da8538a6 Add --with-sqlapi-port switch 2013-07-15 13:55:13 +02:00
Sandro Santilli
381b9a9edf Take cache_buster value, if present, as a Last-Modified timestamp
This makes the Last-Modified header consistent across requests
using the same cache_buster (embedded in the token for multilayer
API).
2013-07-15 13:48:06 +02:00
Sandro Santilli
76c056c7a1 Revert "Use a constant Last-Modified time with cache_policy=persist"
This reverts commit 4b5899ff1a.

The reason is that setting Last-Modified to a remote date in the past
triggers early expiration of cache (as max-age will be reached sooner)
2013-07-15 13:14:06 +02:00
Sandro Santilli
4b5899ff1a Use a constant Last-Modified time with cache_policy=persist
After all if the client is asking for persistance it doesn't make
sense to set a different Last-Modified for different incoming
requests (even if we don't expect any) ....
2013-07-15 12:09:13 +02:00
Sandro Santilli
afd4c3b460 Set Last-Modified header to allow for 304 responses 2013-07-15 12:02:54 +02:00
Luis Bosque
8b7cc64567 Merge branch 'release/staging' 2013-07-09 16:08:07 +02:00
Luis Bosque
308246f324 Target v1.3.3 2013-07-09 10:26:43 +02:00
Luis Bosque
b0b40933d8 Merge branch 'release/staging' 2013-07-09 10:25:50 +02:00
Sandro Santilli
0e13228f5c Update NEWS file 2013-07-08 12:15:01 +02:00
Sandro Santilli
65c7c5fc9c Always serve multilayer tiles and grids with persisting cache request 2013-07-08 12:13:45 +02:00
Sandro Santilli
60242c80f4 Set default layergroup time to live in redis to 2 hours 2013-07-08 11:50:19 +02:00
Luis Bosque
5213216fc4 Target v1.3.2 2013-07-05 15:32:47 +02:00
Sandro Santilli
1c65cec6ed Do not consider broken layergroup configs as good on second look
The fix is really in Windshaft, this commit simply requires a
newer version of it.
2013-07-04 17:05:59 +02:00
Sandro Santilli
316c9c209d Add support for specifying tiler url 2013-07-04 12:50:57 +02:00
Sandro Santilli
563764dc4f Only make curl verbose when -v is passed to commandline 2013-07-04 11:15:21 +02:00
Sandro Santilli
8c51c97102 Be more verbose about curl errors 2013-07-04 11:04:12 +02:00
Sandro Santilli
6416af3f16 Add support for listing all map styles that belong to a user
Also report user database name, as a facility
2013-07-03 09:59:42 +02:00
Sandro Santilli
00c18ab8dd Raise windshaft dependency importing following fixes:
- support for CartoCSS attachments (#layer0::label)
 - only check layergroup validity once
 - use higher zoom level for checking layergroup validity
2013-06-28 19:05:39 +02:00
Sandro Santilli
632d75a7c8 specify units for rendererConfig.cache_ttl 2013-06-28 17:58:11 +02:00
Sandro Santilli
d7b1ff9a80 Set default layergroup ttl locally 2013-06-26 16:26:02 +02:00
Sandro Santilli
10a66fbd66 Fix SQL error reporting to NOT split on newline 2013-06-26 13:26:53 +02:00
Sandro Santilli
4b1d6cd729 Add tile and grid fetching checks at layergroup creation time
Basically requires windshaft 0.12.6, which implements this
2013-06-21 12:46:13 +02:00
Sandro Santilli
e984811eae Fix SQL bug in testcase 2013-06-19 17:24:01 +02:00
Sandro Santilli
eb83851bb7 Fix database authentication with multi-table layergroups 2013-06-17 17:24:09 +02:00
Sandro Santilli
850d4cd6ba Drop unused cluster support 2013-06-17 11:57:35 +02:00
Sandro Santilli
6cb8c85da0 Only return token by default and full response on request (-v) 2013-06-13 10:43:09 +02:00
Sandro Santilli
3d4af14315 Fix deadlock on layergroup post
Required upgrading windshaft to 0.12.5.
Took the chance to also upgrade redis dependency to latest stable.
2013-06-12 18:42:10 +02:00
Sandro Santilli
c07616f889 Run silently, prepare for using against windshaft direct 2013-06-12 18:30:32 +02:00
Sandro Santilli
d53327bc33 Utility to fetch a token from a layergroup config
It's in its infancy, still need to edit the script to use against
remote service or non-standard local deploys
2013-06-11 17:15:02 +02:00
David Arango
f20c98e49c Merge branch 'release/staging' 2013-06-11 14:41:12 +02:00
Luis Bosque
9807a5e12b Target v1.3.1 2013-06-11 10:53:07 +02:00
Sandro Santilli
70f535d13a Properly report error from unsuccessful source table fetching
Report terse error to user, verbose to log
2013-06-11 10:28:05 +02:00
Sandro Santilli
8d326dba2f Add test for CartoCSS error reporting on POST to layergroup 2013-06-10 11:53:28 +02:00
Sandro Santilli
8d0da4d517 Require latest grainstore and windshaft, for multilayer css fixes 2013-06-06 15:45:33 +02:00
Sandro Santilli
63296a87cb Do not increment undefined mapview stat tags 2013-06-06 13:26:59 +02:00
Sandro Santilli
b67a487c48 Fix path to grainstore module 2013-06-06 11:59:11 +02:00
Sandro Santilli
d977f83bd1 Change stats format for multilayer map token request
See https://github.com/Vizzuality/Windshaft-cartodb/wiki/Redis-stats-format

Target 1.3.0
2013-06-04 13:30:28 +02:00
Sandro Santilli
5b6919e0c6 Fix unit of measure for lastUpdated info extraction 2013-05-30 16:48:40 +02:00
Luis Bosque
92a3d52885 Merge branch 'release/staging' into develop 2013-05-30 11:18:57 +02:00
Luis Bosque
627b3f084d Merge branch 'release/staging' 2013-05-30 11:18:36 +02:00
Sandro Santilli
3763232c14 Require latest windshaft to fix confusion between colors and layer names 2013-05-29 19:14:45 +02:00
Sandro Santilli
3e4f98cb51 Require higher Windshaft to fix handling of CartoCSS layer name 2013-05-29 11:43:27 +02:00
Luis Bosque
977d051518 Target v1.2.2 2013-05-28 12:40:20 +02:00
Sandro Santilli
d7ae28095f Require Windshaft-0.12.1 to fix multilayer post from firefox 2013-05-21 14:43:00 +02:00
Luis Bosque
b98a32c296 Merge branch 'release/staging' 2013-05-20 14:41:41 +02:00
Sandro Santilli
5ab4caea7d Make test for LZMA more robust in case of failure 2013-05-16 09:41:38 +02:00
Luis Bosque
9ce88bcc98 Target v1.2.1 2013-04-29 15:38:36 +02:00
Luis Bosque
94ddbf69d8 Target v1.2.0 in package.json 2013-04-29 15:36:54 +02:00
javi
c9e3cc00be merged with develop 2013-04-24 15:16:20 +02:00
javi
efa79b243c fixed lzma decoding to fix browser requirements 2013-04-24 15:10:58 +02:00
Sandro Santilli
06f781334d Drop unused variable 2013-04-24 12:01:32 +02:00
Sandro Santilli
f0fc44aac9 Fix fetching of affected tables when mapnik tokens are used
We'll replace !bbox! with an empty box and !pixel_width! and
!pixel_height! with 1 before passing the query to CDB_QueryTable
2013-04-23 17:29:49 +02:00
Fabio Rueda
b678f82be8 Merge branch 'release/staging' 2013-04-17 16:17:02 +02:00
Sandro Santilli
44a8db03e2 Add node-varnish to the list of submodules tested by check-full 2013-04-15 09:33:41 +02:00
Sandro Santilli
4a12ed1f19 Oops, forgot to drop --nodrop switch after unifying local tests 2013-04-15 09:32:32 +02:00
Sandro Santilli
de24e7fc34 Update to new LZMA to fix global variable leakage
Stop ignoring leaks during testing
2013-04-15 09:22:50 +02:00
Sandro Santilli
1b6a662a72 Tweak PATH during submodule check, to find mocha from subdirs 2013-04-15 09:20:51 +02:00
Sandro Santilli
6f8fd69101 Add note about the stats addition 2013-04-12 17:57:57 +02:00
Sandro Santilli
78a6f4de1b Keep a counter of layergroup created per user.
The counter is in redis db 5, in a field "mapviews" of an hash
"tiler:users:USERNAME". It's incremented whenever the layergroup
token for a configuration is requested.
2013-04-12 17:28:34 +02:00
Sandro Santilli
afb875c32a Add missing fixtures (thanks Fabio) 2013-04-12 14:34:45 +02:00
Sandro Santilli
369b0f6110 Ignore variable leaks exposed by server.js test (due to LZMA mod)
This will have to be fixed once LZMA module is updated.
See https://github.com/nmrugg/LZMA-JS/issues/8

With this change "make check-full" completes successfully for me.
Looking forward to Jenkins experience.
2013-04-12 11:52:09 +02:00
Sandro Santilli
1c910ec513 Insert test data in a single statement 2013-04-11 18:33:51 +02:00
Sandro Santilli
08d1d73b4f Fix "make check" to exit with FAILURE on failure
Also upgrade Windshaft for the same purpose (for make check-full)
2013-04-11 18:31:01 +02:00
Sandro Santilli
83e6e0d457 More verbose logging for SQL api connection errors 2013-04-09 18:07:53 +02:00
Sandro Santilli
e5af3b90f4 Revert "Require interactivity param in single-layer grid fetching request"
This reverts commit 3383c44eb7.

Fixes regression with default interactivity parameter.
Closes #74. See #69.
2013-04-05 18:11:36 +02:00
Luis Bosque
7c82498f8f Merge branch 'release/staging' into develop 2013-04-04 14:23:39 +02:00
Luis Bosque
9162d2cd43 Merge branch 'release/staging' 2013-04-04 14:22:47 +02:00
Sandro Santilli
a0b6f467b1 HOTFIX: require windshaft-0.11.1 to drop tilelive internal cache 2013-04-03 11:10:09 +02:00
Luis Bosque
782edd9506 Target v1.1.10 2013-04-02 14:02:00 +02:00
Sandro Santilli
7ed4320493 Merge branch 'develop-multilayer2' into develop
Target 1.1.9
2013-04-02 13:49:22 +02:00
Sandro Santilli
113b70cf98 Add support for creating layergroups via GET 2013-04-02 13:30:49 +02:00
Sandro Santilli
106e95940d Revert backward incompatible changes in multilayer handling 2013-04-02 12:24:03 +02:00
Luis Bosque
4329ffd61a Target v1.2.1 2013-04-02 11:42:21 +02:00
Sandro Santilli
3383c44eb7 Require interactivity param in single-layer grid fetching request
Closes #69
2013-03-29 18:25:28 +01:00
Sandro Santilli
aea107f1af Upgrade Windshaft to 0.10.0, changing multilayer interface
WARNING: starting from this commit the grid fetching route changed
         to NOT include layer name nor interactivity (which is now
         specified solely as part of layergroup configuration)

Target 1.2.0 release
2013-03-29 16:37:37 +01:00
Sandro Santilli
2b2c22cdd5 Add test showing use of mapnik subtitution tokens in multilayer config 2013-03-28 12:48:00 +01:00
Sandro Santilli
001bf97d69 Add support for LZMA compressed GET parameters
You can now replace the whole query string with a single `lzma`
parameter having as value an hex encoded LZMA compressed version
of the whole query string as a JSON object.
2013-03-22 18:55:59 +01:00
Sandro Santilli
2da8c44914 Fix support for ampersend characters in CartoCSS
Required upgrading grainstore dependency to 0.12.2
2013-03-22 12:42:38 +01:00
javi
e53122de7e fixed last_update in laytergroup response 2013-03-21 11:39:55 +01:00
Sandro Santilli
4e7f92c60d Write a deprecation warning when handling SIGUSR1 (#71) 2013-03-18 18:14:18 +01:00
Sandro Santilli
d95ac85b17 Deprecate USR1 signal handling, add USR2 with same semantic
Closes #71
2013-03-18 16:38:50 +01:00
Sandro Santilli
3ff3dc2c97 Cleanup, handle error in req2param on flushCache 2013-03-15 19:25:13 +01:00
Sandro Santilli
4605bd1e1d Add last_modified field to POST layergroup response (#72)
Includes testcases
2013-03-13 18:41:37 +01:00
Sandro Santilli
dfc4a02398 Fix X-Cache-Channel for multilayer (by token) responses
Required upgrading Windshaft to 0.9.2
Includes testcases
2013-03-13 16:45:15 +01:00
Sandro Santilli
899d8a3c64 Run multilayer test as part of "make check" 2013-03-13 16:40:54 +01:00
Sandro Santilli
402fc90e63 Absence of X-Cache-Channel will be enough for Varnish to skip caching
Do not override Cache-Control in this case, which means let the
clients or geographical proxies cache the response with usual TTL.
2013-03-13 12:01:35 +01:00
Sandro Santilli
fcd6d55ba4 Draft test for X-Cache-Channel in multilayer response
The test is disabled because it fails
2013-03-13 11:55:57 +01:00
Sandro Santilli
4622dac81b Update NEWS 2013-03-13 10:40:06 +01:00
Sandro Santilli
e8cbc666e2 Handle SQL API errors by logging them and requesting NO cache
SQL api is used to determine the list of source tables affected
by a query. Before this commit, the X-Cache-Channel header set
on sql api error was an arbitrary 'table' string, now the header
is omitted, the error logged and Cache-Control and Pragma headers
are sent as an attempt to request no caching.

The code includes test for this mechanism.
2013-03-13 10:39:00 +01:00
Sandro Santilli
49aad435b9 More ignores 2013-03-13 08:48:30 +01:00
Luis Bosque
23f6c82f0e Merge branch 'release/staging' into develop
Conflicts:
	package.json
2013-03-05 14:15:53 +01:00
Luis Bosque
4995011f1e Merge branch 'release/staging'
Conflicts:
	NEWS.md
2013-03-05 14:15:07 +01:00
Luis Bosque
e038aa7522 V1.1.8 in package.json 2013-03-04 11:38:43 +01:00
Luis Bosque
c77dce105c Target v1.1.9 2013-03-04 11:37:10 +01:00
Sandro Santilli
2fa09aee88 Require Windshaft-0.9.1, to reduce harmfulness of cache_buster param 2013-03-01 13:11:46 +01:00
Luis Bosque
a7afdac67e Target v1.1.8 2013-02-28 15:09:54 +01:00
Sandro Santilli
f6d50fafb1 Expose renderer settings in the environment config files
These are: metatile, bufferSize and cache_ttl
2013-02-25 17:05:59 +01:00
Sandro Santilli
f076b0c4d1 Require windshaft-0.9 for multilayer support 2013-02-25 15:08:28 +01:00
Sandro Santilli
9b04abb36c Add UTF grid checker function 2013-02-22 11:34:03 +01:00
Sandro Santilli
14e3ead06e Add redis.max configuration setting and document it. 2013-02-21 12:56:04 +01:00
Sandro Santilli
b98a0f9104 Do not let /etc/services confuse FD checker (munin plugin) 2013-02-20 12:14:16 +01:00
David Arango
dc188817a8 Bump to 1.1.7 2013-02-19 13:57:14 +01:00
Sandro Santilli
b81c83aace Add maxConnection and cache dump notice in NEWS for 1.1.6 2013-02-19 13:37:11 +01:00
Sandro Santilli
9dcf6a1acf Set 'base_url_notable' config for Windshaft-0.9 (multilayer) 2013-02-12 18:53:41 +01:00
Sandro Santilli
c3f53a7987 Rename munin plugin, put all under munin dir 2013-02-11 18:24:18 +01:00
Sandro Santilli
3101dbd433 Add cache count to the stats reported by checkfds.sh (munin plugin) 2013-02-11 17:35:17 +01:00
Sandro Santilli
3c5e358c32 Regenerated npm-shrinkwrap.json with npm-1.1.x
See https://github.com/isaacs/npm/issues/3145 for the rationale
2013-02-11 17:05:44 +01:00
Sandro Santilli
219caf7eab Require windshaft 0.8.5 with some stability issue fixed
Additionally we can now control renderer cache time to live and
metatiling
2013-02-11 16:39:21 +01:00
Sandro Santilli
fb33583df9 Update news file 2013-02-11 15:10:41 +01:00
Sandro Santilli
a79b999e7a Do not try to send commands to an unoconnected redis client
This changes "Cannot read property 'HGET' of null" messages into
"Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED".
2013-02-11 15:05:23 +01:00
Sandro Santilli
031c6ee0cd Allow "staging" as env name from app.js 2013-02-11 13:41:51 +01:00
Sandro Santilli
b3f8515fd5 Fix regexp to find incoming http connections (munin fds plugin) 2013-02-08 18:17:15 +01:00
Sandro Santilli
6e6c1101fe avoid scaling counters (munin) 2013-02-08 17:48:54 +01:00
Sandro Santilli
39c0d3a9a4 tweak graph labels of munin plugin 2013-02-08 17:05:43 +01:00
Sandro Santilli
6476b975d4 Ignore generated munin plugin config file 2013-02-08 16:48:42 +01:00
Sandro Santilli
60b578ae56 Report environment name in munin graph 2013-02-08 16:47:59 +01:00
Sandro Santilli
7dd7d09cf5 Add Makefile rule to install munin plugin 2013-02-08 16:44:34 +01:00
Sandro Santilli
c314640c3b Remove debugging output (munin wouldn't like it) 2013-02-08 16:10:56 +01:00
Sandro Santilli
d1d2074146 Further improvements: support specifying a TILER_ENVIRONMENT env variable
.. or the same thing (a filename) as a command line argument
2013-02-08 16:08:24 +01:00
Sandro Santilli
56319a5ac0 Improvements to the fd checker
1. Finds listening processes automatically
2. Reports highest value among processes for each connection type
3. Reduces lsof calls
4. Uses munin-like output
2013-02-08 15:24:25 +01:00
Sandro Santilli
6b71cde56e Do not throw an Error embedding another Error
Should fix #68, but doesn't come with an automated test
2013-02-08 12:27:49 +01:00
Sandro Santilli
7d34cbbd63 Add item about async throws 2013-02-08 12:23:25 +01:00
Sandro Santilli
cb57dfb27d Fix async throws in getGeometryType, getInfoWindow and getMapMetadata 2013-02-08 12:14:53 +01:00
Sandro Santilli
0b56dd09d9 checkfds: use lsof only once, then grep in the report 2013-02-07 13:26:11 +01:00
Sandro Santilli
2d35a2c269 Add checkfds utility script 2013-02-07 12:32:06 +01:00
Sandro Santilli
6c40d936ef Add a log on cluster startup, including date and pid 2013-02-01 11:28:08 +01:00
Sandro Santilli
61f4212ba2 Remove use of ANSI colors from all example log formats 2013-01-30 12:59:05 +01:00
Sandro Santilli
e408d04fc5 Require Windshaft 0.8.4 to add dump of cache stats on SIGUSR1 2013-01-30 11:29:44 +01:00
Sandro Santilli
2510a47262 Add maxConnection environment configuration, have it default to 128
The number gives the maximum number of contemporary connections and
is dimensioned on the limit of open file descriptors found to be
needed on a per-connection basis.
2013-01-29 17:36:50 +01:00
Sandro Santilli
8d5baebf1d Require latest grainstore and windshaft stable releases
Fixes some http response status to be 400 rather than 500
2013-01-29 13:13:14 +01:00
Sandro Santilli
42b3d0ab9c Add redis timeout and reap interval options in production.js.example
Use default values, for documentation purposes
2013-01-29 13:01:17 +01:00
Sandro Santilli
8d4f033a56 Revert "getDatabase: properly handle redis connection failures"
This reverts commit dd19d74149.

The code was already correct
2013-01-28 17:39:50 +01:00
Sandro Santilli
dd19d74149 getDatabase: properly handle redis connection failures 2013-01-28 17:30:58 +01:00
Sandro Santilli
ac49abe750 Do not leak redis client connections on redis command error 2013-01-28 17:13:49 +01:00
Sandro Santilli
b130b67f24 Check redis connection at pool creation time 2013-01-28 17:12:21 +01:00
Sandro Santilli
093d3de66e We don't run tests with expresso anymore... 2012-12-21 17:32:00 +01:00
Luis Bosque
fea30dcea4 Merge branch 'release/staging'
Conflicts:
	NEWS.md
2012-12-21 14:10:15 +01:00
Sandro Santilli
6e8bfffff1 Merge branch 'master' into develop
Conflicts:
	Makefile
	NEWS.md
	package.json
2012-12-21 13:30:14 +01:00
Sandro Santilli
0ff403fa83 Require grainstore 0.10.9, fixing an issue with multi-geom markers 2012-12-21 13:24:38 +01:00
Sandro Santilli
ab1a0e0339 Add check-full to run testsuite of submodules
This model should be improved to avoid double-checking when the same
submodule could be installed or referenced by multiple levels...
2012-12-20 13:15:47 +01:00
Luis Bosque
290e005e14 Target v1.1.5 2012-12-20 12:28:43 +01:00
Sandro Santilli
d1979a5265 Fix bogus cached return of utf grid for fully contained tiles (#67) 2012-12-20 11:30:29 +01:00
Sandro Santilli
9db49a25e4 Require windshaft-0.8.1 for cache debugging facilities
Also upgrades node-mapnik to 0.7.18
2012-12-19 18:31:58 +01:00
Sandro Santilli
a69afe4cd7 Enhance run_tests.sh to allow running single tests and skipping preparation 2012-12-19 09:04:53 +01:00
David Arango
556aaf3330 Bump to 1.1.5 2012-12-13 11:45:14 +01:00
David Arango
7b1184db8f Bump to 1.1.5 2012-12-13 11:43:11 +01:00
David Arango
e1070d3998 Merge branch 'release/staging' 2012-12-10 17:26:48 +01:00
Sandro Santilli
cc91e0dcff Add a row limitof 65535 (256x256) in the example configs.
Closes #64
2012-12-07 20:34:24 +01:00
Sandro Santilli
081cc41a34 Drop extended styles. Closes #58. Add some documentation in header. 2012-12-07 20:21:13 +01:00
Sandro Santilli
9d52b8b11f Update NEWS 2012-12-07 20:06:26 +01:00
Sandro Santilli
a8a3e739ad Change interface of reset_style to read full config from env files
Closes #62
It is highly recommended to invoke reset_styles after upgrade
2012-12-07 20:04:31 +01:00
Sandro Santilli
b884fe00ea The parameter to simplify geometries is "simplify_geometries"
Closes #63
2012-12-07 19:50:57 +01:00
Sandro Santilli
4f8b855f1f Add reference to the list of accepted parameters for the postgres section 2012-12-07 18:58:31 +01:00
Sandro Santilli
6f5e3837e3 Use an env config parameter for socket timeout 2012-12-05 13:59:20 +01:00
Luis Bosque
de1df4f33c Merge branch 'release/v2.0' into develop
Conflicts:
	NEWS.md
2012-11-30 16:53:55 +01:00
Luis Bosque
7231864e1c Merge branch 'release/v2.0' 2012-11-30 16:52:55 +01:00
Luis Bosque
e813209768 Updated NEWS vor 1.1.3 2012-11-30 16:51:31 +01:00
Sandro Santilli
69508f05d7 Reduce default extent to allow for consistent proj4 round-tripping
See https://github.com/Vizzuality/grainstore/issues/42
2012-11-29 10:20:37 +01:00
Sandro Santilli
2f70640340 Require grainstore-0.10.8 to workaround bubble map bug
See https://github.com/Vizzuality/grainstore/issues/44
2012-11-28 20:17:02 +01:00
Luis Bosque
02d4473766 Target version 1.1.4 2012-11-28 16:43:19 +01:00
David Arango
72cf824235 Fix on convert_database_styles script 2012-11-28 15:34:05 +01:00
Sandro Santilli
a3d09339de Require grainstore-0.10.7 to enhance marker type transform (2.0 -> 2.1)
See https://github.com/Vizzuality/grainstore/blob/0.10.7/NEWS.md
2012-11-28 12:36:47 +01:00
Sandro Santilli
a0cd4354a7 Enlarge default map extent
See https://github.com/Vizzuality/grainstore/issues/42
2012-11-28 11:24:04 +01:00
Sandro Santilli
820c836050 Require grainstore-0.10.6 to enhance marker type transform (2.0 -> 2.1)
See https://github.com/Vizzuality/grainstore/issues/39
2012-11-28 10:06:43 +01:00
Sandro Santilli
bbdc29faae Set max_size=500 in the example configurations
TODO: add a ./configure switch to set it
2012-11-27 18:30:08 +01:00
Sandro Santilli
c976506c67 Require grainstore-0.10.5 to resize arrow markers ( 2.0 -> 2.1 ) 2012-11-27 17:31:53 +01:00
Sandro Santilli
11025eb7c4 Update with the change in reset_styles 2012-11-26 13:20:39 +01:00
Sandro Santilli
08c75843de Really skip extended keys 2012-11-26 12:51:55 +01:00
Sandro Santilli
c3169745ee Require grainstore ~0.10.4 for mapnik-2.1.1 support 2012-11-23 12:39:34 +01:00
Sandro Santilli
32007403c0 Fix testcase 2012-11-22 19:12:21 +01:00
Sandro Santilli
59a1911950 Add test for #57 (succeeds)
The ticket is actually invalid, there's no such bug here...
2012-11-22 16:39:00 +01:00
Sandro Santilli
2be0ebb808 Add --with-mapnik-version configure switch 2012-11-21 13:23:04 +01:00
Sandro Santilli
6ccb7f6f15 Shrinkwrap latest grainstore, to not be fooled by CartoCSS comments 2012-11-20 19:07:47 +01:00
David Arango
bb59524914 Adds script to convert single tables 2012-11-19 12:54:27 +01:00
Sandro Santilli
9645d0fb58 Require grainstore 0.10.1 to handle conditional markers in style transform 2012-11-15 16:12:55 +01:00
Sandro Santilli
635b5db3e6 Nicer indent in CartoCSS (less likely to be converted) 2012-11-15 16:01:34 +01:00
Sandro Santilli
19436a8b14 Let "style_convert" pass by, add tests for GET and POST with it 2012-11-14 15:28:58 +01:00
Sandro Santilli
1ebe862594 Add style_convert and style_version parameters in the docs 2012-11-14 13:45:11 +01:00
Sandro Santilli
2f0ef03cd3 Accept style_convert parameter to GET /styl request
Require grainstore-0.10 and windshaft-0.8 to allow for it
2012-11-14 13:41:46 +01:00
Luis Bosque
597008d9d4 Merge branch 'release/staging' 2012-11-14 12:48:07 +01:00
Sandro Santilli
f9b78e2cb2 Use grainstore 0.9.7 for mapnik version dependent default styles 2012-11-14 10:42:20 +01:00
Luis Bosque
33e68d9069 target v1.1.3 2012-11-12 12:28:32 +01:00
Sandro Santilli
b5658a9f43 Fix point markers shift due to polygon clipping (2.0 -> 2.1)
Done by requiring grainstore 0.9.6
2012-11-09 17:28:22 +01:00
Sandro Santilli
4b8c165261 Fix usage string for "show_style" tool 2012-11-08 18:58:09 +01:00
Sandro Santilli
cd6002879e Add tool to show formatted style stored in redis from user/table 2012-11-07 10:59:39 +01:00
Sandro Santilli
43bb96cc60 Require grainstore 0.9.5, fixing one type of style transform 2012-11-06 18:02:46 +01:00
Sandro Santilli
52303e7821 Fix use of "style_version" with GET (inline styles)
It took a lot of time to produce a testcase for this as the test
config was setting srid to 4326 but not changing geom column name
thus all tiles fetched by tests returned blank (ouch!)
2012-11-06 12:45:04 +01:00
Luis Bosque
37cba2836c timeout is in milseconds, not in seconds 2012-11-02 23:48:08 +01:00
Luis Bosque
8ef952f138 set 600 seconds timeout in cluster.js 2012-11-02 23:24:45 +01:00
Sandro Santilli
b5db3a8138 Require grainstore 0.9.4, for better 2.0 -> 2.1 css transforms 2012-11-02 17:53:25 +01:00
Luis Bosque
d1d321194d target 1.1.2 version 2012-11-02 15:47:54 +01:00
Luis Bosque
8120e6579a updated NEWS 2012-11-02 15:46:54 +01:00
Luis Bosque
f9e0b8708c target version 1.1.1 2012-10-30 18:53:49 +01:00
Luis Bosque
6401278317 Merge branch 'release/staging' into develop
Conflicts:
	NEWS.md
	npm-shrinkwrap.json
	package.json
	test/acceptance/server.js
2012-10-30 18:49:42 +01:00
Luis Bosque
1873322a90 Merge branch 'release/staging'
Conflicts:
	package.json
2012-10-30 18:45:47 +01:00
Luis Bosque
2d2a14e9a6 updated NEW for v1.1.0 2012-10-30 18:43:31 +01:00
Sandro Santilli
1da7484c2a Shrinkwrap newest windshaft and grainstore 2012-10-30 18:00:16 +01:00
Sandro Santilli
2bc09a61cf Add support for cache_policy=persistent
When cache_policy=persistent is given the response will contain
a Cache-Control header requesting for 1 year lifetime caching
2012-10-24 09:40:05 +02:00
Sandro Santilli
d9e6aeb254 Fix crash on unknown user. Closes #55. 2012-10-22 15:30:16 +02:00
Sandro Santilli
1a60c55fea Rename carto version parameters and add its support to GET tile
Also upgrades "carto" to 0.9.3 and "millstone" to 0.5.11
2012-10-19 12:54:11 +02:00
Sandro Santilli
ab8cb5bbb3 Add Windshaft-cartodb version to the /version route 2012-10-15 17:03:57 +02:00
Sandro Santilli
4c6d74b69e Use windshaft-0.6.2 sendError function to send non-200 responses
Ensures all errors are logged
2012-10-11 16:58:11 +02:00
Sandro Santilli
20dca2e8f8 Use windshaft-0.6.2 sendError function to send non-200 responses
Ensures all errors are logged
2012-10-11 16:48:41 +02:00
Sandro Santilli
90d726c0cb Fix test expectance after windshaft/grainstore upgrade
Now GET /style response includes CartoCSS version...
2012-10-11 11:23:35 +02:00
Sandro Santilli
00dccd4c27 Use 'host' configuration for HTTP listening (both app and cluster) 2012-10-11 11:23:33 +02:00
Sandro Santilli
d691f94978 Require grainstore 0.9.1 for automatic styles reset on mapnik upgrade 2012-10-11 11:23:32 +02:00
Sandro Santilli
11910bb218 Use "undefined" mapnik_version in the example configs
Using "undefined" for mapnik_version triggers autodetection,
which is more appropriate.
2012-10-11 11:23:31 +02:00
Sandro Santilli
f0c655294f Upgrade windshaft/grainstore to fix /version route 2012-10-11 11:23:30 +02:00
Sandro Santilli
8e3c900580 Print a warning when configured mapnik version doesn't match installed 2012-10-11 11:23:28 +02:00
Sandro Santilli
65e4cf1510 Batch-convert and mapnik version detection support in reset_styles 2012-10-11 11:23:26 +02:00
Sandro Santilli
41d7000daf Update windshaft to 0.6 exposing CartoCSS versioning support 2012-10-11 11:23:25 +02:00
Sandro Santilli
0e37b32e52 Updated 2012-10-11 11:23:24 +02:00
Sandro Santilli
9ad574efdc Autodetect target mapnik version and let config override it
Closes #40
2012-10-11 11:23:23 +02:00
Sandro Santilli
8d5c52ce1b Make test tolerant to additional fields in responses to POST style 2012-10-11 11:23:22 +02:00
Sandro Santilli
926b47b009 Fix test expectance after windshaft/grainstore upgrade
Now GET /style response includes CartoCSS version...
2012-10-09 18:35:27 +02:00
Sandro Santilli
bb00bf1c05 Use 'host' configuration for HTTP listening (both app and cluster) 2012-10-09 18:31:06 +02:00
Sandro Santilli
bc51b14485 Require grainstore 0.9.1 for automatic styles reset on mapnik upgrade 2012-10-09 14:39:38 +02:00
Sandro Santilli
9cdd2800fa Use "undefined" mapnik_version in the example configs
Using "undefined" for mapnik_version triggers autodetection,
which is more appropriate.
2012-10-09 12:12:33 +02:00
Sandro Santilli
0697873a64 Upgrade windshaft/grainstore to fix /version route 2012-10-09 11:53:23 +02:00
Sandro Santilli
6a1933bed9 Print a warning when configured mapnik version doesn't match installed 2012-10-09 11:45:57 +02:00
Sandro Santilli
703c63d5d6 Batch-convert and mapnik version detection support in reset_styles 2012-10-08 18:06:12 +02:00
Sandro Santilli
89ca4e1a5a Update windshaft to 0.6 exposing CartoCSS versioning support 2012-10-08 18:02:28 +02:00
Sandro Santilli
f8e88153f4 Updated 2012-10-08 17:45:52 +02:00
Sandro Santilli
961269fa1f Autodetect target mapnik version and let config override it
Closes #40
2012-10-08 17:45:03 +02:00
Sandro Santilli
90f6e464d2 Make test tolerant to additional fields in responses to POST style 2012-10-08 17:45:03 +02:00
Luis Bosque
a42f03c224 target 1.1.0 version 2012-10-08 12:50:50 +02:00
Luis Bosque
34df118160 fixed problem in cluster2 with pidfile name 2012-10-04 11:02:31 +02:00
Luis Bosque
b6f28d7dd2 version 1.0.0 in package.json 2012-10-03 16:56:50 +02:00
Luis Bosque
43298f58fb Merge branch 'develop0.8' 2012-10-03 16:42:03 +02:00
Luis Bosque
5d62c6b588 Merge branch 'release/staging' 2012-09-25 17:31:58 +02:00
Sandro Santilli
4216d43db2 Fix grainstore include after direct dependency drop 2008-06-17 05:25:38 +02:00
Sandro Santilli
f85ca16c62 Change LZMA expected encoding from HEX to base64, reducing its size 2013-04-19 16:16:20 +02:00
Sandro Santilli
14953e992f Multilayer API changes, target 1.2.0
- Layers passed by index in grid fetching url
 - Interactivity only specified in layergroup config
 - Encode cache_buster as part of the token
2013-04-15 18:51:28 +02:00
Fabio Rueda
0122c6a386 targeted 1.1.11 2013-04-15 13:05:16 +02:00
304 changed files with 48468 additions and 2398 deletions

10
.gitignore vendored
View File

@@ -1,3 +1,11 @@
node_modules
node_modules*
config.status*
config/environments/*.js
.idea
tools/munin/windshaft.conf
logs/
pids/
redis.pid
test.log
npm-debug.log
coverage/

4
.jshintignore Normal file
View File

@@ -0,0 +1,4 @@
test/results/
test/monkey/
test/benchmark.js
test/support/

95
.jshintrc Normal file
View File

@@ -0,0 +1,95 @@
{
// // JSHint Default Configuration File (as on JSHint website)
// // See http://jshint.com/docs/ for more details
//
// "maxerr" : 50, // {int} Maximum error before stopping
//
// // Enforcing
// "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.)
// "camelcase" : false, // true: Identifiers must be in camelCase
"curly" : true, // true: Require {} for every new block or scope
"eqeqeq" : true, // true: Require triple equals (===) for comparison
"forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty()
"freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
"immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
// "indent" : 4, // {int} Number of spaces to use for indentation
// "latedef" : false, // true: Require variables/functions to be defined before being used
"newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
"noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
// "noempty" : true, // true: Prohibit use of empty blocks
"nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
"nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
// "plusplus" : false, // true: Prohibit use of `++` & `--`
// "quotmark" : false, // Quotation mark consistency:
// // false : do nothing (default)
// // true : ensure whatever is used is consistent
// // "single" : require single quotes
// // "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : true, // true: Require all defined variables be used
// "strict" : true, // true: Requires all functions run in ES5 Strict Mode
// "maxparams" : false, // {int} Max number of formal params allowed per function
// "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
// "maxstatements" : false, // {int} Max number statements per function
"maxcomplexity" : 6, // {int} Max cyclomatic complexity per function
"maxlen" : 120, // {int} Max number of characters per line
//
// // Relaxing
// "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
// "boss" : false, // true: Tolerate assignments where comparisons would be expected
"debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
// "eqnull" : false, // true: Tolerate use of `== null`
// "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
// "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`)
// "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
// // (ex: `for each`, multiple try/catch, function expression…)
// "evil" : false, // true: Tolerate use of `eval` and `new Function()`
// "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
// "funcscope" : false, // true: Tolerate defining variables inside control statements
// "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
// "iterator" : false, // true: Tolerate using the `__iterator__` property
// "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
// "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
// "laxcomma" : false, // true: Tolerate comma-first style coding
// "loopfunc" : false, // true: Tolerate functions being defined in loops
// "multistr" : false, // true: Tolerate multi-line strings
// "noyield" : false, // true: Tolerate generator functions with no yield statement in them.
// "notypeof" : false, // true: Tolerate invalid typeof operator values
// "proto" : false, // true: Tolerate using the `__proto__` property
// "scripturl" : false, // true: Tolerate script-targeted URLs
// "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
// "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
// "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
// "validthis" : false, // true: Tolerate using this in a non-constructor function
//
// // Environments
// "browser" : true, // Web Browser (window, document, etc)
// "browserify" : false, // Browserify (node.js code in the browser)
// "couch" : false, // CouchDB
// "devel" : true, // Development/debugging (alert, confirm, etc)
// "dojo" : false, // Dojo Toolkit
// "jasmine" : false, // Jasmine
// "jquery" : false, // jQuery
// "mocha" : true, // Mocha
// "mootools" : false, // MooTools
"node" : true, // Node.js
// "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
// "prototypejs" : false, // Prototype and Scriptaculous
// "qunit" : false, // QUnit
// "rhino" : false, // Rhino
// "shelljs" : false, // ShellJS
// "worker" : false, // Web Workers
// "wsh" : false, // Windows Scripting Host
// "yui" : false, // Yahoo User Interface
// Custom predefined global variables
"predef": [
"-console", // disallows console, use debug
"beforeEach",
"afterEach",
"before",
"after",
"describe",
"it"
]
}

30
.travis.yml Normal file
View File

@@ -0,0 +1,30 @@
sudo: false
addons:
postgresql: "9.4"
apt:
packages:
- postgresql-plpython-9.4
- pkg-config
- libcairo2-dev
- libjpeg8-dev
- libgif-dev
before_install:
- npm install -g npm@2
- createdb template_postgis
- createuser publicuser
- psql -c "CREATE EXTENSION postgis" template_postgis
env:
- NPROCS=1 JOBS=1 PGUSER=postgres
language: node_js
node_js:
- "0.10"
notifications:
irc:
channels:
- "irc.freenode.org#cartodb"
use_notice: true

11
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,11 @@
Contributing
---
The issue tracker is at [github.com/CartoDB/Windshaft-cartodb](https://github.com/CartoDB/Windshaft-cartodb).
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://cartodb.com/contributing).

19
HOWTO_RELEASE Normal file
View File

@@ -0,0 +1,19 @@
1. Test (make clean all check), fix if broken before proceeding
2. Ensure proper version in package.json
3. Ensure NEWS section exists for the new version, review it, add release date
4. Recreate npm-shrinkwrap.json with: `npm install --no-shrinkwrap && npm shrinkwrap`
5. Commit package.json, npm-shrinwrap.json, NEWS
6. git tag -a Major.Minor.Patch # use NEWS section as content
7. Announce on cartodb@googlegroups.com
8. Stub NEWS/package for next version
Versions:
Bugfix releases increment Patch component of version.
Feature releases increment Minor and set Patch to zero.
If backward compatibility is broken, increment Major and
set to zero Minor and Patch.
Branches named 'b<Major>.<Minor>' are kept for any critical
fix that might need to be shipped before next feature release
is ready.

53
INSTALL.md Normal file
View File

@@ -0,0 +1,53 @@
# Installing Windshaft-CartoDB #
## Requirements ##
Make sure that you have the requirements needed. These are
- Core
- Node.js >=0.8
- npm >=1.2.1 <2.0.0
- PostgreSQL >8.3.x, PostGIS >1.5.x
- Redis >2.4.0 (http://www.redis.io)
- Mapnik 2.0.1, 2.0.2, 2.1.0, 2.2.0, 2.3.0. See [Installing Mapnik](https://github.com/CartoDB/Windshaft#installing-mapnik).
- Windshaft: check [Windshaft dependencies and installation notes](https://github.com/CartoDB/Windshaft#dependencies)
- libcairo2-dev, libpango1.0-dev, libjpeg8-dev and libgif-dev for server side canvas support
- For cache control (optional)
- CartoDB 0.9.5+ (for `CDB_QueryTables`)
- Varnish (http://www.varnish-cache.org)
On Ubuntu 14.04 the dependencies can be installed with
```shell
sudo apt-get update
sudo apt-get install -y make g++ pkg-config git-core \
libgif-dev libjpeg-dev libcairo2-dev \
libhiredis-dev redis-server \
nodejs nodejs-legacy npm \
postgresql-9.3-postgis-2.1 postgresql-plpython-9.3 postgresql-server-dev-9.3
```
On Ubuntu 12.04 the [cartodb/cairo PPA](https://launchpad.net/~cartodb/+archive/ubuntu/cairo) may be useful.
## PostGIS setup ##
A `template_postgis` database is expected. One can be set up with
```shell
createdb --owner postgres --template template0 template_postgis
psql -d template_postgis -c 'CREATE EXTENSION postgis;'
```
## Build/install ##
To fetch and build all node-based dependencies, run:
```
npm install
```
Note that the ```npm install``` step will populate the node_modules/
directory with modules, some of which being compiled on demand. If you
happen to have startup errors you may need to force rebuilding those
modules. At any time just wipe out the node_modules/ directory and run
```npm install``` again.

27
LICENCE
View File

@@ -1,27 +0,0 @@
Copyright (c) 2011, Vizzuality
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Vizzuality.
4. Neither the name of Vizzuality nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

27
LICENSE Normal file
View File

@@ -0,0 +1,27 @@
Copyright (c) 2015, CartoDB
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,11 +1,53 @@
SHELL=/bin/bash
pre-install:
@$(SHELL) ./scripts/check-node-canvas.sh
all:
npm install
@$(SHELL) ./scripts/install.sh
clean:
rm -rf node_modules/*
config/environments/test.js: config/environments/test.js.example
./configure
distclean: clean
rm config.status*
check: config/environments/test.js
./run_tests.sh
config.status--test:
./configure --environment=test
config/environments/test.js: config.status--test
./config.status--test
TEST_SUITE := $(shell find test/{acceptance,integration,unit} -name "*.js")
TEST_SUITE_UNIT := $(shell find test/unit -name "*.js")
TEST_SUITE_INTEGRATION := $(shell find test/integration -name "*.js")
TEST_SUITE_ACCEPTANCE := $(shell find test/acceptance -name "*.js")
test: config/environments/test.js
@echo "***tests***"
@$(SHELL) ./run_tests.sh ${RUNTESTFLAGS} $(TEST_SUITE)
test-unit: config/environments/test.js
@echo "***tests***"
@$(SHELL) ./run_tests.sh ${RUNTESTFLAGS} $(TEST_SUITE_UNIT)
test-integration: config/environments/test.js
@echo "***tests***"
@$(SHELL) ./run_tests.sh ${RUNTESTFLAGS} $(TEST_SUITE_INTEGRATION)
test-acceptance: config/environments/test.js
@echo "***tests***"
@$(SHELL) ./run_tests.sh ${RUNTESTFLAGS} $(TEST_SUITE_ACCEPTANCE)
jshint:
@echo "***jshint***"
@./node_modules/.bin/jshint lib/ test/ app.js
test-all: test jshint
coverage:
@RUNTESTFLAGS=--with-coverage make test
check: test
.PHONY: pre-install test jshint coverage

1746
NEWS.md

File diff suppressed because it is too large Load Diff

101
README.md
View File

@@ -1,33 +1,21 @@
Windshaft-CartoDB
==================
NOTE: requires node-0.8.x
[![Build Status](https://travis-ci.org/CartoDB/Windshaft-cartodb.svg?branch=master)](https://travis-ci.org/CartoDB/Windshaft-cartodb)
This is the CartoDB map tiler. It extends Windshaft with some extra
functionality and custom filters for authentication
This is the [CartoDB Maps API](http://docs.cartodb.com/cartodb-platform/maps-api.html) tiler. It extends
[Windshaft](https://github.com/CartoDB/Windshaft) with some extra functionality and custom filters for authentication.
* reads dbname from subdomain and cartodb redis for pretty tile urls
* configures windshaft to publish ``cartodb_id`` as the interactivity layer
* configures windshaft to publish `cartodb_id` as the interactivity layer
* gets the default geometry type from the cartodb redis store
* allows tiles to be styled individually
* provides a link to varnish high speed cache
* provides a infowindow endpoint for windshaft
* provides a ``map_metadata`` endpoint for windshaft
* provides a [template maps API](https://github.com/CartoDB/Windshaft-cartodb/blob/master/docs/Template-maps.md)
Requirements
------------
[core]
- node-0.6.x+
- PostgreSQL-8.3+
- PostGIS-1.5.0+
- Redis 2.2.0+ (http://www.redis.io)
- Mapnik 2.0 or 2.1
[for cache control]
- CartoDB-SQL-API 1.0.0+
- CartoDB 0.9.5+ (for ``CDB_QueryTables``)
- Varnish (https://www.varnish-cache.org)
Install
-------
See [INSTALL.md](INSTALL.md) for detailed installation instructions.
Configure
---------
@@ -38,23 +26,15 @@ see ```./configure --help``` to see available options.
Look at lib/cartodb/server_options.js for more on config
Build/install
-------------
Upgrading
---------
To fetch and build all node-based dependencies, run:
Checkout your commit/branch. If you need to reinstall dependencies (you can check [NEWS](NEWS.md)) do the following:
```
git clone
npm install
rm -rf node_modules; npm install
```
Note that the ```npm install``` step will populate the node_modules/
directory with modules, some of which being compiled on demand. If you
happen to have startup errors you may need to force rebuilding those
modules. At any time just wipe out the node_modules/ directory and run
```npm install``` again.
Run
---
@@ -69,49 +49,34 @@ there may be out-of-sync records in there.
Take a look: http://redis.io/commands
URLs
----
Documentation
-------------
**TILES**
[GET] subdomain.cartodb.com/tiles/:table_name/:z/:x/:y.[png|png8|grid.json]
Args:
* sql - plain SQL arguments
* interactivity - specify the column to use in UTFGrid
* cache_buster - if needed you can add a cachebuster to make sure you're
rendering new
* geom_type - override the cartodb default
* style - override the default map style with Carto
The [docs directory](https://github.com/CartoDB/Windshaft-cartodb/tree/master/docs) contains different documentation
resources, from higher level to more detailed ones:
The [Maps API](https://github.com/CartoDB/Windshaft-cartodb/blob/master/docs/Map-API.md) defined the endpoints and their
expected parameters and outputs.
**STYLE**
Examples
--------
[GET/POST] subdomain.cartodb.com/tiles/:table_name/style
[CartoDB's Map Gallery](http://cartodb.com/gallery/) showcases several examples of visualisations built on top of this.
Args:
Contributing
---
* style - the style in CartoCSS you want to set
See [CONTRIBUTING.md](CONTRIBUTING.md).
### Developing with a custom windshaft version
**INFOWINDOW**
If you plan or want to use a custom / not released yet version of windshaft (or any other dependency) the best option is
to use `npm link`. You can read more about it at [npm-link: Symlink a package folder](https://docs.npmjs.com/cli/link).
[GET] subdomain.cartodb.com/tiles/:table_name/infowindow
**Quick start**:
Args:
* infowindow - returns contents of infowindow from CartoDB.
**MAP METADATA**
[GET] subdomain.cartodb.com/tiles/:table_name/map_metadata
Args:
* infowindow - returns contents of infowindow from CartoDB.
All GET requests are wrappable with JSONP using callback argument,
including the UTFGrid map tile call.
```shell
~/windshaft-directory $ npm install
~/windshaft-directory $ npm link
~/windshaft-cartodb-directory $ npm link windshaft
```

138
app.js
View File

@@ -1,37 +1,125 @@
/*
* Windshaft-CartoDB
* ===============
*
* ./app.js [environment]
*
* environments: [development, production]
*/
var http = require('http');
var https = require('https');
var path = require('path');
var fs = require('fs');
var _ = require('underscore');
var ENVIRONMENT;
if ( process.argv[2] ) {
ENVIRONMENT = process.argv[2];
} else if ( process.env.NODE_ENV ) {
ENVIRONMENT = process.env.NODE_ENV;
} else {
ENVIRONMENT = 'development';
}
// jshint undef:false
var log = console.log.bind(console);
var logError = console.error.bind(console);
// jshint undef:true
var availableEnvironments = {
production: true,
staging: true,
development: true
};
// sanity check
var ENV = process.argv[2]
if (ENV != 'development' && ENV != 'production'){
console.error("\nnode app.js [environment]");
console.error("environments: [development, production]\n");
if (!availableEnvironments[ENVIRONMENT]){
logError('node app.js [environment]');
logError('environments: %s', Object.keys(availableEnvironments).join(', '));
process.exit(1);
}
var _ = require('underscore')
, Step = require('step')
, CartodbWindshaft = require('./lib/cartodb/cartodb_windshaft');
process.env.NODE_ENV = ENVIRONMENT;
// set environment specific variables
global.settings = require(__dirname + '/config/settings');
global.environment = require(__dirname + '/config/environments/' + ENV);
_.extend(global.settings, global.environment);
global.environment = require('./config/environments/' + ENVIRONMENT);
// Include cart_data.js only _after_ the "global" variable is set
global.log4js = require('log4js');
var log4js_config = {
appenders: [],
replaceConsole: true
};
if (global.environment.uv_threadpool_size) {
process.env.UV_THREADPOOL_SIZE = global.environment.uv_threadpool_size;
}
// set global HTTP and HTTPS agent default configurations
// ref https://nodejs.org/api/http.html#http_new_agent_options
var agentOptions = _.defaults(global.environment.httpAgent || {}, {
keepAlive: false,
keepAliveMsecs: 1000,
maxSockets: Infinity,
maxFreeSockets: 256
});
http.globalAgent = new http.Agent(agentOptions);
https.globalAgent = new https.Agent(agentOptions);
if ( global.environment.log_filename ) {
var logdir = path.dirname(global.environment.log_filename);
// See cwd inlog4js.configure call below
logdir = path.resolve(__dirname, logdir);
if ( ! fs.existsSync(logdir) ) {
logError("Log filename directory does not exist: " + logdir);
process.exit(1);
}
log("Logs will be written to " + global.environment.log_filename);
log4js_config.appenders.push(
{ type: "file", filename: global.environment.log_filename }
);
} else {
log4js_config.appenders.push(
{ type: "console", layout: { type:'basic' } }
);
}
global.log4js.configure(log4js_config, { cwd: __dirname });
global.logger = global.log4js.getLogger();
global.environment.api_hostname = require('os').hostname().split('.')[0];
// Include cartodb_windshaft only _after_ the "global" variable is set
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/28
var cartoData = require('./lib/cartodb/carto_data');
var Windshaft = require('windshaft');
var cartodbWindshaft = require('./lib/cartodb/server');
var serverOptions = require('./lib/cartodb/server_options');
ws = CartodbWindshaft(serverOptions);
ws.listen(global.environment.port);
console.log("Windshaft tileserver started on port " + global.environment.port);
var server = cartodbWindshaft(serverOptions);
// Maximum number of connections for one process
// 128 is a good number if you have up to 1024 filedescriptors
// 4 is good if you have max 32 filedescriptors
// 1 is good if you have max 16 filedescriptors
var backlog = global.environment.maxConnections || 128;
var listener = server.listen(serverOptions.bind.port, serverOptions.bind.host, backlog);
var version = require("./package").version;
listener.on('listening', function() {
log(
"Windshaft tileserver %s started on %s:%s PID=%d (%s)",
version, serverOptions.bind.host, serverOptions.bind.port, process.pid, ENVIRONMENT
);
});
setInterval(function() {
var memoryUsage = process.memoryUsage();
Object.keys(memoryUsage).forEach(function(k) {
global.statsClient.gauge('windshaft.memory.' + k, memoryUsage[k]);
});
}, 5000);
process.on('SIGHUP', function() {
global.log4js.clearAndShutdownAppenders(function() {
global.log4js.configure(log4js_config);
global.logger = global.log4js.getLogger();
log('Log files reloaded');
});
});
process.on('uncaughtException', function(err) {
global.logger.error('Uncaught exception: ' + err.stack);
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,52 +0,0 @@
/*
* Windshaft-CartoDB
* ===============
*
* ./app.js [environment]
*
* environments: [development, production]
*/
var Cluster = require('cluster2');
// sanity check
var ENV = process.argv[2]
if (ENV != 'development' && ENV != 'production' && ENV != 'staging'){
console.error("\nnode app.js [environment]");
console.error("environments: [development, production, staging]\n");
process.exit(1);
}
var _ = require('underscore')
, Step = require('step')
, CartodbWindshaft = require('./lib/cartodb/cartodb_windshaft');
// set environment specific variables
global.settings = require(__dirname + '/config/settings');
global.environment = require(__dirname + '/config/environments/' + ENV);
_.extend(global.settings, global.environment);
// Include cart_data.js only _after_ the "global" variable is set
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/28
var cartoData = require('./lib/cartodb/carto_data');
var Windshaft = require('windshaft');
var serverOptions = require('./lib/cartodb/server_options');
var ws = CartodbWindshaft(serverOptions);
//.use(cluster.logger('logs'))
//.use(cluster.stats())
//.use(cluster.pidfiles('pids'))
var cluster = new Cluster({
port: global.environment.port,
monPort: global.environment.port+1,
noWorkers: 1 // .set('workers', 1)
});
cluster.listen(function(cb) {
cb(ws);
});
console.log("Windshaft tileserver started on port " + global.environment.port);

View File

@@ -2,42 +2,295 @@ var config = {
environment: 'development'
,port: 8181
,host: '127.0.0.1'
// Size of the threadpool which can be used to run user code and get notified in the loop thread
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
// See http://docs.libuv.org/en/latest/threadpool.html
,uv_threadpool_size: undefined
// Regular expression pattern to extract username
// from hostname. Must have a single grabbing block.
,user_from_host: '^(.*)\\.localhost'
// Base URLs for the APIs
//
// See http://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
//
// Base url for the Templated Maps API
// "/api/v1/map/named" is the new API,
// "/tiles/template" is for compatibility with versions up to 1.6.x
,base_url_templated: '(?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)'
// Base url for the Detached Maps API
// "maps" is the the new API,
// "tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128
// Maximum number of templates per user. Unlimited by default.
,maxUserTemplates:1024
// Seconds since "last creation" before a detached
// or template instance map expires. Or: how long do you want
// to be able to navigate the map without a reload ?
// Defaults to 7200 (2 hours)
,mapConfigTTL: 7200
// idle socket timeout, in milliseconds
,socket_timeout: 600000
,enable_cors: true
,cache_enabled: false
,log_format: '[:date] :req[X-Real-IP] \033[90m:method\033[0m \033[36m:req[Host]:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'
,log_format: ':req[X-Real-IP] :method :req[Host]:url :status :response-time ms -> :res[Content-Type] (:res[X-Tiler-Profiler])'
// If log_filename is given logs will be written
// there, in append mode. Otherwise stdout is used (default).
// Log file will be re-opened on receiving the HUP signal
,log_filename: undefined
// Templated database username for authorized user
// Supported labels: 'user_id' (read from redis)
,postgres_auth_user: 'development_cartodb_user_<%= user_id %>'
// Templated database password for authorized user
// Supported labels: 'user_id', 'user_password' (both read from redis)
,postgres_auth_pass: '<%= user_password %>'
,postgres: {
// Parameters to pass to datasource plugin of mapnik
// See http://github.com/mapnik/mapnik/wiki/PostGIS
type: "postgis",
user: "publicuser",
password: "public",
host: '127.0.0.1',
port: 5432,
extent: "-20005048.4188,-20005048.4188,20005048.4188,20005048.4188",
extent: "-20037508.3,-20037508.3,20037508.3,20037508.3",
/* experimental
geometry_field: "the_geom",
extent: "-180,-90,180,90",
srid: 4326,
*/
simplify: true
row_limit: 65535,
simplify_geometries: true,
use_overviews: true, // use overviews to retrieve raster
/*
* Set persist_connection to false if you want
* database connections to be closed on renderer
* expiration (1 minute after last use).
* Setting to true (the default) would never
* close any connection for the server's lifetime
*/
persist_connection: false,
max_size: 500
}
,mapnik_version: undefined
,mapnik_tile_format: 'png8:m=h'
,statsd: {
host: 'localhost',
port: 8125,
prefix: 'dev.',
cacheDns: true
// support all allowed node-statsd options
}
,renderer: {
// Milliseconds since last access before renderer cache item expires
cache_ttl: 60000,
statsInterval: 5000, // milliseconds between each report to statsd about number of renderers and mapnik pool status
mapnik: {
// The size of the pool of internal mapnik backend
// This pool size is per mapnik renderer created in Windshaft's RendererFactory
// See https://github.com/CartoDB/Windshaft/blob/master/lib/windshaft/renderers/renderer_factory.js
// Important: check the configuration of uv_threadpool_size to use suitable value
poolSize: 8,
// Metatile is the number of tiles-per-side that are going
// to be rendered at once. If all of them will be requested
// we'd have saved time. If only one will be used, we'd have
// wasted time.
metatile: 2,
// tilelive-mapnik uses an internal cache to store tiles/grids
// generated when using metatile. This options allow to tune
// the behaviour for that internal cache.
metatileCache: {
// Time an object must stay in the cache until is removed
ttl: 0,
// Whether an object must be removed after the first hit
// Usually you want to use `true` here when ttl>0.
deleteOnHit: false
},
// Override metatile behaviour depending on the format
formatMetatile: {
png: 2,
'grid.json': 1
},
// Buffer size is the tickness in pixel of a buffer
// around the rendered (meta?)tile.
//
// This is important for labels and other marker that overlap tile boundaries.
// Setting to 128 ensures no render artifacts.
// 64 may have artifacts but is faster.
// Less important if we can turn metatiling on.
bufferSize: 64,
// SQL queries will be wrapped with ST_SnapToGrid
// Snapping all points of the geometry to a regular grid
snapToGrid: false,
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
limits: {
// Time in milliseconds a render request can take before it fails, some notes:
// - 0 means no render limit
// - it considers metatiling, naive implementation: (render timeout) * (number of tiles in metatile)
render: 0,
// As the render request will finish even if timed out, whether it should be placed in the internal
// cache or it should be fully discarded. When placed in the internal cache another attempt to retrieve
// the same tile will result in an immediate response, however that will use a lot of more application
// memory. If we want to enforce this behaviour we have to implement a cache eviction policy for the
// internal cache.
cacheOnTimeout: true
},
geojson: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
},
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
// geometries will be simplified using ST_RemoveRepeatedPoints
// which cost is no more expensive than snapping and results are
// much closer to the original geometry
removeRepeatedPoints: false // this requires postgis >=2.2
}
},
http: {
timeout: 2000, // the timeout in ms for a http tile request
proxy: undefined, // the url for a proxy server
whitelist: [ // the whitelist of urlTemplates that can be used
'.*', // will enable any URL
'http://{s}.example.com/{z}/{x}/{y}.png'
],
// image to use as placeholder when urlTemplate is not in the whitelist
// if provided the http renderer will use it instead of throw an error
fallbackImage: {
type: 'fs', // 'fs' and 'url' supported
src: __dirname + '/../../assets/default-placeholder.png'
}
},
torque: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
}
}
}
// anything analyses related
,analysis: {
// batch configuration
batch: {
// Inline execution avoid the use of SQL API as batch endpoint
// When set to true it will run all analysis queries in series, with a direct connection to the DB
// This might be useful for:
// - testing
// - running an standalone server without any dependency on external services
inlineExecution: false,
// where the SQL API is running, it will use a custom Host header to specify the username.
endpoint: 'http://127.0.0.1:8080/api/v2/sql/job',
// the template to use for adding the host header in the batch api requests
hostHeaderTemplate: '{{=it.username}}.localhost.lan'
}
}
,millstone: {
// Needs to be writable by server user
cache_basedir: '/tmp/cdb-tiler-dev/millstone-dev'
}
,redis: {
host: '127.0.0.1',
port: 6379,
idleTimeoutMillis: 1,
reapIntervalMillis: 1
// Max number of connections in each pool.
// Users will be put on a queue when the limit is hit.
// Set to maxConnection to have no possible queues.
// There are currently 2 pools involved in serving
// windshaft-cartodb requests so multiply this number
// by 2 to know how many possible connections will be
// kept open by the server. The default is 50.
max: 50,
returnToHead: true, // defines the behaviour of the pool: false => queue, true => stack
idleTimeoutMillis: 1, // idle time before dropping connection
reapIntervalMillis: 1, // time between cleanups
slowQueries: {
log: true,
elapsedThreshold: 200
},
slowPool: {
log: true, // whether a slow acquire must be logged or not
elapsedThreshold: 25 // the threshold to determine an slow acquire must be reported or not
},
emitter: {
statusInterval: 5000 // time, in ms, between each status report is emitted from the pool, status is sent to statsd
},
unwatchOnRelease: false, // Send unwatch on release, see http://github.com/CartoDB/Windshaft-cartodb/issues/161
noReadyCheck: true // Check `no_ready_check` at https://github.com/mranney/node_redis/tree/v0.12.1#overloading
}
,sqlapi: {
protocol: 'http',
host: 'localhost.lan',
port: 8080,
version: 'v1'
// For more details about this options check https://nodejs.org/api/http.html#http_new_agent_options
,httpAgent: {
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 25,
maxFreeSockets: 256
}
,varnish: {
host: 'localhost',
port: 6082,
ttl: 86400
port: 6082, // the por for the telnet interface where varnish is listening to
http_port: 6081, // the port for the HTTP interface where varnish is listening to
purge_enabled: false, // whether the purge/invalidation mechanism is enabled in varnish or not
secret: 'xxx',
ttl: 86400,
layergroupTtl: 86400 // the max-age for cache-control header in layergroup responses
}
// this [OPTIONAL] configuration enables invalidating by surrogate key in fastly
,fastly: {
// whether the invalidation is enabled or not
enabled: false,
// the fastly api key
apiKey: 'wadus_api_key',
// the service that will get surrogate key invalidation
serviceId: 'wadus_service_id'
}
// If useProfiler is true every response will be served with an
// X-Tiler-Profile header containing elapsed timing for various
// steps taken for producing the response.
,useProfiler:true
// Settings for the health check available at /health
,health: {
enabled: false,
username: 'localhost',
z: 0,
x: 0,
y: 0
}
,disabled_file: 'pids/disabled'
// Use this as a feature flags enabling/disabling mechanism
,enabledFeatures: {
// whether it should intercept tile render errors an act based on them, enabled by default.
onTileErrorStrategy: true,
// whether the affected tables for a given SQL must query directly postgresql or use the SQL API
cdbQueryTablesFromPostgres: true,
// whether in mapconfig is available stats & metadata for each layer
layerMetadata: true
}
};

View File

@@ -2,34 +2,294 @@ var config = {
environment: 'production'
,port: 8181
,host: '127.0.0.1'
// Size of the threadpool which can be used to run user code and get notified in the loop thread
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
// See http://docs.libuv.org/en/latest/threadpool.html
,uv_threadpool_size: undefined
// Regular expression pattern to extract username
// from hostname. Must have a single grabbing block.
,user_from_host: '^(.*)\\.cartodb\\.com$'
// Base URLs for the APIs
//
// See http://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
//
// Base url for the Templated Maps API
// "/api/v1/map/named" is the new API,
// "/tiles/template" is for compatibility with versions up to 1.6.x
,base_url_templated: '(?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)'
// Base url for the Detached Maps API
// "maps" is the the new API,
// "tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128
// Maximum number of templates per user. Unlimited by default.
,maxUserTemplates:1024
// Seconds since "last creation" before a detached
// or template instance map expires. Or: how long do you want
// to be able to navigate the map without a reload ?
// Defaults to 7200 (2 hours)
,mapConfigTTL: 7200
// idle socket timeout, in milliseconds
,socket_timeout: 600000
,enable_cors: true
,cache_enabled: true
,log_format: '[:date] :req[X-Real-IP] \033[90m:method\033[0m \033[36m:req[Host]:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'
,log_format: ':req[X-Real-IP] :method :req[Host]:url :status :response-time ms -> :res[Content-Type] (:res[X-Tiler-Profiler])'
// If log_filename is given logs will be written
// there, in append mode. Otherwise stdout is used (default).
// Log file will be re-opened on receiving the HUP signal
,log_filename: 'logs/node-windshaft.log'
// Templated database username for authorized user
// Supported labels: 'user_id' (read from redis)
,postgres_auth_user: 'cartodb_user_<%= user_id %>'
// Templated database password for authorized user
// Supported labels: 'user_id', 'user_password' (both read from redis)
,postgres_auth_pass: '<%= user_password %>'
,postgres: {
// Parameters to pass to datasource plugin of mapnik
// See http://github.com/mapnik/mapnik/wiki/PostGIS
user: "publicuser",
password: "public",
host: '127.0.0.1',
port: 6432,
extent: "-20005048.4188,-20005048.4188,20005048.4188,20005048.4188",
simplify: true
extent: "-20037508.3,-20037508.3,20037508.3,20037508.3",
row_limit: 65535,
/*
* Set persist_connection to false if you want
* database connections to be closed on renderer
* expiration (1 minute after last use).
* Setting to true (the default) would never
* close any connection for the server's lifetime
*/
persist_connection: false,
simplify_geometries: true,
use_overviews: true, // use overviews to retrieve raster
max_size: 500
}
,mapnik_version: undefined
,mapnik_tile_format: 'png8:m=h'
,statsd: {
host: 'localhost',
port: 8125,
prefix: ':host.', // could be hostname, better not containing dots
cacheDns: true
// support all allowed node-statsd options
}
,renderer: {
// Milliseconds since last access before renderer cache item expires
cache_ttl: 60000,
statsInterval: 5000, // milliseconds between each report to statsd about number of renderers and mapnik pool status
mapnik: {
// The size of the pool of internal mapnik backend
// This pool size is per mapnik renderer created in Windshaft's RendererFactory
// See https://github.com/CartoDB/Windshaft/blob/master/lib/windshaft/renderers/renderer_factory.js
// Important: check the configuration of uv_threadpool_size to use suitable value
poolSize: 8,
// Metatile is the number of tiles-per-side that are going
// to be rendered at once. If all of them will be requested
// we'd have saved time. If only one will be used, we'd have
// wasted time.
metatile: 2,
// tilelive-mapnik uses an internal cache to store tiles/grids
// generated when using metatile. This options allow to tune
// the behaviour for that internal cache.
metatileCache: {
// Time an object must stay in the cache until is removed
ttl: 0,
// Whether an object must be removed after the first hit
// Usually you want to use `true` here when ttl>0.
deleteOnHit: false
},
// Override metatile behaviour depending on the format
formatMetatile: {
png: 2,
'grid.json': 1
},
// Buffer size is the tickness in pixel of a buffer
// around the rendered (meta?)tile.
//
// This is important for labels and other marker that overlap tile boundaries.
// Setting to 128 ensures no render artifacts.
// 64 may have artifacts but is faster.
// Less important if we can turn metatiling on.
bufferSize: 64,
// SQL queries will be wrapped with ST_SnapToGrid
// Snapping all points of the geometry to a regular grid
snapToGrid: false,
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
limits: {
// Time in milliseconds a render request can take before it fails, some notes:
// - 0 means no render limit
// - it considers metatiling, naive implementation: (render timeout) * (number of tiles in metatile)
render: 0,
// As the render request will finish even if timed out, whether it should be placed in the internal
// cache or it should be fully discarded. When placed in the internal cache another attempt to retrieve
// the same tile will result in an immediate response, however that will use a lot of more application
// memory. If we want to enforce this behaviour we have to implement a cache eviction policy for the
// internal cache.
cacheOnTimeout: true
},
geojson: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
},
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
// geometries will be simplified using ST_RemoveRepeatedPoints
// which cost is no more expensive than snapping and results are
// much closer to the original geometry
removeRepeatedPoints: false // this requires postgis >=2.2
}
},
http: {
timeout: 2000, // the timeout in ms for a http tile request
proxy: undefined, // the url for a proxy server
whitelist: [ // the whitelist of urlTemplates that can be used
'.*', // will enable any URL
'http://{s}.example.com/{z}/{x}/{y}.png'
],
// image to use as placeholder when urlTemplate is not in the whitelist
// if provided the http renderer will use it instead of throw an error
fallbackImage: {
type: 'fs', // 'fs' and 'url' supported
src: __dirname + '/../../assets/default-placeholder.png'
}
},
torque: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
}
}
}
// anything analyses related
,analysis: {
// batch configuration
batch: {
// Inline execution avoid the use of SQL API as batch endpoint
// When set to true it will run all analysis queries in series, with a direct connection to the DB
// This might be useful for:
// - testing
// - running an standalone server without any dependency on external services
inlineExecution: false,
// where the SQL API is running, it will use a custom Host header to specify the username.
endpoint: 'http://127.0.0.1:8080/api/v2/sql/job',
// the template to use for adding the host header in the batch api requests
hostHeaderTemplate: '{{=it.username}}.localhost.lan'
}
}
,millstone: {
// Needs to be writable by server user
cache_basedir: '/home/ubuntu/tile_assets/'
}
,redis: {
host: '127.0.0.1',
port: 6379
port: 6379,
// Max number of connections in each pool.
// Users will be put on a queue when the limit is hit.
// Set to maxConnection to have no possible queues.
// There are currently 2 pools involved in serving
// windshaft-cartodb requests so multiply this number
// by 2 to know how many possible connections will be
// kept open by the server. The default is 50.
max: 50,
returnToHead: true, // defines the behaviour of the pool: false => queue, true => stack
idleTimeoutMillis: 30000, // idle time before dropping connection
reapIntervalMillis: 1000, // time between cleanups
slowQueries: {
log: true,
elapsedThreshold: 200
},
slowPool: {
log: true, // whether a slow acquire must be logged or not
elapsedThreshold: 25 // the threshold to determine an slow acquire must be reported or not
},
emitter: {
statusInterval: 5000 // time, in ms, between each status report is emitted from the pool, status is sent to statsd
},
unwatchOnRelease: false, // Send unwatch on release, see http://github.com/CartoDB/Windshaft-cartodb/issues/161
noReadyCheck: true // Check `no_ready_check` at https://github.com/mranney/node_redis/tree/v0.12.1#overloading
}
,sqlapi: {
protocol: 'https',
host: 'cartodb.com',
port: 8080,
version: 'v2'
// For more details about this options check https://nodejs.org/api/http.html#http_new_agent_options
,httpAgent: {
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 25,
maxFreeSockets: 256
}
,varnish: {
host: 'localhost',
port: 6082,
ttl: 86400
port: 6082, // the por for the telnet interface where varnish is listening to
http_port: 6081, // the port for the HTTP interface where varnish is listening to
purge_enabled: false, // whether the purge/invalidation mechanism is enabled in varnish or not
secret: 'xxx',
ttl: 86400,
layergroupTtl: 86400 // the max-age for cache-control header in layergroup responses
}
// this [OPTIONAL] configuration enables invalidating by surrogate key in fastly
,fastly: {
// whether the invalidation is enabled or not
enabled: false,
// the fastly api key
apiKey: 'wadus_api_key',
// the service that will get surrogate key invalidation
serviceId: 'wadus_service_id'
}
// If useProfiler is true every response will be served with an
// X-Tiler-Profile header containing elapsed timing for various
// steps taken for producing the response.
,useProfiler:false
,serverMetadata: {
cdn_url: {
http: 'api.cartocdn.com',
https: 'cartocdn.global.ssl.fastly.net'
}
}
// Settings for the health check available at /health
,health: {
enabled: true,
username: 'localhost',
z: 0,
x: 0,
y: 0
}
,disabled_file: 'pids/disabled'
// Use this as a feature flags enabling/disabling mechanism
,enabledFeatures: {
// whether it should intercept tile render errors an act based on them, enabled by default.
onTileErrorStrategy: true,
// whether the affected tables for a given SQL must query directly postgresql or use the SQL API
cdbQueryTablesFromPostgres: true,
// whether in mapconfig is available stats & metadata for each layer
layerMetadata: false
}
};

View File

@@ -2,34 +2,294 @@ var config = {
environment: 'production'
,port: 8181
,host: '127.0.0.1'
// Size of the threadpool which can be used to run user code and get notified in the loop thread
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
// See http://docs.libuv.org/en/latest/threadpool.html
,uv_threadpool_size: undefined
// Regular expression pattern to extract username
// from hostname. Must have a single grabbing block.
,user_from_host: '^(.*)\\.cartodb\\.com$'
// Base URLs for the APIs
//
// See http://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
//
// Base url for the Templated Maps API
// "/api/v1/maps/named" is the new API,
// "/tiles/template" is for compatibility with versions up to 1.6.x
,base_url_templated: '(?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)'
// Base url for the Detached Maps API
// "/api/v1/maps" is the the new API,
// "/tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128
// Maximum number of templates per user. Unlimited by default.
,maxUserTemplates:1024
// Seconds since "last creation" before a detached
// or template instance map expires. Or: how long do you want
// to be able to navigate the map without a reload ?
// Defaults to 7200 (2 hours)
,mapConfigTTL: 7200
// idle socket timeout, in milliseconds
,socket_timeout: 600000
,enable_cors: true
,cache_enabled: true
,log_format: '[:date] :req[X-Real-IP] \033[90m:method\033[0m \033[36m:req[Host]:url\033[0m \033[90m:status :response-time ms -> :res[Content-Type]\033[0m'
,log_format: ':req[X-Real-IP] :method :req[Host]:url :status :response-time ms (:res[X-Tiler-Profiler]) -> :res[Content-Type]'
// If log_filename is given logs will be written
// there, in append mode. Otherwise stdout is used (default).
// Log file will be re-opened on receiving the HUP signal
,log_filename: 'logs/node-windshaft.log'
// Templated database username for authorized user
// Supported labels: 'user_id' (read from redis)
,postgres_auth_user: 'cartodb_staging_user_<%= user_id %>'
// Templated database password for authorized user
// Supported labels: 'user_id', 'user_password' (both read from redis)
,postgres_auth_pass: '<%= user_password %>'
,postgres: {
// Parameters to pass to datasource plugin of mapnik
// See http://github.com/mapnik/mapnik/wiki/PostGIS
user: "publicuser",
password: "public",
host: '127.0.0.1',
port: 6432,
extent: "-20005048.4188,-20005048.4188,20005048.4188,20005048.4188",
simplify: true
extent: "-20037508.3,-20037508.3,20037508.3,20037508.3",
row_limit: 65535,
simplify_geometries: true,
use_overviews: true, // use overviews to retrieve raster
/*
* Set persist_connection to false if you want
* database connections to be closed on renderer
* expiration (1 minute after last use).
* Setting to true (the default) would never
* close any connection for the server's lifetime
*/
persist_connection: false,
max_size: 500
}
,mapnik_version: undefined
,mapnik_tile_format: 'png8:m=h'
,statsd: {
host: 'localhost',
port: 8125,
prefix: 'stage.:host.',
cacheDns: true
// support all allowed node-statsd options
}
,renderer: {
// Milliseconds since last access before renderer cache item expires
cache_ttl: 60000,
statsInterval: 5000, // milliseconds between each report to statsd about number of renderers and mapnik pool status
mapnik: {
// The size of the pool of internal mapnik backend
// This pool size is per mapnik renderer created in Windshaft's RendererFactory
// See https://github.com/CartoDB/Windshaft/blob/master/lib/windshaft/renderers/renderer_factory.js
// Important: check the configuration of uv_threadpool_size to use suitable value
poolSize: 8,
// Metatile is the number of tiles-per-side that are going
// to be rendered at once. If all of them will be requested
// we'd have saved time. If only one will be used, we'd have
// wasted time.
metatile: 2,
// tilelive-mapnik uses an internal cache to store tiles/grids
// generated when using metatile. This options allow to tune
// the behaviour for that internal cache.
metatileCache: {
// Time an object must stay in the cache until is removed
ttl: 0,
// Whether an object must be removed after the first hit
// Usually you want to use `true` here when ttl>0.
deleteOnHit: false
},
// Override metatile behaviour depending on the format
formatMetatile: {
png: 2,
'grid.json': 1
},
// Buffer size is the tickness in pixel of a buffer
// around the rendered (meta?)tile.
//
// This is important for labels and other marker that overlap tile boundaries.
// Setting to 128 ensures no render artifacts.
// 64 may have artifacts but is faster.
// Less important if we can turn metatiling on.
bufferSize: 64,
// SQL queries will be wrapped with ST_SnapToGrid
// Snapping all points of the geometry to a regular grid
snapToGrid: false,
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
limits: {
// Time in milliseconds a render request can take before it fails, some notes:
// - 0 means no render limit
// - it considers metatiling, naive implementation: (render timeout) * (number of tiles in metatile)
render: 0,
// As the render request will finish even if timed out, whether it should be placed in the internal
// cache or it should be fully discarded. When placed in the internal cache another attempt to retrieve
// the same tile will result in an immediate response, however that will use a lot of more application
// memory. If we want to enforce this behaviour we have to implement a cache eviction policy for the
// internal cache.
cacheOnTimeout: true
},
geojson: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
},
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
// geometries will be simplified using ST_RemoveRepeatedPoints
// which cost is no more expensive than snapping and results are
// much closer to the original geometry
removeRepeatedPoints: false // this requires postgis >=2.2
}
},
http: {
timeout: 2000, // the timeout in ms for a http tile request
proxy: undefined, // the url for a proxy server
whitelist: [ // the whitelist of urlTemplates that can be used
'.*', // will enable any URL
'http://{s}.example.com/{z}/{x}/{y}.png'
],
// image to use as placeholder when urlTemplate is not in the whitelist
// if provided the http renderer will use it instead of throw an error
fallbackImage: {
type: 'fs', // 'fs' and 'url' supported
src: __dirname + '/../../assets/default-placeholder.png'
}
},
torque: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
}
}
}
// anything analyses related
,analysis: {
// batch configuration
batch: {
// Inline execution avoid the use of SQL API as batch endpoint
// When set to true it will run all analysis queries in series, with a direct connection to the DB
// This might be useful for:
// - testing
// - running an standalone server without any dependency on external services
inlineExecution: false,
// where the SQL API is running, it will use a custom Host header to specify the username.
endpoint: 'http://127.0.0.1:8080/api/v2/sql/job',
// the template to use for adding the host header in the batch api requests
hostHeaderTemplate: '{{=it.username}}.localhost.lan'
}
}
,millstone: {
// Needs to be writable by server user
cache_basedir: '/home/ubuntu/tile_assets/'
}
,redis: {
host: '127.0.0.1',
port: 6379
port: 6379,
// Max number of connections in each pool.
// Users will be put on a queue when the limit is hit.
// Set to maxConnection to have no possible queues.
// There are currently 2 pools involved in serving
// windshaft-cartodb requests so multiply this number
// by 2 to know how many possible connections will be
// kept open by the server. The default is 50.
max: 50,
returnToHead: true, // defines the behaviour of the pool: false => queue, true => stack
idleTimeoutMillis: 30000, // idle time before dropping connection
reapIntervalMillis: 1000, // time between cleanups
slowQueries: {
log: true,
elapsedThreshold: 200
},
slowPool: {
log: true, // whether a slow acquire must be logged or not
elapsedThreshold: 25 // the threshold to determine an slow acquire must be reported or not
},
emitter: {
statusInterval: 5000 // time, in ms, between each status report is emitted from the pool, status is sent to statsd
},
unwatchOnRelease: false, // Send unwatch on release, see http://github.com/CartoDB/Windshaft-cartodb/issues/161
noReadyCheck: true // Check `no_ready_check` at https://github.com/mranney/node_redis/tree/v0.12.1#overloading
}
,sqlapi: {
protocol: 'https',
host: 'cartodb.com',
port: 8080,
version: 'v2'
// For more details about this options check https://nodejs.org/api/http.html#http_new_agent_options
,httpAgent: {
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 25,
maxFreeSockets: 256
}
,varnish: {
host: 'localhost',
port: 6082,
ttl: 86400
port: 6082, // the por for the telnet interface where varnish is listening to
http_port: 6081, // the port for the HTTP interface where varnish is listening to
purge_enabled: false, // whether the purge/invalidation mechanism is enabled in varnish or not
secret: 'xxx',
ttl: 86400,
layergroupTtl: 86400 // the max-age for cache-control header in layergroup responses
}
// this [OPTIONAL] configuration enables invalidating by surrogate key in fastly
,fastly: {
// whether the invalidation is enabled or not
enabled: false,
// the fastly api key
apiKey: 'wadus_api_key',
// the service that will get surrogate key invalidation
serviceId: 'wadus_service_id'
}
// If useProfiler is true every response will be served with an
// X-Tiler-Profile header containing elapsed timing for various
// steps taken for producing the response.
,useProfiler:true
,serverMetadata: {
cdn_url: {
http: 'api.cartocdn.com',
https: 'cartocdn.global.ssl.fastly.net'
}
}
// Settings for the health check available at /health
,health: {
enabled: false,
username: 'localhost',
z: 0,
x: 0,
y: 0
}
,disabled_file: 'pids/disabled'
// Use this as a feature flags enabling/disabling mechanism
,enabledFeatures: {
// whether it should intercept tile render errors an act based on them, enabled by default.
onTileErrorStrategy: true,
// whether the affected tables for a given SQL must query directly postgresql or use the SQL API
cdbQueryTablesFromPostgres: true,
// whether in mapconfig is available stats & metadata for each layer
layerMetadata: true
}
};

View File

@@ -2,37 +2,289 @@ var config = {
environment: 'test'
,port: 8888
,host: '127.0.0.1'
// Size of the threadpool which can be used to run user code and get notified in the loop thread
// Its default size is 4, but it can be changed at startup time (the absolute maximum is 128).
// See http://docs.libuv.org/en/latest/threadpool.html
,uv_threadpool_size: undefined
// Regular expression pattern to extract username
// from hostname. Must have a single grabbing block.
,user_from_host: '(.*)'
// Base URLs for the APIs
//
// See https://github.com/CartoDB/Windshaft-cartodb/wiki/Unified-Map-API
//
// Base url for the Templated Maps API
// "/api/v1/map/named" is the new API,
// "/tiles/template" is for compatibility with versions up to 1.6.x
,base_url_templated: '(?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)'
// Base url for the Detached Maps API
// "maps" is the the new API,
// "tiles/layergroup" is for compatibility with versions up to 1.6.x
,base_url_detached: '(?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)'
// Maximum number of connections for one process
// 128 is a good value with a limit of 1024 open file descriptors
,maxConnections:128
// Maximum number of templates per user. Unlimited by default.
,maxUserTemplates:1024
// Seconds since "last creation" before a detached
// or template instance map expires. Or: how long do you want
// to be able to navigate the map without a reload ?
// Defaults to 7200 (2 hours)
,mapConfigTTL: 7200
// idle socket timeout, in milliseconds
,socket_timeout: 600000
,enable_cors: true
,cache_enabled: false
,log_format: '[:date] :req[X-Real-IP] :method :req[Host]:url :status :response-time ms -> :res[Content-Type]'
,postgres_auth_user: 'test_cartodb_user_<%= user_id %>'
,log_format: '[:date] :req[X-Real-IP] :method :req[Host]:url :status :response-time ms -> :res[Content-Type] (:res[X-Tiler-Profiler])'
// If log_filename is given logs will be written
// there, in append mode. Otherwise stdout is used (default).
// Log file will be re-opened on receiving the HUP signal
//,log_filename: 'logs/node-windshaft.log'
// Templated database username for authorized user
// Supported labels: 'user_id' (read from redis)
,postgres_auth_user: 'test_windshaft_cartodb_user_<%= user_id %>'
// Templated database password for authorized user
// Supported labels: 'user_id', 'user_password' (both read from redis)
,postgres_auth_pass: 'test_windshaft_cartodb_user_<%= user_id %>_pass'
,postgres: {
user: "publicuser",
// Parameters to pass to datasource plugin of mapnik
// See http://github.com/mapnik/mapnik/wiki/PostGIS
user: "test_windshaft_publicuser",
password: "public",
host: '127.0.0.1',
port: 5432,
srid: 4326,
extent: "-20005048.4188,-20005048.4188,20005048.4188,20005048.4188",
simplify: true
extent: "-20037508.3,-20037508.3,20037508.3,20037508.3",
row_limit: 65535,
simplify_geometries: true,
use_overviews: true, // use overviews to retrieve raster
/*
* Set persist_connection to false if you want
* database connections to be closed on renderer
* expiration (1 minute after last use).
* Setting to true (the default) would never
* close any connection for the server's lifetime
*/
persist_connection: false,
max_size: 500
}
,mapnik_version: ''
,mapnik_tile_format: 'png8:m=h'
,statsd: {
host: 'localhost',
port: 8125,
prefix: 'test.:host.',
cacheDns: true
// support all allowed node-statsd options
}
,renderer: {
// Milliseconds since last access before renderer cache item expires
cache_ttl: 60000,
statsInterval: 5000, // milliseconds between each report to statsd about number of renderers and mapnik pool status
mapnik: {
// The size of the pool of internal mapnik backend
// This pool size is per mapnik renderer created in Windshaft's RendererFactory
// See https://github.com/CartoDB/Windshaft/blob/master/lib/windshaft/renderers/renderer_factory.js
// Important: check the configuration of uv_threadpool_size to use suitable value
poolSize: 8,
// Metatile is the number of tiles-per-side that are going
// to be rendered at once. If all of them will be requested
// we'd have saved time. If only one will be used, we'd have
// wasted time.
metatile: 2,
// tilelive-mapnik uses an internal cache to store tiles/grids
// generated when using metatile. This options allow to tune
// the behaviour for that internal cache.
metatileCache: {
// Time an object must stay in the cache until is removed
ttl: 0,
// Whether an object must be removed after the first hit
// Usually you want to use `true` here when ttl>0.
deleteOnHit: false
},
// Override metatile behaviour depending on the format
formatMetatile: {
png: 2,
'grid.json': 1
},
// Buffer size is the tickness in pixel of a buffer
// around the rendered (meta?)tile.
//
// This is important for labels and other marker that overlap tile boundaries.
// Setting to 128 ensures no render artifacts.
// 64 may have artifacts but is faster.
// Less important if we can turn metatiling on.
bufferSize: 64,
// SQL queries will be wrapped with ST_SnapToGrid
// Snapping all points of the geometry to a regular grid
snapToGrid: false,
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
limits: {
// Time in milliseconds a render request can take before it fails, some notes:
// - 0 means no render limit
// - it considers metatiling, naive implementation: (render timeout) * (number of tiles in metatile)
render: 0,
// As the render request will finish even if timed out, whether it should be placed in the internal
// cache or it should be fully discarded. When placed in the internal cache another attempt to retrieve
// the same tile will result in an immediate response, however that will use a lot of more application
// memory. If we want to enforce this behaviour we have to implement a cache eviction policy for the
// internal cache.
cacheOnTimeout: true
},
geojson: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
},
// SQL queries will be wrapped with ST_ClipByBox2D
// Returning the portion of a geometry falling within a rectangle
// It will only work if snapToGrid is enabled
clipByBox2d: false, // this requires postgis >=2.2 and geos >=3.5
// geometries will be simplified using ST_RemoveRepeatedPoints
// which cost is no more expensive than snapping and results are
// much closer to the original geometry
removeRepeatedPoints: false // this requires postgis >=2.2
}
},
http: {
timeout: 2000, // the timeout in ms for a http tile request
proxy: undefined, // the url for a proxy server
whitelist: [ // the whitelist of urlTemplates that can be used
'.*', // will enable any URL
'http://{s}.example.com/{z}/{x}/{y}.png',
// for testing purposes
'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png'
],
// image to use as placeholder when urlTemplate is not in the whitelist
// if provided the http renderer will use it instead of throw an error
fallbackImage: {
type: 'fs', // 'fs' and 'url' supported
src: __dirname + '/../../assets/default-placeholder.png'
}
},
torque: {
dbPoolParams: {
// maximum number of resources to create at any given time
size: 16,
// max milliseconds a resource can go unused before it should be destroyed
idleTimeout: 3000,
// frequency to check for idle resources
reapInterval: 1000
}
}
}
// anything analyses related
,analysis: {
// batch configuration
batch: {
// Inline execution avoid the use of SQL API as batch endpoint
// When set to true it will run all analysis queries in series, with a direct connection to the DB
// This might be useful for:
// - testing
// - running an standalone server without any dependency on external services
inlineExecution: true,
// where the SQL API is running, it will use a custom Host header to specify the username.
endpoint: 'http://127.0.0.1:8080/api/v2/sql/job',
// the template to use for adding the host header in the batch api requests
hostHeaderTemplate: '{{=it.username}}.localhost.lan'
}
}
,millstone: {
// Needs to be writable by server user
cache_basedir: '/tmp/cdb-tiler-test/millstone'
}
,redis: {
host: '127.0.0.1',
port: 6333,
idleTimeoutMillis: 1,
reapIntervalMillis: 1
port: 6335,
// Max number of connections in each pool.
// Users will be put on a queue when the limit is hit.
// Set to maxConnection to have no possible queues.
// There are currently 2 pools involved in serving
// windshaft-cartodb requests so multiply this number
// by 2 to know how many possible connections will be
// kept open by the server. The default is 50.
max: 50,
returnToHead: true, // defines the behaviour of the pool: false => queue, true => stack
idleTimeoutMillis: 1, // idle time before dropping connection
reapIntervalMillis: 1, // time between cleanups
slowQueries: {
log: true,
elapsedThreshold: 200
},
slowPool: {
log: true, // whether a slow acquire must be logged or not
elapsedThreshold: 25 // the threshold to determine an slow acquire must be reported or not
},
emitter: {
statusInterval: 5000 // time, in ms, between each status report is emitted from the pool, status is sent to statsd
},
unwatchOnRelease: false, // Send unwatch on release, see http://github.com/CartoDB/Windshaft-cartodb/issues/161
noReadyCheck: true // Check `no_ready_check` at https://github.com/mranney/node_redis/tree/v0.12.1#overloading
}
,sqlapi: {
protocol: 'http',
host: 'localhost.lan',
port: 8080,
version: 'v1'
// For more details about this options check https://nodejs.org/api/http.html#http_new_agent_options
,httpAgent: {
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 25,
maxFreeSockets: 256
}
,varnish: {
host: '',
port: null,
ttl: 86400
port: null, // the por for the telnet interface where varnish is listening to
http_port: 6081, // the port for the HTTP interface where varnish is listening to
purge_enabled: false, // whether the purge/invalidation mechanism is enabled in varnish or not
secret: 'xxx',
ttl: 86400,
layergroupTtl: 86400 // the max-age for cache-control header in layergroup responses
}
// this [OPTIONAL] configuration enables invalidating by surrogate key in fastly
,fastly: {
// whether the invalidation is enabled or not
enabled: false,
// the fastly api key
apiKey: 'wadus_api_key',
// the service that will get surrogate key invalidation
serviceId: 'wadus_service_id'
}
// If useProfiler is true every response will be served with an
// X-Tiler-Profile header containing elapsed timing for various
// steps taken for producing the response.
,useProfiler:true
// Settings for the health check available at /health
,health: {
enabled: false,
username: 'localhost',
z: 0,
x: 0,
y: 0
}
,disabled_file: 'pids/disabled'
// Use this as a feature flags enabling/disabling mechanism
,enabledFeatures: {
// whether it should intercept tile render errors an act based on them, enabled by default.
onTileErrorStrategy: true,
// whether the affected tables for a given SQL must query directly postgresql or use the SQL API
cdbQueryTablesFromPostgres: true,
// whether in mapconfig is available stats & metadata for each layer
layerMetadata: true
}
};

View File

@@ -1 +0,0 @@
module.exports.oneDay = 86400000;

56
configure vendored
View File

@@ -17,16 +17,24 @@
# --strk(2012-07-23)
#
ENVDIR=config/environments
PGPORT=
MAPNIK_VERSION=
ENVIRONMENT=development
STATUS="$0 $*"
usage() {
echo "Usage: $0 [OPTION]"
echo
echo "Configuration:"
echo " --help display this help and exit"
echo " --with-pgport=NUM access PostgreSQL server on TCP port NUM"
echo " --help display this help and exit"
echo " --with-pgport=NUM access PostgreSQL server on TCP port NUM [$PGPORT]"
echo " --with-mapnik-version=STRING set mapnik version string [$MAPNIK_VERSION]"
echo " --environment=STRING set output environment name [$ENVIRONMENT]"
}
PGPORT=5432
while test -n "$1"; do
case "$1" in
--help|-h)
@@ -36,20 +44,38 @@ while test -n "$1"; do
--with-pgport=*)
PGPORT=`echo "$1" | cut -d= -f2`
;;
--with-mapnik-version=*)
MAPNIK_VERSION=`echo "$1" | cut -d= -f2`
;;
--environment=*)
ENVIRONMENT=`echo "$1" | cut -d= -f2`
;;
*)
echo "Unknown option '$1'" >&2
usage >&2
exit 1
echo "Unused option '$1'" >&2
;;
esac
shift
done
echo "PGPORT: $PGPORT"
ENVEX=./${ENVDIR}/${ENVIRONMENT}.js.example
if [ -z "$PGPORT" ]; then
PGPORT=`node -e "console.log(require('${ENVEX}').postgres.port)"`
fi
echo "PGPORT: $PGPORT"
echo "MAPNIK_VERSION: $MAPNIK_VERSION"
echo "ENVIRONMENT: $ENVIRONMENT"
o=`dirname "${ENVEX}"`/`basename "${ENVEX}" .example`
echo "Writing $o"
# See http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/
sed -n "1h;1!H;\${;g;s/\(,postgres: {[^}]*port: *'\?\)[^',]*\('\?,\)/\1$PGPORT\2/;p;}" < "${ENVEX}" \
| sed "s/mapnik_version:.*/mapnik_version: '$MAPNIK_VERSION'/" \
> "$o"
STATUSFILE=config.status--${ENVIRONMENT}
echo "Writing ${STATUSFILE}"
echo ${STATUS} > ${STATUSFILE} && chmod +x ${STATUSFILE}
# TODO: allow specifying configuration settings !
for f in config/environments/*.example; do
o=`dirname "$f"`/`basename "$f" .example`
echo "Writing $o"
# See http://austinmatzko.com/2008/04/26/sed-multi-line-search-and-replace/
sed -n "1h;1!H;\${;g;s/\(,postgres: {[^}]*port: *'\?\)[^',]*\('\?,\)/\1$PGPORT\2/;p;}" < "$f" > "$o"
done

19
docs/Map-API.md Normal file
View File

@@ -0,0 +1,19 @@
# Maps API
The CartoDB Maps API allows you to generate maps based on data hosted in your CartoDB account and apply custom SQL and CartoCSS to the data. The API generates a XYZ-based URL to fetch Web Mercator projected tiles, using web clients such as [Leaflet](http://leafletjs.com), [Google Maps](https://developers.google.com/maps/), or [OpenLayers](http://openlayers.org/).
You can create two types of maps with the Maps API:
- **Anonymous Maps**
You can create maps using your CartoDB public data. Any client can change the read-only SQL and CartoCSS parameters that generate the map tiles. These maps can be created from a JavaScript application alone and no authenticated calls are needed. See [this CartoDB.js example](/cartodb-platform/cartodb-js/getting-started/).
- **Named Maps**
There are also maps that have access to your private data. These maps require an owner to setup and modify any SQL and CartoCSS parameters and are not modifiable without new setup calls.
## Documentation
* [Quickstart](quickstart.md)
* [General Concepts](general_concepts.md)
* [Anonymous Maps](anonymous_maps.md)
* [Named Maps](named_maps.md)
* [Static Maps API](static_maps_api.md)

View File

@@ -0,0 +1,93 @@
# 1. Purpose
This specification describes an extension for
[MapConfig 1.4.0](https://github.com/CartoDB/Windshaft/blob/master/doc/MapConfig-1.4.0.md) version.
# 2. Changes over specification
This extension targets layers with `sql` option, including layer types: `cartodb`, `mapnik`, and `torque`.
It extends MapConfig with a new attribute: `analyses`.
## 2.1 Analyses attribute
The new analyses attribute must be an array of analyses as per [camshaft](https://github.com/CartoDB/camshaft). Each
analysis must adhere to the [camshaft-reference](https://github.com/CartoDB/camshaft/blob/0.8.0/reference/versions/0.7.0/reference.json) specification.
Each node can have an id that can be later references to consume the query from MapConfig's layers.
Basic analyses example:
```javascript
[
{
// REQUIRED
// string, `id` free identifier that can be reference from any layer
"id": "HEAD",
// REQUIRED
// string, `type` camshaft's analysis type
"type": "source",
// REQUIRED
// object, `params` will depend on `type`, check camshaft-reference for more information
"params": {
"query": "select * from your_table"
}
}
]
```
# 2.2. Integration with layers
As pointed before an analysis node id can be referenced from layers to consume its output query.
The layer consuming the output must reference it with the following option:
```
{
"options": {
// REQUIRED
// object, `source` as in the future we might want to have other source options
"source": {
// REQUIRED
// string, `id` the analysis node identifier
"id": "HEAD"
}
}
}
```
## 2.3. Complete example
```
{
"version": "1.4.0",
"layers": [
{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
},
"cartocss": "...",
"cartocss_version": "2.3.0"
}
}
],
"analyses": [
{
"id": "HEAD",
"type": "source",
"params": {
"query": "select * from your_table"
}
}
]
}
```
# History
## 1.0.0
- Initial version

View File

@@ -0,0 +1,314 @@
# 1. Purpose
This specification describes an extension for
[MapConfig 1.4.0](https://github.com/CartoDB/Windshaft/blob/master/doc/MapConfig-1.4.0.md) version.
# 2. Changes over specification
This extension depends on Analyses extension. It extends MapConfig with a new attribute: `dataviews`.
It makes possible to get tabular data from analysis nodes: lists, aggregated lists, aggregations, and histograms.
## 2.1. Dataview types
### List
A list is a simple result set per row where is possible to retrieve several columns from the original layer query.
Definition
```
{
// REQUIRED
// string, `type` the list type
“type”: “list”,
// REQUIRED
// object, `options` dataview params
“options”: {
// REQUIRED
// array, `columns` to select for the list
“columns”: [“name”, “description”]
}
}
```
Expected output
```
{
"type": "list",
"rows": [
{
"{columnName1}": "val1",
"{columnName2}": 100
},
{
"{columnName1}": "val2",
"{columnName2}": 200
}
]
}
```
### Aggregation
An aggregation is very similar to a list but results are aggregated by a column and a given aggregation function.
Definition
```
{
// REQUIRED
// string, `type` the aggregation type
“type”: “aggregation”,
// REQUIRED
// object, `options` dataview params
“options”: {
// REQUIRED
// string, `column` column name to aggregate by
“column”: “country”,
// REQUIRED
// string, `aggregation` operation to perform
“aggregation”: “count”
// OPTIONAL
// string, `aggregationColumn` column value to aggregate
// This param is required when `aggregation` is different than "count"
“aggregationColumn”: “population”
}
}
```
Expected output
```
{
"type": "aggregation",
"categories": [
{
"category": "foo",
"value": 100
},
{
"category": "bar",
"value": 200
}
]
}
```
### Histograms
Histograms represent the data distribution for a column.
Definition
```
{
// REQUIRED
// string, `type` the histogram type
“type”: “histogram”,
// REQUIRED
// object, `options` dataview params
“options”: {
// REQUIRED
// string, `column` column name to aggregate by
“column”: “name”,
// OPTIONAL
// number, `bins` how many buckets the histogram should use
“bins”: 10
}
}
```
Expected output
```
{
"type": "histogram",
"bins": [{"bin": 0, "start": 2, "end": 2, "min": 2, "max": 2, "freq": 1}, null, null, {"bin": 3, "min": 40, "max": 44, "freq": 2}, null],
"width": 10
}
```
### Formula
Formulas given a final value representing the whole dataset.
Definition
```
{
// REQUIRED
// string, `type` the formula type
“type”: “formula”,
// REQUIRED
// object, `options` dataview params
“options”: {
// REQUIRED
// string, `column` column name to aggregate by
“column”: “name”,
// REQUIRED
// string, `aggregation` operation to perform
“operation”: “count”
}
}
```
Operation must be: “min”, “max”, “count”, “avg”, or “sum”.
Result
```
{
"type": "formula",
"operation": "count",
"result": 1000,
"nulls": 0
}
```
## 2.2 Dataviews attribute
The new dataviews attribute must be a dictionary of dataviews.
An analysis node id can be referenced from dataviews to consume its output query.
The layer consuming the output must reference it with the following option:
```
{
// REQUIRED
// object, `source` as in the future we might want to have other source options
"source": {
// REQUIRED
// string, `id` the analysis node identifier
"id": "HEAD"
}
}
```
## 2.3. Complete example
```
{
"version": "1.4.0",
"layers": [
{
"type": "cartodb",
"options": {
"source": {
"id": "HEAD"
},
"cartocss": "...",
"cartocss_version": "2.3.0"
}
}
],
"dataviews" {
"basic_histogram": {
"source": {
"id": "HEAD"
},
"type": "histogram",
"options": {
"column": "pop_max"
}
}
},
"analyses": [
{
"id": "HEAD",
"type": "source",
"params": {
"query": "select * from your_table"
}
}
]
}
```
## 3. Filters
Camshaft's analyses expose a filtering capability and `aggregation` and `histogram` dataviews get them for free with
this extension. Filters are available with the very dataview id, so if you have a "basic_histogram" histogram dataview
you can filter with a range filter with "basic_histogram" name.
## 3.1 Filter types
### Category
Allows to remove results that are not contained within a set of elements.
Initially this filter can be applied to a `numeric` or `text` columns.
Params
```
{
“accept”: [“Spain”, “Germany”]
“reject”: [“Japan”]
}
```
### Range filter
Allows to remove results that dont satisfy numeric min and max values.
Filter is applied to a numeric column.
Params
```
{
“min”: 0,
“max”: 1000
}
```
## 3.2. How to apply filters
Filters must be applied at map instantiation time.
With :mapconfig as a valid MapConfig and with :filters (a valid JSON) as:
### Anonymous map
`GET /api/v1/map?config=:mapconfig&filters=:filters`
`POST /api/v1/map?filters=:filters`
with `BODY=:mapconfig`
If in the future we need to support a bigger filters param and it doesnt fit in the query string,
we might solve it by accepting:
`POST /api/v1/map`
with `BODY={“config”: :mapconfig, “filters”: :filters}`
### Named map
Assume :params (a valid JSON) as named maps params, like in: `{“color”: “red”}`
`GET /api/v1/named/:name/jsonp?config=:params&filters=:filters&callback=cb`
`POST /api/v1/named/:name?filters=:filters`
with `BODY=:params`
If, again, in the future we need to support a bigger filters param that doesnt fit in the query string,
we might solve it by accepting:
`POST /api/v1/named/:name`
with `BODY={“config”: :params, “filters”: :filters}`
## 3.3 Bounding box special filter
A bounding box filter allows to remove results that dont satisfy a geospatial range.
The bounding box special filter is available per dataview and there is no need to create a bounding box definition as
its always possible to apply a bbox filter per dataview.
A dataview can get its result filtered by bounding box by sending a bbox param in the query string,
param must be in the form `west,south,east,north`.
So applying a bbox filter to a dataview looks like:
GET /api/v1/map/:layergroupid/dataview/:dataview_name?bbox=-90,-45,90,45
# History
## 1.0.0-alpha
- WIP document

View File

@@ -0,0 +1,56 @@
# 1. Purpose
This specification describes an extension for
[MapConfig 1.3.0](https://github.com/CartoDB/Windshaft/blob/master/doc/MapConfig-1.3.0.md) version.
# 2. Changes over specification
This extension introduces a new layer type so it's possible to use a Named Map by its name as a layer.
## 2.1 Named layers definition
```javascript
{
// REQUIRED
// string, `named` is the only supported value
type: "named",
// REQUIRED
// object, set `named` map layers configuration
options: {
// REQUIRED
// string, the name for the Named Map to use
name: "world_borders",
// OPTIONAL
// object, the replacement values for the Named Map's template placeholders
// See https://github.com/CartoDB/Windshaft-cartodb/blob/master/docs/Map-API.md#instantiate-1 for more details
config: {
"color": "#000"
},
// OPTIONAL
// string array, the authorized tokens in case the Named Map has auth method set to `token`
// See https://github.com/CartoDB/Windshaft-cartodb/blob/master/docs/Map-API.md#named-maps-1 for more details
auth_tokens: [
"token1",
"token2"
]
}
}
```
## 2.2 Limitations
1. A Named Map will not allow to have `named` type layers inside their templates layergroup's layers definition.
2. A `named` layer does not allow Named Maps form other accounts, it's only possible to use Named Maps from the very
same user account.
# History
## 1.0.0
- Initial version

28
docs/MultiLayer-API.md Normal file
View File

@@ -0,0 +1,28 @@
The Windshaft-CartoDB MultiLayer API extends the [Windshaft MultiLayer API](https://github.com/CartoDB/Windshaft/blob/master/doc/Multilayer-API.md) in a few ways.
## Last modification timestamp embedded in the token
It encodes a timestamp of 'last modification time' into the map token (token:EPOCH) returned to the client.
It accepts tokens with encoded timestamp from the client considering the token suffix as a cache_buster value.
Clients don't need to be aware of the extension but rather use the API as they would use the base one.
The only difference will be that the _same_ layergroup configuration may result in different tokens if source data was modified between the mapview requests.
## Additional attributes in the response object
Windshaft-CartoDB adds the following attributes in the response object
- ``last_update`` field with ISO format (2013-11-30T12:23:10).
- ``cdn_url`` object containing CDN url client should use (not mandatory) to access the tiles. It's in the form:
```json
{
"http": "http://cdn_url.com/",
"https": "https://secure.cdn_url.com/"
}
```
## Stats tag
Windshaft-CartoDB adds support for a ``stat_tag`` element in the multilayer configuration to help [stats](https://github.com/CartoDB/Windshaft-cartodb/wiki/Redis-stats-format) gathering.

114
docs/Routes.md Normal file
View File

@@ -0,0 +1,114 @@
This document list all routes available in Windshaft-cartodb Maps API server.
## Routes list
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/:token/:z/:x/:y@:scale_factor?x.:format {:user(f),:token(f),:z(f),:x(f),:y(f),:scale_factor(t),:format(f)} (1)`
<br/>Notes: Mapnik retina tiles [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/:token/:z/:x/:y.:format {:user(f),:token(f),:z(f),:x(f),:y(f),:format(f)} (1)`
<br/>Notes: Mapnik tiles [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/:token/:layer/:z/:x/:y.(:format) {:user(f),:token(f),:layer(f),:z(f),:x(f),:y(f),:format(f)} (1)`
<br/>Notes: Per :layer rendering based on :format [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/:token/:layer/attributes/:fid {:user(f),:token(f),:layer(f),:fid(f)} (1)`
<br/>Notes: Endpoint for info windows data, alternative for sql api when tables are private [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/static/center/:token/:z/:lat/:lng/:width/:height.:format {:user(f),:token(f),:z(f),:lat(f),:lng(f),:width(f),:height(f),:format(f)} (1)`
<br/>Notes: Static Maps API [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format {:user(f),:token(f),:west(f),:south(f),:east(f),:north(f),:width(f),:height(f),:format(f)} (1)`
<br/>Notes: Static Maps API [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/:token/:layer/widget/:widgetName {:user(f),:token(f),:layer(f),:widgetName(f)} (1)`
<br/>Notes: By :widgetName per :layer widget [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/:token/:layer/widget/:widgetName/search {:user(f),:token(f),:layer(f),:widgetName(f)} (1)`
<br/>Notes: By :widgetName per :layer widget search [0]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup) {:user(f)} (1)`
<br/>Notes: Map instantiation [0]
1. `POST (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup) {:user(f)} (1)`
<br/>Notes: Map instantiation [0]
1. `GET (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)/:template_id/jsonp {:user(f),:template_id(f)} (1)`
<br/>Notes: Named maps JSONP instantiation [1]
1. `POST (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)/:template_id {:user(f),:template_id(f)} (1)`
<br/>Notes: Instantiate named map [1]
1. `OPTIONS (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup) {:user(f)} (1)`
<br/>Notes: CORS [0]
1. `GET (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)/:template_id/:layer/:z/:x/:y.(:format) {:user(f),:template_id(f),:layer(f),:z(f),:x(f),:y(f),:0(f),:format(f)} (1)`
<br/>Notes: Per :layer fixed URL named map tiles [1]
1. `GET (?:/api/v1/map|/user/:user/api/v1/map|/tiles/layergroup)/static/named/:template_id/:width/:height.:format {:user(f),:template_id(f),:width(f),:height(f),:format(f)} (1)`
<br/>Notes: Static map for named maps [1]
1. `POST (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template) {:user(f)} (1)`
<br/>Notes: Create named map (w/ API KEY) [1]
1. `PUT (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)/:template_id {:user(f),:template_id(f)} (1)`
<br/>Notes: Update a named map (w/ API KEY) [1]
1. `GET (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)/:template_id {:user(f),:template_id(f)} (1)`
<br/>Notes: Named map retrieval (w/ API KEY) [1]
1. `DELETE (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)/:template_id {:user(f),:template_id(f)} (1)`
<br/>Notes: Delete named map (w/ API KEY) [1]
1. `GET (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template) {:user(f)} (1)`
<br/>Notes: List named maps (w/ API KEY) [1]
1. `OPTIONS (?:/api/v1/map/named|/user/:user/api/v1/map/named|/tiles/template)/:template_id {:user(f),:template_id(f)} (1)`
<br/>Notes: CORS [1]
1. `GET /health {} (1)`
<br/>Notes: Health check
1. `GET / {} (1)`
<br/>Notes: Welcome message
1. `GET /version {} (1)`
<br/>Notes: Return relevant module versions: mapnik, grainstore, etc
## Optional deprecated routes
- [0] `/tiles/layergroup` is deprecated and `/api/v1/map` should be used but we keep it for now.
- [1] `/tiles/template` is deprecated and `/api/v1/map/named` should be used but we keep it for now.
## How to generate the list of routes
Something like the following patch should do the trick
```javascript
diff --git a/lib/cartodb/server.js b/lib/cartodb/server.js
index 5f62850..bca377d 100644
--- a/lib/cartodb/server.js
+++ b/lib/cartodb/server.js
@@ -215,6 +215,20 @@ module.exports = function(serverOptions) {
* END Routing
******************************************************************************************************************/
+ var format = require('util').format;
+ var routesNotes = app._router.stack
+ .filter(function(handler) { return !!handler.route; })
+ .map(function(handler) {
+ return format("\n1. `%s %s {%s} (1)`\n<br/>Notes: [DEPRECATED]? ",
+ Object.keys(handler.route.methods)[0].toUpperCase(),
+ handler.route.path,
+ handler.keys.map(function(k) {
+ return format(':%s(%s)', k.name, k.optional ? 't' : 'f');
+ }).join(',')
+ );
+ });
+ console.log(routesNotes.join('\n'));
+
return app;
};
```

194
docs/anonymous_maps.md Normal file
View File

@@ -0,0 +1,194 @@
# Anonymous Maps
Anonymous Maps allows you to instantiate a map given SQL and CartoCSS. It also allows you to add interaction capabilities using [UTF Grid.](https://github.com/mapbox/utfgrid-spec)
## Instantiate
#### Definition
```html
POST /api/v1/map
```
#### Params
```javascript
{
"version": "1.3.0",
"layers": [{
"type": "mapnik",
"options": {
"cartocss_version": "2.1.1",
"cartocss": "#layer { polygon-fill: #FFF; }",
"sql": "select * from european_countries_e",
"interactivity": ["cartodb_id", "iso3"]
}
}]
}
```
See [MapConfig File Formats](http://docs.cartodb.com/cartodb-platform/maps-api/mapconfig/) for details.
#### Response
The response includes:
Attributes | Description
--- | ---
layergroupid | The ID for that map, used to compose the URL for the tiles. The final URL is: `https://{username}.cartodb.com/api/v1/map/{layergroupid}/{z}/{x}/{y}.png`
updated_at | The ISO date of the last time the data involved in the query was updated.
metadata | Includes information about the layers.
cdn_url | URLs to fetch the data using the best CDN for your zone.
### Example
#### Call
```bash
curl 'https://{username}.cartodb.com/api/v1/map' -H 'Content-Type: application/json' -d @mapconfig.json
```
#### Response
```javascript
{
"layergroupid": "c01a54877c62831bb51720263f91fb33:0",
"last_updated": "1970-01-01T00:00:00.000Z",
"metadata": {
"layers": [
{
"type": "mapnik",
"meta": {}
}
]
},
"cdn_url": {
"http": "http://cdb.com",
"https": "https://cdb.com"
}
}
```
### Retrieve resources from the layergroup
When you have a layergroup, there are several resources for retrieving layergoup details such as, accessing Mapnik tiles, getting individual layers, accessing defined Attributes, and blending and layer selection.
#### Mapnik tiles
These tiles will get just the Mapnik layers. To get individual layers, see the following section.
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/{z}/{x}/{y}.png
```
#### Individual layers
The MapConfig specification holds the layers definition in a 0-based index. Layers can be requested individually in different formats depending on the layer type.
Individual layers can be accessed using that 0-based index. For UTF grid tiles:
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/{layer}/{z}/{x}/{y}.grid.json
```
In this case, `layer` as 0 returns the UTF grid tiles/attributes for layer 0, the only layer in the example MapConfig.
If the MapConfig had a Torque layer at index 1 it could be possible to request it with:
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/1/{z}/{x}/{y}.torque.json
```
#### Attributes defined in `attributes` section
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/{layer}/attributes/{feature_id}
```
Which returns JSON with the attributes defined, like:
```javascript
{ "c": 1, "d": 2 }
```
#### Blending and layer selection
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/{layer_filter}/{z}/{x}/{y}.png
```
Note: currently format is limited to `png`.
`layer_filter` can be used to select some layers to be rendered together. `layer_filter` supports two formats:
- `all` alias
Using `all` as `layer_filter` will blend all layers in the layergroup
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/all/{z}/{x}/{y}.png
```
- Filter by layer index
A list of comma separated layer indexes can be used to just render a subset of layers. For example `0,3,4` will filter and blend layers with indexes 0, 3, and 4.
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/0,3,4/{z}/{x}/{y}.png
```
Some notes about filtering:
- Invalid index values or out of bounds indexes will end in `Invalid layer filtering` errors.
- Once a Mapnik layer is selected, all Mapnik layers will get blended. As this may change in the future **it is
recommended** to always select all Mapnik layers if you want to select at least one so you will get a consistent
behavior in the future.
- Ordering is not considered. So right now filtering layers 0,3,4 is the very same thing as filtering 3,4,0. As this
may change in the future **it is recommended** to always select the layers in ascending order so you will get a
consistent behavior in the future.
## Create JSONP
The JSONP endpoint is provided in order to allow web browsers access which don't support CORS.
#### Definition
```bash
GET /api/v1/map?callback=method
```
#### Params
Param | Description
--- | ---
config | Encoded JSON with the params for creating Named Maps (the variables defined in the template).
lmza | This attribute contains the same as config but LZMA compressed. It cannot be used at the same time as `config`.
callback | JSON callback name.
### Example
#### Call
```bash
curl "https://{username}.cartodb.com/api/v1/map?callback=callback&config=%7B%22version%22%3A%221.0.1%22%2C%22layers%22%3A%5B%7B%22type%22%3A%22cartodb%22%2C%22options%22%3A%7B%22sql%22%3A%22select+%2A+from+european_countries_e%22%2C%22cartocss%22%3A%22%23european_countries_e%7B+polygon-fill%3A+%23FF6600%3B+%7D%22%2C%22cartocss_version%22%3A%222.3.0%22%2C%22interactivity%22%3A%5B%22cartodb_id%22%5D%7D%7D%5D%7D"
```
#### Response
```javascript
callback({
layergroupid: "d9034c133262dfb90285cea26c5c7ad7:0",
cdn_url: {
"http": "http://cdb.com",
"https": "https://cdb.com"
},
last_updated: "1970-01-01T00:00:00.000Z"
})
```
## Remove
Anonymous Maps cannot be removed by an API call. They will expire after about five minutes, or sometimes longer. If an Anonymous Map expires and tiles are requested from it, an error will be raised. This could happen if a user leaves a map open and after time, returns to the map and attempts to interact with it in a way that requires new tiles (e.g. zoom). The client will need to go through the steps of creating the map again to fix the problem.

27
docs/general_concepts.md Normal file
View File

@@ -0,0 +1,27 @@
# General Concepts
The following concepts are the same for every endpoint in the API except when it's noted explicitly.
## Auth
By default, users do not have access to private tables in CartoDB. In order to instantiate a map from private table data an API Key is required. Additionally, to include some endpoints, an API Key must be included (e.g. creating a Named Map).
To execute an authorized request, `api_key=YOURAPIKEY` should be added to the request URL. The param can be also passed as POST param. Using HTTPS is mandatory when you are performing requests that include your `api_key`.
## Errors
Errors are reported using standard HTTP codes and extended information encoded in JSON with this format:
```javascript
{
"errors": [
"access forbidden to table TABLE"
]
}
```
If you use JSONP, the 200 HTTP code is always returned so the JavaScript client can receive errors from the JSON object.
## CORS support
All the endpoints, which might be accessed using a web browser, add CORS headers and allow OPTIONS method.

42
docs/metrics.md Normal file
View File

@@ -0,0 +1,42 @@
Windshaft-cartodb metrics
=========================
See [Windshaft metrics documentation](https://github.com/CartoDB/Windshaft/blob/master/doc/metrics.md) to understand the full picture.
The next list includes the API endpoints, each endpoint may have several inner timers, some of them are displayed within this list as subitems. Find the description for them in the Inner timers section.
## Timers
- **windshaft-cartodb.flush_cache**: time to flush the tile and sql cache
- **windshaft-cartodb.get_template**: time to retrieve an specific template
- **windshaft-cartodb.delete_template**: time to delete an specific template
- **windshaft-cartodb.get_template_list**: time to retrieve the list of owned templates
- **windshaft-cartodb.instance_template_post**: time to create a template via HTTP POST
- **windshaft-cartodb.instance_template_get**: time to create a template via HTTP GET
+ TemplateMaps_instance
+ createLayergroup
There are some endpoints that are not being tracked:
- Adding a template
- Updating a template
### Inner timers
Again, each inner timer may have several inner timers.
- **addCacheChannel**: time to add X-Cache-Channel header based on table last modifications
- **LZMA decompress**: time to decompress request params with LZMA
- **TemplateMaps_instance**: time to retrieve a map template instance, see *getTemplate* and *authorizedByCert*
- **affectedTables**: time to check what are the affected tables for adding the cache channel, see *addCacheChannel*
- **authorize**: time to authorize a request, see *authorizedByAPIKey*, *authorizedByCert*, *authorizedBySigner*
- **authorizedByCert**: time to authorize a template instantiation
- **findLastUpdated**: time to retrieve the last update time for a list of tables, see *affectedTables*
- **generateCacheChannel**: time to generate the headers for the cache channel based on the request, see *addCacheChannel*
- **getSignerMapKey**: time to retrieve from redis the authorized user for a template map
- **getTablePrivacy**: time to retrieve from redis the privacy of a table
- **getTemplate**: time to retrieve from redis the template for a map
- **getUserMapKey**: time to retrieve from redis the user key for a map
- **incMapviewCount**: time to incremenent in redis the map views
- **mapStore_load**: time to retrieve from redis a map configuration
- **req2params.setup**: time to prepare the params from a request, see *req2params* in Windshaft documentation
- **setDBAuth**: time to retrieve from redis and set db user and db password from a user
- **setDBConn**: time to retrieve from redis and set db host and db name from a user
- **setDBParams**: time to prepare all db params to be able to connect/query a database, see *setDBAuth* and *setDBConn*
- **tablePrivacy_getUserDBName**: time to retrieve from redis the database for a user

564
docs/named_maps.md Normal file
View File

@@ -0,0 +1,564 @@
# Named Maps
Named Maps are essentially the same as Anonymous Maps except the MapConfig is stored on the server, and the map is given a unique name. You can create Named Maps from private data, and users without an API Key can view your Named Map (while keeping your data private).
The Named Map workflow consists of uploading a MapConfig file to CartoDB servers, to select data from your CartoDB user database by using SQL, and specifying the CartoCSS for your map.
The response back from the API provides the template_id of your Named Map as the `name` (the identifier of your Named Map), which is the name that you specified in the MapConfig. You can which you can then use to create your Named Map details, or [fetch XYZ tiles](#fetching-xyz-tiles-for-named-maps) directly for Named Maps.
**Tip:** You can also use a Named Map that you created (which is defined by its `name`), to create a map using CartoDB.js. This is achieved by adding the [`namedmap` type](http://docs.cartodb.com/cartodb-platform/cartodb-js/layer-source-object/#named-maps-layer-source-object-type-namedmap) layer source object to draw the Named Map.
The main differences, compared to Anonymous Maps, is that Named Maps include:
- **auth token**
This allows you to control who is able to see the map based on an auth token, and create a secure Named Map with password-protection.
- **template map**
The template map is static and may contain placeholders, enabling you to modify your maps appearance by using variables. Templates maps are persistent with no preset expiration. They can only be created, or deleted, by a CartoDB user with a valid API KEY (See [auth argument](#arguments)).
Uploading a MapConfig creates a Named Map. MapConfigs are uploaded to the server by sending the server a "template".json file, which contain the [MapConfig specifications](http://docs.cartodb.com/cartodb-platform/maps-api/mapconfig/).
**Note:** There is a limit of 4,096 Named Maps allowed per account. If you need to create more Named Maps, it is recommended to use a single Named Map and change the variables using [placeholders](#placeholder-format), instead of uploading multiple [Named Map MapConfigs](http://docs.cartodb.com/cartodb-platform/maps-api/mapconfig/#named-map-layer-options).
## Create
#### Definition
```html
POST /api/v1/map/named
```
#### Params
Params | Description
--- | ---
api_key | is required
MapConfig | a [Named Map MapConfig](http://docs.cartodb.com/cartodb-platform/maps-api/mapconfig/#named-map-layer-options) is required to create a Named Map
#### template.json
The `name` argument defines how to name this "template_name".json. Note that there are some requirements for how to name a Named Map template. See the [`name`](#arguments) argument description for details.
```javascript
{
"version": "0.0.1",
"name": "template_name",
"auth": {
"method": "token",
"valid_tokens": [
"auth_token1",
"auth_token2"
]
},
"placeholders": {
"color": {
"type": "css_color",
"default": "red"
},
"cartodb_id": {
"type": "number",
"default": 1
}
},
"layergroup": {
"version": "1.0.1",
"layers": [
{
"type": "cartodb",
"options": {
"cartocss_version": "2.1.1",
"cartocss": "#layer { polygon-fill: <%= color %>; }",
"sql": "select * from european_countries_e WHERE cartodb_id = <%= cartodb_id %>"
}
}
]
},
"view": {
"zoom": 4,
"center": {
"lng": 0,
"lat": 0
},
"bounds": {
"west": -45,
"south": -45,
"east": 45,
"north": 45
}
}
}
```
#### Arguments
Params | Description
--- | ---
name | There can only be _one_ template with the same name for any user. Valid names start with a letter or a number, and only contain letters, numbers, dashes (-), or underscores (_). _This is specific to the name of your Named Map that is specified in the `name` property of the template file_.
auth |
--- | ---
&#124;_ method | `"token"` or `"open"` (`"open"` is the default if no method is specified. Use `"token"` to password-protect your map)
&#124;_ valid_tokens | when `"method"` is set to `"token"`, the values listed here allow you to instantiate the Named Map. See this [example](http://docs.cartodb.com/faqs/manipulating-your-data/#how-to-create-a-password-protected-named-map) for how to create a password-protected map.
placeholders | Placeholders are variables that can be placed in your template.json file's SQL or CartoCSS.
layergroup | the layergroup configurations, as specified in the template. See [MapConfig File Format](http://docs.cartodb.com/cartodb-platform/maps-api/mapconfig/) for more information.
view (optional) | extra keys to specify the view area for the map. It can be used to have a static preview of a Named Map without having to instantiate it. It is possible to specify it with `center` + `zoom` or with a bounding box `bbox`. Center+zoom takes precedence over bounding box.
--- | ---
&#124;_ zoom | The zoom level to use
&#124;_ center |
--- | ---
&#124;_ &#124;_ lng | The longitude to use for the center
&#124;_ &#124;_ lat | The latitude to use for the center
&#124;_ bounds |
--- | ---
&#124;_ &#124;_ west | LowerCorner longitude for the bounding box, in decimal degrees (aka most western)
&#124;_ &#124;_ south | LowerCorner latitude for the bounding box, in decimal degrees (aka most southern)
&#124;_ &#124;_ east | UpperCorner longitude for the bounding box, in decimal degrees (aka most eastern)
&#124;_ &#124;_ north | UpperCorner latitude for the bounding box, in decimal degrees (aka most northern)
### Placeholder Format
Placeholders are variables that can be placed in your template.json file. Placeholders need to be defined with a `type` and a default value for MapConfigs. See details about defining a MapConfig `type` for [Layergoup configurations](http://docs.cartodb.com/cartodb-platform/maps-api/mapconfig/#layergroup-configurations).
Valid placeholder names start with a letter and can only contain letters, numbers, or underscores. They have to be written between the `<%=` and `%>` strings in order to be replaced inside the Named Maps API.
#### Example
```javascript
<%= my_color %>
```
The set of supported placeholders for a template need to be explicitly defined with a specific type, and default value, for each placeholder.
### Placeholder Types
The placeholder type will determine the kind of escaping for the associated value. Supported types are:
Types | Description
--- | ---
sql_literal | internal single-quotes will be sql-escaped
sql_ident | internal double-quotes will be sql-escaped
number | can only contain numerical representation
css_color | can only contain color names or hex-values
Placeholder default values will be used whenever new values are not provided as options, at the time of creation on the client. They can also be used to test the template by creating a default version with new options provided.
When using templates, be very careful about your selections as they can give broad access to your data if they are defined loosely.
#### Call
This is the call for creating the Named Map. It is sending the template.json file to the service, and the server responds with the template id.
```bash
curl -X POST \
-H 'Content-Type: application/json' \
-d @template.json \
'https://{username}.cartodb.com/api/v1/map/named?api_key={api_key}'
```
#### Response
The response back from the API provides the name of your MapConfig as a template, enabling you to edit the Named Map details by inserting your variables into the template where placeholders are defined, and create custom queries using SQL.
```javascript
{
"template_id":"name"
}
```
## Instantiate
Instantiating a Named Map allows you to fetch the map tiles. You can use the Maps API to instantiate, or use the CartoDB.js `createLayer()` function. The result is an Anonymous Map.
#### Definition
```html
POST /api/v1/map/named/{template_name}
```
#### Param
Param | Description
--- | ---
auth_token | `"token"` or `"open"` (`"open"` is the default if not specified. Use `"token"` to password-protect your map)
```javascript
// params.json, this is required if the Named Map allows variables (if placeholders were defined in the template.json by the user)
{
"color": "#ff0000",
"cartodb_id": 3
}
```
The fields you pass as `params.json` depend on the variables allowed by the Named Map. If there are variables missing, it will raise an error (HTTP 400).
**Note:** It is required that you include a `params.json` file to instantiate a Named Map that contains variables, even if you have no fields to pass and the JSON is empty. (This is specific to when a Named Map allows variables (if placeholders were defined in the template.json by the user).
#### Example
You can initialize a template map by passing all of the required parameters in a POST to `/api/v1/map/named/{template_name}`.
Valid auth token will be needed, if required by the template.
#### Call
```bash
curl -X POST \
-H 'Content-Type: application/json' \
-d @params.json \
'https://{username}.cartodb.com/api/v1/map/named/{template_name}?auth_token={auth_token}'
```
#### Response
```javascript
{
"layergroupid": "docs@fd2861af@c01a54877c62831bb51720263f91fb33:123456788",
"last_updated": "2013-11-14T11:20:15.000Z"
}
```
#### Error
```javascript
{
"errors" : ["Some error string here"]
}
```
You can then use the `layergroupid` for fetching tiles and grids as you would normally (see [Anonymous Maps](http://docs.cartodb.com/cartodb-platform/maps-api/anonymous-maps/)).
## Update
#### Definition
```bash
PUT /api/v1/map/named/{template_name}
```
#### Params
Param | Description
--- | ---
api_key | is required
#### Response
Same as updating a map.
### Other Information
Updating a Named Map removes all the Named Map instances, so they need to be initialized again.
### Example
#### Call
```bash
curl -X PUT \
-H 'Content-Type: application/json' \
-d @template.json \
'https://{username}.cartodb.com/api/v1/map/named/{template_name}?api_key={api_key}'
```
#### Response
```javascript
{
"template_id": "@template_name"
}
```
If any template has the same name, it will be updated.
If a template with the same name does NOT exist, a 400 HTTP response is generated with an error in this format:
```javascript
{
"errors" : ["error string here"]
}
```
## Delete
Deletes the specified template map from the server, and disables any previously initialized versions of the map.
#### Definition
```bash
DELETE /api/v1/map/named/{template_name}
```
#### Params
Param | Description
--- | ---
api_key | is required
### Example
#### Call
```bash
curl -X DELETE 'https://{username}.cartodb.com/api/v1/map/named/{template_name}?api_key={api_key}'
```
#### Response
```javascript
{
"errors" : ["Some error string here"]
}
```
On success, a 204 (No Content) response will be issued. Otherwise a 4xx response with an error will be returned.
## Listing Available Templates
This allows you to get a list of all available templates.
#### Definition
```bash
GET /api/v1/map/named/
```
#### Params
Param | Description
--- | ---
api_key | is required
### Example
#### Call
```bash
curl -X GET 'https://{username}.cartodb.com/api/v1/map/named?api_key={api_key}'
```
#### Response
```javascript
{
"template_ids": ["@template_name1","@template_name2"]
}
```
#### Error
```javascript
{
"errors" : ["Some error string here"]
}
```
## Get Template Definition
This gets the definition of a requested template.
#### Definition
```bash
GET /api/v1/map/named/{template_name}
```
#### Params
Param | Description
--- | ---
api_key | is required
### Example
#### Call
```bash
curl -X GET 'https://{username}.cartodb.com/api/v1/map/named/{template_name}?api_key={api_key}'
```
#### Response
```javascript
{
"template": {...} // see [template.json](#templatejson)
}
```
#### Error
```javascript
{
"errors" : ["Some error string here"]
}
```
## JSONP for Named Maps
If using a [JSONP](https://en.wikipedia.org/wiki/JSONP) (for old browsers) request, there is a special endpoint used to initialize and create a Named Map.
#### Definition
```bash
GET /api/v1/map/named/{template_name}/jsonp
```
#### Params
Params | Description
--- | ---
auth_token | `"token"` or `"open"` (`"open"` is the default if no method is specified. Use `"token"` to password-protect your map)
params | Encoded JSON with the params (variables) needed for the Named Map
lmza | You can use an LZMA compressed file instead of a params JSON file
callback | JSON callback name
#### Call
```bash
curl 'https://{username}.cartodb.com/api/v1/map/named/{template_name}/jsonp?auth_token={auth_token}&callback=callback&config=template_params_json'
```
#### Response
```javascript
callback({
"layergroupid":"c01a54877c62831bb51720263f91fb33:0",
"last_updated":"1970-01-01T00:00:00.000Z"
"cdn_url": {
"http": "http://cdb.com",
"https": "https://cdb.com"
}
})
```
This takes the `callback` function (required), `auth_token` if the template needs auth, and `config` which is the variable for the template (in cases where it has variables).
```javascript
url += "config=" + encodeURIComponent(
JSON.stringify({ color: 'red' });
```
The response is:
```javascript
callback({
layergroupid: "dev@744bd0ed9b047f953fae673d56a47b4d:1390844463021.1401",
last_updated: "2014-01-27T17:41:03.021Z"
})
```
## CartoDB.js for Named Maps
You can use a Named Map that you created (which is defined by its `name`), to create a map using CartoDB.js. This is achieved by adding the [`namedmap` type](http://docs.cartodb.com/cartodb-platform/cartodb-js/layer-source-object/#named-maps-layer-source-object-type-namedmap) layer source object to draw the Named Map.
```javascript
{
user_name: '{username}', // Required
type: 'namedmap', // Required
named_map: {
name: '{name_of_map}', // Required, the 'name' of the Named Map that you have created
// Optional
layers: [{
layer_name: "sublayer0", // Optional
interactivity: "column1, column2, ..." // Optional
},
{
layer_name: "sublayer1",
interactivity: "column1, column2, ..."
},
...
],
// Optional
params: {
color: "hex_value",
num: 2
}
}
}
```
**Note:** Instantiating a Named Map over a `createLayer` does not require an API Key and by default, does not include auth tokens. _If_ you defined auth tokens for the Named Map configuration, then you will have to include them.
[CartoDB.js](http://docs.cartodb.com/cartodb-platform/cartodb-js/) has methods for accessing your Named Maps.
1. [layer.setParams()](http://docs.cartodb.com/cartodb-platform/cartodb-js/api-methods/#layersetparamskey-value) allows you to change the template variables (in the placeholders object) via JavaScript
**Note:** The CartoDB.js `layer.setParams()` function is not supported when using Named Maps for Torque. Alternatively, you can create a [Torque layer in a Named Map](http://bl.ocks.org/iriberri/de37be6406f9cc7cfe5a)
2. [layer.setAuthToken()](http://docs.cartodb.com/cartodb-platform/cartodb-js/api-methods/#layersetauthtokenauthtoken) allows you to set the auth tokens to create the layer
### Torque Layer in a Named Map
If you are creating a Torque layer in a Named Map without using the Torque.js library, you can apply the Torque layer by applying the following code with CartoDBjs:
```javascript
// add cartodb layer with one sublayer
cartodb.createLayer(map, {
user_name: '{username}',
type: 'torque',
order: 1,
options: {
query: "",
table_name: "named_map_tutorial_table",
user_name: "{username}",
tile_style: 'Map { -torque-frame-count:512; -torque-animation-duration:10; -torque-time-attribute:"cartodb_id"; -torque-aggregation-function:"count(cartodb_id)"; -torque-resolution:2; -torque-data-aggregation:linear; } #named_map_tutorial_table_copy{ comp-op: lighter; marker-fill-opacity: 0.9; marker-line-color: #FFF; marker-line-width: 1.5; marker-line-opacity: 1; marker-type: ellipse; marker-width: 6; marker-fill: #FF9900; } #named_map_tutorial_table_copy[frame-offset=1] { marker-width:8; marker-fill-opacity:0.45; } #named_map_tutorial_table_copy[frame-offset=2] { marker-width:10; marker-fill-opacity:0.225; }'
},
named_map: {
name: "{namedmap_example}",
layers: [{
layer_name: "t"
}]
}
})
.addTo(map)
.done(function(layer) {
});
}
```
#### Examples of Named Maps created with CartoDB.js
- [Named Map selectors with interaction](http://bl.ocks.org/ohasselblad/515a8af1f99d5e690484)
- [Named Map with interactivity](http://bl.ocks.org/ohasselblad/d1a45b8ff5e7bd90cd68)
- [Toggling sublayers in a Named Map](http://bl.ocks.org/ohasselblad/c1a0f4913610eec53cd3)
## Fetching XYZ Tiles for Named Maps
Optionally, authenticated users can fetch projected tiles (XYZ tiles or Mapnik Retina tiles) for your Named Map.
### Fetch XYZ Tiles Directly with a URL
Authenticated users, with an auth token, can use XYZ-based URLs to fetch tiles directly, and instantiate the Named Map as part of the request to your application. You do not have to do any other steps to initialize your map.
To call a template_id in a URL:
`/{template_id}/{layer}/{z}/{x}/{y}.{format}`
For example, a complete URL might appear as:
"https://{username}.cartodb.com/api/v1/map/named/{template_id}/{layer}/{z}/{x}/{y}.png"
The placeholders indicate the following:
- [`template_id`](http://docs.cartodb.com/cartodb-platform/maps-api/named-maps/#response) is the response of your Named Map.
- layers can be a number (referring to the # layer of your map), all layers of your map, or a list of layers.
- To show just the basemap layer, enter the number value `0` in the layer placeholder "https://{username}.cartodb.com/api/v1/map/named/{template_id}/0/{z}/{x}/{y}.png"
- To show the first layer, enter the number value `1` in the layer placeholder "https://{username}.cartodb.com/api/v1/map/named/{template_id}/1/{z}/{x}/{y}.png"
- To show all layers, enter the value `all` for the layer placeholder "https://{username}.cartodb.com/api/v1/map/named/{template_id}/all/{z}/{x}/{y}.png"
- To show a [list of layers](http://docs.cartodb.com/cartodb-platform/maps-api/anonymous-maps/#blending-and-layer-selection), enter the comma separated layer value as 0,1,2 in the layer placeholder. For example, to show the basemap and the first layer, "https://{username}.cartodb.com/api/v1/map/named/{template_id}/0,1/{z}/{x}/{y}.png"
### Get Mapnik Retina Tiles
Mapnik Retina tiles are not directly supported for Named Maps, so you cannot use the Named Map template_id. To fetch Mapnik Retina tiles, get the [layergroupid](http://docs.cartodb.com/cartodb-platform/maps-api/named-maps/#response-1) to initialize the map.
Instantiate the map by using your `layergroupid` in the token placeholder:
`{token}/{z}/{x}/{y}@{scale_factor}?{x}.{format}`

100
docs/quickstart.md Normal file
View File

@@ -0,0 +1,100 @@
# Quickstart
## Anonymous Maps
Here is an example of how to create an Anonymous Map with JavaScript:
```javascript
var mapconfig = {
"version": "1.3.1",
"layers": [{
"type": "cartodb",
"options": {
"cartocss_version": "2.1.1",
"cartocss": "#layer { polygon-fill: #FFF; }",
"sql": "select * from european_countries_e"
}
}]
}
$.ajax({
crossOrigin: true,
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: 'https://{username}.cartodb.com/api/v1/map',
data: JSON.stringify(mapconfig),
success: function(data) {
var templateUrl = 'https://{username}.cartodb.com/api/v1/map/' + data.layergroupid + '/{z}/{x}/{y}.png'
console.log(templateUrl);
}
})
```
## Named Maps
Let's create a Named Map using some private tables in a CartoDB account.
The following map config sets up a map of European countries that have a white fill color:
```javascript
{
"version": "0.0.1",
"name": "test",
"auth": {
"method": "open"
},
"layergroup": {
"layers": [{
"type": "mapnik",
"options": {
"cartocss_version": "2.1.1",
"cartocss": "#layer { polygon-fill: #FFF; }",
"sql": "select * from european_countries_e"
}
}]
}
}
```
The MapConfig needs to be sent to CartoDB's Map API using an authenticated call. Here we will use a command line tool called `curl`. For more info about this tool, see [this blog post](http://quickleft.com/blog/command-line-tutorials-curl), or type `man curl` in bash. Using `curl`, and storing the config from above in a file `MapConfig.json`, the call would look like:
#### Call
```bash
curl 'https://{username}.cartodb.com/api/v1/map/named?api_key={api_key}' -H 'Content-Type: application/json' -d @mapconfig.json
```
To get the `URL` to fetch the tiles you need to instantiate the map, where `template_id` is the template name from the previous response.
#### Call
```bash
curl -X POST 'https://{username}.cartodb.com/api/v1/map/named/{template_id}' -H 'Content-Type: application/json'
```
The response will return JSON with properties for the `layergroupid`, the timestamp (`last_updated`) of the last data modification and some key/value pairs with `metadata` for the `layers`.
Note: all `layers` in `metadata` will always have a `type` string and a `meta` dictionary with the key/value pairs.
#### Response
```javascript
{
"layergroupid": "c01a54877c62831bb51720263f91fb33:0",
"last_updated": "1970-01-01T00:00:00.000Z",
"metadata": {
"layers": [
{
"type": "mapnik",
"meta": {}
}
]
}
}
```
You can use the `layergroupid` to instantiate a URL template for accessing tiles on the client. Here we use the `layergroupid` from the example response above in this URL template:
```bash
https://{username}.cartodb.com/api/v1/map/{layergroupid}/{z}/{x}/{y}.png
```

221
docs/static_maps_api.md Normal file
View File

@@ -0,0 +1,221 @@
# Static Maps API
The Static Maps API can be initiated using both Named and Anonymous Maps using the 'layergroupid' token. The API can be used to create static images of parts of maps and thumbnails for use in web design, graphic design, print, field work, and many other applications that require standard image formats.
## Maps API endpoints
Begin by instantiating either a Named or Anonymous Map using the `layergroupid token` as demonstrated in the Maps API documentation above. The `layergroupid` token calls to the map and allows for parameters in the definition to generate static images.
### Zoom + center
#### Definition
```bash
GET /api/v1/map/static/center/{token}/{z}/{lat}/{lng}/{width}/{height}.{format}
```
#### Params
Param | Description
--- | ---
token | the layergroupid token from the map instantiation
z | the zoom level of the map
lat | the latitude for the center of the map
format | the format for the image, supported types: `png`, `jpg`
--- | ---
&#124;_ jpg | will have a default quality of 85.
### Bounding Box
#### Definition
```bash
GET /api/v1/map/static/bbox/{token}/{bbox}/{width}/{height}.{format}`
```
#### Params
Param | Description
--- | ---
token | the layergroupid token from the map instantiation
bbox | the bounding box in WGS 84 (EPSG:4326), comma separated values for:
--- | ---
| LowerCorner longitude, in decimal degrees (aka most western)
| LowerCorner latitude, in decimal degrees (aka most southern)
| UpperCorner longitude, in decimal degrees (aka most eastern)
| UpperCorner latitude, in decimal degrees (aka most northern)
width | the width in pixels for the output image
height | the height in pixels for the output image
format | the format for the image, supported types: `png`, `jpg`
--- | ---
&#124;_ jpg | will have a default quality of 85.
Note: you can see this endpoint as
```bash
GET /api/v1/map/static/bbox/{token}/{west},{south},{east},{north}/{width}/{height}.{format}`
```
### Named Map
#### Definition
```bash
GET /api/v1/map/static/named/{name}/{width}/{height}.{format}
```
#### Params
Param | Description
--- | ---
name | the name of the Named Map
width | the width in pixels for the output image
height | the height in pixels for the output image
format | the format for the image, supported types: `png`, `jpg`
--- | ---
&#124;_ jpg | will have a default quality of 85.
A Named Maps static image will get its constraints from the [`view` argument of the Create Named Map function](http://docs.cartodb.com/cartodb-platform/maps-api/named-maps/#arguments). If `view` is not defined, it will estimate the extent based on the involved tables, otherwise it fallbacks to `"zoom": 1`, `"lng": 0` and `"lat": 0`.
#### Layers
The Static Maps API allows for multiple layers of incorporation into the `MapConfig` to allow for maximum versatility in creating a static map. The examples below were used to generate the static image example in the next section, and appear in the specific order designated.
**Basemaps**
```javascript
{
"type": "http",
"options": {
"urlTemplate": "http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
]
}
}
```
By manipulating the `"urlTemplate"` custom basemaps can be used in generating static images. Supported map types for the Static Maps API are:
```javascript
'http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
'http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png',
'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
'http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png',
```
**Mapnik**
```javascript
{
"type": "mapnik",
"options": {
"sql": "select null::geometry the_geom_webmercator",
"cartocss": "#layer {\n\tpolygon-fill: #FF3300;\n\tpolygon-opacity: 0;\n\tline-color: #333;\n\tline-width: 0;\n\tline-opacity: 0;\n}",
"cartocss_version": "2.2.0"
}
},
```
**CartoDB**
As described in the [MapConfig File Format](http://docs.cartodb.com/cartodb-platform/maps-api/mapconfig/), a "cartodb" type layer is now just an alias to a "mapnik" type layer as above, intended for backwards compatibility.
```javascript
{
"type": "cartodb",
"options": {
"sql": "select * from park",
"cartocss": "/** simple visualization */\n\n#park{\n polygon-fill: #229A00;\n polygon-opacity: 0.7;\n line-color: #FFF;\n line-width: 0;\n line-opacity: 1;\n}",
"cartocss_version": "2.1.1"
}
}
```
Additionally, static images from Torque maps and other map layers can be used together to generate highly customizable and versatile static maps.
### Caching
It is important to note that generated images are cached from the live data referenced with the `layergroupid token` on the specified CartoDB account. This means that if the data changes, the cached image will also change. When linking dynamically, it is important to take into consideration the state of the data and longevity of the static image to avoid broken images or changes in how the image is displayed. To obtain a static snapshot of the map as it is today and preserve the image long-term regardless of changes in data, the image must be saved and stored locally.
### Limits
* While images can encompass an entirety of a map, the default limit for pixel range is 8192 x 8192.
* Image resolution by default is set to 72 DPI
* JPEG quality by default is 85%
* Timeout limits for generating static maps are the same across the CartoDB Editor and Platform. It is important to ensure timely processing of queries.
## Examples
After instantiating a map from a CartoDB account:
#### Call
```bash
GET /api/v1/map/static/center/{layergroupid}/{z}/{x}/{y}/{width}/{height}.png
```
#### Response
<p class="wrap-border"><img src="https://raw.githubusercontent.com/namessanti/Pictures/master/static_api.png" alt="static-api"/></p>
### MapConfig
For this map, the multiple layers, order, and stylings are defined by the MapConfig.
```javascript
{
"version": "1.3.0",
"layers": [
{
"type": "http",
"options": {
"urlTemplate": "http://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
]
}
},
{
"type": "mapnik",
"options": {
"sql": "select null::geometry the_geom_webmercator",
"cartocss": "#layer {\n\tpolygon-fill: #FF3300;\n\tpolygon-opacity: 0;\n\tline-color: #333;\n\tline-width: 0;\n\tline-opacity: 0;\n}",
"cartocss_version": "2.2.0"
}
},
{
"type": "cartodb",
"options": {
"sql": "select * from park",
"cartocss": "/** simple visualization */\n\n#park{\n polygon-fill: #229A00;\n polygon-opacity: 0.7;\n line-color: #FFF;\n line-width: 0;\n line-opacity: 1;\n}",
"cartocss_version": "2.1.1"
}
},
{
"type": "cartodb",
"options": {
"sql": "select * from residential_zoning_2009",
"cartocss": "/** simple visualization */\n\n#residential_zoning_2009{\n polygon-fill: #c7eae5;\n polygon-opacity: 1;\n line-color: #FFF;\n line-width: 0.2;\n line-opacity: 0.5;\n}",
"cartocss_version": "2.1.1"
}
},
{
"type": "cartodb",
"options": {
"sql": "select * from nycha_developments_july2011",
"cartocss": "/** simple visualization */\n\n#nycha_developments_july2011{\n polygon-fill: #ef3b2c;\n polygon-opacity: 0.7;\n line-color: #FFF;\n line-width: 0;\n line-opacity: 1;\n}",
"cartocss_version": "2.1.1"
}
}
]
}
```

141
lib/cartodb/api/auth_api.js Normal file
View File

@@ -0,0 +1,141 @@
var assert = require('assert');
var step = require('step');
/**
*
* @param {PgConnection} pgConnection
* @param metadataBackend
* @param {MapStore} mapStore
* @param {TemplateMaps} templateMaps
* @constructor
* @type {AuthApi}
*/
function AuthApi(pgConnection, metadataBackend, mapStore, templateMaps) {
this.pgConnection = pgConnection;
this.metadataBackend = metadataBackend;
this.mapStore = mapStore;
this.templateMaps = templateMaps;
}
module.exports = AuthApi;
// Check if a request is authorized by a signer
//
// @param req express request object
// @param callback function(err, signed_by) signed_by will be
// null if the request is not signed by anyone
// or will be a string cartodb username otherwise.
//
AuthApi.prototype.authorizedBySigner = function(req, callback) {
if ( ! req.params.token || ! req.params.signer ) {
return callback(null, false); // no signer requested
}
var self = this;
var layergroup_id = req.params.token;
var auth_token = req.params.auth_token;
this.mapStore.load(layergroup_id, function(err, mapConfig) {
if (err) {
return callback(err);
}
var authorized = self.templateMaps.isAuthorized(mapConfig.obj().template, auth_token);
return callback(null, authorized);
});
};
// Check if a request is authorized by api_key
//
// @param user
// @param req express request object
// @param callback function(err, authorized)
// NOTE: authorized is expected to be 0 or 1 (integer)
//
AuthApi.prototype.authorizedByAPIKey = function(user, req, callback) {
var givenKey = req.query.api_key || req.query.map_key;
if ( ! givenKey && req.body ) {
// check also in request body
givenKey = req.body.api_key || req.body.map_key;
}
if ( ! givenKey ) {
return callback(null, 0); // no api key, no authorization...
}
var self = this;
step(
function () {
self.metadataBackend.getUserMapKey(user, this);
},
function checkApiKey(err, val){
assert.ifError(err);
return val && givenKey === val;
},
function finish(err, authorized) {
callback(err, authorized);
}
);
};
/**
* Check access authorization
*
* @param req - standard req object. Importantly contains table and host information
* @param callback function(err, allowed) is access allowed not?
*/
AuthApi.prototype.authorize = function(req, callback) {
var self = this;
var user = req.context.user;
step(
function () {
self.authorizedByAPIKey(user, req, this);
},
function checkApiKey(err, authorized){
if (req.profiler) {
req.profiler.done('authorizedByAPIKey');
}
assert.ifError(err);
// if not authorized by api_key, continue
if (!authorized) {
// not authorized by api_key, check if authorized by signer
return self.authorizedBySigner(req, this);
}
// authorized by api key, login as the given username and stop
self.pgConnection.setDBAuth(user, req.params, function(err) {
callback(err, true); // authorized (or error)
});
},
function checkSignAuthorized(err, authorized) {
if (err) {
return callback(err);
}
if ( ! authorized ) {
// request not authorized by signer.
// if no signer name was given, let dbparams and
// PostgreSQL do the rest.
//
if ( ! req.params.signer ) {
return callback(null, true); // authorized so far
}
// if signer name was given, return no authorization
return callback(null, false);
}
self.pgConnection.setDBAuth(user, req.params, function(err) {
if (req.profiler) {
req.profiler.done('setDBAuth');
}
callback(err, true); // authorized (or error)
});
}
);
};

View File

@@ -0,0 +1,59 @@
var _ = require('underscore');
var step = require('step');
var CamshaftFilter = require('../models/filter/camshaft');
function FilterStatsApi(pgQueryRunner) {
this.pgQueryRunner = pgQueryRunner;
}
module.exports = FilterStatsApi;
function getEstimatedRows(pgQueryRunner, username, query, callback) {
pgQueryRunner.run(username, "EXPLAIN (FORMAT JSON)"+query, function(err, result_rows) {
if (err){
callback(err);
return;
}
var rows;
if ( result_rows[0] && result_rows[0]['QUERY PLAN'] &&
result_rows[0]['QUERY PLAN'][0] && result_rows[0]['QUERY PLAN'][0].Plan ) {
rows = result_rows[0]['QUERY PLAN'][0].Plan['Plan Rows'];
}
return callback(null, rows);
});
}
FilterStatsApi.prototype.getFilterStats = function (username, unfiltered_query, filters, callback) {
var stats = {};
var self = this;
step(
function getUnfilteredRows() {
getEstimatedRows(self.pgQueryRunner, username, unfiltered_query, this);
},
function receiveUnfilteredRows(err, rows) {
if (err){
callback(err);
return;
}
stats.unfiltered_rows = rows;
this(null, rows);
},
function getFilteredRows() {
if ( filters && !_.isEmpty(filters)) {
var camshaftFilter = new CamshaftFilter(filters);
var query = camshaftFilter.sql(unfiltered_query);
getEstimatedRows(self.pgQueryRunner, username, query, this);
} else {
this(null, null);
}
},
function receiveFilteredRows(err, rows) {
if (err){
callback(err);
return;
}
stats.filtered_rows = rows;
callback(null, stats);
}
);
};

View File

@@ -0,0 +1,40 @@
var SubstitutionTokens = require('../utils/substitution-tokens');
function OverviewsMetadataApi(pgQueryRunner) {
this.pgQueryRunner = pgQueryRunner;
}
module.exports = OverviewsMetadataApi;
function prepareSql(sql) {
return sql && SubstitutionTokens.replace(sql, {
bbox: 'ST_MakeEnvelope(0,0,0,0)',
scale_denominator: '0',
pixel_width: '1',
pixel_height: '1'
});
}
OverviewsMetadataApi.prototype.getOverviewsMetadata = function (username, sql, callback) {
// FIXME: Currently using internal function _cdb_schema_name
// CDB_Overviews should provide the schema information directly.
var query = 'SELECT *, _cdb_schema_name(base_table)' +
' FROM CDB_Overviews(CDB_QueryTablesText($windshaft$' + prepareSql(sql) + '$windshaft$))';
this.pgQueryRunner.run(username, query, function handleOverviewsRows(err, rows) {
if (err){
callback(err);
return;
}
var metadata = rows.reduce(function(metadata, row){
var table = row.base_table;
var schema = row._cdb_schema_name;
if ( !metadata[table] ) {
metadata[table] = {};
}
metadata[table][row.z] = { table: row.overview_table };
metadata[table].schema = schema;
return metadata;
}, {});
return callback(null, metadata);
});
};

View File

@@ -0,0 +1,47 @@
function TablesExtentApi(pgQueryRunner) {
this.pgQueryRunner = pgQueryRunner;
}
module.exports = TablesExtentApi;
/**
* Given a username and a list of tables it will return the estimated extent in SRID 4326 for all the tables based on
* the_geom_webmercator (SRID 3857) column.
*
* @param {String} username
* @param {Array} tableNames The named can be schema qualified, so this accepts both `schema_name.table_name` and
* `table_name` format as valid input
* @param {Function} callback function(err, result) {Object} result with `west`, `south`, `east`, `north`
*/
TablesExtentApi.prototype.getBounds = function (username, tables, callback) {
var estimatedExtentSQLs = tables.map(function(table) {
return "ST_EstimatedExtent('" + table.schema_name + "', '" + table.table_name + "', 'the_geom_webmercator')";
});
var query = [
"WITH ext as (" +
"SELECT ST_Transform(ST_SetSRID(ST_Extent(ST_Union(ARRAY[",
estimatedExtentSQLs.join(','),
"])), 3857), 4326) geom)",
"SELECT",
"ST_XMin(geom) west,",
"ST_YMin(geom) south,",
"ST_XMax(geom) east,",
"ST_YMax(geom) north",
"FROM ext"
].join(' ');
this.pgQueryRunner.run(username, query, function handleBoundsResult (err, rows) {
if (err) {
var msg = err.message ? err.message : err;
return callback(new Error('could not fetch source tables: ' + msg));
}
var result = null;
if (rows.length > 0) {
result = {
bounds: rows[0]
};
}
callback(null, result);
});
};

View File

@@ -0,0 +1,28 @@
/**
*
* @param metadataBackend
* @param options
* @constructor
* @type {UserLimitsApi}
*/
function UserLimitsApi(metadataBackend, options) {
this.metadataBackend = metadataBackend;
this.options = options || {};
this.options.limits = this.options.limits || {};
}
module.exports = UserLimitsApi;
UserLimitsApi.prototype.getRenderLimits = function (username, callback) {
var self = this;
this.metadataBackend.getTilerRenderLimit(username, function handleTilerLimits(err, renderLimit) {
if (err) {
return callback(err);
}
return callback(null, {
cacheOnTimeout: self.options.limits.cacheOnTimeout || false,
render: renderLimit || self.options.limits.render || 0
});
});
};

View File

@@ -0,0 +1,49 @@
var PSQL = require('cartodb-psql');
function AnalysisStatusBackend() {
}
module.exports = AnalysisStatusBackend;
AnalysisStatusBackend.prototype.getNodeStatus = function (params, callback) {
var nodeId = params.nodeId;
var statusQuery = 'SELECT node_id, status, updated_at FROM cdb_analysis_catalog where node_id = \'' + nodeId + '\'';
var pg = new PSQL(dbParamsFromReqParams(params));
pg.query(statusQuery, function(err, result) {
if (err) {
return callback(err, result);
}
result = result || {};
var rows = result.rows || [];
return callback(null, rows[0] || {
node_id: nodeId,
status: 'unknown'
});
}, true); // use read-only transaction
};
function dbParamsFromReqParams(params) {
var dbParams = {};
if ( params.dbuser ) {
dbParams.user = params.dbuser;
}
if ( params.dbpassword ) {
dbParams.pass = params.dbpassword;
}
if ( params.dbhost ) {
dbParams.host = params.dbhost;
}
if ( params.dbport ) {
dbParams.port = params.dbport;
}
if ( params.dbname ) {
dbParams.dbname = params.dbname;
}
return dbParams;
}

View File

@@ -0,0 +1,19 @@
var camshaft = require('camshaft');
function AnalysisBackend(options) {
var batchConfig = options.batch || {};
batchConfig.endpoint = batchConfig.endpoint || 'http://127.0.0.1:8080/api/v1/sql/job';
batchConfig.inlineExecution = batchConfig.inlineExecution || false;
batchConfig.hostHeaderTemplate = batchConfig.hostHeaderTemplate || '{{=it.username}}.localhost.lan';
this.batchConfig = batchConfig;
}
module.exports = AnalysisBackend;
AnalysisBackend.prototype.create = function(analysisConfiguration, analysisDefinition, callback) {
analysisConfiguration.batch.endpoint = this.batchConfig.endpoint;
analysisConfiguration.batch.inlineExecution = this.batchConfig.inlineExecution;
analysisConfiguration.batch.hostHeaderTemplate = this.batchConfig.hostHeaderTemplate;
camshaft.create(analysisConfiguration, analysisDefinition, callback);
};

View File

@@ -0,0 +1,339 @@
var assert = require('assert');
var _ = require('underscore');
var PSQL = require('cartodb-psql');
var camshaft = require('camshaft');
var step = require('step');
var Timer = require('../stats/timer');
var BBoxFilter = require('../models/filter/bbox');
var DataviewFactory = require('../models/dataview/factory');
var DataviewFactoryWithOverviews = require('../models/dataview/overviews/factory');
var OverviewsQueryRewriter = require('../utils/overviews_query_rewriter');
var overviewsQueryRewriter = new OverviewsQueryRewriter({
zoom_level: 'CDB_ZoomFromScale(!scale_denominator!)'
});
var dot = require('dot');
dot.templateSettings.strip = false;
function DataviewBackend(analysisBackend) {
this.analysisBackend = analysisBackend;
}
module.exports = DataviewBackend;
DataviewBackend.prototype.getDataview = function (mapConfigProvider, user, params, callback) {
var self = this;
var timer = new Timer();
var dataviewName = params.dataviewName;
var mapConfig;
var dataviewDefinition;
step(
function getMapConfig() {
mapConfigProvider.getMapConfig(this);
},
function _getDataviewDefinition(err, _mapConfig) {
assert.ifError(err);
mapConfig = _mapConfig;
var _dataviewDefinition = getDataviewDefinition(mapConfig.obj(), dataviewName);
if (!_dataviewDefinition) {
throw new Error("Dataview '" + dataviewName + "' does not exists");
}
dataviewDefinition = _dataviewDefinition;
return dataviewDefinition;
},
function loadAnalysis(err) {
assert.ifError(err);
var analysisConfiguration = {
db: {
host: params.dbhost,
port: params.dbport,
dbname: params.dbname,
user: params.dbuser,
pass: params.dbpassword
},
batch: {
username: user,
apiKey: params.api_key
}
};
var sourceId = dataviewDefinition.source.id;
var analysisDefinition = getAnalysisDefinition(mapConfig.obj().analyses, sourceId);
var next = this;
self.analysisBackend.create(analysisConfiguration, analysisDefinition, function(err, analysis) {
if (err) {
return next(err);
}
var sourceId2Node = {};
var rootNode = analysis.getRoot();
if (rootNode.params && rootNode.params.id) {
sourceId2Node[rootNode.params.id] = rootNode;
}
analysis.getSortedNodes().forEach(function(node) {
if (node.params && node.params.id) {
sourceId2Node[node.params.id] = node;
}
});
var node = sourceId2Node[sourceId];
if (!node) {
return next(new Error('Analysis node not found for dataview'));
}
return next(null, node);
});
},
function runDataviewQuery(err, node) {
assert.ifError(err);
var pg = new PSQL(dbParamsFromReqParams(params));
var ownFilter = +params.own_filter;
ownFilter = !!ownFilter;
var query = layerQuery(node, dataviewName, ownFilter);
var sourceId = dataviewDefinition.source.id; // node.id
var layer = _.find(
mapConfig.obj().layers,
function(l){ return l.options.source && (l.options.source.id === sourceId); }
);
var queryRewriteData = layer && layer.options.query_rewrite_data;
if ( queryRewriteData ) {
if ( node.type === 'source' ) {
var filters = node.getFilters();
var filters_disabler = Object.keys(filters).reduce(
function(disabler, filter_id){ disabler[filter_id] = false; return disabler; },
{}
);
var unfiltered_query = node.getQuery(filters_disabler);
queryRewriteData = _.extend(
{},
queryRewriteData, { filters: filters, unfiltered_query: unfiltered_query }
);
}
}
if (params.bbox) {
var bboxFilter = new BBoxFilter({column: 'the_geom_webmercator', srid: 3857}, {bbox: params.bbox});
query = bboxFilter.sql(query);
if ( queryRewriteData ) {
var bbox_filter_definition = {
type: 'bbox',
options: {
column: 'the_geom_webmercator',
srid: 3857
},
params: {
bbox: params.bbox
}
};
queryRewriteData = _.extend(queryRewriteData, { bbox_filter: bbox_filter_definition });
}
}
var dataviewFactory = DataviewFactoryWithOverviews.getFactory(
overviewsQueryRewriter, queryRewriteData, { bbox: params.bbox }
);
var overrideParams = _.reduce(_.pick(params, 'start', 'end', 'bins'),
function castNumbers(overrides, val, k) {
overrides[k] = Number.isFinite(+val) ? +val : val;
return overrides;
},
{ownFilter: ownFilter}
);
var dataview = dataviewFactory.getDataview(query, dataviewDefinition);
dataview.getResult(pg, overrideParams, this);
},
function returnCallback(err, result) {
return callback(err, result, timer.getTimes());
}
);
};
DataviewBackend.prototype.search = function (mapConfigProvider, user, params, callback) {
var self = this;
var timer = new Timer();
var dataviewName = params.dataviewName;
var mapConfig;
var dataviewDefinition;
step(
function getMapConfig() {
mapConfigProvider.getMapConfig(this);
},
function _getDataviewDefinition(err, _mapConfig) {
assert.ifError(err);
mapConfig = _mapConfig;
var _dataviewDefinition = getDataviewDefinition(mapConfig.obj(), dataviewName);
if (!_dataviewDefinition) {
throw new Error("Dataview '" + dataviewName + "' does not exists");
}
dataviewDefinition = _dataviewDefinition;
return dataviewDefinition;
},
function loadAnalysis(err) {
assert.ifError(err);
var analysisConfiguration = {
db: {
host: params.dbhost,
port: params.dbport,
dbname: params.dbname,
user: params.dbuser,
pass: params.dbpassword
},
batch: {
// TODO load this from configuration
endpoint: 'http://127.0.0.1:8080/api/v1/sql/job',
username: user,
apiKey: params.api_key
}
};
var sourceId = dataviewDefinition.source.id;
var analysisDefinition = getAnalysisDefinition(mapConfig.obj().analyses, sourceId);
var next = this;
self.analysisBackend.create(analysisConfiguration, analysisDefinition, function(err, analysis) {
if (err) {
return next(err);
}
var sourceId2Node = {};
var rootNode = analysis.getRoot();
if (rootNode.params && rootNode.params.id) {
sourceId2Node[rootNode.params.id] = rootNode;
}
analysis.getSortedNodes().forEach(function(node) {
if (node.params && node.params.id) {
sourceId2Node[node.params.id] = node;
}
});
var node = sourceId2Node[sourceId];
if (!node) {
return next(new Error('Analysis node not found for dataview'));
}
return next(null, node);
});
},
function runDataviewQuery(err, node) {
assert.ifError(err);
var pg = new PSQL(dbParamsFromReqParams(params));
var ownFilter = +params.own_filter;
ownFilter = !!ownFilter;
var query = layerQuery(node, dataviewName, ownFilter);
if (params.bbox) {
var bboxFilter = new BBoxFilter({column: 'the_geom', srid: 4326}, {bbox: params.bbox});
query = bboxFilter.sql(query);
}
var userQuery = params.q;
var dataview = DataviewFactory.getDataview(query, dataviewDefinition);
dataview.search(pg, userQuery, this);
},
function returnCallback(err, result) {
return callback(err, result, timer.getTimes());
}
);
};
function getAnalysisDefinition(mapConfigAnalyses, sourceId) {
mapConfigAnalyses = mapConfigAnalyses || [];
for (var i = 0; i < mapConfigAnalyses.length; i++) {
var analysisGraph = new camshaft.reference.AnalysisGraph(mapConfigAnalyses[i]);
var nodes = analysisGraph.getNodesWithId();
if (nodes.hasOwnProperty(sourceId)) {
return mapConfigAnalyses[i];
}
}
throw new Error('There is no associated analysis for the dataview source id');
}
function getDataviewDefinition(mapConfig, dataviewName) {
var dataviews = mapConfig.dataviews || {};
return dataviews[dataviewName];
}
function dbParamsFromReqParams(params) {
var dbParams = {};
if ( params.dbuser ) {
dbParams.user = params.dbuser;
}
if ( params.dbpassword ) {
dbParams.pass = params.dbpassword;
}
if ( params.dbhost ) {
dbParams.host = params.dbhost;
}
if ( params.dbport ) {
dbParams.port = params.dbport;
}
if ( params.dbname ) {
dbParams.dbname = params.dbname;
}
return dbParams;
}
var SKIP_COLUMNS = {
'the_geom': true,
'the_geom_webmercator': true
};
function skipColumns(columnNames) {
return columnNames
.filter(function(columnName) { return !SKIP_COLUMNS[columnName]; });
}
var layerQueryTemplate = dot.template([
'SELECT {{=it._columns}}',
'FROM ({{=it._query}}) _cdb_analysis_query'
].join('\n'));
function layerQuery(node, dataviewName, ownFilter) {
var applyFilters = {};
if (!ownFilter) {
applyFilters[dataviewName] = false;
}
if (node.type === 'source') {
return node.getQuery(applyFilters);
}
var _columns = ['ST_Transform(the_geom, 3857) the_geom_webmercator'].concat(skipColumns(node.getColumns()));
return layerQueryTemplate({ _query: node.getQuery(applyFilters), _columns: _columns.join(', ') });
}

View File

@@ -0,0 +1,136 @@
var assert = require('assert');
var step = require('step');
var PSQL = require('cartodb-psql');
var _ = require('underscore');
function PgConnection(metadataBackend) {
this.metadataBackend = metadataBackend;
}
module.exports = PgConnection;
// Set db authentication parameters to those of the given username
//
// @param username the cartodb username, mapped to a database username
// via CartodbRedis metadata records
//
// @param params the parameters to set auth options into
// added params are: "dbuser" and "dbpassword"
//
// @param callback function(err)
//
PgConnection.prototype.setDBAuth = function(username, params, callback) {
var self = this;
var user_params = {};
var auth_user = global.environment.postgres_auth_user;
var auth_pass = global.environment.postgres_auth_pass;
step(
function getId() {
self.metadataBackend.getUserId(username, this);
},
function(err, user_id) {
assert.ifError(err);
user_params.user_id = user_id;
var dbuser = _.template(auth_user, user_params);
_.extend(params, {dbuser:dbuser});
// skip looking up user_password if postgres_auth_pass
// doesn't contain the "user_password" label
if (!auth_pass || ! auth_pass.match(/\buser_password\b/) ) {
return null;
}
self.metadataBackend.getUserDBPass(username, this);
},
function(err, user_password) {
assert.ifError(err);
user_params.user_password = user_password;
if ( auth_pass ) {
var dbpass = _.template(auth_pass, user_params);
_.extend(params, {dbpassword:dbpass});
}
return true;
},
function finish(err) {
callback(err);
}
);
};
// Set db connection parameters to those for the given username
//
// @param dbowner cartodb username of database owner,
// mapped to a database username
// via CartodbRedis metadata records
//
// @param params the parameters to set connection options into
// added params are: "dbname", "dbhost"
//
// @param callback function(err)
//
PgConnection.prototype.setDBConn = function(dbowner, params, callback) {
var self = this;
// Add default database connection parameters
// if none given
_.defaults(params, {
dbuser: global.environment.postgres.user,
dbpassword: global.environment.postgres.password,
dbhost: global.environment.postgres.host,
dbport: global.environment.postgres.port
});
step(
function getConnectionParams() {
self.metadataBackend.getUserDBConnectionParams(dbowner, this);
},
function extendParams(err, dbParams){
assert.ifError(err);
// we don't want null values or overwrite a non public user
if (params.dbuser !== 'publicuser' || !dbParams.dbuser) {
delete dbParams.dbuser;
}
if ( dbParams ) {
_.extend(params, dbParams);
}
return null;
},
function finish(err) {
callback(err);
}
);
};
/**
* Returns a `cartodb-psql` object for a given username.
* @param {String} username
* @param {Function} callback function({Error}, {PSQL})
*/
PgConnection.prototype.getConnection = function(username, callback) {
var self = this;
var params = {};
require('debug')('cachechan')("getConn1");
step(
function setAuth() {
self.setDBAuth(username, params, this);
},
function setConn(err) {
assert.ifError(err);
self.setDBConn(username, params, this);
},
function openConnection(err) {
assert.ifError(err);
return callback(err, new PSQL({
user: params.dbuser,
pass: params.dbpass,
host: params.dbhost,
port: params.dbport,
dbname: params.dbname
}));
}
);
};

View File

@@ -0,0 +1,46 @@
var assert = require('assert');
var PSQL = require('cartodb-psql');
var step = require('step');
function PgQueryRunner(pgConnection) {
this.pgConnection = pgConnection;
}
module.exports = PgQueryRunner;
/**
* Runs `query` with `username`'s PostgreSQL role, callback receives error and rows array.
*
* @param {String} username
* @param {String} query
* @param {Function} callback function({Error}, {Array}) second argument is guaranteed to be an array
*/
PgQueryRunner.prototype.run = function(username, query, callback) {
var self = this;
var params = {};
step(
function setAuth() {
self.pgConnection.setDBAuth(username, params, this);
},
function setConn(err) {
assert.ifError(err);
self.pgConnection.setDBConn(username, params, this);
},
function executeQuery(err) {
assert.ifError(err);
var psql = new PSQL({
user: params.dbuser,
pass: params.dbpass,
host: params.dbhost,
port: params.dbport,
dbname: params.dbname
});
psql.query(query, function(err, resultSet) {
resultSet = resultSet || {};
return callback(err, resultSet.rows || []);
});
}
);
};

View File

@@ -0,0 +1,519 @@
var assert = require('assert');
var crypto = require('crypto');
var debug = require('debug')('windshaft:templates');
var step = require('step');
var _ = require('underscore');
var dot = require('dot');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
// Class handling map templates
//
// See http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps
//
// @param redis_pool an instance of a "redis-mpool"
// See https://github.com/CartoDB/node-redis-mpool
// Needs version 0.x.x of the API.
//
// @param opts TemplateMap options. Supported elements:
// 'max_user_templates' limit on the number of per-user
//
//
function TemplateMaps(redis_pool, opts) {
if (!(this instanceof TemplateMaps)) {
return new TemplateMaps();
}
EventEmitter.call(this);
this.redis_pool = redis_pool;
this.opts = opts || {};
// Database containing templates
// TODO: allow configuring ?
// NOTE: currently it is the same as
// the one containing layergroups
this.db_signatures = 0;
//
// Map templates are owned by a user that specifies access permissions
// for their instances.
//
// We have the following datastores:
//
// 1. User templates: set of per-user map templates
// User templates (HASH:tpl_id->tpl_val)
this.key_usr_tpl = dot.template("map_tpl|{{=it.owner}}");
}
util.inherits(TemplateMaps, EventEmitter);
module.exports = TemplateMaps;
var o = TemplateMaps.prototype;
//--------------- PRIVATE METHODS --------------------------------
o._userTemplateLimit = function() {
return this.opts.max_user_templates || 0;
};
/**
* Internal function to communicate with redis
*
* @param redisFunc - the redis function to execute
* @param redisArgs - the arguments for the redis function in an array
* @param callback - function to pass results too.
*/
o._redisCmd = function(redisFunc, redisArgs, callback) {
var redisClient;
var that = this;
var db = that.db_signatures;
step(
function getRedisClient() {
that.redis_pool.acquire(db, this);
},
function executeQuery(err, data) {
assert.ifError(err);
redisClient = data;
redisArgs.push(this);
redisClient[redisFunc.toUpperCase()].apply(redisClient, redisArgs);
},
function releaseRedisClient(err, data) {
if ( ! _.isUndefined(redisClient) ) {
that.redis_pool.release(db, redisClient);
}
callback(err, data);
}
);
};
var _reValidNameIdentifier = /^[a-z0-9][0-9a-z_\-]*$/i;
var _reValidPlaceholderIdentifier = /^[a-z][0-9a-z_]*$/i;
// jshint maxcomplexity:15
o._checkInvalidTemplate = function(template) {
if ( template.version !== '0.0.1' ) {
return new Error("Unsupported template version " + template.version);
}
var tplname = template.name;
if ( ! tplname ) {
return new Error("Missing template name");
}
if ( ! tplname.match(_reValidNameIdentifier) ) {
return new Error("Invalid characters in template name '" + tplname + "'");
}
var invalidError = isInvalidLayergroup(template.layergroup);
if (invalidError) {
return invalidError;
}
var placeholders = template.placeholders || {};
var placeholderKeys = Object.keys(placeholders);
for (var i = 0, len = placeholderKeys.length; i < len; i++) {
var placeholderKey = placeholderKeys[i];
if (!placeholderKey.match(_reValidPlaceholderIdentifier)) {
return new Error("Invalid characters in placeholder name '" + placeholderKey + "'");
}
if ( ! placeholders[placeholderKey].hasOwnProperty('default') ) {
return new Error("Missing default for placeholder '" + placeholderKey + "'");
}
if ( ! placeholders[placeholderKey].hasOwnProperty('type') ) {
return new Error("Missing type for placeholder '" + placeholderKey + "'");
}
}
var auth = template.auth || {};
switch ( auth.method ) {
case 'open':
break;
case 'token':
if ( ! _.isArray(auth.valid_tokens) ) {
return new Error("Invalid 'token' authentication: missing valid_tokens");
}
if ( ! auth.valid_tokens.length ) {
return new Error("Invalid 'token' authentication: no valid_tokens");
}
break;
default:
return new Error("Unsupported authentication method: " + auth.method);
}
return false;
};
function isInvalidLayergroup(layergroup) {
if (!layergroup) {
return new Error('Missing layergroup');
}
var layers = layergroup.layers;
if (!_.isArray(layers) || layers.length === 0) {
return new Error('Missing or empty layers array from layergroup config');
}
var invalidLayers = layers
.map(function(layer, layerIndex) {
return layer.options ? null : layerIndex;
})
.filter(function(layerIndex) {
return layerIndex !== null;
});
if (invalidLayers.length) {
return new Error('Missing `options` in layergroup config for layers: ' + invalidLayers.join(', '));
}
return false;
}
function templateDefaults(template) {
var templateAuth = _.defaults({}, template.auth || {}, {
method: 'open'
});
return _.defaults({ auth: templateAuth }, template, {
placeholders: {}
});
}
//--------------- PUBLIC API -------------------------------------
// Add a template
//
// NOTE: locks user+template_name or fails
//
// @param owner cartodb username of the template owner
//
// @param template layergroup template, see
// http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps#template-format
//
// @param callback function(err, tpl_id)
// Return template identifier (only valid for given user)
//
o.addTemplate = function(owner, template, callback) {
var self = this;
template = templateDefaults(template);
var invalidError = this._checkInvalidTemplate(template);
if ( invalidError ) {
return callback(invalidError);
}
var templateName = template.name;
var userTemplatesKey = this.key_usr_tpl({ owner:owner });
var limit = this._userTemplateLimit();
step(
function checkLimit() {
if ( ! limit ) {
return 0;
}
self._redisCmd('HLEN', [ userTemplatesKey ], this);
},
function installTemplateIfDoesNotExist(err, numberOfTemplates) {
assert.ifError(err);
if ( limit && numberOfTemplates >= limit ) {
var limitReachedError = new Error("User '" + owner + "' reached limit on number of templates (" +
numberOfTemplates + "/" + limit + ")");
limitReachedError.http_status = 409;
throw limitReachedError;
}
self._redisCmd('HSETNX', [ userTemplatesKey, templateName, JSON.stringify(template) ], this);
},
function validateInstallation(err, wasSet) {
assert.ifError(err);
if ( ! wasSet ) {
throw new Error("Template '" + templateName + "' of user '" + owner + "' already exists");
}
return true;
},
function finish(err) {
if (!err) {
self.emit('add', owner, templateName, template);
}
callback(err, templateName, template);
}
);
};
// Delete a template
//
// @param owner cartodb username of the template owner
//
// @param tpl_id template identifier as returned
// by addTemplate or listTemplates
//
// @param callback function(err)
//
o.delTemplate = function(owner, tpl_id, callback) {
var self = this;
step(
function deleteTemplate() {
self._redisCmd('HDEL', [ self.key_usr_tpl({ owner:owner }), tpl_id ], this);
},
function handleDeletion(err, deleted) {
assert.ifError(err);
if (!deleted) {
throw new Error("Template '" + tpl_id + "' of user '" + owner + "' does not exist");
}
return true;
},
function finish(err) {
if (!err) {
self.emit('delete', owner, tpl_id);
}
callback(err);
}
);
};
// Update a template
//
// NOTE: locks user+template_name or fails
//
// Also deletes and re-creates associated authentication certificate,
// which in turn deletes all instance signatures
//
// @param owner cartodb username of the template owner
//
// @param tpl_id template identifier as returned by addTemplate
//
// @param template layergroup template, see
// http://github.com/CartoDB/Windshaft-cartodb/wiki/Template-maps#template-format
//
// @param callback function(err)
//
o.updTemplate = function(owner, tpl_id, template, callback) {
var self = this;
template = templateDefaults(template);
var invalidError = this._checkInvalidTemplate(template);
if ( invalidError ) {
return callback(invalidError);
}
var templateName = template.name;
if ( tpl_id !== templateName ) {
return callback(new Error("Cannot update name of a map template ('" + tpl_id + "' != '" + templateName + "')"));
}
var userTemplatesKey = this.key_usr_tpl({ owner:owner });
var previousTemplate = null;
step(
function getExistingTemplate() {
self._redisCmd('HGET', [ userTemplatesKey, tpl_id ], this);
},
function updateTemplate(err, _currentTemplate) {
assert.ifError(err);
if (!_currentTemplate) {
throw new Error("Template '" + tpl_id + "' of user '" + owner + "' does not exist");
}
previousTemplate = _currentTemplate;
self._redisCmd('HSET', [ userTemplatesKey, templateName, JSON.stringify(template) ], this);
},
function handleTemplateUpdate(err, didSetNewField) {
assert.ifError(err);
if (didSetNewField) {
debug('New template created on update operation');
}
return true;
},
function finish(err) {
if (!err) {
if (self.fingerPrint(JSON.parse(previousTemplate)) !== self.fingerPrint(template)) {
self.emit('update', owner, templateName, template);
}
}
callback(err, template);
}
);
};
// List user templates
//
// @param owner cartodb username of the templates owner
//
// @param callback function(err, tpl_id_list)
// Returns a list of template identifiers
//
o.listTemplates = function(owner, callback) {
this._redisCmd('HKEYS', [ this.key_usr_tpl({owner:owner}) ], callback);
};
// Get a templates
//
// @param owner cartodb username of the template owner
//
// @param tpl_id template identifier as returned
// by addTemplate or listTemplates
//
// @param callback function(err, template)
// Return full template definition
//
o.getTemplate = function(owner, tpl_id, callback) {
var self = this;
step(
function getTemplate() {
self._redisCmd('HGET', [ self.key_usr_tpl({owner:owner}), tpl_id ], this);
},
function parseTemplate(err, tpl_val) {
assert.ifError(err);
return JSON.parse(tpl_val);
},
function finish(err, tpl) {
callback(err, tpl);
}
);
};
o.isAuthorized = function(template, authTokens) {
if (!template) {
return false;
}
authTokens = _.isArray(authTokens) ? authTokens : [authTokens];
var templateAuth = template.auth;
if (!templateAuth) {
return false;
}
if (_.isString(templateAuth) && templateAuth === 'open') {
return true;
}
if (templateAuth.method === 'open') {
return true;
}
if (templateAuth.method === 'token') {
return _.intersection(templateAuth.valid_tokens, authTokens).length > 0;
}
return false;
};
// Perform placeholder substitutions on a template
//
// @param template a template object (will not be modified)
//
// @param params an object containing named subsitution parameters
// Only the ones found in the template's placeholders object
// will be used, with missing ones taking default values.
//
// @returns a layergroup configuration
//
// @throws Error on malformed template or parameter
//
var _reNumber = /^([-+]?[\d\.]?\d+([eE][+-]?\d+)?)$/,
_reCSSColorName = /^[a-zA-Z]+$/,
_reCSSColorVal = /^#[0-9a-fA-F]{3,6}$/;
function _replaceVars (str, params) {
//return _.template(str, params); // lazy way, possibly dangerous
// Construct regular expressions for each param
Object.keys(params).forEach(function(k) {
str = str.replace(new RegExp("<%=\\s*" + k + "\\s*%>", "g"), params[k]);
});
return str;
}
o.instance = function(template, params) {
var all_params = {};
var phold = template.placeholders || {};
Object.keys(phold).forEach(function(k) {
var val = params.hasOwnProperty(k) ? params[k] : phold[k].default;
var type = phold[k].type;
// properly escape
if ( type === 'sql_literal' ) {
// duplicate any single-quote
val = val.replace(/'/g, "''");
}
else if ( type === 'sql_ident' ) {
// duplicate any double-quote
val = val.replace(/"/g, '""');
}
else if ( type === 'number' ) {
// check it's a number
if ( typeof(val) !== 'number' && ! val.match(_reNumber) ) {
throw new Error("Invalid number value for template parameter '" + k + "': " + val);
}
}
else if ( type === 'css_color' ) {
// check it only contains letters or
// starts with # and only contains hexdigits
if ( ! val.match(_reCSSColorName) && ! val.match(_reCSSColorVal) ) {
throw new Error("Invalid css_color value for template parameter '" + k + "': " + val);
}
}
else {
// NOTE: should be checked at template create/update time
throw new Error("Invalid placeholder type '" + type + "'");
}
all_params[k] = val;
});
// NOTE: we're deep-cloning the layergroup here
var layergroup = JSON.parse(JSON.stringify(template.layergroup));
for (var i=0; i<layergroup.layers.length; ++i) {
var lyropt = layergroup.layers[i].options;
if ( params.styles && params.styles[i] ) {
// dynamic styling for this layer
lyropt.cartocss = params.styles[i];
} else if ( lyropt.cartocss ) {
lyropt.cartocss = _replaceVars(lyropt.cartocss, all_params);
}
if ( lyropt.sql) {
lyropt.sql = _replaceVars(lyropt.sql, all_params);
}
// Anything else ?
}
// extra information about the template
layergroup.template = {
name: template.name,
auth: template.auth
};
return layergroup;
};
// Return a fingerPrint of the object
o.fingerPrint = function(template) {
return crypto.createHash('md5')
.update(JSON.stringify(template))
.digest('hex')
;
};
module.exports.templateName = function templateName(templateId) {
var templateIdTokens = templateId.split('@');
var name = templateIdTokens[0];
if (templateIdTokens.length > 1) {
name = templateIdTokens[1];
}
return name;
};

View File

@@ -0,0 +1,97 @@
'use strict';
var dot = require('dot');
dot.templateSettings.strip = false;
function createTemplate(method) {
return dot.template([
'SELECT',
method,
'FROM ({{=it._sql}}) _table_sql WHERE {{=it._column}} IS NOT NULL'
].join('\n'));
}
var methods = {
quantiles: 'CDB_QuantileBins(array_agg(distinct({{=it._column}}::numeric)), {{=it._buckets}}) as quantiles',
equal: 'CDB_EqualIntervalBins(array_agg({{=it._column}}::numeric), {{=it._buckets}}) as equal',
jenks: 'CDB_JenksBins(array_agg(distinct({{=it._column}}::numeric)), {{=it._buckets}}) as jenks',
headtails: 'CDB_HeadsTailsBins(array_agg(distinct({{=it._column}}::numeric)), {{=it._buckets}}) as headtails'
};
var methodTemplates = Object.keys(methods).reduce(function(methodTemplates, methodName) {
methodTemplates[methodName] = createTemplate(methods[methodName]);
return methodTemplates;
}, {});
methodTemplates.category = dot.template([
'WITH',
'categories AS (',
' SELECT {{=it._column}} AS category, count(1) AS value, row_number() OVER (ORDER BY count(1) desc) as rank',
' FROM ({{=it._sql}}) _cdb_aggregation_all',
' GROUP BY {{=it._column}}',
' ORDER BY 2 DESC',
'),',
'agg_categories AS (',
' SELECT \'__other\' category',
' FROM categories',
' WHERE rank >= {{=it._buckets}}',
' GROUP BY 1',
' UNION ALL',
' SELECT CAST(category AS text)',
' FROM categories',
' WHERE rank < {{=it._buckets}}',
')',
'SELECT array_agg(category) AS category FROM agg_categories'
].join('\n'));
var STRATEGY = {
SPLIT: 'split',
EXACT: 'exact'
};
var method2strategy = {
headtails: STRATEGY.SPLIT,
category: STRATEGY.EXACT
};
function PostgresDatasource (psql, query) {
this.psql = psql;
this.query = query;
}
PostgresDatasource.prototype.getName = function () {
return 'PostgresDatasource';
};
PostgresDatasource.prototype.getRamp = function (column, buckets, method, callback) {
if (method && !methodTemplates.hasOwnProperty(method)) {
return callback(new Error(
'Invalid method "' + method + '", valid methods: [' + Object.keys(methodTemplates).join(',') + ']'
));
}
var methodName = method || 'quantiles';
var template = methodTemplates[methodName];
var query = template({ _column: column, _sql: this.query, _buckets: buckets });
this.psql.query(query, function (err, resultSet) {
if (err) {
return callback(err);
}
resultSet = resultSet || {};
var result = resultSet.rows || [];
var strategy = method2strategy[methodName];
var ramp = result[0][methodName] || [];
if (strategy !== STRATEGY.EXACT) {
ramp = ramp.sort(function(a, b) {
return a - b;
});
}
return callback(null, { ramp: ramp, strategy: strategy });
}, true); // use read-only transaction
};
module.exports = PostgresDatasource;

16
lib/cartodb/cache/backend/fastly.js vendored Normal file
View File

@@ -0,0 +1,16 @@
var FastlyPurge = require('fastly-purge');
function FastlyCacheBackend(apiKey, serviceId) {
this.serviceId = serviceId;
this.fastlyPurge = new FastlyPurge(apiKey, { softPurge: false });
}
module.exports = FastlyCacheBackend;
/**
* @param cacheObject should respond to `key() -> String` method
* @param {Function} callback
*/
FastlyCacheBackend.prototype.invalidate = function(cacheObject, callback) {
this.fastlyPurge.key(this.serviceId, cacheObject.key(), callback);
};

View File

@@ -0,0 +1,30 @@
var request = require('request');
function VarnishHttpCacheBackend(host, port) {
this.host = host;
this.port = port;
}
module.exports = VarnishHttpCacheBackend;
/**
* @param cacheObject should respond to `key() -> String` method
* @param {Function} callback
*/
VarnishHttpCacheBackend.prototype.invalidate = function(cacheObject, callback) {
request(
{
method: 'PURGE',
url: 'http://' + this.host + ':' + this.port + '/key',
headers: {
'Invalidation-Match': '\\b' + cacheObject.key() + '\\b'
}
},
function(err, response) {
if (err || response.statusCode !== 204) {
return callback(new Error('Unable to invalidate Varnish object'));
}
return callback(null);
}
);
};

View File

@@ -0,0 +1,24 @@
var LruCache = require('lru-cache');
function LayergroupAffectedTables() {
// dbname + layergroupId -> affected tables cache
this.cache = new LruCache({ max: 2000 });
}
module.exports = LayergroupAffectedTables;
LayergroupAffectedTables.prototype.hasAffectedTables = function(dbName, layergroupId) {
return this.cache.has(createKey(dbName, layergroupId));
};
LayergroupAffectedTables.prototype.set = function(dbName, layergroupId, affectedTables) {
this.cache.set(createKey(dbName, layergroupId), affectedTables);
};
LayergroupAffectedTables.prototype.get = function(dbName, layergroupId) {
return this.cache.get(createKey(dbName, layergroupId));
};
function createKey(dbName, layergroupId) {
return dbName + ':' + layergroupId;
}

View File

@@ -0,0 +1,18 @@
var crypto = require('crypto');
function NamedMaps(owner, name) {
this.namespace = 'n';
this.owner = owner;
this.name = name;
}
module.exports = NamedMaps;
NamedMaps.prototype.key = function() {
return this.namespace + ':' + shortHashKey(this.owner + ':' + this.name);
};
function shortHashKey(target) {
return crypto.createHash('sha256').update(target).digest('base64').substring(0,6);
}

View File

@@ -0,0 +1,86 @@
var _ = require('underscore');
var dot = require('dot');
var NamedMapMapConfigProvider = require('../models/mapconfig/provider/named-map-provider');
var templateName = require('../backends/template_maps').templateName;
var queue = require('queue-async');
var LruCache = require("lru-cache");
function NamedMapProviderCache(templateMaps, pgConnection, metadataBackend, userLimitsApi, mapConfigAdapter) {
this.templateMaps = templateMaps;
this.pgConnection = pgConnection;
this.metadataBackend = metadataBackend;
this.userLimitsApi = userLimitsApi;
this.mapConfigAdapter = mapConfigAdapter;
this.providerCache = new LruCache({ max: 2000 });
}
module.exports = NamedMapProviderCache;
NamedMapProviderCache.prototype.get = function(user, templateId, config, authToken, params, callback) {
var namedMapKey = createNamedMapKey(user, templateId);
var namedMapProviders = this.providerCache.get(namedMapKey) || {};
var providerKey = createProviderKey(config, authToken, params);
if (!namedMapProviders.hasOwnProperty(providerKey)) {
namedMapProviders[providerKey] = new NamedMapMapConfigProvider(
this.templateMaps,
this.pgConnection,
this.metadataBackend,
this.userLimitsApi,
this.mapConfigAdapter,
user,
templateId,
config,
authToken,
params
);
this.providerCache.set(namedMapKey, namedMapProviders);
// early exit, if provider did not exist we just return it
return callback(null, namedMapProviders[providerKey]);
}
var namedMapProvider = namedMapProviders[providerKey];
var self = this;
queue(2)
.defer(namedMapProvider.getTemplate.bind(namedMapProvider))
.defer(this.templateMaps.getTemplate.bind(this.templateMaps), user, templateId)
.awaitAll(function templatesQueueDone(err, results) {
if (err) {
return callback(err);
}
// We want to reset provider its template has changed
// Ideally this should be done in a passive mode where this cache gets notified of template changes
var uniqueFingerprints = _.uniq(results.map(self.templateMaps.fingerPrint)).length;
if (uniqueFingerprints > 1) {
namedMapProvider.reset();
}
return callback(null, namedMapProvider);
});
};
NamedMapProviderCache.prototype.invalidate = function(user, templateId) {
this.providerCache.del(createNamedMapKey(user, templateId));
};
function createNamedMapKey(user, templateId) {
return user + ':' + templateName(templateId);
}
var providerKey = '{{=it.authToken}}:{{=it.configHash}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}';
var providerKeyTpl = dot.template(providerKey);
function createProviderKey(config, authToken, params) {
var tplValues = _.defaults({}, params, {
authToken: authToken || '',
configHash: NamedMapMapConfigProvider.configHash(config),
layer: '',
format: '',
scale_factor: 1
});
return providerKeyTpl(tplValues);
}

View File

@@ -0,0 +1,53 @@
var queue = require('queue-async');
/**
* @param {Array|Object} cacheBackends each backend backend should respond to `invalidate(cacheObject, callback)` method
* @constructor
*/
function SurrogateKeysCache(cacheBackends) {
this.cacheBackends = Array.isArray(cacheBackends) ? cacheBackends : [cacheBackends];
}
module.exports = SurrogateKeysCache;
/**
* @param response should respond to `header(key, value)` method
* @param cacheObject should respond to `key() -> String` method
*/
SurrogateKeysCache.prototype.tag = function(response, cacheObject) {
var newKey = cacheObject.key();
response.set('Surrogate-Key', appendSurrogateKey(
response.get('Surrogate-Key'),
Array.isArray(newKey) ? cacheObject.key().join(' ') : newKey
));
};
function appendSurrogateKey(currentKey, newKey) {
if (!!currentKey) {
newKey = currentKey + ' ' + newKey;
}
return newKey;
}
/**
* @param cacheObject should respond to `key() -> String` method
* @param {Function} callback
*/
SurrogateKeysCache.prototype.invalidate = function(cacheObject, callback) {
var invalidationQueue = queue(this.cacheBackends.length);
this.cacheBackends.forEach(function(cacheBackend) {
invalidationQueue.defer(function(cacheBackend, done) {
cacheBackend.invalidate(cacheObject, done);
}, cacheBackend);
});
invalidationQueue.awaitAll(function(err, result) {
if (err) {
return callback(err);
}
callback(null, result);
});
};

View File

@@ -1,89 +0,0 @@
var _ = require('underscore'),
Varnish = require('node-varnish'),
request = require('request'),
crypto = require('crypto'),
channelCache = {},
varnish_queue = null;
function init(host, port) {
varnish_queue = new Varnish.VarnishQueue(host, port);
}
function invalidate_db(dbname, table) {
try{
varnish_queue.run_cmd('purge obj.http.X-Cache-Channel ~ "^' + dbname + ':(.*'+ table +'.*)|(table)$"');
console.log('[SUCCESS FLUSHING CACHE]');
} catch (e) {
console.log("[ERROR FLUSHING CACHE] Is enable_cache set to true? Failed for: " + 'purge obj.http.X-Cache-Channel ~ "^' + dbname + ':(.*'+ table +'.*)|(table)$"');
}
}
function generateCacheChannel(req, callback){
var cacheChannel = "";
// use key to call sql api with sql request if present, else just return dbname and table name
// base key
var tableNames = req.params.table;
var dbName = req.params.dbname;
var username = req.headers.host.split('.')[0];
// replace tableNames with the results of the explain if present
if (_.isString(req.params.sql) && req.params.sql != ''){
// initialise MD5 key of sql for cache lookups
var sql_md5 = generateMD5(req.params.sql);
var api = global.environment.sqlapi;
var qs = {};
// use cache if present
if (!_.isNull(channelCache[sql_md5]) && !_.isUndefined(channelCache[sql_md5])) {
callback(channelCache[sql_md5]);
} else{
// strip out windshaft/mapnik inserted sql if present
var sql = req.params.sql.match(/^\((.*)\)\sas\scdbq$/);
sql = (sql != null) ? sql[1] : req.params.sql;
// build up api string
var sqlapi = api.protocol + '://' + username + '.' + api.host + ':' + api.port + '/api/' + api.version + '/sql'
// add query to querystring
qs.q = 'SELECT CDB_QueryTables($windshaft$' + sql + '$windshaft$)';
// add api_key if present in tile request (means table is private)
if (_.isString(req.params.map_key) && req.params.map_key != ''){
qs.api_key = req.params.map_key;
}
// call sql api
request.get({url:sqlapi, qs:qs, json:true}, function(err, response, body){
if (!err && response.statusCode == 200) {
tableNames = body.rows[0].cdb_querytables.split(/^\{(.*)\}$/)[1];
} else {
//oops, no SQL API. Just cache using fallback 'table' key
tableNames = 'table';
}
cacheChannel = buildCacheChannel(dbName,tableNames);
channelCache[sql_md5] = cacheChannel; // store for caching
callback(cacheChannel);
});
}
} else {
cacheChannel = buildCacheChannel(dbName,tableNames);
callback(cacheChannel);
}
}
function buildCacheChannel(dbName, tableNames){
return dbName + ':' + tableNames;
}
function generateMD5(data){
var hash = crypto.createHash('md5');
hash.update(data);
return hash.digest('hex');
}
module.exports = {
init: init,
invalidate_db: invalidate_db,
generateCacheChannel: generateCacheChannel
}

View File

@@ -1,243 +0,0 @@
/**
* User: simon
* Date: 30/08/2011
* Time: 21:10
* Desc: CartoDB helper.
* Retrieves dbname (based on subdomain/username)
* and geometry type from the redis stores of cartodb
*/
var RedisPool = require("./redis_pool")
, _ = require('underscore')
, Step = require('step');
module.exports = function() {
var redis_pool = new RedisPool(global.environment.redis);
var me = {
user_metadata_db: 5,
table_metadata_db: 0,
user_key: "rails:users:<%= username %>",
table_key: "rails:<%= database_name %>:<%= table_name %>"
};
/**
* Get the database name for this particular subdomain/username
*
* @param req - standard express req object. importantly contains host information
* @param callback - gets called with args(err, dbname)
*/
me.getDatabase = function(req, callback) {
// strip subdomain from header host
var username = req.headers.host.split('.')[0]
var redisKey = _.template(this.user_key, {username: username});
this.retrieve(this.user_metadata_db, redisKey, 'database_name', function(err, dbname) {
if ( err ) callback(err, null);
else if ( dbname === null ) {
callback(new Error("missing " + username + "'s dbname in redis (try CARTODB/script/restore_redis)"), null);
}
else callback(err, dbname);
});
};
/**
* Get the user id for this particular subdomain/username
*
* @param req - standard express req object. importantly contains host information
* @param callback
*/
me.getId= function(req, callback) {
// strip subdomain from header host
var username = req.headers.host.split('.')[0];
var redisKey = _.template(this.user_key, {username: username});
this.retrieve(this.user_metadata_db, redisKey, 'id', function(err, dbname) {
if ( err ) callback(err, null);
else if ( dbname === null ) {
callback(new Error("missing " + username + "'s dbuser in redis (try CARTODB/script/restore_redis)"), null);
}
else callback(err, dbname);
});
};
/**
* Check the user map key for this particular subdomain/username
*
* @param req - standard express req object. importantly contains host information
* @param callback
*/
me.checkMapKey = function(req, callback) {
// strip subdomain from header host
var username = req.headers.host.split('.')[0];
var redisKey = "rails:users:" + username;
this.retrieve(this.user_metadata_db, redisKey, "map_key", function(err, val) {
var valid = 0;
if ( val ) {
if ( val == req.query.map_key ) valid = 1;
else if ( val == req.query.api_key ) valid = 1;
// check also in request body
else if ( req.body && req.body.map_key && val == req.body.map_key ) valid = 1;
else if ( req.body && req.body.api_key && val == req.body.api_key ) valid = 1;
}
callback(err, valid);
});
};
/**
* Get privacy for cartodb table
*
* @param req - standard req object. Importantly contains table and host information
* @param callback - is the table private or not?
*/
me.authorize= function(req, callback) {
var that = this;
Step(
function(){
that.checkMapKey(req, this);
},
function checkIfInternal(err, check_result){
if (err) throw err;
if (check_result === 1) {
// authorized by key, login as db owner
that.getId(req, function(err, user_id) {
if (err) throw new Error(err);
var dbuser = _.template(global.settings.postgres_auth_user, {user_id: user_id});
_.extend(req, {dbuser:dbuser});
callback(err, true);
});
} else {
return true; // continue to check if the table is public/private
}
}
,function (err, data){
if (err) throw err;
that.getDatabase(req, this);
},
function(err, data){
if (err) throw err;
var redisKey = _.template(that.table_key, {database_name: data, table_name: req.params.table});
that.retrieve(that.table_metadata_db, redisKey, 'privacy', this);
},
function(err, data){
if (err) throw err;
callback(err, data);
}
);
};
/**
* Get the geometry type for this particular table;
* @param req - standard req object. Importantly contains table and host information
* @param callback
*/
me.getGeometryType = function(req, callback){
var that = this;
Step(
function(){
that.getDatabase(req, this)
},
function(err, data){
if (err) throw err;
var redisKey = _.template(that.table_key, {database_name: data, table_name: req.params.table});
that.retrieve(that.table_metadata_db, redisKey, 'the_geom_type', this);
},
function(err, data){
if (err) throw err;
callback(err, data);
}
);
};
me.getInfowindow = function(req, callback){
var that = this;
Step(
function(){
that.getDatabase(req, this);
},
function(err, data) {
if (err) throw err;
var redisKey = _.template(that.table_key, {database_name: data, table_name: req.params.table});
that.retrieve(that.table_metadata_db, redisKey, 'infowindow', this);
},
function(err, data){
if (err) throw err;
callback(err, data);
}
);
};
me.getMapMetadata = function(req, callback){
var that = this;
Step(
function(){
that.getDatabase(req, this);
},
function(err, data) {
if (err) throw err;
var redisKey = _.template(that.table_key, {database_name: data, table_name: req.params.table});
that.retrieve(that.table_metadata_db, redisKey, 'map_metadata', this);
},
function(err, data){
if (err) throw err;
callback(err, data);
}
);
};
// Redis Hash lookup
// @param callback will be invoked with args (err, reply)
// note that reply is null when the key is missing
me.retrieve = function(db, redisKey, hashKey, callback) {
this.redisCmd(db,'HGET',[redisKey, hashKey], callback);
};
// Redis Set member check
me.inSet = function(db, setKey, member, callback) {
this.redisCmd(db,'SISMEMBER',[setKey, member], callback);
};
/**
* Use Redis
*
* @param db - redis database number
* @param redisFunc - the redis function to execute
* @param redisArgs - the arguments for the redis function in an array
* @param callback - function to pass results too.
*/
me.redisCmd = function(db, redisFunc, redisArgs, callback) {
var redisClient;
Step(
function getRedisClient() {
redis_pool.acquire(db, this);
},
function executeQuery(err, data) {
redisClient = data;
redisArgs.push(this);
redisClient[redisFunc.toUpperCase()].apply(redisClient, redisArgs);
},
function releaseRedisClient(err, data) {
if (err) throw err;
redis_pool.release(db, redisClient);
callback(err, data);
}
);
};
return me;
}();

View File

@@ -1,90 +0,0 @@
var _ = require('underscore')
, Step = require('step')
, Windshaft = require('windshaft')
, Cache = require('./cache_validator');
var CartodbWindshaft = function(serverOptions) {
if(serverOptions.cache_enabled) {
console.log("cache invalidation enabled, varnish on ", serverOptions.varnish_host, ' ', serverOptions.varnish_port);
Cache.init(serverOptions.varnish_host, serverOptions.varnish_port);
serverOptions.afterStateChange = function(req, data, callback) {
Cache.invalidate_db(req.params.dbname, req.params.table);
callback(null, data);
}
}
serverOptions.beforeStateChange = function(req, callback) {
var err = null;
if ( ! req.hasOwnProperty('dbuser') ) {
err = new Error("map state cannot be changed by unauthenticated request!");
}
callback(err, req);
}
// boot
var ws = new Windshaft.Server(serverOptions);
/**
* Helper to allow access to the layer to be used in the maps infowindow popup.
*/
ws.get(serverOptions.base_url + '/infowindow', function(req, res){
ws.doCORS(res);
Step(
function(){
serverOptions.getInfowindow(req, this);
},
function(err, data){
if (err){
res.send({error: err.message}, 500);
} else {
res.send({infowindow: data}, 200);
}
}
);
});
/**
* Helper to allow access to metadata to be used in embedded maps.
*/
ws.get(serverOptions.base_url + '/map_metadata', function(req, res){
ws.doCORS(res);
Step(
function(){
serverOptions.getMapMetadata(req, this);
},
function(err, data){
if (err){
res.send(err.message, 500);
} else {
res.send({map_metadata: data}, 200);
}
}
);
});
/**
* Helper API to allow per table tile cache (and sql cache) to be invalidated remotely.
* TODO: Move?
*/
ws.del(serverOptions.base_url + '/flush_cache', function(req, res){
ws.doCORS(res);
Step(
function(){
serverOptions.flushCache(req, serverOptions.cache_enabled ? Cache : null, this);
},
function(err, data){
if (err){
res.send(500);
} else {
res.send({status: 'ok'}, 200);
}
}
);
});
return ws;
}
module.exports = CartodbWindshaft;

View File

@@ -0,0 +1,287 @@
var assert = require('assert');
var _ = require('underscore');
var step = require('step');
var debug = require('debug')('windshaft:cartodb');
var LZMA = require('lzma').LZMA;
var lzmaWorker = new LZMA();
// Whitelist query parameters and attach format
var REQUEST_QUERY_PARAMS_WHITELIST = [
'config',
'map_key',
'api_key',
'auth_token',
'callback',
'zoom',
'lon',
'lat',
// widgets & filters
'filters', // json
'own_filter', // 0, 1
'bbox', // w,s,e,n
'bins', // number
'start', // number
'end', // number
'column_type', // string
// widgets search
'q'
];
function BaseController(authApi, pgConnection) {
this.authApi = authApi;
this.pgConnection = pgConnection;
}
module.exports = BaseController;
// jshint maxcomplexity:9
/**
* Whitelist input and get database name & default geometry type from
* subdomain/user metadata held in CartoDB Redis
* @param req - standard express request obj. Should have host & table
* @param callback
*/
BaseController.prototype.req2params = function(req, callback){
var self = this;
if ( req.query.lzma ) {
// Decode (from base64)
var lzma = new Buffer(req.query.lzma, 'base64')
.toString('binary')
.split('')
.map(function(c) {
return c.charCodeAt(0) - 128;
});
// Decompress
lzmaWorker.decompress(
lzma,
function(result) {
if (req.profiler) {
req.profiler.done('lzma');
}
try {
delete req.query.lzma;
_.extend(req.query, JSON.parse(result));
self.req2params(req, callback);
} catch (err) {
req.profiler.done('req2params');
callback(new Error('Error parsing lzma as JSON: ' + err));
}
}
);
return;
}
req.query = _.pick(req.query, REQUEST_QUERY_PARAMS_WHITELIST);
req.params = _.extend({}, req.params); // shuffle things as request is a strange array/object
var user = req.context.user;
if ( req.params.token ) {
// Token might match the following patterns:
// - {user}@{tpl_id}@{token}:{cache_buster}
var tksplit = req.params.token.split(':');
req.params.token = tksplit[0];
if ( tksplit.length > 1 ) {
req.params.cache_buster= tksplit[1];
}
tksplit = req.params.token.split('@');
if ( tksplit.length > 1 ) {
req.params.signer = tksplit.shift();
if ( ! req.params.signer ) {
req.params.signer = user;
}
else if ( req.params.signer !== user ) {
var err = new Error(
'Cannot use map signature of user "' + req.params.signer + '" on db of user "' + user + '"'
);
err.http_status = 403;
req.profiler.done('req2params');
callback(err);
return;
}
if ( tksplit.length > 1 ) {
/*var template_hash = */tksplit.shift(); // unused
}
req.params.token = tksplit.shift();
}
}
// bring all query values onto req.params object
_.extend(req.params, req.query);
if (req.profiler) {
req.profiler.done('req2params.setup');
}
step(
function getPrivacy(){
self.authApi.authorize(req, this);
},
function validateAuthorization(err, authorized) {
if (req.profiler) {
req.profiler.done('authorize');
}
assert.ifError(err);
if(!authorized) {
err = new Error("Sorry, you are unauthorized (permission denied)");
err.http_status = 403;
throw err;
}
return null;
},
function getDatabase(err){
assert.ifError(err);
self.pgConnection.setDBConn(user, req.params, this);
},
function finishSetup(err) {
if ( err ) {
req.profiler.done('req2params');
return callback(err, req);
}
// Add default database connection parameters
// if none given
_.defaults(req.params, {
dbuser: global.environment.postgres.user,
dbpassword: global.environment.postgres.password,
dbhost: global.environment.postgres.host,
dbport: global.environment.postgres.port
});
req.profiler.done('req2params');
callback(null, req);
}
);
};
// jshint maxcomplexity:6
// jshint maxcomplexity:9
BaseController.prototype.send = function(req, res, body, status, headers) {
if (req.params.dbhost) {
res.set('X-Served-By-DB-Host', req.params.dbhost);
}
if (req.profiler) {
res.set('X-Tiler-Profiler', req.profiler.toJSONString());
}
if (headers) {
res.set(headers);
}
res.status(status);
if (!Buffer.isBuffer(body) && typeof body === 'object') {
if (req.query && req.query.callback) {
res.jsonp(body);
} else {
res.json(body);
}
} else {
res.send(body);
}
if (req.profiler) {
try {
// May throw due to dns, see
// See http://github.com/CartoDB/Windshaft/issues/166
req.profiler.sendStats();
} catch (err) {
debug("error sending profiling stats: " + err);
}
}
};
// jshint maxcomplexity:6
BaseController.prototype.sendError = function(req, res, err, label) {
var allErrors = Array.isArray(err) ? err : [err];
label = label || 'UNKNOWN';
err = allErrors[0] || new Error(label);
allErrors[0] = err;
var statusCode = findStatusCode(err);
debug('[%s ERROR] -- %d: %s, %s', label, statusCode, err, err.stack);
// If a callback was requested, force status to 200
if (req.query && req.query.callback) {
statusCode = 200;
}
var errorResponseBody = {
errors: allErrors.map(errorMessage),
errors_with_context: allErrors.map(errorMessageWithContext)
};
this.send(req, res, errorResponseBody, statusCode);
};
function stripConnectionInfo(message) {
// Strip connection info, if any
return message
// See https://github.com/CartoDB/Windshaft/issues/173
.replace(/Connection string: '[^']*'\n\s/im, '')
// See https://travis-ci.org/CartoDB/Windshaft/jobs/20703062#L1644
.replace(/is the server.*encountered/im, 'encountered');
}
function errorMessage(err) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
var message = (_.isString(err) ? err : err.message) || 'Unknown error';
return stripConnectionInfo(message);
}
function errorMessageWithContext(err) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
var message = (_.isString(err) ? err : err.message) || 'Unknown error';
return {
type: err.type || 'unknown',
message: stripConnectionInfo(message),
context: err.context || 'unknown'
};
}
module.exports.errorMessage = errorMessage;
function findStatusCode(err) {
var statusCode;
if ( err.http_status ) {
statusCode = err.http_status;
} else {
statusCode = statusFromErrorMessage('' + err);
}
return statusCode;
}
module.exports.findStatusCode = findStatusCode;
function statusFromErrorMessage(errMsg) {
// Find an appropriate statusCode based on message
// jshint maxcomplexity:7
var statusCode = 400;
if ( -1 !== errMsg.indexOf('permission denied') ) {
statusCode = 403;
}
else if ( -1 !== errMsg.indexOf('authentication failed') ) {
statusCode = 403;
}
else if (errMsg.match(/Postgis Plugin.*[\s|\n].*column.*does not exist/)) {
statusCode = 400;
}
else if ( -1 !== errMsg.indexOf('does not exist') ) {
if ( -1 !== errMsg.indexOf(' role ') ) {
statusCode = 403; // role 'xxx' does not exist
} else if ( errMsg.match(/function .* does not exist/) ) {
statusCode = 400; // invalid SQL (SQL function does not exist)
} else {
statusCode = 404;
}
}
return statusCode;
}

View File

@@ -0,0 +1,7 @@
module.exports = {
Layergroup: require('./layergroup'),
Map: require('./map'),
NamedMaps: require('./named_maps'),
NamedMapsAdmin: require('./named_maps_admin'),
ServerInfo: require('./server_info')
};

View File

@@ -0,0 +1,429 @@
var assert = require('assert');
var step = require('step');
var util = require('util');
var BaseController = require('./base');
var cors = require('../middleware/cors');
var userMiddleware = require('../middleware/user');
var DataviewBackend = require('../backends/dataview');
var AnalysisStatusBackend = require('../backends/analysis-status');
var MapStoreMapConfigProvider = require('../models/mapconfig/provider/map-store-provider');
var QueryTables = require('cartodb-query-tables');
/**
* @param {AuthApi} authApi
* @param {PgConnection} pgConnection
* @param {MapStore} mapStore
* @param {TileBackend} tileBackend
* @param {PreviewBackend} previewBackend
* @param {AttributesBackend} attributesBackend
* @param {SurrogateKeysCache} surrogateKeysCache
* @param {UserLimitsApi} userLimitsApi
* @param {LayergroupAffectedTables} layergroupAffectedTables
* @param {AnalysisBackend} analysisBackend
* @constructor
*/
function LayergroupController(authApi, pgConnection, mapStore, tileBackend, previewBackend, attributesBackend,
surrogateKeysCache, userLimitsApi, layergroupAffectedTables, analysisBackend) {
BaseController.call(this, authApi, pgConnection);
this.pgConnection = pgConnection;
this.mapStore = mapStore;
this.tileBackend = tileBackend;
this.previewBackend = previewBackend;
this.attributesBackend = attributesBackend;
this.surrogateKeysCache = surrogateKeysCache;
this.userLimitsApi = userLimitsApi;
this.layergroupAffectedTables = layergroupAffectedTables;
this.dataviewBackend = new DataviewBackend(analysisBackend);
this.analysisStatusBackend = new AnalysisStatusBackend();
}
util.inherits(LayergroupController, BaseController);
module.exports = LayergroupController;
LayergroupController.prototype.register = function(app) {
app.get(app.base_url_mapconfig +
'/:token/:z/:x/:y@:scale_factor?x.:format', cors(), userMiddleware,
this.tile.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:z/:x/:y.:format', cors(), userMiddleware,
this.tile.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:layer/:z/:x/:y.(:format)', cors(), userMiddleware,
this.layer.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:layer/attributes/:fid', cors(), userMiddleware,
this.attributes.bind(this));
app.get(app.base_url_mapconfig +
'/static/center/:token/:z/:lat/:lng/:width/:height.:format', cors(), userMiddleware,
this.center.bind(this));
app.get(app.base_url_mapconfig +
'/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format', cors(), userMiddleware,
this.bbox.bind(this));
// Undocumented/non-supported API endpoint methods.
// Use at your own peril.
app.get(app.base_url_mapconfig +
'/:token/dataview/:dataviewName', cors(), userMiddleware,
this.dataview.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:layer/widget/:dataviewName', cors(), userMiddleware,
this.dataview.bind(this));
app.get(app.base_url_mapconfig +
'/:token/dataview/:dataviewName/search', cors(), userMiddleware,
this.dataviewSearch.bind(this));
app.get(app.base_url_mapconfig +
'/:token/:layer/widget/:dataviewName/search', cors(), userMiddleware,
this.dataviewSearch.bind(this));
app.get(app.base_url_mapconfig +
'/:token/analysis/node/:nodeId', cors(), userMiddleware,
this.analysisNodeStatus.bind(this));
};
LayergroupController.prototype.analysisNodeStatus = function(req, res) {
var self = this;
step(
function setupParams() {
self.req2params(req, this);
},
function retrieveNodeStatus(err) {
assert.ifError(err);
self.analysisStatusBackend.getNodeStatus(req.params, this);
},
function finish(err, nodeStatus, stats) {
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'GET NODE STATUS');
} else {
self.sendResponse(req, res, nodeStatus, 200, {
'Cache-Control': 'public,max-age=5',
'Last-Modified': new Date().toUTCString()
});
}
}
);
};
LayergroupController.prototype.dataview = function(req, res) {
var self = this;
step(
function setupParams() {
self.req2params(req, this);
},
function retrieveDataview(err) {
assert.ifError(err);
var mapConfigProvider = new MapStoreMapConfigProvider(
self.mapStore, req.context.user, self.userLimitsApi, req.params
);
self.dataviewBackend.getDataview(mapConfigProvider, req.context.user, req.params, this);
},
function finish(err, dataview, stats) {
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'GET DATAVIEW');
} else {
self.sendResponse(req, res, dataview, 200);
}
}
);
};
LayergroupController.prototype.dataviewSearch = function(req, res) {
var self = this;
step(
function setupParams() {
self.req2params(req, this);
},
function searchDataview(err) {
assert.ifError(err);
var mapConfigProvider = new MapStoreMapConfigProvider(
self.mapStore, req.context.user, self.userLimitsApi, req.params
);
self.dataviewBackend.search(mapConfigProvider, req.context.user, req.params, this);
},
function finish(err, searchResult, stats) {
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'GET DATAVIEW SEARCH');
} else {
self.sendResponse(req, res, searchResult, 200);
}
}
);
};
LayergroupController.prototype.attributes = function(req, res) {
var self = this;
req.profiler.start('windshaft.maplayer_attribute');
step(
function setupParams() {
self.req2params(req, this);
},
function retrieveFeatureAttributes(err) {
assert.ifError(err);
var mapConfigProvider = new MapStoreMapConfigProvider(
self.mapStore, req.context.user, self.userLimitsApi, req.params
);
self.attributesBackend.getFeatureAttributes(mapConfigProvider, req.params, false, this);
},
function finish(err, tile, stats) {
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'GET ATTRIBUTES');
} else {
self.sendResponse(req, res, tile, 200);
}
}
);
};
// Gets a tile for a given token and set of tile ZXY coords. (OSM style)
LayergroupController.prototype.tile = function(req, res) {
req.profiler.start('windshaft.map_tile');
this.tileOrLayer(req, res);
};
// Gets a tile for a given token, layer set of tile ZXY coords. (OSM style)
LayergroupController.prototype.layer = function(req, res, next) {
if (req.params.token === 'static') {
return next();
}
req.profiler.start('windshaft.maplayer_tile');
this.tileOrLayer(req, res);
};
LayergroupController.prototype.tileOrLayer = function (req, res) {
var self = this;
step(
function mapController$prepareParams() {
self.req2params(req, this);
},
function mapController$getTileOrGrid(err) {
assert.ifError(err);
self.tileBackend.getTile(
new MapStoreMapConfigProvider(self.mapStore, req.context.user, self.userLimitsApi, req.params),
req.params, this
);
},
function mapController$finalize(err, tile, headers, stats) {
req.profiler.add(stats);
self.finalizeGetTileOrGrid(err, req, res, tile, headers);
}
);
};
// This function is meant for being called as the very last
// step by all endpoints serving tiles or grids
LayergroupController.prototype.finalizeGetTileOrGrid = function(err, req, res, tile, headers) {
var supportedFormats = {
grid_json: true,
json_torque: true,
torque_json: true,
png: true
};
var formatStat = 'invalid';
if (req.params.format) {
var format = req.params.format.replace('.', '_');
if (supportedFormats[format]) {
formatStat = format;
}
}
if (err) {
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/68
var errMsg = err.message ? ( '' + err.message ) : ( '' + err );
// Rewrite mapnik parsing errors to start with layer number
var matches = errMsg.match("(.*) in style 'layer([0-9]+)'");
if (matches) {
errMsg = 'style'+matches[2]+': ' + matches[1];
}
err.message = errMsg;
this.sendError(req, res, err, 'TILE RENDER');
global.statsClient.increment('windshaft.tiles.error');
global.statsClient.increment('windshaft.tiles.' + formatStat + '.error');
} else {
this.sendResponse(req, res, tile, 200, headers);
global.statsClient.increment('windshaft.tiles.success');
global.statsClient.increment('windshaft.tiles.' + formatStat + '.success');
}
};
LayergroupController.prototype.bbox = function(req, res) {
this.staticMap(req, res, +req.params.width, +req.params.height, {
west: +req.params.west,
north: +req.params.north,
east: +req.params.east,
south: +req.params.south
});
};
LayergroupController.prototype.center = function(req, res) {
this.staticMap(req, res, +req.params.width, +req.params.height, +req.params.z, {
lng: +req.params.lng,
lat: +req.params.lat
});
};
LayergroupController.prototype.staticMap = function(req, res, width, height, zoom /* bounds */, center) {
var format = req.params.format === 'jpg' ? 'jpeg' : 'png';
req.params.layer = 'all';
req.params.format = 'png';
var self = this;
step(
function reqParams() {
self.req2params(req, this);
},
function getImage(err) {
assert.ifError(err);
if (center) {
self.previewBackend.getImage(
new MapStoreMapConfigProvider(self.mapStore, req.context.user, self.userLimitsApi, req.params),
format, width, height, zoom, center, this);
} else {
self.previewBackend.getImage(
new MapStoreMapConfigProvider(self.mapStore, req.context.user, self.userLimitsApi, req.params),
format, width, height, zoom /* bounds */, this);
}
},
function handleImage(err, image, headers, stats) {
req.profiler.done('render-' + format);
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'STATIC_MAP');
} else {
res.set('Content-Type', headers['Content-Type'] || 'image/' + format);
self.sendResponse(req, res, image, 200);
}
}
);
};
LayergroupController.prototype.sendResponse = function(req, res, body, status, headers) {
var self = this;
res.set('Cache-Control', 'public,max-age=31536000');
// Set Last-Modified header
var lastUpdated;
if (req.params.cache_buster) {
// Assuming cache_buster is a timestamp
lastUpdated = new Date(parseInt(req.params.cache_buster));
} else {
lastUpdated = new Date();
}
res.set('Last-Modified', lastUpdated.toUTCString());
var dbName = req.params.dbname;
step(
function getAffectedTables() {
self.getAffectedTables(req.context.user, dbName, req.params.token, this);
},
function sendResponse(err, affectedTables) {
req.profiler.done('affectedTables');
if (err) {
global.logger.warn('ERROR generating cache channel: ' + err);
}
if (!!affectedTables) {
res.set('X-Cache-Channel', affectedTables.getCacheChannel());
self.surrogateKeysCache.tag(res, affectedTables);
}
self.send(req, res, body, status, headers);
}
);
};
LayergroupController.prototype.getAffectedTables = function(user, dbName, layergroupId, callback) {
if (this.layergroupAffectedTables.hasAffectedTables(dbName, layergroupId)) {
return callback(null, this.layergroupAffectedTables.get(dbName, layergroupId));
}
var self = this;
step(
function extractSQL() {
step(
function loadFromStore() {
self.mapStore.load(layergroupId, this);
},
function getSQL(err, mapConfig) {
assert.ifError(err);
var queries = mapConfig.getLayers()
.map(function(lyr) {
return lyr.options.sql;
})
.filter(function(sql) {
return !!sql;
});
return queries.length ? queries.join(';') : null;
},
this
);
},
function findAffectedTables(err, sql) {
assert.ifError(err);
if ( ! sql ) {
throw new Error("this request doesn't need an X-Cache-Channel generated");
}
step(
function getConnection() {
self.pgConnection.getConnection(user, this);
},
function getAffectedTables(err, connection) {
assert.ifError(err);
QueryTables.getAffectedTablesFromQuery(connection, sql, this);
},
this
);
},
function buildCacheChannel(err, tables) {
assert.ifError(err);
self.layergroupAffectedTables.set(dbName, layergroupId, tables);
return tables;
},
callback
);
};

View File

@@ -0,0 +1,416 @@
var _ = require('underscore');
var assert = require('assert');
var step = require('step');
var windshaft = require('windshaft');
var QueryTables = require('cartodb-query-tables');
var util = require('util');
var BaseController = require('./base');
var cors = require('../middleware/cors');
var userMiddleware = require('../middleware/user');
var MapConfig = windshaft.model.MapConfig;
var Datasource = windshaft.model.Datasource;
var NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
var NamedMapMapConfigProvider = require('../models/mapconfig/provider/named-map-provider');
var CreateLayergroupMapConfigProvider = require('../models/mapconfig/provider/create-layergroup-provider');
/**
* @param {AuthApi} authApi
* @param {PgConnection} pgConnection
* @param {TemplateMaps} templateMaps
* @param {MapBackend} mapBackend
* @param metadataBackend
* @param {SurrogateKeysCache} surrogateKeysCache
* @param {UserLimitsApi} userLimitsApi
* @param {LayergroupAffectedTables} layergroupAffectedTables
* @param {MapConfigAdapter} mapConfigAdapter
* @constructor
*/
function MapController(authApi, pgConnection, templateMaps, mapBackend, metadataBackend,
surrogateKeysCache, userLimitsApi, layergroupAffectedTables, mapConfigAdapter) {
BaseController.call(this, authApi, pgConnection);
this.pgConnection = pgConnection;
this.templateMaps = templateMaps;
this.mapBackend = mapBackend;
this.metadataBackend = metadataBackend;
this.surrogateKeysCache = surrogateKeysCache;
this.userLimitsApi = userLimitsApi;
this.layergroupAffectedTables = layergroupAffectedTables;
this.mapConfigAdapter = mapConfigAdapter;
}
util.inherits(MapController, BaseController);
module.exports = MapController;
MapController.prototype.register = function(app) {
app.get(app.base_url_mapconfig, cors(), userMiddleware, this.createGet.bind(this));
app.post(app.base_url_mapconfig, cors(), userMiddleware, this.createPost.bind(this));
app.get(app.base_url_templated + '/:template_id/jsonp', cors(), userMiddleware, this.jsonp.bind(this));
app.post(app.base_url_templated + '/:template_id', cors(), userMiddleware, this.instantiate.bind(this));
app.options(app.base_url_mapconfig, cors('Content-Type'));
};
MapController.prototype.createGet = function(req, res){
req.profiler.start('windshaft.createmap_get');
this.create(req, res, function createGet$prepareConfig(err, req) {
assert.ifError(err);
if ( ! req.params.config ) {
throw new Error('layergroup GET needs a "config" parameter');
}
return JSON.parse(req.params.config);
});
};
MapController.prototype.createPost = function(req, res) {
req.profiler.start('windshaft.createmap_post');
this.create(req, res, function createPost$prepareConfig(err, req) {
assert.ifError(err);
if (!req.is('application/json')) {
throw new Error('layergroup POST data must be of type application/json');
}
return req.body;
});
};
MapController.prototype.instantiate = function(req, res) {
if (req.profiler) {
req.profiler.start('windshaft-cartodb.instance_template_post');
}
this.instantiateTemplate(req, res, function prepareTemplateParams(callback) {
if (!req.is('application/json')) {
return callback(new Error('Template POST data must be of type application/json'));
}
return callback(null, req.body);
});
};
MapController.prototype.jsonp = function(req, res) {
if (req.profiler) {
req.profiler.start('windshaft-cartodb.instance_template_get');
}
this.instantiateTemplate(req, res, function prepareJsonTemplateParams(callback) {
var err = null;
if ( req.query.callback === undefined || req.query.callback.length === 0) {
err = new Error('callback parameter should be present and be a function name');
}
var templateParams = {};
if (req.query.config) {
try {
templateParams = JSON.parse(req.query.config);
} catch(e) {
err = new Error('Invalid config parameter, should be a valid JSON');
}
}
return callback(err, templateParams);
});
};
MapController.prototype.create = function(req, res, prepareConfigFn) {
var self = this;
var mapConfig;
var context = {};
step(
function setupParams(){
self.req2params(req, this);
},
prepareConfigFn,
function prepareAdapterMapConfig(err, requestMapConfig) {
assert.ifError(err);
context.analysisConfiguration = {
db: {
host: req.params.dbhost,
port: req.params.dbport,
dbname: req.params.dbname,
user: req.params.dbuser,
pass: req.params.dbpassword
},
batch: {
username: req.context.user,
apiKey: req.params.api_key
}
};
self.mapConfigAdapter.getMapConfig(req.context.user, requestMapConfig, req.params, context, this);
},
function createLayergroup(err, requestMapConfig) {
assert.ifError(err);
var datasource = context.datasource || Datasource.EmptyDatasource();
mapConfig = new MapConfig(requestMapConfig, datasource);
self.mapBackend.createLayergroup(
mapConfig, req.params,
new CreateLayergroupMapConfigProvider(mapConfig, req.context.user, self.userLimitsApi, req.params),
this
);
},
function afterLayergroupCreate(err, layergroup) {
assert.ifError(err);
self.afterLayergroupCreate(req, res, mapConfig, layergroup, context.analysesResults, this);
},
function finish(err, layergroup) {
if (err) {
self.sendError(req, res, err, 'ANONYMOUS LAYERGROUP');
} else {
var analysesResults = context.analysesResults || [];
addDataviewsAndWidgetsUrls(req.context.user, layergroup, mapConfig.obj());
addAnalysesMetadata(req.context.user, layergroup, analysesResults, true);
res.set('X-Layergroup-Id', layergroup.layergroupid);
self.send(req, res, layergroup, 200);
}
}
);
};
MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn) {
var self = this;
var cdbuser = req.context.user;
var mapConfigProvider;
var mapConfig;
step(
function setupParams(){
self.req2params(req, this);
},
function getTemplateParams() {
prepareParamsFn(this);
},
function getTemplate(err, templateParams) {
assert.ifError(err);
mapConfigProvider = new NamedMapMapConfigProvider(
self.templateMaps,
self.pgConnection,
self.metadataBackend,
self.userLimitsApi,
self.mapConfigAdapter,
cdbuser,
req.params.template_id,
templateParams,
req.query.auth_token,
req.params
);
mapConfigProvider.getMapConfig(this);
},
function createLayergroup(err, mapConfig_, rendererParams) {
assert.ifError(err);
mapConfig = mapConfig_;
self.mapBackend.createLayergroup(
mapConfig, rendererParams,
new CreateLayergroupMapConfigProvider(mapConfig, cdbuser, self.userLimitsApi, rendererParams),
this
);
},
function afterLayergroupCreate(err, layergroup) {
assert.ifError(err);
self.afterLayergroupCreate(req, res, mapConfig, layergroup, mapConfigProvider.analysesResults, this);
},
function finishTemplateInstantiation(err, layergroup) {
if (err) {
self.sendError(req, res, err, 'NAMED MAP LAYERGROUP');
} else {
var templateHash = self.templateMaps.fingerPrint(mapConfigProvider.template).substring(0, 8);
layergroup.layergroupid = cdbuser + '@' + templateHash + '@' + layergroup.layergroupid;
addDataviewsAndWidgetsUrls(cdbuser, layergroup, mapConfig.obj());
addAnalysesMetadata(cdbuser, layergroup, mapConfigProvider.analysesResults);
res.set('X-Layergroup-Id', layergroup.layergroupid);
self.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(cdbuser, mapConfigProvider.getTemplateName()));
self.send(req, res, layergroup, 200);
}
}
);
};
MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, layergroup, analysesResults, callback) {
var self = this;
var username = req.context.user;
var tasksleft = 2; // redis key and affectedTables
var errors = [];
var done = function(err) {
if ( err ) {
errors.push('' + err);
}
if ( ! --tasksleft ) {
err = errors.length ? new Error(errors.join('\n')) : null;
callback(err, layergroup);
}
};
// include in layergroup response the variables in serverMedata
// those variables are useful to send to the client information
// about how to reach this server or information about it
_.extend(layergroup, global.environment.serverMetadata);
// Don't wait for the mapview count increment to
// take place before proceeding. Error will be logged
// asynchronously
this.metadataBackend.incMapviewCount(username, mapconfig.obj().stat_tag, function(err) {
if (req.profiler) {
req.profiler.done('incMapviewCount');
}
if ( err ) {
global.logger.log("ERROR: failed to increment mapview count for user '" + username + "': " + err);
}
done();
});
var sql = mapconfig.getLayers().map(function(layer) {
return layer.options.sql;
}).join(';');
var dbName = req.params.dbname;
var layergroupId = layergroup.layergroupid;
step(
function getPgConnection() {
self.pgConnection.getConnection(username, this);
},
function getAffectedTablesAndLastUpdatedTime(err, connection) {
assert.ifError(err);
QueryTables.getAffectedTablesFromQuery(connection, sql, this);
},
function handleAffectedTablesAndLastUpdatedTime(err, result) {
if (req.profiler) {
req.profiler.done('queryTablesAndLastUpdated');
}
assert.ifError(err);
// feed affected tables cache so it can be reused from, for instance, layergroup controller
self.layergroupAffectedTables.set(dbName, layergroupId, result);
var lastUpdateTime = result.getLastUpdatedAt();
lastUpdateTime = getLastUpdatedTime(analysesResults, lastUpdateTime) || lastUpdateTime;
// last update for layergroup cache buster
layergroup.layergroupid = layergroup.layergroupid + ':' + lastUpdateTime;
layergroup.last_updated = new Date(lastUpdateTime).toISOString();
if (req.method === 'GET') {
var ttl = global.environment.varnish.layergroupTtl || 86400;
res.set('Cache-Control', 'public,max-age='+ttl+',must-revalidate');
res.set('Last-Modified', (new Date()).toUTCString());
res.set('X-Cache-Channel', result.getCacheChannel());
if (result.tables && result.tables.length > 0) {
self.surrogateKeysCache.tag(res, result);
}
}
return null;
},
function finish(err) {
done(err);
}
);
};
function getLastUpdatedTime(analysesResults, lastUpdateTime) {
if (!Array.isArray(analysesResults)) {
return lastUpdateTime;
}
return analysesResults.reduce(function(lastUpdateTime, analysis) {
return analysis.getSortedNodes().reduce(function(lastNodeUpdatedAtTime, node) {
var nodeUpdatedAtDate = node.getUpdatedAt();
var nodeUpdatedTimeAt = (nodeUpdatedAtDate && nodeUpdatedAtDate.getTime()) || 0;
return nodeUpdatedTimeAt > lastNodeUpdatedAtTime ? nodeUpdatedTimeAt : lastNodeUpdatedAtTime;
}, lastUpdateTime);
}, lastUpdateTime);
}
function addAnalysesMetadata(username, layergroup, analysesResults, includeQuery) {
includeQuery = includeQuery || false;
analysesResults = analysesResults || [];
layergroup.metadata.analyses = [];
analysesResults.forEach(function(analysis) {
var nodes = analysis.getSortedNodes();
layergroup.metadata.analyses.push({
nodes: nodes.reduce(function(nodesIdMap, node) {
if (node.params.id) {
var nodeResource = layergroup.layergroupid + '/analysis/node/' + node.id();
nodesIdMap[node.params.id] = {
status: node.getStatus(),
url: getUrls(username, nodeResource)
};
if (includeQuery) {
nodesIdMap[node.params.id].query = node.getQuery();
}
}
return nodesIdMap;
}, {})
});
});
}
// TODO this should take into account several URL patterns
function addDataviewsAndWidgetsUrls(username, layergroup, mapConfig) {
addDataviewsUrls(username, layergroup, mapConfig);
addWidgetsUrl(username, layergroup, mapConfig);
}
function addDataviewsUrls(username, layergroup, mapConfig) {
layergroup.metadata.dataviews = layergroup.metadata.dataviews || {};
var dataviews = mapConfig.dataviews || {};
Object.keys(dataviews).forEach(function(dataviewName) {
var resource = layergroup.layergroupid + '/dataview/' + dataviewName;
layergroup.metadata.dataviews[dataviewName] = {
url: getUrls(username, resource)
};
});
}
function addWidgetsUrl(username, layergroup, mapConfig) {
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) {
layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) {
var mapConfigLayer = mapConfig.layers[layerIndex];
if (mapConfigLayer.options && mapConfigLayer.options.widgets) {
layer.widgets = layer.widgets || {};
Object.keys(mapConfigLayer.options.widgets).forEach(function(widgetName) {
var resource = layergroup.layergroupid + '/' + layerIndex + '/widget/' + widgetName;
layer.widgets[widgetName] = {
type: mapConfigLayer.options.widgets[widgetName].type,
url: getUrls(username, resource)
};
});
}
return layer;
});
}
}
function getUrls(username, resource) {
var cdnUrl = global.environment.serverMetadata && global.environment.serverMetadata.cdn_url;
if (cdnUrl) {
return {
http: 'http://' + cdnUrl.http + '/' + username + '/api/v1/map/' + resource,
https: 'https://' + cdnUrl.https + '/' + username + '/api/v1/map/' + resource
};
} else {
var port = global.environment.port;
return {
http: 'http://' + username + '.' + 'localhost.lan:' + port + '/api/v1/map/' + resource
};
}
}

View File

@@ -0,0 +1,308 @@
var step = require('step');
var assert = require('assert');
var _ = require('underscore');
var NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
var util = require('util');
var BaseController = require('./base');
var cors = require('../middleware/cors');
var userMiddleware = require('../middleware/user');
function NamedMapsController(authApi, pgConnection, namedMapProviderCache, tileBackend, previewBackend,
surrogateKeysCache, tablesExtentApi, metadataBackend) {
BaseController.call(this, authApi, pgConnection);
this.namedMapProviderCache = namedMapProviderCache;
this.tileBackend = tileBackend;
this.previewBackend = previewBackend;
this.surrogateKeysCache = surrogateKeysCache;
this.tablesExtentApi = tablesExtentApi;
this.metadataBackend = metadataBackend;
}
util.inherits(NamedMapsController, BaseController);
module.exports = NamedMapsController;
NamedMapsController.prototype.register = function(app) {
app.get(app.base_url_templated +
'/:template_id/:layer/:z/:x/:y.(:format)', cors(), userMiddleware,
this.tile.bind(this));
app.get(app.base_url_mapconfig +
'/static/named/:template_id/:width/:height.:format', cors(), userMiddleware,
this.staticMap.bind(this));
};
NamedMapsController.prototype.sendResponse = function(req, res, resource, headers, namedMapProvider) {
this.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(req.context.user, namedMapProvider.getTemplateName()));
res.set('Content-Type', headers['content-type'] || headers['Content-Type'] || 'image/png');
res.set('Cache-Control', 'public,max-age=7200,must-revalidate');
var self = this;
step(
function getAffectedTablesAndLastUpdatedTime() {
namedMapProvider.getAffectedTablesAndLastUpdatedTime(this);
},
function sendResponse(err, result) {
req.profiler.done('affectedTables');
if (err) {
global.logger.log('ERROR generating cache channel: ' + err);
}
if (!result || !!result.tables) {
// we increase cache control as we can invalidate it
res.set('Cache-Control', 'public,max-age=31536000');
var lastModifiedDate;
if (Number.isFinite(result.lastUpdatedTime)) {
lastModifiedDate = new Date(result.getLastUpdatedAt());
} else {
lastModifiedDate = new Date();
}
res.set('Last-Modified', lastModifiedDate.toUTCString());
res.set('X-Cache-Channel', result.getCacheChannel());
if (result.tables.length > 0) {
self.surrogateKeysCache.tag(res, result);
}
}
self.send(req, res, resource, 200);
}
);
};
NamedMapsController.prototype.tile = function(req, res) {
var self = this;
var cdbUser = req.context.user;
var namedMapProvider;
step(
function reqParams() {
self.req2params(req, this);
},
function getNamedMapProvider(err) {
assert.ifError(err);
self.namedMapProviderCache.get(
cdbUser,
req.params.template_id,
req.query.config,
req.query.auth_token,
req.params,
this
);
},
function getTile(err, _namedMapProvider) {
assert.ifError(err);
namedMapProvider = _namedMapProvider;
self.tileBackend.getTile(namedMapProvider, req.params, this);
},
function handleImage(err, tile, headers, stats) {
if (req.profiler) {
req.profiler.add(stats);
}
if (err) {
self.sendError(req, res, err, 'NAMED_MAP_TILE');
} else {
self.sendResponse(req, res, tile, headers, namedMapProvider);
}
}
);
};
NamedMapsController.prototype.staticMap = function(req, res) {
var self = this;
var cdbUser = req.context.user;
var format = req.params.format === 'jpg' ? 'jpeg' : 'png';
req.params.format = 'png';
req.params.layer = 'all';
var namedMapProvider;
step(
function reqParams() {
self.req2params(req, this);
},
function getNamedMapProvider(err) {
assert.ifError(err);
self.namedMapProviderCache.get(
cdbUser,
req.params.template_id,
req.query.config,
req.query.auth_token,
req.params,
this
);
},
function prepareImageOptions(err, _namedMapProvider) {
assert.ifError(err);
namedMapProvider = _namedMapProvider;
self.getStaticImageOptions(cdbUser, req.params, namedMapProvider, this);
},
function getImage(err, imageOpts) {
assert.ifError(err);
var width = +req.params.width;
var height = +req.params.height;
if (!_.isUndefined(imageOpts.zoom) && imageOpts.center) {
self.previewBackend.getImage(
namedMapProvider, format, width, height, imageOpts.zoom, imageOpts.center, this);
} else {
self.previewBackend.getImage(
namedMapProvider, format, width, height, imageOpts.bounds, this);
}
},
function incrementMapViews(err, image, headers, stats) {
assert.ifError(err);
var next = this;
namedMapProvider.getMapConfig(function(mapConfigErr, mapConfig) {
self.metadataBackend.incMapviewCount(cdbUser, mapConfig.obj().stat_tag, function(sErr) {
if (err) {
global.logger.log("ERROR: failed to increment mapview count for user '%s': %s", cdbUser, sErr);
}
next(err, image, headers, stats);
});
});
},
function handleImage(err, image, headers, stats) {
if (req.profiler) {
req.profiler.done('render-' + format);
req.profiler.add(stats || {});
}
if (err) {
self.sendError(req, res, err, 'STATIC_VIZ_MAP');
} else {
self.sendResponse(req, res, image, headers, namedMapProvider);
}
}
);
};
var DEFAULT_ZOOM_CENTER = {
zoom: 1,
center: {
lng: 0,
lat: 0
}
};
function numMapper(n) {
return +n;
}
NamedMapsController.prototype.getStaticImageOptions = function(cdbUser, params, namedMapProvider, callback) {
var self = this;
if ([params.zoom, params.lon, params.lat].map(numMapper).every(Number.isFinite)) {
return callback(null, {
zoom: params.zoom,
center: {
lng: params.lon,
lat: params.lat
}
});
}
if (params.bbox) {
var bbox = params.bbox.split(',').map(numMapper);
if (bbox.length === 4 && bbox.every(Number.isFinite)) {
return callback(null, {
bounds: {
west: bbox[0],
south: bbox[1],
east: bbox[2],
north: bbox[3]
}
});
}
}
step(
function getTemplate() {
namedMapProvider.getTemplate(this);
},
function handleTemplateView(err, template) {
assert.ifError(err);
if (template.view) {
var zoomCenter = templateZoomCenter(template.view);
if (zoomCenter) {
if (Number.isFinite(+params.zoom)) {
zoomCenter.zoom = +params.zoom;
}
return zoomCenter;
}
var bounds = templateBounds(template.view);
if (bounds) {
return bounds;
}
}
return false;
},
function estimateBoundsIfNoImageOpts(err, imageOpts) {
if (imageOpts) {
return imageOpts;
}
var next = this;
namedMapProvider.getAffectedTablesAndLastUpdatedTime(function(err, affectedTablesAndLastUpdate) {
if (err) {
return next(null);
}
var affectedTables = affectedTablesAndLastUpdate.tables || [];
if (affectedTables.length === 0) {
return next(null);
}
self.tablesExtentApi.getBounds(cdbUser, affectedTables, function(err, result) {
return next(null, result);
});
});
},
function returnCallback(err, imageOpts) {
return callback(err, imageOpts || DEFAULT_ZOOM_CENTER);
}
);
};
function templateZoomCenter(view) {
if (!_.isUndefined(view.zoom) && view.center) {
return {
zoom: view.zoom,
center: view.center
};
}
return false;
}
function templateBounds(view) {
if (view.bounds) {
var hasAllBounds = _.every(['west', 'south', 'east', 'north'], function(prop) {
return Number.isFinite(view.bounds[prop]);
});
if (hasAllBounds) {
return {
bounds: {
west: view.bounds.west,
south: view.bounds.south,
east: view.bounds.east,
north: view.bounds.north
}
};
} else {
return false;
}
}
return false;
}

View File

@@ -0,0 +1,203 @@
var step = require('step');
var assert = require('assert');
var templateName = require('../backends/template_maps').templateName;
var util = require('util');
var BaseController = require('./base');
var cors = require('../middleware/cors');
var userMiddleware = require('../middleware/user');
/**
* @param {AuthApi} authApi
* @param {PgConnection} pgConnection
* @param {TemplateMaps} templateMaps
* @constructor
*/
function NamedMapsAdminController(authApi, pgConnection, templateMaps) {
BaseController.call(this, authApi, pgConnection);
this.authApi = authApi;
this.templateMaps = templateMaps;
}
util.inherits(NamedMapsAdminController, BaseController);
module.exports = NamedMapsAdminController;
NamedMapsAdminController.prototype.register = function(app) {
app.post(app.base_url_templated, cors(), userMiddleware, this.create.bind(this));
app.put(app.base_url_templated + '/:template_id', cors(), userMiddleware, this.update.bind(this));
app.get(app.base_url_templated + '/:template_id', cors(), userMiddleware, this.retrieve.bind(this));
app.delete(app.base_url_templated + '/:template_id', cors(), userMiddleware, this.destroy.bind(this));
app.get(app.base_url_templated, cors(), userMiddleware, this.list.bind(this));
app.options(app.base_url_templated + '/:template_id', cors('Content-Type'));
};
NamedMapsAdminController.prototype.create = function(req, res) {
var self = this;
var cdbuser = req.context.user;
step(
function checkPerms(){
self.authApi.authorizedByAPIKey(cdbuser, req, this);
},
function addTemplate(err, authenticated) {
assert.ifError(err);
ifUnauthenticated(authenticated, 'Only authenticated users can get template maps');
ifInvalidContentType(req, 'template POST data must be of type application/json');
var cfg = req.body;
self.templateMaps.addTemplate(cdbuser, cfg, this);
},
function prepareResponse(err, tpl_id){
assert.ifError(err);
return { template_id: tpl_id };
},
finishFn(self, req, res, 'POST TEMPLATE')
);
};
NamedMapsAdminController.prototype.update = function(req, res) {
var self = this;
var cdbuser = req.context.user;
var template;
var tpl_id;
step(
function checkPerms(){
self.authApi.authorizedByAPIKey(cdbuser, req, this);
},
function updateTemplate(err, authenticated) {
assert.ifError(err);
ifUnauthenticated(authenticated, 'Only authenticated user can update templated maps');
ifInvalidContentType(req, 'template PUT data must be of type application/json');
template = req.body;
tpl_id = templateName(req.params.template_id);
self.templateMaps.updTemplate(cdbuser, tpl_id, template, this);
},
function prepareResponse(err){
assert.ifError(err);
return { template_id: tpl_id };
},
finishFn(self, req, res, 'PUT TEMPLATE')
);
};
NamedMapsAdminController.prototype.retrieve = function(req, res) {
var self = this;
if (req.profiler) {
req.profiler.start('windshaft-cartodb.get_template');
}
var cdbuser = req.context.user;
var tpl_id;
step(
function checkPerms(){
self.authApi.authorizedByAPIKey(cdbuser, req, this);
},
function getTemplate(err, authenticated) {
assert.ifError(err);
ifUnauthenticated(authenticated, 'Only authenticated users can get template maps');
tpl_id = templateName(req.params.template_id);
self.templateMaps.getTemplate(cdbuser, tpl_id, this);
},
function prepareResponse(err, tpl_val) {
assert.ifError(err);
if ( ! tpl_val ) {
err = new Error("Cannot find template '" + tpl_id + "' of user '" + cdbuser + "'");
err.http_status = 404;
throw err;
}
// auth_id was added by ourselves,
// so we remove it before returning to the user
delete tpl_val.auth_id;
return { template: tpl_val };
},
finishFn(self, req, res, 'GET TEMPLATE')
);
};
NamedMapsAdminController.prototype.destroy = function(req, res) {
var self = this;
if (req.profiler) {
req.profiler.start('windshaft-cartodb.delete_template');
}
var cdbuser = req.context.user;
var tpl_id;
step(
function checkPerms(){
self.authApi.authorizedByAPIKey(cdbuser, req, this);
},
function deleteTemplate(err, authenticated) {
assert.ifError(err);
ifUnauthenticated(authenticated, 'Only authenticated users can delete template maps');
tpl_id = templateName(req.params.template_id);
self.templateMaps.delTemplate(cdbuser, tpl_id, this);
},
function prepareResponse(err/*, tpl_val*/){
assert.ifError(err);
return '';
},
finishFn(self, req, res, 'DELETE TEMPLATE', 204)
);
};
NamedMapsAdminController.prototype.list = function(req, res) {
var self = this;
if ( req.profiler ) {
req.profiler.start('windshaft-cartodb.get_template_list');
}
var cdbuser = req.context.user;
step(
function checkPerms(){
self.authApi.authorizedByAPIKey(cdbuser, req, this);
},
function listTemplates(err, authenticated) {
assert.ifError(err);
ifUnauthenticated(authenticated, 'Only authenticated user can list templated maps');
self.templateMaps.listTemplates(cdbuser, this);
},
function prepareResponse(err, tpl_ids){
assert.ifError(err);
return { template_ids: tpl_ids };
},
finishFn(self, req, res, 'GET TEMPLATE LIST')
);
};
function finishFn(controller, req, res, description, status) {
return function finish(err, response){
if (err) {
controller.sendError(req, res, err, description);
} else {
controller.send(req, res, response, status || 200);
}
};
}
function ifUnauthenticated(authenticated, description) {
if (!authenticated) {
var err = new Error(description);
err.http_status = 403;
throw err;
}
}
function ifInvalidContentType(req, description) {
if (!req.is('application/json')) {
throw new Error(description);
}
}

View File

@@ -0,0 +1,48 @@
var HealthCheck = require('../monitoring/health_check');
var WELCOME_MSG = "This is the CartoDB Maps API, " +
"see the documentation at http://docs.cartodb.com/cartodb-platform/maps-api.html";
function ServerInfoController(versions) {
this.healthConfig = global.environment.health || {};
this.healthCheck = new HealthCheck(global.environment.disabled_file);
this.versions = versions || {};
}
module.exports = ServerInfoController;
ServerInfoController.prototype.register = function(app) {
app.get('/health', this.health.bind(this));
app.get('/', this.welcome.bind(this));
app.get('/version', this.version.bind(this));
};
ServerInfoController.prototype.welcome = function(req, res) {
res.status(200).send(WELCOME_MSG);
};
ServerInfoController.prototype.version = function(req, res) {
res.status(200).send(this.versions);
};
ServerInfoController.prototype.health = function(req, res) {
if (!!this.healthConfig.enabled) {
var startTime = Date.now();
this.healthCheck.check(function(err) {
var ok = !err;
var response = {
enabled: true,
ok: ok,
elapsed: Date.now() - startTime
};
if (err) {
response.err = err.message;
}
res.status(ok ? 200 : 503).send(response);
});
} else {
res.status(200).send({enabled: false, ok: true});
}
};

View File

@@ -0,0 +1,11 @@
module.exports = function cors(extraHeaders) {
return function(req, res, next) {
var baseHeaders = "X-Requested-With, X-Prototype-Version, X-CSRF-Token";
if(extraHeaders) {
baseHeaders += ", " + extraHeaders;
}
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Headers", baseHeaders);
next();
};
};

View File

@@ -0,0 +1,7 @@
var CdbRequest = require('../models/cdb_request');
var cdbRequest = new CdbRequest();
module.exports = function userMiddleware(req, res, next) {
req.context.user = cdbRequest.userByReq(req);
next();
};

View File

@@ -0,0 +1,25 @@
function CdbRequest() {
this.RE_USER_FROM_HOST = new RegExp(global.environment.user_from_host ||
'^([^\\.]+)\\.' // would extract "strk" from "strk.cartodb.com"
);
}
module.exports = CdbRequest;
CdbRequest.prototype.userByReq = function(req) {
var host = req.headers.host || '';
if (req.params.user) {
return req.params.user;
}
var mat = host.match(this.RE_USER_FROM_HOST);
if ( ! mat ) {
global.logger.error("Pattern '%s' does not match hostname '%s'", this.RE_USER_FROM_HOST, host);
return;
}
if ( mat.length !== 2 ) {
global.logger.error("Pattern '%s' gave unexpected matches against '%s': %s", this.RE_USER_FROM_HOST, host, mat);
return;
}
return mat[1];
};

View File

@@ -0,0 +1,282 @@
var _ = require('underscore');
var BaseWidget = require('./base');
var debug = require('debug')('windshaft:widget:aggregation');
var dot = require('dot');
dot.templateSettings.strip = false;
var summaryQueryTpl = dot.template([
'summary AS (',
' SELECT',
' count(1) AS count,',
' sum(CASE WHEN {{=it._column}} IS NULL THEN 1 ELSE 0 END) AS nulls_count',
' FROM ({{=it._query}}) _cdb_aggregation_nulls',
')'
].join('\n'));
var rankedCategoriesQueryTpl = dot.template([
'categories AS(',
' SELECT {{=it._column}} AS category, {{=it._aggregation}} AS value,',
' row_number() OVER (ORDER BY {{=it._aggregation}} desc) as rank',
' FROM ({{=it._query}}) _cdb_aggregation_all',
' GROUP BY {{=it._column}}',
' ORDER BY 2 DESC',
')'
].join('\n'));
var categoriesSummaryQueryTpl = dot.template([
'categories_summary AS(',
' SELECT count(1) categories_count, max(value) max_val, min(value) min_val',
' FROM categories',
')'
].join('\n'));
var rankedAggregationQueryTpl = dot.template([
'SELECT CAST(category AS text), value, false as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' WHERE rank < {{=it._limit}}',
'UNION ALL',
'SELECT \'Other\' category, sum(value), true as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' WHERE rank >= {{=it._limit}}',
'GROUP BY nulls_count, min_val, max_val, count, categories_count'
].join('\n'));
var aggregationQueryTpl = dot.template([
'SELECT CAST({{=it._column}} AS text) AS category, {{=it._aggregation}} AS value, false as agg,',
' nulls_count, min_val, max_val, count, categories_count',
'FROM ({{=it._query}}) _cdb_aggregation_all, summary, categories_summary',
'GROUP BY category, nulls_count, min_val, max_val, count, categories_count',
'ORDER BY value DESC'
].join('\n'));
var CATEGORIES_LIMIT = 6;
var VALID_OPERATIONS = {
count: [],
sum: ['aggregationColumn'],
avg: ['aggregationColumn'],
min: ['aggregationColumn'],
max: ['aggregationColumn']
};
var TYPE = 'aggregation';
/**
{
type: 'aggregation',
options: {
column: 'name',
aggregation: 'count' // it could be, e.g., sum if column is numeric
}
}
*/
function Aggregation(query, options) {
if (!_.isString(options.column)) {
throw new Error('Aggregation expects `column` in widget options');
}
if (!_.isString(options.aggregation)) {
throw new Error('Aggregation expects `aggregation` operation in widget options');
}
if (!VALID_OPERATIONS[options.aggregation]) {
throw new Error("Aggregation does not support '" + options.aggregation + "' operation");
}
var requiredOptions = VALID_OPERATIONS[options.aggregation];
var missingOptions = _.difference(requiredOptions, Object.keys(options));
if (missingOptions.length > 0) {
throw new Error(
"Aggregation '" + options.aggregation + "' is missing some options: " + missingOptions.join(',')
);
}
BaseWidget.apply(this);
this.query = query;
this.column = options.column;
this.aggregation = options.aggregation;
this.aggregationColumn = options.aggregationColumn;
}
Aggregation.prototype = new BaseWidget();
Aggregation.prototype.constructor = Aggregation;
module.exports = Aggregation;
Aggregation.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
override = {};
}
var _query = this.query;
var aggregationSql;
if (!!override.ownFilter) {
aggregationSql = [
"WITH",
[
summaryQueryTpl({
_query: _query,
_column: this.column
}),
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
}),
categoriesSummaryQueryTpl({
_query: _query,
_column: this.column
})
].join(',\n'),
aggregationQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql(),
_limit: CATEGORIES_LIMIT
})
].join('\n');
} else {
aggregationSql = [
"WITH",
[
summaryQueryTpl({
_query: _query,
_column: this.column
}),
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
}),
categoriesSummaryQueryTpl({
_query: _query,
_column: this.column
})
].join(',\n'),
rankedAggregationQueryTpl({
_query: _query,
_column: this.column,
_limit: CATEGORIES_LIMIT
})
].join('\n');
}
debug(aggregationSql);
return callback(null, aggregationSql);
};
var aggregationFnQueryTpl = dot.template('{{=it._aggregationFn}}({{=it._aggregationColumn}})');
Aggregation.prototype.getAggregationSql = function() {
return aggregationFnQueryTpl({
_aggregationFn: this.aggregation,
_aggregationColumn: this.aggregationColumn || 1
});
};
Aggregation.prototype.format = function(result) {
var categories = [];
var count = 0;
var nulls = 0;
var minValue = 0;
var maxValue = 0;
var categoriesCount = 0;
if (result.rows.length) {
var firstRow = result.rows[0];
count = firstRow.count;
nulls = firstRow.nulls_count;
minValue = firstRow.min_val;
maxValue = firstRow.max_val;
categoriesCount = firstRow.categories_count;
result.rows.forEach(function(row) {
categories.push(_.omit(row, 'count', 'nulls_count', 'min_val', 'max_val', 'categories_count'));
});
}
return {
aggregation: this.aggregation,
count: count,
nulls: nulls,
min: minValue,
max: maxValue,
categoriesCount: categoriesCount,
categories: categories
};
};
var filterCategoriesQueryTpl = dot.template([
'SELECT {{=it._column}} AS category, {{=it._value}} AS value',
'FROM ({{=it._query}}) _cdb_aggregation_search',
'WHERE CAST({{=it._column}} as text) ILIKE {{=it._userQuery}}',
'GROUP BY {{=it._column}}'
].join('\n'));
var searchQueryTpl = dot.template([
'WITH',
'search_unfiltered AS (',
' {{=it._searchUnfiltered}}',
'),',
'search_filtered AS (',
' {{=it._searchFiltered}}',
'),',
'search_union AS (',
' SELECT * FROM search_unfiltered',
' UNION ALL',
' SELECT * FROM search_filtered',
')',
'SELECT category, sum(value) AS value',
'FROM search_union',
'GROUP BY category',
'ORDER BY value desc'
].join('\n'));
Aggregation.prototype.search = function(psql, userQuery, callback) {
var self = this;
var _userQuery = psql.escapeLiteral('%' + userQuery + '%');
// TODO unfiltered will be wrong as filters are already applied at this point
var query = searchQueryTpl({
_searchUnfiltered: filterCategoriesQueryTpl({
_query: this.query,
_column: this.column,
_value: '0',
_userQuery: _userQuery
}),
_searchFiltered: filterCategoriesQueryTpl({
_query: this.query,
_column: this.column,
_value: 'count(1)',
_userQuery: _userQuery
})
});
psql.query(query, function(err, result) {
if (err) {
return callback(err, result);
}
return callback(null, {type: self.getType(), categories: result.rows });
}, true); // use read-only transaction
};
Aggregation.prototype.getType = function() {
return TYPE;
};
Aggregation.prototype.toString = function() {
return JSON.stringify({
_type: TYPE,
_query: this.query,
_column: this.column,
_aggregation: this.aggregation
});
};

View File

@@ -0,0 +1,26 @@
function BaseDataview() {}
module.exports = BaseDataview;
BaseDataview.prototype.getResult = function(psql, override, callback) {
var self = this;
this.sql(psql, override, function(err, query) {
psql.query(query, function(err, result) {
if (err) {
return callback(err, result);
}
result = self.format(result, override);
result.type = self.getType();
return callback(null, result);
}, true); // use read-only transaction
});
};
BaseDataview.prototype.search = function(psql, userQuery, callback) {
return callback(null, this.format({ rows: [] }));
};

View File

@@ -0,0 +1,18 @@
var dataviews = require('./');
var DataviewFactory = {
dataviews: Object.keys(dataviews).reduce(function(allDataviews, dataviewClassName) {
allDataviews[dataviewClassName.toLowerCase()] = dataviews[dataviewClassName];
return allDataviews;
}, {}),
getDataview: function(query, dataviewDefinition) {
var type = dataviewDefinition.type;
if (!this.dataviews[type]) {
throw new Error('Invalid dataview type: "' + type + '"');
}
return new this.dataviews[type](query, dataviewDefinition.options);
}
};
module.exports = DataviewFactory;

View File

@@ -0,0 +1,104 @@
var _ = require('underscore');
var BaseWidget = require('./base');
var debug = require('debug')('windshaft:widget:formula');
var dot = require('dot');
dot.templateSettings.strip = false;
var formulaQueryTpl = dot.template([
'SELECT',
'{{=it._operation}}({{=it._column}}) AS result,',
'(SELECT count(1) FROM ({{=it._query}}) _cdb_formula_nulls WHERE {{=it._column}} IS NULL) AS nulls_count',
'FROM ({{=it._query}}) _cdb_formula'
].join('\n'));
var VALID_OPERATIONS = {
count: true,
avg: true,
sum: true,
min: true,
max: true
};
var TYPE = 'formula';
/**
{
type: 'formula',
options: {
column: 'name',
operation: 'count' // count, sum, avg
}
}
*/
function Formula(query, options) {
if (!_.isString(options.operation)) {
throw new Error('Formula expects `operation` in widget options');
}
if (!VALID_OPERATIONS[options.operation]) {
throw new Error("Formula does not support '" + options.operation + "' operation");
}
if (options.operation !== 'count' && !_.isString(options.column)) {
throw new Error('Formula expects `column` in widget options');
}
BaseWidget.apply(this);
this.query = query;
this.column = options.column || '1';
this.operation = options.operation;
}
Formula.prototype = new BaseWidget();
Formula.prototype.constructor = Formula;
module.exports = Formula;
Formula.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
override = {};
}
var _query = this.query;
var formulaSql = formulaQueryTpl({
_query: _query,
_operation: this.operation,
_column: this.column
});
debug(formulaSql);
return callback(null, formulaSql);
};
Formula.prototype.format = function(result) {
var formattedResult = {
operation: this.operation,
result: 0,
nulls: 0
};
if (result.rows.length) {
formattedResult.operation = this.operation;
formattedResult.result = result.rows[0].result;
formattedResult.nulls = result.rows[0].nulls_count;
}
return formattedResult;
};
Formula.prototype.getType = function() {
return TYPE;
};
Formula.prototype.toString = function() {
return JSON.stringify({
_type: TYPE,
_query: this.query,
_column: this.column,
_operation: this.operation
});
};

View File

@@ -0,0 +1,307 @@
var _ = require('underscore');
var BaseWidget = require('./base');
var debug = require('debug')('windshaft:dataview:histogram');
var dot = require('dot');
dot.templateSettings.strip = false;
var columnTypeQueryTpl = dot.template(
'SELECT pg_typeof({{=it.column}})::oid FROM ({{=it.query}}) _cdb_histogram_column_type limit 1'
);
var columnCastTpl = dot.template("date_part('epoch', {{=it.column}})");
var BIN_MIN_NUMBER = 6;
var BIN_MAX_NUMBER = 48;
var basicsQueryTpl = dot.template([
'basics AS (',
' SELECT',
' max({{=it._column}}) AS max_val, min({{=it._column}}) AS min_val,',
' avg({{=it._column}}) AS avg_val, count(1) AS total_rows',
' FROM ({{=it._query}}) _cdb_basics',
')'
].join(' \n'));
var overrideBasicsQueryTpl = dot.template([
'basics AS (',
' SELECT',
' max({{=it._end}}) AS max_val, min({{=it._start}}) AS min_val,',
' avg({{=it._column}}) AS avg_val, count(1) AS total_rows',
' FROM ({{=it._query}}) _cdb_basics',
')'
].join('\n'));
var iqrQueryTpl = dot.template([
'iqrange AS (',
' SELECT max(quartile_max) - min(quartile_max) AS iqr',
' FROM (',
' SELECT quartile, max(_cdb_iqr_column) AS quartile_max from (',
' SELECT {{=it._column}} AS _cdb_iqr_column, ntile(4) over (order by {{=it._column}}',
' ) AS quartile',
' FROM ({{=it._query}}) _cdb_rank) _cdb_quartiles',
' WHERE quartile = 1 or quartile = 3',
' GROUP BY quartile',
' ) _cdb_iqr',
')'
].join('\n'));
var binsQueryTpl = dot.template([
'bins AS (',
' SELECT CASE WHEN total_rows = 0 OR iqr = 0',
' THEN 1',
' ELSE GREATEST(',
' LEAST({{=it._minBins}}, CAST(total_rows AS INT)),',
' LEAST(',
' CAST(((max_val - min_val) / (2 * iqr * power(total_rows, 1/3))) AS INT),',
' {{=it._maxBins}}',
' )',
' )',
' END AS bins_number',
' FROM basics, iqrange, ({{=it._query}}) _cdb_bins',
' LIMIT 1',
')'
].join('\n'));
var overrideBinsQueryTpl = dot.template([
'bins AS (',
' SELECT {{=it._bins}} AS bins_number',
')'
].join('\n'));
var nullsQueryTpl = dot.template([
'nulls AS (',
' SELECT',
' count(*) AS nulls_count',
' FROM ({{=it._query}}) _cdb_histogram_nulls',
' WHERE {{=it._column}} IS NULL',
')'
].join('\n'));
var histogramQueryTpl = dot.template([
'SELECT',
' (max_val - min_val) / cast(bins_number as float) AS bin_width,',
' bins_number,',
' nulls_count,',
' avg_val,',
' CASE WHEN min_val = max_val',
' THEN 0',
' ELSE GREATEST(1, LEAST(WIDTH_BUCKET({{=it._column}}, min_val, max_val, bins_number), bins_number)) - 1',
' END AS bin,',
' min({{=it._column}})::numeric AS min,',
' max({{=it._column}})::numeric AS max,',
' avg({{=it._column}})::numeric AS avg,',
' count(*) AS freq',
'FROM ({{=it._query}}) _cdb_histogram, basics, nulls, bins',
'WHERE {{=it._column}} IS NOT NULL',
'GROUP BY bin, bins_number, bin_width, nulls_count, avg_val',
'ORDER BY bin'
].join('\n'));
var TYPE = 'histogram';
/**
{
type: 'histogram',
options: {
column: 'name',
bins: 10 // OPTIONAL
}
}
*/
function Histogram(query, options) {
if (!_.isString(options.column)) {
throw new Error('Histogram expects `column` in widget options');
}
this.query = query;
this.column = options.column;
this.bins = options.bins;
this._columnType = null;
}
Histogram.prototype = new BaseWidget();
Histogram.prototype.constructor = Histogram;
module.exports = Histogram;
var DATE_OIDS = {
1082: true,
1114: true,
1184: true
};
Histogram.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
override = {};
}
var self = this;
var _column = this.column;
var columnTypeQuery = columnTypeQueryTpl({
column: _column, query: this.query
});
if (this._columnType === null) {
psql.query(columnTypeQuery, function(err, result) {
// assume numeric, will fail later
self._columnType = 'numeric';
if (!err && !!result.rows[0]) {
var pgType = result.rows[0].pg_typeof;
if (DATE_OIDS.hasOwnProperty(pgType)) {
self._columnType = 'date';
}
}
self.sql(psql, override, callback);
}, true); // use read-only transaction
return null;
}
if (this._columnType === 'date') {
_column = columnCastTpl({column: _column});
}
var _query = this.query;
var basicsQuery, binsQuery;
if (override && _.has(override, 'start') && _.has(override, 'end') && _.has(override, 'bins')) {
debug('overriding with %j', override);
basicsQuery = overrideBasicsQueryTpl({
_query: _query,
_column: _column,
_start: getBinStart(override),
_end: getBinEnd(override)
});
binsQuery = [
overrideBinsQueryTpl({
_bins: override.bins
})
].join(',\n');
} else {
basicsQuery = basicsQueryTpl({
_query: _query,
_column: _column
});
if (override && _.has(override, 'bins')) {
binsQuery = [
overrideBinsQueryTpl({
_bins: override.bins
})
].join(',\n');
} else {
binsQuery = [
iqrQueryTpl({
_query: _query,
_column: _column
}),
binsQueryTpl({
_query: _query,
_minBins: BIN_MIN_NUMBER,
_maxBins: BIN_MAX_NUMBER
})
].join(',\n');
}
}
var histogramSql = [
"WITH",
[
basicsQuery,
binsQuery,
nullsQueryTpl({
_query: _query,
_column: _column
})
].join(',\n'),
histogramQueryTpl({
_query: _query,
_column: _column
})
].join('\n');
debug(histogramSql);
return callback(null, histogramSql);
};
Histogram.prototype.format = function(result, override) {
override = override || {};
var buckets = [];
var binsCount = getBinsCount(override);
var width = getWidth(override);
var binsStart = getBinStart(override);
var nulls = 0;
var avg;
if (result.rows.length) {
var firstRow = result.rows[0];
binsCount = firstRow.bins_number;
width = firstRow.bin_width || width;
avg = firstRow.avg_val;
nulls = firstRow.nulls_count;
binsStart = override.hasOwnProperty('start') ? getBinStart(override) : firstRow.min;
buckets = result.rows.map(function(row) {
return _.omit(row, 'bins_number', 'bin_width', 'nulls_count', 'avg_val');
});
}
return {
bin_width: width,
bins_count: binsCount,
bins_start: binsStart,
nulls: nulls,
avg: avg,
bins: buckets
};
};
function getBinStart(override) {
if (override.hasOwnProperty('start') && override.hasOwnProperty('end')) {
return Math.min(override.start, override.end);
}
return override.start || 0;
}
function getBinEnd(override) {
if (override.hasOwnProperty('start') && override.hasOwnProperty('end')) {
return Math.max(override.start, override.end);
}
return override.end || 0;
}
function getBinsCount(override) {
return override.bins || 0;
}
function getWidth(override) {
var width = 0;
var binsCount = override.bins;
if (binsCount && Number.isFinite(override.start) && Number.isFinite(override.end)) {
width = (override.end - override.start) / binsCount;
}
return width;
}
Histogram.prototype.getType = function() {
return TYPE;
};
Histogram.prototype.toString = function() {
return JSON.stringify({
_type: TYPE,
_column: this.column,
_query: this.query
});
};

View File

@@ -0,0 +1,6 @@
module.exports = {
Aggregation: require('./aggregation'),
Formula: require('./formula'),
Histogram: require('./histogram'),
List: require('./list')
};

View File

@@ -0,0 +1,66 @@
var dot = require('dot');
dot.templateSettings.strip = false;
var BaseWidget = require('./base');
var TYPE = 'list';
var listSqlTpl = dot.template('select {{=it._columns}} from ({{=it._query}}) as _cdb_list');
/**
{
type: 'list',
options: {
columns: ['name', 'description']
}
}
*/
function List(query, options) {
options = options || {};
if (!Array.isArray(options.columns)) {
throw new Error('List expects `columns` array in widget options');
}
BaseWidget.apply(this);
this.query = query;
this.columns = options.columns;
}
List.prototype = new BaseWidget();
List.prototype.constructor = List;
module.exports = List;
List.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
}
var listSql = listSqlTpl({
_query: this.query,
_columns: this.columns.join(', ')
});
return callback(null, listSql);
};
List.prototype.format = function(result) {
return {
rows: result.rows
};
};
List.prototype.getType = function() {
return TYPE;
};
List.prototype.toString = function() {
return JSON.stringify({
_type: TYPE,
_query: this.query,
_columns: this.columns.join(', ')
});
};

View File

@@ -0,0 +1,141 @@
var BaseOverviewsDataview = require('./base');
var BaseDataview = require('../aggregation');
var dot = require('dot');
dot.templateSettings.strip = false;
var summaryQueryTpl = dot.template([
'summary AS (',
' SELECT',
' sum(_feature_count) AS count,',
' sum(CASE WHEN {{=it._column}} IS NULL THEN 1 ELSE 0 END) AS nulls_count',
' FROM ({{=it._query}}) _cdb_aggregation_nulls',
')'
].join('\n'));
var rankedCategoriesQueryTpl = dot.template([
'categories AS(',
' SELECT {{=it._column}} AS category, {{=it._aggregation}} AS value,',
' row_number() OVER (ORDER BY {{=it._aggregation}} desc) as rank',
' FROM ({{=it._query}}) _cdb_aggregation_all',
' GROUP BY {{=it._column}}',
' ORDER BY 2 DESC',
')'
].join('\n'));
var categoriesSummaryQueryTpl = dot.template([
'categories_summary AS(',
' SELECT count(1) categories_count, max(value) max_val, min(value) min_val',
' FROM categories',
')'
].join('\n'));
var rankedAggregationQueryTpl = dot.template([
'SELECT CAST(category AS text), value, false as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' WHERE rank < {{=it._limit}}',
'UNION ALL',
'SELECT \'Other\' category, sum(value), true as agg, nulls_count, min_val, max_val, count, categories_count',
' FROM categories, summary, categories_summary',
' WHERE rank >= {{=it._limit}}',
'GROUP BY nulls_count, min_val, max_val, count, categories_count'
].join('\n'));
var aggregationQueryTpl = dot.template([
'SELECT CAST({{=it._column}} AS text) AS category, {{=it._aggregation}} AS value, false as agg,',
' nulls_count, min_val, max_val, count, categories_count',
'FROM ({{=it._query}}) _cdb_aggregation_all, summary, categories_summary',
'GROUP BY category, nulls_count, min_val, max_val, count, categories_count',
'ORDER BY value DESC'
].join('\n'));
var CATEGORIES_LIMIT = 6;
function Aggregation(query, options, queryRewriter, queryRewriteData, params) {
BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params);
this.query = query;
this.column = options.column;
this.aggregation = options.aggregation;
this.aggregationColumn = options.aggregationColumn;
}
Aggregation.prototype = Object.create(BaseOverviewsDataview.prototype);
Aggregation.prototype.constructor = Aggregation;
module.exports = Aggregation;
Aggregation.prototype.sql = function(psql, filters, override, callback) {
if (!callback) {
callback = override;
override = {};
}
var _query = this.rewrittenQuery(this.query);
var aggregationSql;
if (!!override.ownFilter) {
aggregationSql = [
"WITH",
[
summaryQueryTpl({
_query: _query,
_column: this.column
}),
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
}),
categoriesSummaryQueryTpl({
_query: _query,
_column: this.column
})
].join(',\n'),
aggregationQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql(),
_limit: CATEGORIES_LIMIT
})
].join('\n');
} else {
aggregationSql = [
"WITH",
[
summaryQueryTpl({
_query: _query,
_column: this.column
}),
rankedCategoriesQueryTpl({
_query: _query,
_column: this.column,
_aggregation: this.getAggregationSql()
}),
categoriesSummaryQueryTpl({
_query: _query,
_column: this.column
})
].join(',\n'),
rankedAggregationQueryTpl({
_query: _query,
_column: this.column,
_limit: CATEGORIES_LIMIT
})
].join('\n');
}
return callback(null, aggregationSql);
};
var aggregationFnQueryTpl = {
count: dot.template('sum(_feature_count)'),
sum: dot.template('sum({{=it._aggregationColumn}}*_feature_count)')
};
Aggregation.prototype.getAggregationSql = function() {
return aggregationFnQueryTpl[this.aggregation]({
_aggregationFn: this.aggregation,
_aggregationColumn: this.aggregationColumn || 1
});
};

View File

@@ -0,0 +1,88 @@
var _ = require('underscore');
var BaseDataview = require('../base');
function BaseOverviewsDataview(query, queryOptions, BaseDataview, queryRewriter, queryRewriteData, options) {
this.BaseDataview = BaseDataview;
this.query = query;
this.queryOptions = queryOptions;
this.queryRewriter = queryRewriter;
this.queryRewriteData = queryRewriteData;
this.options = options;
this.baseDataview = new this.BaseDataview(this.query, this.queryOptions);
}
module.exports = BaseOverviewsDataview;
BaseOverviewsDataview.prototype = new BaseDataview();
BaseOverviewsDataview.prototype.constructor = BaseOverviewsDataview;
// TODO: parameterized these settings
var SETTINGS = {
// use overviews as a default fallback strategy
defaultOverviews: false,
// minimum ratio of bounding box size to grid size
// (this would ideally be based on the viewport size in pixels)
zoomLevelFactor: 1024.0
};
// Compute zoom level so that the the resolution grid size of the
// selected overview is smaller (zoomLevelFactor times smaller at least)
// than the bounding box size.
BaseOverviewsDataview.prototype.zoomLevelForBbox = function(bbox) {
var pxPerTile = 256.0;
var earthWidth = 360.0;
// TODO: now we assume overviews are computed for 1-pixel tolerance;
// should use extended overviews metadata to compute this properly.
if ( bbox ) {
var bboxValues = _.map(bbox.split(','), function(v) { return +v; });
var w = Math.abs(bboxValues[2]-bboxValues[0]);
var h = Math.abs(bboxValues[3]-bboxValues[1]);
var maxDim = Math.min(w, h);
// Find minimum suitable z
// note that the QueryRewirter will use the minimum level overview
// of level >= z if it exists, and otherwise the base table
var z = Math.ceil(-Math.log(maxDim*pxPerTile/earthWidth/SETTINGS.zoomLevelFactor)/Math.log(2.0));
return Math.max(z, 0);
}
return 0;
};
BaseOverviewsDataview.prototype.rewrittenQuery = function(query) {
var zoom_level = this.zoomLevelForBbox(this.options.bbox);
return this.queryRewriter.query(query, this.queryRewriteData, { zoom_level: zoom_level });
};
// Default behaviour
BaseOverviewsDataview.prototype.defaultSql = function(psql, filters, override, callback) {
var query = this.query;
var dataview = this.baseDataview;
if ( SETTINGS.defaultOverviews ) {
query = this.rewrittenQuery(query);
dataview = new this.BaseDataview(query, this.queryOptions);
}
return dataview.sql(psql, filters, override, callback);
};
// default implementation that can be override in derived classes:
BaseOverviewsDataview.prototype.sql = function(psql, filters, override, callback) {
return this.defaultSql(psql, filters, override, callback);
};
BaseOverviewsDataview.prototype.search = function(psql, userQuery, callback) {
return this.baseDataview.search(psql, userQuery, callback);
};
BaseOverviewsDataview.prototype.format = function(result) {
return this.baseDataview.format(result);
};
BaseOverviewsDataview.prototype.getType = function() {
return this.baseDataview.getType();
};
BaseOverviewsDataview.prototype.toString = function() {
return this.baseDataview.toString();
};

View File

@@ -0,0 +1,32 @@
var parentFactory = require('../factory');
var dataviews = require('./');
function OverviewsDataviewFactory(queryRewriter, queryRewriteData, options) {
this.queryRewriter = queryRewriter;
this.queryRewriteData = queryRewriteData;
this.options = options;
}
OverviewsDataviewFactory.prototype.getDataview = function(query, dataviewDefinition) {
var type = dataviewDefinition.type;
var dataviews = OverviewsDataviewMetaFactory.dataviews;
if ( !this.queryRewriter || !this.queryRewriteData || !dataviews[type] ) {
return parentFactory.getDataview(query, dataviewDefinition);
}
return new dataviews[type](
query, dataviewDefinition.options, this.queryRewriter, this.queryRewriteData, this.options
);
};
var OverviewsDataviewMetaFactory = {
dataviews: Object.keys(dataviews).reduce(function(allDataviews, dataviewClassName) {
allDataviews[dataviewClassName.toLowerCase()] = dataviews[dataviewClassName];
return allDataviews;
}, {}),
getFactory: function(queryRewriter, queryRewriteData, options) {
return new OverviewsDataviewFactory(queryRewriter, queryRewriteData, options);
},
};
module.exports = OverviewsDataviewMetaFactory;

View File

@@ -0,0 +1,56 @@
var BaseOverviewsDataview = require('./base');
var BaseDataview = require('../formula');
var dot = require('dot');
dot.templateSettings.strip = false;
var formulaQueryTpls = {
'count': dot.template([
'SELECT',
'sum(_feature_count) AS result,',
'(SELECT count(1) FROM ({{=it._query}}) _cdb_formula_nulls WHERE {{=it._column}} IS NULL) AS nulls_count',
'FROM ({{=it._query}}) _cdb_formula'
].join('\n')),
'sum': dot.template([
'SELECT',
'sum({{=it._column}}*_feature_count) AS result,',
'(SELECT count(1) FROM ({{=it._query}}) _cdb_formula_nulls WHERE {{=it._column}} IS NULL) AS nulls_count',
'FROM ({{=it._query}}) _cdb_formula'
].join('\n')),
'avg': dot.template([
'SELECT',
'sum({{=it._column}}*_feature_count)/sum(_feature_count) AS result,',
'(SELECT count(1) FROM ({{=it._query}}) _cdb_formula_nulls WHERE {{=it._column}} IS NULL) AS nulls_count',
'FROM ({{=it._query}}) _cdb_formula'
].join('\n')),
};
function Formula(query, options, queryRewriter, queryRewriteData, params) {
BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params);
this.column = options.column || '1';
this.operation = options.operation;
}
Formula.prototype = Object.create(BaseOverviewsDataview.prototype);
Formula.prototype.constructor = Formula;
module.exports = Formula;
Formula.prototype.sql = function(psql, filters, override, callback) {
var formulaQueryTpl = formulaQueryTpls[this.operation];
if ( formulaQueryTpl ) {
// supported formula for use with overviews
var formulaSql = formulaQueryTpl({
_query: this.rewrittenQuery(this.query),
_operation: this.operation,
_column: this.column
});
callback = callback || override;
return callback(null, formulaSql);
}
// default behaviour
return this.defaultSql(psql, filters, override, callback);
};

View File

@@ -0,0 +1,217 @@
var _ = require('underscore');
var BaseOverviewsDataview = require('./base');
var BaseDataview = require('../histogram');
var dot = require('dot');
dot.templateSettings.strip = false;
var columnTypeQueryTpl = dot.template(
'SELECT pg_typeof({{=it.column}})::oid FROM ({{=it.query}}) _cdb_histogram_column_type limit 1'
);
var columnCastTpl = dot.template("date_part('epoch', {{=it.column}})");
var BIN_MIN_NUMBER = 6;
var BIN_MAX_NUMBER = 48;
var basicsQueryTpl = dot.template([
'basics AS (',
' SELECT',
' max({{=it._column}}) AS max_val, min({{=it._column}}) AS min_val,',
' sum({{=it._column}}*_feature_count)/sum(_feature_count) AS avg_val, sum(_feature_count) AS total_rows',
' FROM ({{=it._query}}) _cdb_basics',
')'
].join(' \n'));
var overrideBasicsQueryTpl = dot.template([
'basics AS (',
' SELECT',
' max({{=it._end}}) AS max_val, min({{=it._start}}) AS min_val,',
' sum({{=it._column}}*_feature_count)/sum(_feature_count) AS avg_val, sum(_feature_count) AS total_rows',
' FROM ({{=it._query}}) _cdb_basics',
')'
].join('\n'));
var iqrQueryTpl = dot.template([
'iqrange AS (',
' SELECT max(quartile_max) - min(quartile_max) AS iqr',
' FROM (',
' SELECT quartile, max(_cdb_iqr_column) AS quartile_max from (',
' SELECT {{=it._column}} AS _cdb_iqr_column, ntile(4) over (order by {{=it._column}}',
' ) AS quartile',
' FROM ({{=it._query}}) _cdb_rank) _cdb_quartiles',
' WHERE quartile = 1 or quartile = 3',
' GROUP BY quartile',
' ) _cdb_iqr',
')'
].join('\n'));
var binsQueryTpl = dot.template([
'bins AS (',
' SELECT CASE WHEN total_rows = 0 OR iqr = 0',
' THEN 1',
' ELSE GREATEST(',
' LEAST({{=it._minBins}}, CAST(total_rows AS INT)),',
' LEAST(',
' CAST(((max_val - min_val) / (2 * iqr * power(total_rows, 1/3))) AS INT),',
' {{=it._maxBins}}',
' )',
' )',
' END AS bins_number',
' FROM basics, iqrange, ({{=it._query}}) _cdb_bins',
' LIMIT 1',
')'
].join('\n'));
var overrideBinsQueryTpl = dot.template([
'bins AS (',
' SELECT {{=it._bins}} AS bins_number',
')'
].join('\n'));
var nullsQueryTpl = dot.template([
'nulls AS (',
' SELECT',
' count(*) AS nulls_count',
' FROM ({{=it._query}}) _cdb_histogram_nulls',
' WHERE {{=it._column}} IS NULL',
')'
].join('\n'));
var histogramQueryTpl = dot.template([
'SELECT',
' (max_val - min_val) / cast(bins_number as float) AS bin_width,',
' bins_number,',
' nulls_count,',
' avg_val,',
' CASE WHEN min_val = max_val',
' THEN 0',
' ELSE GREATEST(1, LEAST(WIDTH_BUCKET({{=it._column}}, min_val, max_val, bins_number), bins_number)) - 1',
' END AS bin,',
' min({{=it._column}})::numeric AS min,',
' max({{=it._column}})::numeric AS max,',
' sum({{=it._column}}*_feature_count)/sum(_feature_count)::numeric AS avg,',
' sum(_feature_count) AS freq',
'FROM ({{=it._query}}) _cdb_histogram, basics, nulls, bins',
'WHERE {{=it._column}} IS NOT NULL',
'GROUP BY bin, bins_number, bin_width, nulls_count, avg_val',
'ORDER BY bin'
].join('\n'));
function Histogram(query, options, queryRewriter, queryRewriteData, params) {
BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params);
this.query = query;
this.column = options.column;
this.bins = options.bins;
this._columnType = null;
}
Histogram.prototype = Object.create(BaseOverviewsDataview.prototype);
Histogram.prototype.constructor = Histogram;
module.exports = Histogram;
var DATE_OIDS = {
1082: true,
1114: true,
1184: true
};
Histogram.prototype.sql = function(psql, override, callback) {
if (!callback) {
callback = override;
override = {};
}
var self = this;
var _column = this.column;
var columnTypeQuery = columnTypeQueryTpl({
column: _column, query: this.rewrittenQuery(this.query)
});
if (this._columnType === null) {
psql.query(columnTypeQuery, function(err, result) {
// assume numeric, will fail later
self._columnType = 'numeric';
if (!err && !!result.rows[0]) {
var pgType = result.rows[0].pg_typeof;
if (DATE_OIDS.hasOwnProperty(pgType)) {
self._columnType = 'date';
}
}
self.sql(psql, override, callback);
}, true); // use read-only transaction
return null;
}
if (this._columnType === 'date') {
_column = columnCastTpl({column: _column});
}
var _query = this.rewrittenQuery(this.query);
var basicsQuery, binsQuery;
if (override && _.has(override, 'start') && _.has(override, 'end') && _.has(override, 'bins')) {
basicsQuery = overrideBasicsQueryTpl({
_query: _query,
_column: _column,
_start: override.start,
_end: override.end
});
binsQuery = [
overrideBinsQueryTpl({
_bins: override.bins
})
].join(',\n');
} else {
basicsQuery = basicsQueryTpl({
_query: _query,
_column: _column
});
if (override && _.has(override, 'bins')) {
binsQuery = [
overrideBinsQueryTpl({
_bins: override.bins
})
].join(',\n');
} else {
binsQuery = [
iqrQueryTpl({
_query: _query,
_column: _column
}),
binsQueryTpl({
_query: _query,
_minBins: BIN_MIN_NUMBER,
_maxBins: BIN_MAX_NUMBER
})
].join(',\n');
}
}
var histogramSql = [
"WITH",
[
basicsQuery,
binsQuery,
nullsQueryTpl({
_query: _query,
_column: _column
})
].join(',\n'),
histogramQueryTpl({
_query: _query,
_column: _column
})
].join('\n');
return callback(null, histogramSql);
};

View File

@@ -0,0 +1,6 @@
module.exports = {
Aggregation: require('./aggregation'),
Formula: require('./formula'),
Histogram: require('./histogram'),
List: require('./list')
};

View File

@@ -0,0 +1,11 @@
var BaseOverviewsDataview = require('./base');
var BaseDataview = require('../list');
function List(query, options, queryRewriter, queryRewriteData, params) {
BaseOverviewsDataview.call(this, query, options, BaseDataview, queryRewriter, queryRewriteData, params);
}
List.prototype = Object.create(BaseOverviewsDataview.prototype);
List.prototype.constructor = List;
module.exports = List;

View File

@@ -0,0 +1,122 @@
var debug = require('debug')('windshaft:filter:bbox');
var dot = require('dot');
dot.templateSettings.strip = false;
var filterQueryTpl = dot.template([
'SELECT * FROM ({{=it._sql}}) _cdb_bbox_filter',
'WHERE {{=it._filters}}'
].join('\n'));
var bboxFilterTpl = dot.template(
'{{=it._column}} && ST_Transform(ST_MakeEnvelope({{=it._bbox}}, 4326), {{=it._srid}})'
);
var LATITUDE_MAX_VALUE = 85.0511287798066;
var LONGITUDE_LOWER_BOUND = -180;
var LONGITUDE_UPPER_BOUND = 180;
var LONGITUDE_RANGE = LONGITUDE_UPPER_BOUND - LONGITUDE_LOWER_BOUND;
/**
Definition
{
"type”: "bbox",
"options": {
"column": "the_geom_webmercator",
"srid": 3857
}
}
Params
{
“bbox”: "west,south,east,north"
}
*/
function BBox(filterDefinition, filterParams) {
var bbox = filterParams.bbox;
if (!bbox) {
throw new Error('BBox filter expects to have a bbox param');
}
var bboxElements = bbox.split(',').map(function(e) { return +e; });
validateBboxElements(bboxElements);
this.column = filterDefinition.column || 'the_geom_webmercator';
this.srid = filterDefinition.srid || 3857;
// Latitudes must be within max extent
var south = Math.max(bboxElements[1], -LATITUDE_MAX_VALUE);
var north = Math.min(bboxElements[3], LATITUDE_MAX_VALUE);
// Longitudes crossing 180º need another approach
var adjustedLongitudeRange = adjustLongitudeRange([bboxElements[0], bboxElements[2]]);
var west = adjustedLongitudeRange[0];
var east = adjustedLongitudeRange[1];
this.bboxes = getBoundingBoxes(west, south, east, north);
}
function getBoundingBoxes(west, south, east, north) {
var bboxes = [];
if (east - west >= 360) {
bboxes.push([-180, south, 180, north]);
} else if (west >= -180 && east <= 180) {
bboxes.push([west, south, east, north]);
} else {
bboxes.push([west, south, 180, north]);
bboxes.push([-180, south, east % 180, north]);
}
return bboxes;
}
function validateBboxElements(bboxElements) {
var isNumericBbox = bboxElements
.map(function(n) { return Number.isFinite(n); })
.reduce(function(allFinite, isFinite) {
if (!allFinite) {
return false;
}
return isFinite;
}, true);
if (bboxElements.length !== 4 || !isNumericBbox) {
throw new Error('Invalid bbox filter, expected format="west,south,east,north"');
}
}
function adjustLongitudeRange(we) {
var west = we[0];
west -= LONGITUDE_LOWER_BOUND;
west = west - (LONGITUDE_RANGE * Math.floor(west / LONGITUDE_RANGE)) + LONGITUDE_LOWER_BOUND;
var longitudeRange = Math.min(we[1] - we[0], 360);
return [west, west + longitudeRange];
}
module.exports = BBox;
module.exports.adjustLongitudeRange = adjustLongitudeRange;
module.exports.LATITUDE_MAX_VALUE = LATITUDE_MAX_VALUE;
module.exports.LONGITUDE_MAX_VALUE = LONGITUDE_UPPER_BOUND;
BBox.prototype.sql = function(rawSql) {
var bboxSql = filterQueryTpl({
_sql: rawSql,
_filters: this.bboxes.map(function(bbox) {
return bboxFilterTpl({
_column: this.column,
_bbox: bbox.join(','),
_srid: this.srid
});
}.bind(this)).join(' OR ')
});
debug(bboxSql);
return bboxSql;
};

View File

@@ -0,0 +1,35 @@
var filters = {
category: require('./camshaft/category'),
range: require('./camshaft/range')
};
function createFilter(filterDefinition) {
var filterType = filterDefinition.type.toLowerCase();
if (!filters.hasOwnProperty(filterType)) {
throw new Error('Unknown filter type: ' + filterType);
}
return new filters[filterType](filterDefinition.column, filterDefinition.params);
}
function CamshaftFilters(filters) {
this.filters = filters;
}
CamshaftFilters.prototype.sql = function(rawSql) {
var filters = this.filters || {};
var applyFilters = {};
return Object.keys(filters)
.filter(function(filterName) {
return applyFilters.hasOwnProperty(filterName) ? applyFilters[filterName] : true;
})
.map(function(filterName) {
var filterDefinition = filters[filterName];
return createFilter(filterDefinition);
})
.reduce(function(sql, filter) {
return filter.sql(sql);
}, rawSql);
};
module.exports = CamshaftFilters;

View File

@@ -0,0 +1,79 @@
'use strict';
var debug = require('debug')('windshaft:filter:category');
var dot = require('dot');
dot.templateSettings.strip = false;
var filterQueryTpl = dot.template([
'SELECT *',
'FROM ({{=it._sql}}) _camshaft_category_filter',
'WHERE {{=it._filters}}'
].join('\n'));
var escapeStringTpl = dot.template('$escape_{{=it._i}}${{=it._value}}$escape_{{=it._i}}$');
var inConditionTpl = dot.template('{{=it._column}} IN ({{=it._values}})');
var notInConditionTpl = dot.template('{{=it._column}} NOT IN ({{=it._values}})');
function Category(column, filterParams) {
this.column = column;
if (!Array.isArray(filterParams.accept) && !Array.isArray(filterParams.reject)) {
throw new Error('Category filter expects at least one array in accept or reject params');
}
if (Array.isArray(filterParams.accept) && Array.isArray(filterParams.reject)) {
if (filterParams.accept.length === 0 && filterParams.reject.length === 0) {
throw new Error(
'Category filter expects one value either in accept or reject params when both are provided'
);
}
}
this.accept = filterParams.accept;
this.reject = filterParams.reject;
}
module.exports = Category;
/*
- accept: [] => reject all
- reject: [] => accept all
*/
Category.prototype.sql = function(rawSql) {
var valueFilters = [];
if (Array.isArray(this.accept)) {
if (this.accept.length > 0) {
valueFilters.push(inConditionTpl({
_column: this.column,
_values: this.accept.map(function(value, i) {
return Number.isFinite(value) ? value : escapeStringTpl({_i: i, _value: value});
}).join(',')
}));
} else {
valueFilters.push('0 = 1');
}
}
if (Array.isArray(this.reject)) {
if (this.reject.length > 0) {
valueFilters.push(notInConditionTpl({
_column: this.column,
_values: this.reject.map(function (value, i) {
return Number.isFinite(value) ? value : escapeStringTpl({_i: i, _value: value});
}).join(',')
}));
} else {
valueFilters.push('1 = 1');
}
}
debug(filterQueryTpl({
_sql: rawSql,
_filters: valueFilters.join(' AND ')
}));
return filterQueryTpl({
_sql: rawSql,
_filters: valueFilters.join(' AND ')
});
};

View File

@@ -0,0 +1,43 @@
'use strict';
var dot = require('dot');
dot.templateSettings.strip = false;
var betweenFilterTpl = dot.template('{{=it._column}} BETWEEN {{=it._min}} AND {{=it._max}}');
var minFilterTpl = dot.template('{{=it._column}} >= {{=it._min}}');
var maxFilterTpl = dot.template('{{=it._column}} <= {{=it._max}}');
var filterQueryTpl = dot.template('SELECT * FROM ({{=it._sql}}) _camshaft_range_filter WHERE {{=it._filter}}');
function Range(column, filterParams) {
this.column = column;
if (!Number.isFinite(filterParams.min) && !Number.isFinite(filterParams.max)) {
throw new Error('Range filter expect to have at least one value in min or max numeric params');
}
this.min = filterParams.min;
this.max = filterParams.max;
this.columnType = filterParams.columnType;
}
module.exports = Range;
Range.prototype.sql = function(rawSql) {
var minMaxFilter;
if (Number.isFinite(this.min) && Number.isFinite(this.max)) {
minMaxFilter = betweenFilterTpl({
_column: this.column,
_min: this.min,
_max: this.max
});
} else if (Number.isFinite(this.min)) {
minMaxFilter = minFilterTpl({ _column: this.column, _min: this.min });
} else {
minMaxFilter = maxFilterTpl({ _column: this.column, _max: this.max });
}
return filterQueryTpl({
_sql: rawSql,
_filter: minMaxFilter
});
};

View File

@@ -0,0 +1,298 @@
var queue = require('queue-async');
var debug = require('debug')('windshaft:analysis');
var camshaft = require('camshaft');
var dot = require('dot');
dot.templateSettings.strip = false;
function AnalysisMapConfigAdapter(analysisBackend) {
this.analysisBackend = analysisBackend;
}
module.exports = AnalysisMapConfigAdapter;
AnalysisMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) {
// jshint maxcomplexity:7
var self = this;
if (!shouldAdaptLayers(requestMapConfig)) {
return callback(null, requestMapConfig);
}
var analysisConfiguration = context.analysisConfiguration;
var filters = {};
if (params.filters) {
try {
filters = JSON.parse(params.filters);
} catch (e) {
// ignore
}
}
var dataviewsFilters = filters.dataviews || {};
debug(dataviewsFilters);
var dataviews = requestMapConfig.dataviews || {};
var errors = getDataviewsErrors(dataviews);
if (errors.length > 0) {
return callback(errors);
}
var dataviewsFiltersBySourceId = Object.keys(dataviewsFilters).reduce(function(bySourceId, dataviewName) {
var dataview = dataviews[dataviewName];
if (dataview) {
var sourceId = dataview.source.id;
if (!bySourceId.hasOwnProperty(sourceId)) {
bySourceId[sourceId] = {};
}
bySourceId[sourceId][dataviewName] = getFilter(dataview, dataviewsFilters[dataviewName]);
}
return bySourceId;
}, {});
debug(dataviewsFiltersBySourceId);
debug('mapconfig input', JSON.stringify(requestMapConfig, null, 4));
requestMapConfig = appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId);
function createAnalysis(analysisDefinition, index, done) {
self.analysisBackend.create(analysisConfiguration, analysisDefinition, function (err, analysis) {
if (err) {
var error = new Error(err.message);
error.type = 'analysis';
error.context = {};
error.context.layer = {
index: index,
id: analysisDefinition.id,
type: analysisDefinition.type
};
return done(error);
}
done(null, analysis);
});
}
var analysesQueue = queue(requestMapConfig.analyses.length);
requestMapConfig.analyses.forEach(function(analysis, index) {
analysesQueue.defer(createAnalysis, analysis, index);
});
analysesQueue.awaitAll(function(err, analysesResults) {
if (err) {
return callback(err);
}
var sourceId2Node = analysesResults.reduce(function(sourceId2Query, analysis) {
var rootNode = analysis.getRoot();
if (rootNode.params && rootNode.params.id) {
sourceId2Query[rootNode.params.id] = rootNode;
}
analysis.getSortedNodes().forEach(function(node) {
if (node.params && node.params.id) {
sourceId2Query[node.params.id] = node;
}
});
return sourceId2Query;
}, {});
var missingNodesErrors = [];
requestMapConfig.layers = requestMapConfig.layers.map(function(layer, layerIndex) {
if (getLayerSourceId(layer)) {
var layerSourceId = getLayerSourceId(layer);
var layerNode = sourceId2Node[layerSourceId];
if (layerNode) {
var analysisSql = layerQuery(layerNode);
var sqlQueryWrap = layer.options.sql_wrap;
if (sqlQueryWrap) {
layer.options.sql_raw = analysisSql;
analysisSql = sqlQueryWrap.replace(/<%=\s*sql\s*%>/g, analysisSql);
}
layer.options.sql = analysisSql;
layer.options.columns = getDataviewsColumns(getLayerDataviews(layer, dataviews));
} else {
missingNodesErrors.push(
new Error('Missing analysis node.id="' + layerSourceId +'" for layer='+layerIndex)
);
}
}
return layer;
});
debug('mapconfig output', JSON.stringify(requestMapConfig, null, 4));
var missingDataviewsNodesErrors = getMissingDataviewsSourceIds(dataviews, sourceId2Node);
if (missingNodesErrors.length > 0 || missingDataviewsNodesErrors.length > 0) {
return callback(missingNodesErrors.concat(missingDataviewsNodesErrors));
}
context.analysesResults = analysesResults;
return callback(null, requestMapConfig);
});
};
var SKIP_COLUMNS = {
'the_geom': true,
'the_geom_webmercator': true
};
function skipColumns(columnNames) {
return columnNames
.filter(function(columnName) { return !SKIP_COLUMNS[columnName]; });
}
var layerQueryTemplate = dot.template([
'SELECT {{=it._columns}}',
'FROM ({{=it._query}}) _cdb_analysis_query'
].join('\n'));
function layerQuery(node) {
if (node.type === 'source') {
return node.getQuery();
}
var _columns = ['ST_Transform(the_geom, 3857) the_geom_webmercator'].concat(skipColumns(node.getColumns()));
return layerQueryTemplate({ _query: node.getQuery(), _columns: _columns.join(', ') });
}
function appendFiltersToNodes(requestMapConfig, dataviewsFiltersBySourceId) {
var analyses = requestMapConfig.analyses || [];
requestMapConfig.analyses = analyses.map(function(analysisDefinition) {
var analysisGraph = new camshaft.reference.AnalysisGraph(analysisDefinition);
var definition = analysisDefinition;
Object.keys(dataviewsFiltersBySourceId).forEach(function(sourceId) {
definition = analysisGraph.getDefinitionWith(sourceId, {filters: dataviewsFiltersBySourceId[sourceId] });
});
return definition;
});
return requestMapConfig;
}
function shouldAdaptLayers(requestMapConfig) {
return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(getLayerSourceId) ||
(Array.isArray(requestMapConfig.analyses) && requestMapConfig.analyses.length > 0) ||
requestMapConfig.dataviews;
}
var DATAVIEW_TYPE_2_FILTER_TYPE = {
aggregation: 'category',
histogram: 'range'
};
function getFilter(dataview, params) {
var type = dataview.type;
return {
type: DATAVIEW_TYPE_2_FILTER_TYPE[type],
column: dataview.options.column,
params: params
};
}
function getLayerSourceId(layer) {
return layer.options.source && layer.options.source.id;
}
function getDataviewSourceId(dataview) {
return dataview.source && dataview.source.id;
}
function getLayerDataviews(layer, dataviews) {
var layerDataviews = [];
var layerSourceId = getLayerSourceId(layer);
if (layerSourceId) {
var dataviewsList = getDataviewsList(dataviews);
dataviewsList.forEach(function(dataview) {
if (getDataviewSourceId(dataview) === layerSourceId) {
layerDataviews.push(dataview);
}
});
}
return layerDataviews;
}
function getDataviewsColumns(dataviews) {
return Object.keys(dataviews.reduce(function(columnsDict, dataview) {
getDataviewColumns(dataview).forEach(function(columnName) {
if (!!columnName) {
columnsDict[columnName] = true;
}
});
return columnsDict;
}, {}));
}
function getDataviewColumns(dataview) {
var columns = [];
var options = dataview.options;
['column', 'aggregationColumn'].forEach(function(opt) {
if (options.hasOwnProperty(opt) && !!options[opt]) {
columns.push(options[opt]);
}
});
return columns;
}
function getDataviewsList(dataviews) {
return Object.keys(dataviews).map(function(dataviewKey) { return dataviews[dataviewKey]; });
}
function getDataviewsErrors(dataviews) {
var dataviewType = typeof dataviews;
if (dataviewType !== 'object') {
return [new Error('"dataviews" must be a valid JSON object: "' + dataviewType + '" type found')];
}
if (Array.isArray(dataviews)) {
return [new Error('"dataviews" must be a valid JSON object: "array" type found')];
}
var errors = [];
Object.keys(dataviews).forEach(function(dataviewName) {
var dataview = dataviews[dataviewName];
if (!dataview.hasOwnProperty('source') || !dataview.source.id) {
errors.push(new Error('Dataview "' + dataviewName + '" is missing `source.id` attribute'));
}
if (!dataview.type) {
errors.push(new Error('Dataview "' + dataviewName + '" is missing `type` attribute'));
}
});
return errors;
}
function getMissingDataviewsSourceIds(dataviews, sourceId2Node) {
var missingDataviewsSourceIds = [];
Object.keys(dataviews).forEach(function(dataviewName) {
var dataview = dataviews[dataviewName];
var dataviewSourceId = getDataviewSourceId(dataview);
if (!sourceId2Node.hasOwnProperty(dataviewSourceId)) {
missingDataviewsSourceIds.push(new AnalysisError('Node with `source.id="' + dataviewSourceId +'"`' +
' not found in analyses for dataview "' + dataviewName + '"'));
}
});
return missingDataviewsSourceIds;
}
function AnalysisError(message) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.type = 'analysis';
this.message = message;
}
require('util').inherits(AnalysisError, Error);

View File

@@ -0,0 +1,98 @@
function DataviewsWidgetsMapConfigAdapter() {
}
module.exports = DataviewsWidgetsMapConfigAdapter;
DataviewsWidgetsMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) {
if (!shouldAdapt(requestMapConfig)) {
return callback(null, requestMapConfig);
}
// prepare placeholders for new dataviews created from widgets
requestMapConfig.analyses = requestMapConfig.analyses || [];
requestMapConfig.dataviews = requestMapConfig.dataviews || {};
requestMapConfig.layers.forEach(function(layer, index) {
var layerSourceId = getLayerSourceId(layer);
if (!layer.options.widgets) {
return;
}
if (!layerSourceId && !layer.options.sql) {
return;
}
var dataviewSourceId = layerSourceId || 'cdb-layer-source-' + index;
// Append a new analysis if layer has no source id but sql.
if (!layerSourceId) {
requestMapConfig.analyses.push(
{
id: dataviewSourceId,
type: 'source',
params: {
query: layer.options.sql
}
}
);
}
var source = { id: dataviewSourceId };
var layerWidgets = layer.options.widgets || {};
Object.keys(layerWidgets).forEach(function(widgetId) {
var dataview = layerWidgets[widgetId];
requestMapConfig.dataviews[widgetId] = {
source: source,
type: dataview.type,
options: dataview.options
};
});
layer.options.source = source;
delete layer.options.sql;
// don't delete widgets for now as it might be useful for old clients
//delete layer.options.widgets;
});
// filters have to be rewritten also
var filters = getFilters(params);
var layersFilters = filters.layers || [];
filters.dataviews = filters.dataviews || {};
layersFilters.forEach(function(layerFilters) {
Object.keys(layerFilters).forEach(function(filterName) {
if (!filters.dataviews.hasOwnProperty(filterName)) {
filters.dataviews[filterName] = layerFilters[filterName];
}
});
});
delete filters.layers;
params.filters = JSON.stringify(filters);
return callback(null, requestMapConfig);
};
function shouldAdapt(requestMapConfig) {
return Array.isArray(requestMapConfig.layers) && requestMapConfig.layers.some(function hasWidgets(layer) {
return layer.options && layer.options.widgets && Object.keys(layer.options.widgets).length > 0;
});
}
function getLayerSourceId(layer) {
return layer.options.source && layer.options.source.id;
}
function getFilters(params) {
var filters = {};
if (params.filters) {
try {
filters = JSON.parse(params.filters);
} catch (e) {
// ignore
}
}
return filters;
}

View File

@@ -0,0 +1,26 @@
'use strict';
function MapConfigAdapter(adapters) {
this.adapters = Array.isArray(adapters) ? adapters : Array.apply(null, arguments);
}
module.exports = MapConfigAdapter;
MapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) {
var self = this;
var i = 0;
var tasksLeft = this.adapters.length;
function next(err, _requestMapConfig) {
if (err) {
return callback(err);
}
if (tasksLeft-- === 0) {
return callback(null, _requestMapConfig);
}
var nextAdapter = self.adapters[i++];
nextAdapter.getMapConfig(user, _requestMapConfig, params, context, next);
}
next(null, requestMapConfig);
};

View File

@@ -0,0 +1,131 @@
var queue = require('queue-async');
var _ = require('underscore');
var Datasource = require('windshaft').model.Datasource;
function MapConfigNamedLayersAdapter(templateMaps, pgConnection) {
this.templateMaps = templateMaps;
this.pgConnection = pgConnection;
}
module.exports = MapConfigNamedLayersAdapter;
MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) {
var self = this;
var layers = requestMapConfig.layers;
if (!layers) {
return callback(null, requestMapConfig);
}
var adaptLayersQueue = queue(layers.length);
function adaptLayer(layer, done) {
if (isNamedTypeLayer(layer)) {
if (!layer.options.name) {
return done(new Error('Missing Named Map `name` in layer options'));
}
var templateName = layer.options.name;
var templateConfigParams = layer.options.config || {};
var templateAuthTokens = layer.options.auth_tokens;
self.templateMaps.getTemplate(user, templateName, function(err, template) {
if (err || !template) {
return done(new Error("Template '" + templateName + "' of user '" + user + "' not found"));
}
if (self.templateMaps.isAuthorized(template, templateAuthTokens)) {
var nestedNamedLayers = template.layergroup.layers.filter(function(layer) {
return layer.type === 'named';
});
if (nestedNamedLayers.length > 0) {
var nestedNamedMapsError = new Error('Nested named layers are not allowed');
// nestedNamedMapsError.http_status = 400;
return done(nestedNamedMapsError);
}
try {
var templateLayergroupConfig = self.templateMaps.instance(template, templateConfigParams);
return done(null, {
datasource: true,
layers: templateLayergroupConfig.layers
});
} catch (err) {
return done(err);
}
} else {
var unauthorizedError = new Error("Unauthorized '" + templateName + "' template instantiation");
unauthorizedError.http_status = 403;
return done(unauthorizedError);
}
});
} else {
return done(null, {
datasource: false,
layers: [layer]
});
}
}
var datasourceBuilder = new Datasource.Builder();
function layersAdaptQueueFinish(err, layersResults) {
if (err) {
return callback(err);
}
if (!layersResults || layersResults.length === 0) {
return callback(new Error('Missing layers array from layergroup config'));
}
var layers = [],
currentLayerIndex = 0;
layersResults.forEach(function(layersResult) {
layersResult.layers.forEach(function(layer) {
layers.push(layer);
if (layersResult.datasource) {
datasourceBuilder.withLayerDatasource(currentLayerIndex, {
user: dbAuth.dbuser
});
}
currentLayerIndex++;
});
});
requestMapConfig.layers = layers;
context.datasource = datasourceBuilder.build();
return callback(null, requestMapConfig);
}
var dbAuth = {};
if (_.some(layers, isNamedTypeLayer)) {
// Lazy load dbAuth
this.pgConnection.setDBAuth(user, dbAuth, function(err) {
if (err) {
return callback(err);
}
layers.forEach(function(layer) {
adaptLayersQueue.defer(adaptLayer, layer);
});
adaptLayersQueue.awaitAll(layersAdaptQueueFinish);
});
} else {
context.datasource = datasourceBuilder.build();
return callback(null, requestMapConfig);
}
};
function isNamedTypeLayer(layer) {
return layer.type === 'named';
}

View File

@@ -0,0 +1,101 @@
var step = require('step');
var queue = require('queue-async');
var _ = require('underscore');
function MapConfigOverviewsAdapter(overviewsMetadataApi, filterStatsApi) {
this.overviewsMetadataApi = overviewsMetadataApi;
this.filterStatsApi = filterStatsApi;
}
module.exports = MapConfigOverviewsAdapter;
MapConfigOverviewsAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) {
var self = this;
var layers = requestMapConfig.layers;
var analysesResults = context.analysesResults;
if (!layers || layers.length === 0) {
return callback(null, requestMapConfig);
}
var augmentLayersQueue = queue(layers.length);
function augmentLayer(layer, done) {
if ( layer.type !== 'mapnik' && layer.type !== 'cartodb' ) {
return done(null, layer);
}
self.overviewsMetadataApi.getOverviewsMetadata(user, layer.options.sql, function(err, metadata){
if (err) {
done(err, layer);
} else {
var query_rewrite_data = { overviews: metadata };
step(
function collectFiltersData() {
var filters, unfiltered_query;
if ( layer.options.source && analysesResults ) {
var sourceId = layer.options.source.id;
var node = _.find(analysesResults, function(a){ return a.rootNode.params.id === sourceId; });
if ( node ) {
node = node.rootNode;
filters = node.getFilters();
var filters_disabler = Object.keys(filters).reduce(
function(disabler, filter_id){ disabler[filter_id] = false; return disabler; },
{}
);
unfiltered_query = node.getQuery(filters_disabler);
query_rewrite_data.filters = filters;
query_rewrite_data.unfiltered_query = unfiltered_query;
}
}
this(null, filters, unfiltered_query);
},
function collectStatsData(err, filters, unfiltered_query) {
var next_step = this;
if ( filters ) {
self.filterStatsApi.getFilterStats(
user,
unfiltered_query, filters,
function(err, stats) {
if ( !err ) {
query_rewrite_data.filter_stats = stats;
}
return next_step(err);
}
);
} else {
return next_step(null);
}
},
function addDataToLayer(err) {
if ( !err && !_.isEmpty(metadata) ) {
layer = _.extend({}, layer);
layer.options = _.extend({}, layer.options, { query_rewrite_data: query_rewrite_data });
}
done(null, layer);
}
);
}
});
}
function layersAugmentQueueFinish(err, layers) {
if (err) {
return callback(err);
}
if (!layers || layers.length === 0) {
return callback(new Error('Missing layers array from layergroup config'));
}
requestMapConfig.layers = layers;
return callback(null, requestMapConfig);
}
layers.forEach(function(layer) {
augmentLayersQueue.defer(augmentLayer, layer);
});
augmentLayersQueue.awaitAll(layersAugmentQueueFinish);
};

View File

@@ -0,0 +1,25 @@
function SqlWrapMapConfigAdapter() {
}
module.exports = SqlWrapMapConfigAdapter;
SqlWrapMapConfigAdapter.prototype.getMapConfig = function(user, requestMapConfig, params, context, callback) {
if (requestMapConfig && Array.isArray(requestMapConfig.layers)) {
requestMapConfig.layers = requestMapConfig.layers.map(function(layer) {
if (layer.options) {
var sqlQueryWrap = layer.options.sql_wrap;
if (sqlQueryWrap) {
var layerSql = layer.options.sql;
if (layerSql) {
layer.options.sql_raw = layerSql;
layer.options.sql = sqlQueryWrap.replace(/<%=\s*sql\s*%>/g, layerSql);
}
}
}
return layer;
});
}
return callback(null, requestMapConfig);
};

View File

@@ -0,0 +1,162 @@
'use strict';
var dot = require('dot');
dot.templateSettings.strip = false;
var queue = require('queue-async');
var PSQL = require('cartodb-psql');
var turboCarto = require('turbo-carto');
var SubstitutionTokens = require('../../../utils/substitution-tokens');
var PostgresDatasource = require('../../../backends/turbo-carto-postgres-datasource');
function TurboCartoAdapter() {
}
module.exports = TurboCartoAdapter;
TurboCartoAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) {
var self = this;
var layers = requestMapConfig.layers;
if (!layers || layers.length === 0) {
return callback(null, requestMapConfig);
}
var parseCartoQueue = queue(layers.length);
layers.forEach(function(layer, index) {
parseCartoQueue.defer(self._parseCartoCss.bind(self), user, params, layer, index);
});
parseCartoQueue.awaitAll(function (err, layers) {
if (err) {
return callback(err);
}
requestMapConfig.layers = layers;
return callback(null, requestMapConfig);
});
};
var tokensQueryTpl = dot.template([
'WITH input_query AS (',
' {{=it._sql}}',
'),',
'bbox_query AS (',
' SELECT ST_SetSRID(ST_Extent(the_geom_webmercator), 3857) as bbox from input_query',
'),',
'zoom_query as (',
' SELECT GREATEST(',
' ceil(log(40075017000 / 256 / GREATEST(ST_XMax(bbox) - ST_XMin(bbox), ST_YMax(bbox) - ST_YMin(bbox)))/log(2)),',
' 0) as zoom',
' FROM bbox_query',
'),',
'pixel_size_query as (',
' SELECT 40075017 * cos(radians(ST_Y(ST_Transform(ST_Centroid(bbox), 4326)))) / 2 ^ ((zoom) + 8) as pixel_size',
' FROM bbox_query, zoom_query',
'),',
'scale_denominator_query as (',
' SELECT (pixel_size / 0.00028)::numeric as scale_denominator',
' FROM pixel_size_query',
')',
'select ST_AsText(bbox) bbox, pixel_size, scale_denominator, zoom',
'from bbox_query, pixel_size_query, scale_denominator_query, zoom_query'
].join('\n'));
TurboCartoAdapter.prototype._parseCartoCss = function (username, params, layer, index, callback) {
if (!shouldParseLayerCartocss(layer)) {
return callback(null, layer);
}
var pg = new PSQL(dbParamsFromReqParams(params));
function processCallback(err, cartocss) {
// Only return turbo-carto errors
if (err && err.name === 'TurboCartoError') {
var error = new Error('turbo-carto: ' + err.message);
error.http_status = 400;
error.type = 'turbo-carto';
error.context = err.context;
error.context.layer = {
index: index,
type: layer.type
};
return callback(error);
}
// Try to continue in the rest of the cases
if (cartocss) {
layer.options.cartocss = cartocss;
}
return callback(null, layer);
}
var layerSql = layer.options.sql;
var layerRawSql = layer.options.sql_raw;
if (SubstitutionTokens.hasTokens(layerSql) && layerRawSql) {
var self = this;
var tokensQuery = tokensQueryTpl({_sql: layerRawSql});
return pg.query(tokensQuery, function(err, resultSet) {
if (err) {
var error = new Error('turbo-carto: ' + err.message);
error.type = 'turbo-carto';
return callback(error);
}
resultSet = resultSet || {};
var rows = resultSet.rows || [];
var result = rows[0] || {};
var tokens = {
bbox: 'ST_SetSRID(ST_GeomFromText(\'' + result.bbox + '\'), 3857)',
scale_denominator: result.scale_denominator,
pixel_width: result.pixel_size,
pixel_height: result.pixel_size
};
var sql = SubstitutionTokens.replace(layerSql, tokens);
self.process(pg, layer.options.cartocss, sql, processCallback);
}, true); // use read-only transaction
}
var tokens = {
bbox: 'ST_MakeEnvelope(-20037508.34,-20037508.34,20037508.34,20037508.34,3857)',
scale_denominator: '500000001',
pixel_width: '156412',
pixel_height: '156412'
};
var sql = SubstitutionTokens.replace(layerSql, tokens);
this.process(pg, layer.options.cartocss, sql, processCallback);
};
TurboCartoAdapter.prototype.process = function (psql, cartocss, sql, callback) {
var datasource = new PostgresDatasource(psql, sql);
turboCarto(cartocss, datasource, callback);
};
function shouldParseLayerCartocss(layer) {
return layer && layer.options && layer.options.cartocss && layer.options.sql;
}
function dbParamsFromReqParams(params) {
var dbParams = {};
if ( params.dbuser ) {
dbParams.user = params.dbuser;
}
if ( params.dbpassword ) {
dbParams.pass = params.dbpassword;
}
if ( params.dbhost ) {
dbParams.host = params.dbhost;
}
if ( params.dbport ) {
dbParams.port = params.dbport;
}
if ( params.dbname ) {
dbParams.dbname = params.dbname;
}
return dbParams;
}

View File

@@ -0,0 +1,48 @@
var assert = require('assert');
var step = require('step');
var MapStoreMapConfigProvider = require('./map-store-provider');
/**
* @param {MapConfig} mapConfig
* @param {String} user
* @param {UserLimitsApi} userLimitsApi
* @param {Object} params
* @constructor
* @type {CreateLayergroupMapConfigProvider}
*/
function CreateLayergroupMapConfigProvider(mapConfig, user, userLimitsApi, params) {
this.mapConfig = mapConfig;
this.user = user;
this.userLimitsApi = userLimitsApi;
this.params = params;
this.cacheBuster = params.cache_buster || 0;
}
module.exports = CreateLayergroupMapConfigProvider;
CreateLayergroupMapConfigProvider.prototype.getMapConfig = function(callback) {
var self = this;
var context = {};
step(
function prepareContextLimits() {
self.userLimitsApi.getRenderLimits(self.user, this);
},
function handleRenderLimits(err, renderLimits) {
assert.ifError(err);
context.limits = renderLimits;
return null;
},
function finish(err) {
return callback(err, self.mapConfig, self.params, context);
}
);
};
CreateLayergroupMapConfigProvider.prototype.getKey = MapStoreMapConfigProvider.prototype.getKey;
CreateLayergroupMapConfigProvider.prototype.getCacheBuster = MapStoreMapConfigProvider.prototype.getCacheBuster;
CreateLayergroupMapConfigProvider.prototype.filter = MapStoreMapConfigProvider.prototype.filter;
CreateLayergroupMapConfigProvider.prototype.createKey = MapStoreMapConfigProvider.prototype.createKey;

View File

@@ -0,0 +1,77 @@
var _ = require('underscore');
var assert = require('assert');
var dot = require('dot');
var step = require('step');
/**
* @param {MapStore} mapStore
* @param {String} user
* @param {UserLimitsApi} userLimitsApi
* @param {Object} params
* @constructor
* @type {MapStoreMapConfigProvider}
*/
function MapStoreMapConfigProvider(mapStore, user, userLimitsApi, params) {
this.mapStore = mapStore;
this.user = user;
this.userLimitsApi = userLimitsApi;
this.params = params;
this.token = params.token;
this.cacheBuster = params.cache_buster || 0;
}
module.exports = MapStoreMapConfigProvider;
MapStoreMapConfigProvider.prototype.getMapConfig = function(callback) {
var self = this;
var context = {};
step(
function prepareContextLimits() {
self.userLimitsApi.getRenderLimits(self.user, this);
},
function handleRenderLimits(err, renderLimits) {
assert.ifError(err);
context.limits = renderLimits;
return null;
},
function loadMapConfig(err) {
assert.ifError(err);
self.mapStore.load(self.token, this);
},
function finish(err, mapConfig) {
return callback(err, mapConfig, self.params, context);
}
);
};
MapStoreMapConfigProvider.prototype.getKey = function() {
return this.createKey(false);
};
MapStoreMapConfigProvider.prototype.getCacheBuster = function() {
return this.cacheBuster;
};
MapStoreMapConfigProvider.prototype.filter = function(key) {
var regex = new RegExp('^' + this.createKey(true) + '.*');
return key && key.match(regex);
};
// Configure bases for cache keys suitable for string interpolation
var baseKey = '{{=it.dbname}}:{{=it.token}}';
var rendererKey = baseKey + ':{{=it.dbuser}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}';
var baseKeyTpl = dot.template(baseKey);
var rendererKeyTpl = dot.template(rendererKey);
MapStoreMapConfigProvider.prototype.createKey = function(base) {
var tplValues = _.defaults({}, this.params, {
dbname: '',
token: '',
dbuser: '',
format: '',
layer: '',
scale_factor: 1
});
return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues);
};

View File

@@ -0,0 +1,286 @@
var _ = require('underscore');
var assert = require('assert');
var crypto = require('crypto');
var dot = require('dot');
var step = require('step');
var MapConfig = require('windshaft').model.MapConfig;
var templateName = require('../../../backends/template_maps').templateName;
var QueryTables = require('cartodb-query-tables');
/**
* @constructor
* @type {NamedMapMapConfigProvider}
*/
function NamedMapMapConfigProvider(templateMaps, pgConnection, metadataBackend, userLimitsApi, mapConfigAdapter,
owner, templateId, config, authToken, params) {
this.templateMaps = templateMaps;
this.pgConnection = pgConnection;
this.metadataBackend = metadataBackend;
this.userLimitsApi = userLimitsApi;
this.mapConfigAdapter = mapConfigAdapter;
this.owner = owner;
this.templateName = templateName(templateId);
this.config = config;
this.authToken = authToken;
this.params = params;
this.cacheBuster = Date.now();
// use template after call to mapConfig
this.template = null;
this.affectedTablesAndLastUpdate = null;
// providing
this.err = null;
this.mapConfig = null;
this.rendererParams = null;
this.context = {};
this.analysesResults = [];
}
module.exports = NamedMapMapConfigProvider;
NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
if (!!this.err || this.mapConfig !== null) {
return callback(this.err, this.mapConfig, this.rendererParams, this.context);
}
var self = this;
var mapConfig = null;
var rendererParams;
var apiKey;
var context = {};
step(
function getTemplate() {
self.getTemplate(this);
},
function prepareDbParams(err, tpl) {
assert.ifError(err);
self.template = tpl;
rendererParams = _.extend({}, self.params, {
user: self.owner
});
self.setDBParams(self.owner, rendererParams, this);
},
function getUserApiKey(err) {
assert.ifError(err);
self.metadataBackend.getUserMapKey(self.owner, this);
},
function prepareParams(err, _apiKey) {
assert.ifError(err);
apiKey = _apiKey;
var templateParams = {};
if (self.config) {
try {
templateParams = _.isString(self.config) ? JSON.parse(self.config) : self.config;
} catch (e) {
throw new Error('malformed config parameter, should be a valid JSON');
}
}
return templateParams;
},
function instantiateTemplate(err, templateParams) {
assert.ifError(err);
return self.templateMaps.instance(self.template, templateParams);
},
function prepareAdapterMapConfig(err, requestMapConfig) {
assert.ifError(err);
context.analysisConfiguration = {
db: {
host: rendererParams.dbhost,
port: rendererParams.dbport,
dbname: rendererParams.dbname,
user: rendererParams.dbuser,
pass: rendererParams.dbpassword
},
batch: {
username: self.owner,
apiKey: apiKey
}
};
self.mapConfigAdapter.getMapConfig(self.owner, requestMapConfig, rendererParams, context, this);
},
function prepareContextLimits(err, _mapConfig) {
assert.ifError(err);
mapConfig = _mapConfig;
self.userLimitsApi.getRenderLimits(self.owner, this);
},
function cacheAndReturnMapConfig(err, renderLimits) {
self.err = err;
self.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource);
self.analysesResults = context.analysesResults || [];
self.rendererParams = rendererParams;
self.context.limits = renderLimits || {};
return callback(self.err, self.mapConfig, self.rendererParams, self.context);
}
);
};
NamedMapMapConfigProvider.prototype.getTemplate = function(callback) {
var self = this;
if (!!this.err || this.template !== null) {
return callback(this.err, this.template);
}
step(
function getTemplate() {
self.templateMaps.getTemplate(self.owner, self.templateName, this);
},
function checkExists(err, tpl) {
assert.ifError(err);
if (!tpl) {
var notFoundErr = new Error(
"Template '" + self.templateName + "' of user '" + self.owner + "' not found"
);
notFoundErr.http_status = 404;
throw notFoundErr;
}
return tpl;
},
function checkAuthorized(err, tpl) {
assert.ifError(err);
var authorized = false;
try {
authorized = self.templateMaps.isAuthorized(tpl, self.authToken);
} catch (err) {
// we catch to add http_status
var authorizationFailedErr = new Error('Failed to authorize template');
authorizationFailedErr.http_status = 403;
throw authorizationFailedErr;
}
if ( ! authorized ) {
var unauthorizedErr = new Error('Unauthorized template instantiation');
unauthorizedErr.http_status = 403;
throw unauthorizedErr;
}
return tpl;
},
function cacheAndReturnTemplate(err, template) {
self.err = err;
self.template = template;
return callback(self.err, self.template);
}
);
};
NamedMapMapConfigProvider.prototype.getKey = function() {
return this.createKey(false);
};
NamedMapMapConfigProvider.prototype.getCacheBuster = function() {
return this.cacheBuster;
};
NamedMapMapConfigProvider.prototype.reset = function() {
this.template = null;
this.affectedTablesAndLastUpdate = null;
this.err = null;
this.mapConfig = null;
this.cacheBuster = Date.now();
};
NamedMapMapConfigProvider.prototype.filter = function(key) {
var regex = new RegExp('^' + this.createKey(true) + '.*');
return key && key.match(regex);
};
// Configure bases for cache keys suitable for string interpolation
var baseKey = '{{=it.dbname}}:{{=it.owner}}:{{=it.templateName}}';
var rendererKey = baseKey + ':{{=it.authToken}}:{{=it.configHash}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}';
var baseKeyTpl = dot.template(baseKey);
var rendererKeyTpl = dot.template(rendererKey);
NamedMapMapConfigProvider.prototype.createKey = function(base) {
var tplValues = _.defaults({}, this.params, {
dbname: '',
owner: this.owner,
templateName: this.templateName,
authToken: this.authToken || '',
configHash: configHash(this.config),
layer: '',
scale_factor: 1
});
return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues);
};
function configHash(config) {
if (!config) {
return '';
}
return crypto.createHash('md5').update(JSON.stringify(config)).digest('hex').substring(0,8);
}
module.exports.configHash = configHash;
NamedMapMapConfigProvider.prototype.setDBParams = function(cdbuser, params, callback) {
var self = this;
step(
function setAuth() {
self.pgConnection.setDBAuth(cdbuser, params, this);
},
function setConn(err) {
assert.ifError(err);
self.pgConnection.setDBConn(cdbuser, params, this);
},
function finish(err) {
callback(err);
}
);
};
NamedMapMapConfigProvider.prototype.getTemplateName = function() {
return this.templateName;
};
NamedMapMapConfigProvider.prototype.getAffectedTablesAndLastUpdatedTime = function(callback) {
var self = this;
if (this.affectedTablesAndLastUpdate !== null) {
return callback(null, this.affectedTablesAndLastUpdate);
}
step(
function getMapConfig() {
self.getMapConfig(this);
},
function getSql(err, mapConfig) {
assert.ifError(err);
return mapConfig.getLayers().map(function(layer) {
return layer.options.sql;
}).join(';');
},
function getAffectedTables(err, sql) {
assert.ifError(err);
step(
function getConnection() {
self.pgConnection.getConnection(self.owner, this);
},
function getAffectedTables(err, connection) {
assert.ifError(err);
QueryTables.getAffectedTablesFromQuery(connection, sql, this);
},
this
);
},
function finish(err, result) {
self.affectedTablesAndLastUpdate = result;
return callback(err, result);
}
);
};

View File

@@ -0,0 +1,19 @@
var fs = require('fs');
function HealthCheck(disableFile) {
this.disableFile = disableFile;
}
module.exports = HealthCheck;
HealthCheck.prototype.check = function(callback) {
fs.readFile(this.disableFile, function handleDisabledFile(err, data) {
var disabledError = null;
if (!err) {
disabledError = new Error(data || 'Unknown error');
disabledError.http_status = 503;
}
return callback(disabledError);
});
};

View File

@@ -1,77 +0,0 @@
/**
* RedisPool. A database specific redis pooling lib
*
*/
var redis = require('redis')
, _ = require('underscore')
, Pool = require('generic-pool').Pool;
// constructor.
//
// - `opts` {Object} optional config for redis and pooling
var RedisPool = function(opts){
var opts = opts || {};
var defaults = {
host: '127.0.0.1',
port: '6379',
max: 50,
idleTimeoutMillis: 10000,
reapIntervalMillis: 1000,
log: false
};
var options = _.defaults(opts, defaults)
var me = {
pools: {} // cached pools by DB name
};
// Acquire resource.
//
// - `database` {String} redis database name
// - `callback` {Function} callback to call once acquired. Takes the form
// `callback(err, resource)`
me.acquire = function(database, callback) {
if (!this.pools[database]) {
this.pools[database] = this.makePool(database);
}
this.pools[database].acquire(function(err,resource) {
callback(err, resource);
});
};
// Release resource.
//
// - `database` {String} redis database name
// - `resource` {Object} resource object to release
me.release = function(database, resource) {
this.pools[database] && this.pools[database].release(resource);
};
// Factory for pool objects.
me.makePool = function(database) {
return Pool({
name: database,
create: function(callback){
var client = redis.createClient(options.port, options.host);
client.on('connect', function () {
client.send_anyway = true;
client.select(database);
client.send_anyway = false;
});
return callback(null, client);
},
destroy: function(client) {
return client.quit();
},
max: options.max,
idleTimeoutMillis: options.idleTimeoutMillis,
reapIntervalMillis: options.reapIntervalMillis,
log: options.log
});
};
return me;
};
module.exports = RedisPool;

374
lib/cartodb/server.js Normal file
View File

@@ -0,0 +1,374 @@
var express = require('express');
var bodyParser = require('body-parser');
var RedisPool = require('redis-mpool');
var cartodbRedis = require('cartodb-redis');
var _ = require('underscore');
var controller = require('./controllers');
var SurrogateKeysCache = require('./cache/surrogate_keys_cache');
var NamedMapsCacheEntry = require('./cache/model/named_maps_entry');
var VarnishHttpCacheBackend = require('./cache/backend/varnish_http');
var FastlyCacheBackend = require('./cache/backend/fastly');
var StatsClient = require('./stats/client');
var Profiler = require('./stats/profiler_proxy');
var RendererStatsReporter = require('./stats/reporter/renderer');
var windshaft = require('windshaft');
var mapnik = windshaft.mapnik;
var TemplateMaps = require('./backends/template_maps.js');
var OverviewsMetadataApi = require('./api/overviews_metadata_api');
var FilterStatsApi = require('./api/filter_stats_api');
var UserLimitsApi = require('./api/user_limits_api');
var AuthApi = require('./api/auth_api');
var LayergroupAffectedTablesCache = require('./cache/layergroup_affected_tables');
var NamedMapProviderCache = require('./cache/named_map_provider_cache');
var PgQueryRunner = require('./backends/pg_query_runner');
var PgConnection = require('./backends/pg_connection');
var AnalysisBackend = require('./backends/analysis');
var timeoutErrorTilePath = __dirname + '/../../assets/render-timeout-fallback.png';
var timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, {encoding: null});
var SqlWrapMapConfigAdapter = require('./models/mapconfig/adapter/sql-wrap-mapconfig-adapter');
var MapConfigNamedLayersAdapter = require('./models/mapconfig/adapter/mapconfig-named-layers-adapter');
var AnalysisMapConfigAdapter = require('./models/mapconfig/adapter/analysis-mapconfig-adapter');
var MapConfigOverviewsAdapter = require('./models/mapconfig/adapter/mapconfig-overviews-adapter');
var TurboCartoAdapter = require('./models/mapconfig/adapter/turbo-carto-adapter');
var DataviewsWidgetsAdapter = require('./models/mapconfig/adapter/dataviews-widgets-adapter');
var MapConfigAdapter = require('./models/mapconfig/adapter');
module.exports = function(serverOptions) {
// Make stats client globally accessible
global.statsClient = StatsClient.getInstance(serverOptions.statsd);
var redisPool = new RedisPool(_.defaults(global.environment.redis, {
name: 'windshaft-server',
unwatchOnRelease: false,
noReadyCheck: true
}));
redisPool.on('status', function(status) {
var keyPrefix = 'windshaft.redis-pool.' + status.name + '.db' + status.db + '.';
global.statsClient.gauge(keyPrefix + 'count', status.count);
global.statsClient.gauge(keyPrefix + 'unused', status.unused);
global.statsClient.gauge(keyPrefix + 'waiting', status.waiting);
});
var metadataBackend = cartodbRedis({pool: redisPool});
var pgConnection = new PgConnection(metadataBackend);
var pgQueryRunner = new PgQueryRunner(pgConnection);
var overviewsMetadataApi = new OverviewsMetadataApi(pgQueryRunner);
var filterStatsApi = new FilterStatsApi(pgQueryRunner);
var userLimitsApi = new UserLimitsApi(metadataBackend, {
limits: {
cacheOnTimeout: serverOptions.renderer.mapnik.limits.cacheOnTimeout || false,
render: serverOptions.renderer.mapnik.limits.render || 0
}
});
var templateMaps = new TemplateMaps(redisPool, {
max_user_templates: global.environment.maxUserTemplates
});
var surrogateKeysCache = new SurrogateKeysCache(surrogateKeysCacheBackends(serverOptions));
function invalidateNamedMap (owner, templateName) {
var startTime = Date.now();
surrogateKeysCache.invalidate(new NamedMapsCacheEntry(owner, templateName), function(err) {
var logMessage = JSON.stringify({
username: owner,
type: 'named_map_invalidation',
elapsed: Date.now() - startTime,
error: !!err ? JSON.stringify(err.message) : undefined
});
if (err) {
global.logger.warn(logMessage);
} else {
global.logger.info(logMessage);
}
});
}
['update', 'delete'].forEach(function(eventType) {
templateMaps.on(eventType, invalidateNamedMap);
});
serverOptions.grainstore.mapnik_version = mapnikVersion(serverOptions);
validateOptions(serverOptions);
bootstrapFonts(serverOptions);
// initialize express server
var app = bootstrap(serverOptions);
// Extend windshaft with all the elements of the options object
_.extend(app, serverOptions);
var mapStore = new windshaft.storage.MapStore({
pool: redisPool,
expire_time: serverOptions.grainstore.default_layergroup_ttl
});
var onTileErrorStrategy;
if (global.environment.enabledFeatures.onTileErrorStrategy !== false) {
onTileErrorStrategy = function onTileErrorStrategy$TimeoutTile(err, tile, headers, stats, format, callback) {
if (err && err.message === 'Render timed out' && format === 'png') {
return callback(null, timeoutErrorTile, { 'Content-Type': 'image/png' }, {});
} else {
return callback(err, tile, headers, stats);
}
};
}
var rendererFactory = new windshaft.renderer.Factory({
onTileErrorStrategy: onTileErrorStrategy,
mapnik: {
redisPool: redisPool,
grainstore: serverOptions.grainstore,
mapnik: serverOptions.renderer.mapnik
},
http: serverOptions.renderer.http
});
// initialize render cache
var rendererCacheOpts = _.defaults(serverOptions.renderCache || {}, {
ttl: 60000, // 60 seconds TTL by default
statsInterval: 60000 // reports stats every milliseconds defined here
});
var rendererCache = new windshaft.cache.RendererCache(rendererFactory, rendererCacheOpts);
var rendererStatsReporter = new RendererStatsReporter(rendererCache, rendererCacheOpts.statsInterval);
rendererStatsReporter.start();
var attributesBackend = new windshaft.backend.Attributes();
var previewBackend = new windshaft.backend.Preview(rendererCache);
var tileBackend = new windshaft.backend.Tile(rendererCache);
var mapValidatorBackend = new windshaft.backend.MapValidator(tileBackend, attributesBackend);
var mapBackend = new windshaft.backend.Map(rendererCache, mapStore, mapValidatorBackend);
var analysisBackend = new AnalysisBackend(serverOptions.analysis);
var layergroupAffectedTablesCache = new LayergroupAffectedTablesCache();
app.layergroupAffectedTablesCache = layergroupAffectedTablesCache;
var mapConfigAdapter = new MapConfigAdapter(
new MapConfigNamedLayersAdapter(templateMaps, pgConnection),
new SqlWrapMapConfigAdapter(),
new DataviewsWidgetsAdapter(),
new AnalysisMapConfigAdapter(analysisBackend),
new MapConfigOverviewsAdapter(overviewsMetadataApi, filterStatsApi),
new TurboCartoAdapter()
);
var namedMapProviderCache = new NamedMapProviderCache(
templateMaps,
pgConnection,
metadataBackend,
userLimitsApi,
mapConfigAdapter
);
['update', 'delete'].forEach(function(eventType) {
templateMaps.on(eventType, namedMapProviderCache.invalidate.bind(namedMapProviderCache));
});
var authApi = new AuthApi(pgConnection, metadataBackend, mapStore, templateMaps);
var TablesExtentApi = require('./api/tables_extent_api');
var tablesExtentApi = new TablesExtentApi(pgQueryRunner);
var versions = getAndValidateVersions(serverOptions);
/*******************************************************************************************************************
* Routing
******************************************************************************************************************/
new controller.Layergroup(
authApi,
pgConnection,
mapStore,
tileBackend,
previewBackend,
attributesBackend,
surrogateKeysCache,
userLimitsApi,
layergroupAffectedTablesCache,
analysisBackend
).register(app);
new controller.Map(
authApi,
pgConnection,
templateMaps,
mapBackend,
metadataBackend,
surrogateKeysCache,
userLimitsApi,
layergroupAffectedTablesCache,
mapConfigAdapter
).register(app);
new controller.NamedMaps(
authApi,
pgConnection,
namedMapProviderCache,
tileBackend,
previewBackend,
surrogateKeysCache,
tablesExtentApi,
metadataBackend
).register(app);
new controller.NamedMapsAdmin(authApi, pgConnection, templateMaps).register(app);
new controller.ServerInfo(versions).register(app);
/*******************************************************************************************************************
* END Routing
******************************************************************************************************************/
return app;
};
function validateOptions(opts) {
if (!_.isString(opts.base_url) || !_.isString(opts.base_url_mapconfig) || !_.isString(opts.base_url_templated)) {
throw new Error("Must initialise server with: 'base_url'/'base_url_mapconfig'/'base_url_templated' URLs");
}
}
function getAndValidateVersions(options) {
// jshint undef:false
var warn = console.warn.bind(console);
// jshint undef:true
var packageDefinition = require('../../package.json');
var declaredDependencies = packageDefinition.dependencies || {};
var installedDependenciesVersions = {
camshaft: require('camshaft').version,
grainstore: windshaft.grainstore.version(),
mapnik: windshaft.mapnik.versions.mapnik,
node_mapnik: windshaft.mapnik.version,
'turbo-carto': require('turbo-carto').version,
windshaft: windshaft.version,
windshaft_cartodb: packageDefinition.version
};
var dependenciesToValidate = ['camshaft', 'turbo-carto', 'windshaft'];
dependenciesToValidate.forEach(function(depName) {
var declaredDependencyVersion = declaredDependencies[depName];
var installedDependencyVersion = installedDependenciesVersions[depName];
if (declaredDependencyVersion !== installedDependencyVersion) {
warn(
'Dependency="%s" installed version="%s" does not match declared version="%s". Check your installation.',
depName, installedDependencyVersion, declaredDependencyVersion
);
}
});
// Be nice and warn if configured mapnik version is != installed mapnik version
if (mapnik.versions.mapnik !== options.grainstore.mapnik_version) {
warn('WARNING: detected mapnik version (' + mapnik.versions.mapnik + ')' +
' != configured mapnik version (' + options.grainstore.mapnik_version + ')');
}
return installedDependenciesVersions;
}
function bootstrapFonts(opts) {
// Set carto renderer configuration for MMLStore
opts.grainstore.carto_env = opts.grainstore.carto_env || {};
var cenv = opts.grainstore.carto_env;
cenv.validation_data = cenv.validation_data || {};
if ( ! cenv.validation_data.fonts ) {
mapnik.register_system_fonts();
mapnik.register_default_fonts();
cenv.validation_data.fonts = _.keys(mapnik.fontFiles());
}
}
function bootstrap(opts) {
var app;
if (_.isObject(opts.https)) {
// use https if possible
app = express.createServer(opts.https);
} else {
// fall back to http by default
app = express();
}
app.enable('jsonp callback');
app.disable('x-powered-by');
app.disable('etag');
app.use(bodyParser.json());
app.use(function bootstrap$prepareRequestResponse(req, res, next) {
req.context = req.context || {};
req.profiler = new Profiler({
statsd_client: global.statsClient,
profile: opts.useProfiler
});
if (global.environment && global.environment.api_hostname) {
res.set('X-Served-By-Host', global.environment.api_hostname);
}
next();
});
// temporary measure until we upgrade to newer version expressjs so we can check err.status
app.use(function(err, req, res, next) {
if (err) {
if (err.name === 'SyntaxError') {
res.status(400).json({ errors: [err.name + ': ' + err.message] });
} else {
next(err);
}
} else {
next();
}
});
setupLogger(app, opts);
return app;
}
function setupLogger(app, opts) {
if (global.log4js && opts.log_format) {
var loggerOpts = {
// Allowing for unbuffered logging is mainly
// used to avoid hanging during unit testing.
// TODO: provide an explicit teardown function instead,
// releasing any event handler or timer set by
// this component.
buffer: !opts.unbuffered_logging,
// optional log format
format: opts.log_format
};
app.use(global.log4js.connectLogger(global.log4js.getLogger(), _.defaults(loggerOpts, {level: 'info'})));
}
}
function surrogateKeysCacheBackends(serverOptions) {
var cacheBackends = [];
if (serverOptions.varnish_purge_enabled) {
cacheBackends.push(
new VarnishHttpCacheBackend(serverOptions.varnish_host, serverOptions.varnish_http_port)
);
}
if (serverOptions.fastly &&
!!serverOptions.fastly.enabled && !!serverOptions.fastly.apiKey && !!serverOptions.fastly.serviceId) {
cacheBackends.push(
new FastlyCacheBackend(serverOptions.fastly.apiKey, serverOptions.fastly.serviceId)
);
}
return cacheBackends;
}
function mapnikVersion(opts) {
return opts.grainstore.mapnik_version || mapnik.versions.mapnik;
}

View File

@@ -1,167 +1,112 @@
var _ = require('underscore')
, Step = require('step')
, cartoData = require('./carto_data')
, Cache = require('./cache_validator');
var os = require('os');
var _ = require('underscore');
var OverviewsQueryRewriter = require('./utils/overviews_query_rewriter');
module.exports = function(){
var me = {
base_url: '/tiles/:table',
grainstore: {
datasource: global.environment.postgres,
cachedir: global.environment.millstone.cache_basedir
},
redis: global.environment.redis,
enable_cors: global.environment.enable_cors,
varnish_host: global.environment.varnish.host,
varnish_port: global.environment.varnish.port,
cache_enabled: global.environment.cache_enabled,
log_format: global.environment.log_format
};
var overviewsQueryRewriter = new OverviewsQueryRewriter({
zoom_level: 'CDB_ZoomFromScale(!scale_denominator!)'
});
// Set the cache chanel info to invalidate the cache on the frontend server
//
// @param req The request object.
// The function will have no effect unless req.res exists.
// It is expected that req.params contains 'table' and 'dbname'
//
// @param cb function(err, channel) will be called when ready.
// the channel parameter will be null if nothing was added
//
me.addCacheChannel = function(req, cb) {
// skip non-GET requests, or requests for which there's no response
if ( req.method != 'GET' || ! req.res ) { cb(null, null); return; }
var res = req.res;
var ttl = global.environment.varnish.ttl || 86400;
Cache.generateCacheChannel(req, function(channel){
res.header('X-Cache-Channel', channel);
res.header('Last-Modified', new Date().toUTCString());
res.header('Cache-Control', 'no-cache,max-age='+ttl+',must-revalidate, public');
cb(null, channel); // add last-modified too ?
});
var rendererConfig = _.defaults(global.environment.renderer || {}, {
cache_ttl: 60000, // milliseconds
statsInterval: 60000,
mapnik: {
poolSize: 8,
metatile: 2,
bufferSize: 64,
snapToGrid: false,
clipByBox2d: false,
limits: {}
},
http: {}
});
rendererConfig.mapnik.queryRewriter = overviewsQueryRewriter;
// Perform keyword substitution in statsd
// See https://github.com/CartoDB/Windshaft-cartodb/issues/153
if (global.environment.statsd) {
if (global.environment.statsd.prefix) {
var host_token = os.hostname().split('.').reverse().join('.');
global.environment.statsd.prefix = global.environment.statsd.prefix.replace(/:host/, host_token);
}
}
/**
* Whitelist input and get database name & default geometry type from
* subdomain/user metadata held in CartoDB Redis
* @param req - standard express request obj. Should have host & table
* @param callback
*/
me.req2params = function(req, callback){
var analysisConfig = _.defaults(global.environment.analysis || {}, {
batch: {
inlineExecution: false,
endpoint: 'http://127.0.0.1:8080/api/v2/sql/job',
hostHeaderTemplate: '{{=it.username}}.localhost.lan'
}
});
// Whitelist query parameters and attach format
var good_query = ['sql', 'geom_type', 'cache_buster','callback', 'interactivity', 'map_key', 'api_key', 'style'];
var bad_query = _.difference(_.keys(req.query), good_query);
module.exports = {
bind: {
port: global.environment.port,
host: global.environment.host
},
// This is for inline maps and table maps
base_url: global.environment.base_url_legacy || '/tiles/:table',
_.each(bad_query, function(key){ delete req.query[key]; });
req.params = _.extend({}, req.params); // shuffle things as request is a strange array/object
/// @deprecated with Windshaft-0.17.0
///base_url_notable: '/tiles',
// bring all query values onto req.params object
_.extend(req.params, req.query);
// This is for Detached maps
//
// "maps" is the official, while
// "tiles/layergroup" is for backward compatibility up to 1.6.x
//
base_url_mapconfig: global.environment.base_url_detached || '(?:/maps|/tiles/layergroup)',
// for cartodb, ensure interactivity is cartodb_id or user specified
req.params.interactivity = req.params.interactivity || 'cartodb_id';
base_url_templated: global.environment.base_url_templated || '(?:/maps/named|/tiles/template)',
req.params.processXML = function(req, xml, callback) {
var dbuser = req.dbuser ? req.dbuser : global.settings.postgres.user;
if ( ! me.rx_dbuser ) me.rx_dbuser = /(<Parameter name="user"><!\[CDATA\[)[^\]]*(]]><\/Parameter>)/;
xml = xml.replace(me.rx_dbuser, "$1" + dbuser + "$2");
callback(null, xml);
grainstore: {
map: {
// TODO: allow to specify in configuration
srid: 3857
},
datasource: global.environment.postgres,
cachedir: global.environment.millstone.cache_basedir,
mapnik_version: global.environment.mapnik_version,
mapnik_tile_format: global.environment.mapnik_tile_format || 'png',
default_layergroup_ttl: global.environment.mapConfigTTL || 7200
},
statsd: global.environment.statsd,
renderCache: {
ttl: rendererConfig.cache_ttl,
statsInterval: rendererConfig.statsInterval
},
renderer: {
mapnik: _.defaults(rendererConfig.mapnik, {
geojson: {
dbPoolParams: {
size: 16,
idleTimeout: 3000,
reapInterval: 1000
},
clipByBox2d: false
}
}),
torque: rendererConfig.torque,
http: rendererConfig.http
},
analysis: {
batch: {
inlineExecution: analysisConfig.batch.inlineExecution,
endpoint: analysisConfig.batch.endpoint,
hostHeaderTemplate: analysisConfig.batch.hostHeaderTemplate
}
var that = this;
Step(
function getPrivacy(){
cartoData.authorize(req, this);
},
function gatekeep(err, data){
if(err) throw err;
if(data === "0") throw new Error("Sorry, you are unauthorized (permission denied)");
return data;
},
function getDatabase(err, data){
if(err) throw err;
cartoData.getDatabase(req, this);
},
function getGeometryType(err, data){
if (err) throw err;
_.extend(req.params, {dbname:data});
cartoData.getGeometryType(req, this);
},
function finishSetup(err, data){
if ( err ) { callback(err, req); return; }
if (!_.isNull(data))
_.extend(req.params, {geom_type: data});
that.addCacheChannel(req, function(err, chan) {
callback(err, req);
});
}
);
};
/**
* Little helper method to get the current list of infowindow variables and return to client
* @param req
* @param callback
*/
me.getInfowindow = function(req, callback){
var that = this;
Step(
function(){
that.req2params(req, this);
},
function(err, data){
if (err) callback(err, null);
else cartoData.getInfowindow(data, callback);
}
);
};
/**
* Little helper method to get map metadata and return to client
* @param req
* @param callback
*/
me.getMapMetadata = function(req, callback){
var that = this;
Step(
function(){
that.req2params(req, this);
},
function(err, data){
if (err) callback(err, null);
else cartoData.getMapMetadata(data, callback);
}
);
};
/**
* Helper to clear out tile cache on request
* @param req
* @param callback
*/
me.flushCache = function(req, Cache, callback){
var that = this;
Step(
function(){
that.req2params(req, this);
},
function(err, data){
if (err) throw err;
if(Cache) {
Cache.invalidate_db(req.params.dbname, req.params.table);
}
callback(null, true);
}
);
};
return me;
}();
},
// Do not send unwatch on release. See http://github.com/CartoDB/Windshaft-cartodb/issues/161
redis: _.extend(global.environment.redis, {unwatchOnRelease: false}),
enable_cors: global.environment.enable_cors,
varnish_host: global.environment.varnish.host,
varnish_port: global.environment.varnish.port,
varnish_http_port: global.environment.varnish.http_port,
varnish_secret: global.environment.varnish.secret,
varnish_purge_enabled: global.environment.varnish.purge_enabled,
fastly: global.environment.fastly || {},
cache_enabled: global.environment.cache_enabled,
log_format: global.environment.log_format,
useProfiler: global.environment.useProfiler
};

View File

@@ -0,0 +1,73 @@
var _ = require('underscore');
var debug = require('debug')('windshaft:stats_client');
var StatsD = require('node-statsd').StatsD;
module.exports = {
/**
* Returns an StatsD instance or an stub object that replicates the StatsD public interface so there is no need to
* keep checking if the stats_client is instantiated or not.
*
* The first call to this method implies all future calls will use the config specified in the very first call.
*
* TODO: It's far from ideal to use make this a singleton, improvement desired.
* We proceed this way to be able to use StatsD from several places sharing one single StatsD instance.
*
* @param config Configuration for StatsD, if undefined it will return an stub
* @returns {StatsD|Object}
*/
getInstance: function(config) {
if (!this.instance) {
var instance;
if (config) {
instance = new StatsD(config);
instance.last_error = { msg: '', count: 0 };
instance.socket.on('error', function (err) {
var last_err = instance.last_error;
var last_msg = last_err.msg;
var this_msg = '' + err;
if (this_msg !== last_msg) {
debug("statsd client socket error: " + err);
instance.last_error.count = 1;
instance.last_error.msg = this_msg;
} else {
++last_err.count;
if (!last_err.interval) {
instance.last_error.interval = setInterval(function () {
var count = instance.last_error.count;
if (count > 1) {
debug("last statsd client socket error repeated " + count + " times");
instance.last_error.count = 1;
clearInterval(instance.last_error.interval);
instance.last_error.interval = null;
}
}, 1000);
}
}
});
} else {
var stubFunc = function (stat, value, sampleRate, callback) {
if (_.isFunction(callback)) {
callback(null, 0);
}
};
instance = {
timing: stubFunc,
increment: stubFunc,
decrement: stubFunc,
gauge: stubFunc,
unique: stubFunc,
set: stubFunc,
sendAll: stubFunc,
send: stubFunc
};
}
this.instance = instance;
}
return this.instance;
}
};

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