Compare commits

...

88 Commits
2.3.0 ... 2.9.0

Author SHA1 Message Date
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
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
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
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
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
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
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
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
Juan Ignacio Sánchez Lara
94e38cef9d Update instructions 2015-06-30 11:00:32 +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
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
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
27 changed files with 787 additions and 319 deletions

98
NEWS.md
View File

@@ -1,5 +1,103 @@
# Changelog
## 2.9.0
Released 2015-08-06
New features:
- Send memory usage stats
## 2.8.0
Released 2015-07-15
Announcements:
- Upgrades windshaft to [0.48.0](https://github.com/CartoDB/Windshaft/releases/tag/0.48.0)
## 2.7.2
Released 2015-07-14
Enhancements:
- Replaces `CDB_QueryTables` with `CDB_QueryTablesText` to avoid issues with long schema+table names
## 2.7.1
Released 2015-07-06
Bug fixes:
- redis-mpool `noReadyCheck` and `unwatchOnRelease` options from config and defaulted
## 2.7.0
Released 2015-07-06
Announcements:
- Upgrades windshaft to [0.47.0](https://github.com/CartoDB/Windshaft/releases/tag/0.47.0)
- Upgrades redis-mpool to [0.4.0](https://github.com/CartoDB/node-redis-mpool/releases/tag/0.4.0)
New features:
- Exposes redis `noReadyCheck` config
Bug fixes:
- Fixes `unwatchOnRelease` redis config
## 2.6.1
Released 2015-07-02
Announcements:
- Upgrades windshaft to [0.46.1](https://github.com/CartoDB/Windshaft/releases/tag/0.46.1)
## 2.6.0
Released 2015-07-02
Announcements:
- Upgrades windshaft to [0.46.0](https://github.com/CartoDB/Windshaft/releases/tag/0.46.0)
- New config to set metatile by format
## 2.5.0
Released 2015-06-18
New features:
- Named maps names can start with numbers and can contain dashes (-).
- Adds layergroupid header in map instantiations
Bug fixes:
- Named maps error responses with `{ "errors": ["message"] }` format (#305)
Announcements:
- Upgrades windshaft to [0.45.0](https://github.com/CartoDB/Windshaft/releases/tag/0.45.0)
Enhancements:
- Fix documentation style and error examples
## 2.4.1
Released 2015-06-01
Announcements:
- Upgrades windshaft to [0.44.1](https://github.com/CartoDB/Windshaft/releases/tag/0.44.1)
## 2.4.0
Released 2015-05-26
Announcements:
- Upgrades windshaft to [0.44.0](https://github.com/CartoDB/Windshaft/releases/tag/0.44.0)
## 2.3.0
Released 2015-05-18

View File

@@ -59,6 +59,14 @@ 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.
Upgrading
---------
Checkout your commit/branch. If you need to reinstall dependencies (you can check [NEWS](NEWS.md)) do the following:
```
rm -rf node_modules; npm install
```
Run
---

15
app.js
View File

@@ -65,8 +65,12 @@ if ( global.environment.log_filename ) {
global.log4js.configure(log4js_config, { cwd: __dirname });
global.logger = global.log4js.getLogger();
var redisOpts = _.extend(global.environment.redis, { name: 'windshaft' }),
redisPool = new RedisPool(redisOpts);
var redisOpts = _.defaults(global.environment.redis, {
name: 'windshaft',
unwatchOnRelease: false,
noReadyCheck: true
});
var redisPool = new RedisPool(redisOpts);
// Include cartodb_windshaft only _after_ the "global" variable is set
// See https://github.com/Vizzuality/Windshaft-cartodb/issues/28
@@ -82,6 +86,13 @@ if (global.statsClient) {
global.statsClient.gauge(keyPrefix + 'unused', status.unused);
global.statsClient.gauge(keyPrefix + 'waiting', status.waiting);
});
setInterval(function() {
var memoryUsage = process.memoryUsage();
Object.keys(memoryUsage).forEach(function(k) {
global.statsClient.gauge('windshaft.memory.' + k, memoryUsage[k]);
});
}, 5000);
}
// Maximum number of connections for one process

View File

@@ -2,6 +2,9 @@ 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.
@@ -86,8 +89,10 @@ var config = {
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 renderers
// Check the configuration of uv_threadpool_size to use suitable value
// 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
@@ -96,6 +101,12 @@ var config = {
// wasted time.
metatile: 2,
// 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.
//
@@ -170,7 +181,9 @@ var config = {
},
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
}
,varnish: {
host: 'localhost',

View File

@@ -2,6 +2,9 @@ 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.
@@ -80,8 +83,10 @@ var config = {
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 renderers
// Check the configuration of uv_threadpool_size to use suitable value
// 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
@@ -90,6 +95,12 @@ var config = {
// wasted time.
metatile: 2,
// 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.
//
@@ -164,7 +175,9 @@ var config = {
},
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
}
,varnish: {
host: 'localhost',

View File

@@ -2,6 +2,9 @@ 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.
@@ -80,8 +83,10 @@ var config = {
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 renderers
// Check the configuration of uv_threadpool_size to use suitable value
// 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
@@ -90,6 +95,12 @@ var config = {
// wasted time.
metatile: 2,
// 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.
//
@@ -164,7 +175,9 @@ var config = {
},
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
}
,varnish: {
host: 'localhost',

View File

@@ -2,6 +2,9 @@ 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.
@@ -80,8 +83,10 @@ var config = {
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 renderers
// Check the configuration of uv_threadpool_size to use suitable value
// 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
@@ -90,6 +95,12 @@ var config = {
// wasted time.
metatile: 2,
// 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.
//
@@ -166,7 +177,9 @@ var config = {
},
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
}
,varnish: {
host: '',

View File

@@ -18,7 +18,7 @@ Here is an example of how to create an anonymous map with JavaScript:
```javascript
var mapconfig = {
"version": "1.0.1",
"version": "1.3.1",
"layers": [{
"type": "cartodb",
"options": {
@@ -57,7 +57,7 @@ The following map config sets up a map of European countries that have a white f
},
"layergroup": {
"layers": [{
"type": "cartodb",
"type": "mapnik",
"options": {
"cartocss_version": "2.1.1",
"cartocss": "#layer { polygon-fill: #FFF; }",
@@ -82,14 +82,23 @@ To get the `URL` to fetch the tiles you need to instantiate the map, where `temp
curl -X POST 'https://{account}.cartodb.com/api/v1/map/named/:template_id' -H 'Content-Type: application/json'
```
The response will return JSON with properties for the `layergroupid` and the timestamp (`last_updated`) of the last data modification.
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.
Here is an example response:
```javascript
{
"layergroupid": "c01a54877c62831bb51720263f91fb33:0",
"last_updated": "1970-01-01T00:00:00.000Z"
"last_updated": "1970-01-01T00:00:00.000Z",
"metadata": {
"layers": [
{
"type": "mapnik",
"meta": {}
}
]
}
}
```
@@ -144,9 +153,9 @@ POST /api/v1/map
```javascript
{
"version": "1.0.1",
"version": "1.3.0",
"layers": [{
"type": "cartodb",
"type": "mapnik",
"options": {
"cartocss_version": "2.1.1",
"cartocss": "#layer { polygon-fill: #FFF; }",
@@ -157,7 +166,7 @@ POST /api/v1/map
}
```
Should be a [Mapconfig](https://github.com/CartoDB/Windshaft/blob/0.19.1/doc/MapConfig-1.1.0.md).
Should be a [Mapconfig](https://github.com/CartoDB/Windshaft/blob/0.44.1/doc/MapConfig-1.3.0.md).
#### Response
@@ -173,8 +182,9 @@ The response includes:
- **updated_at**
The ISO date of the last time the data involved in the query was updated.
- **metadata** *(optional)*
Includes information about the layers. Some layers may not have metadata.
- **metadata**
Includes information about the layers.
-
- **cdn_url**
URLs to fetch the data using the best CDN for your zone.
@@ -189,8 +199,16 @@ curl 'https://documentation.cartodb.com/api/v1/map' -H 'Content-Type: applicatio
<div class="code-title">RESPONSE</div>
```javascript
{
"layergroupid":"c01a54877c62831bb51720263f91fb33:0",
"last_updated":"1970-01-01T00:00:00.000Z"
"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"
@@ -198,19 +216,35 @@ curl 'https://documentation.cartodb.com/api/v1/map' -H 'Content-Type: applicatio
}
```
The tiles can be accessed using:
##### Retrieve resources from the layergroup
###### Mapnik tiles can be accessed using:
These tiles will get just the mapnik layers. To get individual layers see next section.
```bash
https://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/{z}/{x}/{y}.png
```
For UTF grid tiles:
###### 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://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/:layer/{z}/{x}/{y}.grid.json
```
For attributes defined in `attributes` section:
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://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/1/{z}/{x}/{y}.torque.json
```
###### Attributes defined in `attributes` section:
```bash
https://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/:layer/attributes/:feature_id
@@ -219,10 +253,44 @@ https://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/
Which returns JSON with the attributes defined, like:
```javascript
{ c: 1, d: 2 }
{ "c": 1, "d": 2 }
```
Notice UTF Grid and attributes endpoints need an integer parameter, ``layer``. That number is the 0-based index of the layer inside the mapconfig. In this case, 0 returns the UTF grid tiles/attributes for layer 0, the only layer in the example mapconfig. If a second layer was available it could be returned with 1, a third layer with 2, etc.
###### Blending and layer selection
```bash
https://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/: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://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/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://documentation.cartodb.com/api/v1/map/c01a54877c62831bb51720263f91fb33:0/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
@@ -272,7 +340,7 @@ Anonymous maps cannot be removed by an API call. They will expire after about fi
## 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. Two other big differences are: you can create named maps from private data and that users without an API Key can see them even though they are from that private data.
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. Two other big differences are: you can create named maps from private data and that users without an API Key can see them even though they are from that private data.
The main two differences compared to anonymous maps are:
@@ -280,7 +348,7 @@ The main two differences compared to anonymous maps are:
This allows you to control who is able to see the map based on a token auth
- **templates**
Since the mapconfig is static it can contain some variables so the client can modify the map's appearance using those variables.
Since the MapConfig is static it can contain some variables so the client can modify the map's appearance using those variables.
Template 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 section).
@@ -331,18 +399,41 @@ POST /api/v1/map/named
}
}
]
},
"view": {
"zoom": 4,
"center": {
"lng": 0,
"lat": 0
},
"bounds": {
"west": -45,
"south": -45,
"east": 45,
"north": 45
}
}
}
```
##### Arguments
- **name**: There can be at most _one_ template with the same name for any user. Valid names start with a letter, and only contain letters, numbers, or underscores (_).
- **name**: There can be at most _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 (_).
- **auth**:
- **method** `"token"` or `"open"` (the default if no `"method"` is given).
- **valid_tokens** when `"method"` is set to `"token"`, the values listed here allow you to instantiate the named map.
- **placeholders**: Variables not listed here are not substituted. Variables not provided at instantiation time trigger an error. A default is required for optional variables. Type specification is used for quoting, to avoid injections see template format section below.
- **layergroup**: the layer list definition. This is the MapConfig explained in anonymous maps. See [MapConfig documentation](https://github.com/CartoDB/Windshaft/blob/master/doc/MapConfig-1.1.0.md) for more info.
- **layergroup**: the layer list definition. This is the MapConfig explained in anonymous maps. See [MapConfig documentation](https://github.com/CartoDB/Windshaft/blob/0.44.1/doc/MapConfig-1.3.0.md) for more info.
- **view** (optional): extra keys to specify the compelling 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.
- **zoom** The zoom level to use
- **center**
- **lng** The longitude to use for the center
- **lat** The latitude to use for the center
- **bounds**
- **west**: LowerCorner longitude for the bounding box, in decimal degrees (aka most western)
- **south**: LowerCorner latitude for the bounding box, in decimal degrees (aka most southern)
- **east**: UpperCorner longitude for the bounding box, in decimal degrees (aka most eastern)
- **north**: UpperCorner latitude for the bounding box, in decimal degrees (aka most northern)
#### Template Format
@@ -438,7 +529,7 @@ curl -X POST \
<div class="code-title">Error</div>
```javascript
{
"error": "Some error string here"
"errors" : ["Some error string here"]
}
```
@@ -539,7 +630,7 @@ If a template with the same name does NOT exist, a 400 HTTP response is generate
```javascript
{
"error": "error string here"
"errors" : ["error string here"]
}
```
@@ -568,7 +659,7 @@ curl -X DELETE 'https://documentation.cartodb.com/api/v1/map/named/:template_nam
<div class="code-title">RESPONSE</div>
```javascript
{
"error": "Some error string here"
"errors" : ["Some error string here"]
}
```
@@ -606,7 +697,7 @@ curl -X GET 'https://documentation.cartodb.com/api/v1/map/named?api_key=APIKEY'
<div class="code-title">ERROR</div>
```javascript
{
"error": "Some error string here"
"errors" : ["Some error string here"]
}
```
@@ -642,7 +733,7 @@ curl -X GET 'https://documentation.cartodb.com/api/v1/map/named/:template_name?a
<div class="code-title">ERROR</div>
```javascript
{
"error": "Some error string here"
"errors" : ["Some error string here"]
}
```
@@ -672,13 +763,15 @@ cartodb.createLayer('map_dom_id',layerSource)
1. [layer.setParams()](http://docs.cartodb.com/cartodb-platform/cartodb-js.html#layersetparamskey-value) allows you to change the template variables (in the placeholders object) via JavaScript
2. [layer.setAuthToken()](http://docs.cartodb.com/cartodb-platform/cartodb-js.html#layersetauthtokenauthtoken) allows you to set the auth tokens to create the layer
##Static Maps API
## 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 `layergroupsid token` calls to the map and allows for parameters in the definition to generate static images.
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
@@ -726,6 +819,25 @@ Note: you can see this endpoint as:
GET /api/v1/map/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format`
```
#### Named map
##### Definition
<div class="code-title notitle code-request"></div>
```bash
GET /api/v1/map/static/named/:name/:width/:height.:format
```
##### Params
* **: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`
* **jpg** will have a default quality of 85.
A named maps static image will get its constraints from the [view in the template](#Arguments), if `view` is not present it will estimate the extent based on the involved tables otherwise it fallback 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.
@@ -768,6 +880,8 @@ By manipulating the `"urlTemplate"` custom basemaps can be used in generating st
**CartoDB**
As described in the [Mapconfig documentation](https://github.com/CartoDB/Windshaft/blob/0.44.1/doc/MapConfig-1.3.0.md), a "cartodb" type layer is now just an alias to a "mapnik" type layer as above, intended for backwards compatibility.
```javascript
{
"type": "cartodb",
@@ -779,14 +893,14 @@ By manipulating the `"urlTemplate"` custom basemaps can be used in generating st
},
```
Additoinally, static images from Torque maps and other map layers can be used together to generate highly customizable and versatile static maps.
Additionally, static images from Torque maps and other map layers can be used together to generate highly customizable and versatile static maps.
####Caching
#### 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
#### 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
@@ -803,10 +917,11 @@ After instantiating a map from a CartoDB account:
GET /api/v1/map/static/center/4b615ff367e498e770e7d05e99181873:1420231989550.8699/14/40.71502926732618/-73.96039009094238/600/400.png
```
####Response
<div clas="wrap"><p class="wrap-border"><img src="https://raw.githubusercontent.com/namessanti/Pictures/master/static_api.png" alt="static-api"/></p>,</div>
#### Response
####MapConfig
<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.

View File

@@ -1,4 +1,4 @@
The Windshaft-CartoDB MultiLayer API extends the [Windshaft MultiLayer API](https://github.com/Vizzuality/Windshaft/wiki/Multilayer-API) in a few ways.
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

View File

@@ -38,6 +38,9 @@ This document list all routes available in Windshaft-cartodb Maps API server.
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. `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. `GET /health {} (1)`
<br/>Notes: Healt check
@@ -73,10 +76,10 @@ Something like the following patch should do the trick
```javascript
diff --git a/lib/cartodb/cartodb_windshaft.js b/lib/cartodb/cartodb_windshaft.js
index 477a4c2..f69eebb 100644
index b9429a2..e6cc5f9 100644
--- a/lib/cartodb/cartodb_windshaft.js
+++ b/lib/cartodb/cartodb_windshaft.js
@@ -242,6 +242,20 @@ var CartodbWindshaft = function(serverOptions) {
@@ -212,6 +212,20 @@ var CartodbWindshaft = function(serverOptions) {
}
});

View File

@@ -14,7 +14,7 @@ module.exports = QueryTablesApi;
QueryTablesApi.prototype.getAffectedTablesInQuery = function (username, sql, callback) {
var query = 'SELECT CDB_QueryTables($windshaft$' + prepareSql(sql) + '$windshaft$)';
var query = 'SELECT CDB_QueryTablesText($windshaft$' + prepareSql(sql) + '$windshaft$)';
this.pgQueryRunner.run(username, query, handleAffectedTablesInQueryRows, callback);
};
@@ -25,9 +25,9 @@ function handleAffectedTablesInQueryRows(err, rows, callback) {
callback(new Error('could not fetch source tables: ' + msg));
return;
}
var qtables = rows[0].cdb_querytables;
var tableNames = qtables.split(/^\{(.*)\}$/)[1];
tableNames = tableNames ? tableNames.split(',') : [];
// This is an Array, so no need to split into parts
var tableNames = rows[0].cdb_querytablestext;
callback(null, tableNames);
}
@@ -35,7 +35,7 @@ QueryTablesApi.prototype.getAffectedTablesAndLastUpdatedTime = function (usernam
var query = [
'WITH querytables AS (',
'SELECT * FROM CDB_QueryTables($windshaft$' + prepareSql(sql) + '$windshaft$) as tablenames',
'SELECT * FROM CDB_QueryTablesText($windshaft$' + prepareSql(sql) + '$windshaft$) as tablenames',
')',
'SELECT (SELECT tablenames FROM querytables), EXTRACT(EPOCH FROM max(updated_at)) as max',
'FROM CDB_TableMetadata m',
@@ -54,8 +54,8 @@ function handleAffectedTablesAndLastUpdatedTimeRows(err, rows, callback) {
var result = rows[0];
var tableNames = result.tablenames.split(/^\{(.*)\}$/)[1];
tableNames = tableNames ? tableNames.split(',') : [];
// This is an Array, so no need to split into parts
var tableNames = result.tablenames;
var lastUpdatedTime = result.max || 0;

View File

@@ -14,5 +14,3 @@ module.exports = FastlyCacheBackend;
FastlyCacheBackend.prototype.invalidate = function(cacheObject, callback) {
this.fastlyPurge.key(this.serviceId, cacheObject.key(), callback);
};
module.exports = FastlyCacheBackend;

View File

@@ -28,5 +28,3 @@ VarnishHttpCacheBackend.prototype.invalidate = function(cacheObject, callback) {
}
);
};
module.exports = VarnishHttpCacheBackend;

View File

@@ -315,23 +315,23 @@ NamedMapsController.prototype.instantiateTemplate = function(req, res, template_
},
function prepareResponse(err, layergroup) {
if ( err ) {
throw err;
return callback(err, { errors: [''+err] });
}
var tplhash = self.templateMaps.fingerPrint(template).substring(0,8);
layergroup.layergroupid = cdbuser + '@' + tplhash + '@' + layergroup.layergroupid;
res.header('X-Layergroup-Id', layergroup.layergroupid);
self.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(cdbuser, template.name));
return layergroup;
},
callback
callback(null, layergroup);
}
);
};
NamedMapsController.prototype.finish_instantiation = function(err, response, res) {
if (err) {
var statusCode = 400;
response = { error: ''+err };
response = { errors: [''+err] };
if ( ! _.isUndefined(err.http_status) ) {
statusCode = err.http_status;
}
@@ -346,7 +346,7 @@ function finishFn(app, res, description, okResponse) {
var statusCode = 200;
if (err) {
statusCode = 400;
response = { error: '' + err };
response = { errors: ['' + err] };
if ( ! _.isUndefined(err.http_status) ) {
statusCode = err.http_status;
}

View File

@@ -362,17 +362,22 @@ module.exports = function(redisPool) {
var cacheChannel = me.buildCacheChannel(dbName, result.affectedTables);
me.channelCache[cacheKey] = cacheChannel;
if (req.res && req.method == 'GET') {
var res = req.res;
var ttl = global.environment.varnish.layergroupTtl || 86400;
res.header('Cache-Control', 'public,max-age='+ttl+',must-revalidate');
res.header('Last-Modified', (new Date()).toUTCString());
res.header('X-Cache-Channel', cacheChannel);
}
// last update for layergroup cache buster
response.layergroupid = response.layergroupid + ':' + result.lastUpdatedTime;
response.last_updated = new Date(result.lastUpdatedTime).toISOString();
var res = req.res;
if (res) {
if (req.method === 'GET') {
var ttl = global.environment.varnish.layergroupTtl || 86400;
res.header('Cache-Control', 'public,max-age='+ttl+',must-revalidate');
res.header('Last-Modified', (new Date()).toUTCString());
res.header('X-Cache-Channel', cacheChannel);
}
res.header('X-Layergroup-Id', response.layergroupid);
}
return null;
},
function finish(err) {

View File

@@ -88,7 +88,8 @@ o._redisCmd = function(redisFunc, redisArgs, callback) {
);
};
var _reValidIdentifier = /^[a-zA-Z][0-9a-zA-Z_]*$/;
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' ) {
@@ -98,7 +99,7 @@ o._checkInvalidTemplate = function(template) {
if ( ! tplname ) {
return new Error("Missing template name");
}
if ( ! tplname.match(_reValidIdentifier) ) {
if ( ! tplname.match(_reValidNameIdentifier) ) {
return new Error("Invalid characters in template name '" + tplname + "'");
}
@@ -113,7 +114,7 @@ o._checkInvalidTemplate = function(template) {
for (var i = 0, len = placeholderKeys.length; i < len; i++) {
var placeholderKey = placeholderKeys[i];
if (!placeholderKey.match(_reValidIdentifier)) {
if (!placeholderKey.match(_reValidPlaceholderIdentifier)) {
return new Error("Invalid characters in placeholder name '" + placeholderKey + "'");
}
if ( ! placeholders[placeholderKey].hasOwnProperty('default') ) {

270
npm-shrinkwrap.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "windshaft-cartodb",
"version": "2.3.0",
"version": "2.9.0",
"dependencies": {
"cartodb-psql": {
"version": "0.4.0",
@@ -76,9 +76,9 @@
"from": "fastly-purge@~1.0.0",
"dependencies": {
"request": {
"version": "2.55.0",
"version": "2.58.0",
"from": "request@^2.55.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.55.0.tgz",
"resolved": "https://registry.npmjs.org/request/-/request-2.58.0.tgz",
"dependencies": {
"bl": {
"version": "0.9.4",
@@ -114,9 +114,14 @@
}
},
"caseless": {
"version": "0.9.0",
"from": "caseless@~0.9.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.9.0.tgz"
"version": "0.10.0",
"from": "caseless@~0.10.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.10.0.tgz"
},
"extend": {
"version": "2.0.1",
"from": "extend@~2.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-2.0.1.tgz"
},
"forever-agent": {
"version": "0.6.1",
@@ -124,31 +129,43 @@
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
},
"form-data": {
"version": "0.2.0",
"from": "form-data@~0.2.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz",
"version": "1.0.0-rc1",
"from": "form-data@~1.0.0-rc1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc1.tgz",
"dependencies": {
"async": {
"version": "0.9.0",
"from": "async@~0.9.0",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
"version": "1.3.0",
"from": "async@^1.2.1",
"resolved": "https://registry.npmjs.org/async/-/async-1.3.0.tgz"
},
"mime-types": {
"version": "2.1.3",
"from": "mime-types@^2.1.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.3.tgz",
"dependencies": {
"mime-db": {
"version": "1.15.0",
"from": "mime-db@~1.15.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.15.0.tgz"
}
}
}
}
},
"json-stringify-safe": {
"version": "5.0.0",
"version": "5.0.1",
"from": "json-stringify-safe@~5.0.0",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz"
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
},
"mime-types": {
"version": "2.0.11",
"version": "2.0.14",
"from": "mime-types@~2.0.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.11.tgz",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz",
"dependencies": {
"mime-db": {
"version": "1.9.1",
"from": "mime-db@~1.9.1",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.9.1.tgz"
"version": "1.12.0",
"from": "mime-db@~1.12.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz"
}
}
},
@@ -158,24 +175,24 @@
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
},
"qs": {
"version": "2.4.2",
"from": "qs@~2.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-2.4.2.tgz"
"version": "3.1.0",
"from": "qs@~3.1.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-3.1.0.tgz"
},
"tunnel-agent": {
"version": "0.4.0",
"version": "0.4.1",
"from": "tunnel-agent@~0.4.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.0.tgz"
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
},
"tough-cookie": {
"version": "1.1.0",
"version": "2.0.0",
"from": "tough-cookie@>=0.12.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-1.1.0.tgz"
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.0.0.tgz"
},
"http-signature": {
"version": "0.10.1",
"from": "http-signature@~0.10.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz",
"version": "0.11.0",
"from": "http-signature@~0.11.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz",
"dependencies": {
"assert-plus": {
"version": "0.1.5",
@@ -195,9 +212,9 @@
}
},
"oauth-sign": {
"version": "0.6.0",
"from": "oauth-sign@~0.6.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.6.0.tgz"
"version": "0.8.0",
"from": "oauth-sign@~0.8.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.0.tgz"
},
"hawk": {
"version": "2.3.1",
@@ -205,14 +222,14 @@
"resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz",
"dependencies": {
"hoek": {
"version": "2.13.0",
"version": "2.14.0",
"from": "hoek@2.x.x",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.13.0.tgz"
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.14.0.tgz"
},
"boom": {
"version": "2.7.1",
"version": "2.8.0",
"from": "boom@2.x.x",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.7.1.tgz"
"resolved": "https://registry.npmjs.org/boom/-/boom-2.8.0.tgz"
},
"cryptiles": {
"version": "2.0.4",
@@ -237,14 +254,14 @@
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.4.tgz"
},
"combined-stream": {
"version": "0.0.7",
"from": "combined-stream@~0.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
"version": "1.0.5",
"from": "combined-stream@~1.0.1",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"dependencies": {
"delayed-stream": {
"version": "0.0.5",
"from": "delayed-stream@0.0.5",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz"
"version": "1.0.0",
"from": "delayed-stream@~1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
}
}
},
@@ -254,24 +271,24 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
},
"har-validator": {
"version": "1.7.0",
"from": "har-validator@^1.4.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-1.7.0.tgz",
"version": "1.8.0",
"from": "har-validator@^1.6.1",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-1.8.0.tgz",
"dependencies": {
"bluebird": {
"version": "2.9.25",
"from": "bluebird@^2.9.25",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.25.tgz"
"version": "2.9.33",
"from": "bluebird@^2.9.30",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.33.tgz"
},
"chalk": {
"version": "1.0.0",
"version": "1.1.0",
"from": "chalk@^1.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.0.tgz",
"dependencies": {
"ansi-styles": {
"version": "2.0.1",
"from": "ansi-styles@^2.0.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.0.1.tgz"
"version": "2.1.0",
"from": "ansi-styles@^2.1.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz"
},
"escape-string-regexp": {
"version": "1.0.3",
@@ -279,38 +296,33 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz"
},
"has-ansi": {
"version": "1.0.3",
"from": "has-ansi@^1.0.3",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz",
"version": "2.0.0",
"from": "has-ansi@^2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"dependencies": {
"ansi-regex": {
"version": "1.1.1",
"from": "ansi-regex@^1.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz"
},
"get-stdin": {
"version": "4.0.1",
"from": "get-stdin@^4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
"version": "2.0.0",
"from": "ansi-regex@^2.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
}
}
},
"strip-ansi": {
"version": "2.0.1",
"from": "strip-ansi@^2.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
"version": "3.0.0",
"from": "strip-ansi@^3.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz",
"dependencies": {
"ansi-regex": {
"version": "1.1.1",
"from": "ansi-regex@^1.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz"
"version": "2.0.0",
"from": "ansi-regex@^2.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
}
}
},
"supports-color": {
"version": "1.3.1",
"from": "supports-color@^1.3.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz"
"version": "2.0.0",
"from": "supports-color@^2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
}
}
},
@@ -328,7 +340,7 @@
},
"is-my-json-valid": {
"version": "2.12.0",
"from": "is-my-json-valid@^2.10.1",
"from": "is-my-json-valid@^2.12.0",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.12.0.tgz",
"dependencies": {
"generate-function": {
@@ -367,7 +379,7 @@
}
},
"log4js": {
"version": "0.6.21",
"version": "0.6.25",
"from": "https://github.com/CartoDB/log4js-node/tarball/cdb",
"resolved": "https://github.com/CartoDB/log4js-node/tarball/cdb",
"dependencies": {
@@ -401,6 +413,16 @@
"from": "inherits@~2.0.1"
}
}
},
"semver": {
"version": "4.3.6",
"from": "semver@~4.3.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
},
"underscore": {
"version": "1.8.2",
"from": "underscore@1.8.2",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.2.tgz"
}
}
},
@@ -415,9 +437,8 @@
"resolved": "https://registry.npmjs.org/queue-async/-/queue-async-1.0.7.tgz"
},
"redis-mpool": {
"version": "0.3.0",
"from": "redis-mpool@~0.3.0",
"resolved": "https://registry.npmjs.org/redis-mpool/-/redis-mpool-0.3.0.tgz",
"version": "0.4.0",
"from": "redis-mpool@~0.4.0",
"dependencies": {
"generic-pool": {
"version": "2.1.1",
@@ -454,9 +475,9 @@
"resolved": "https://registry.npmjs.org/request/-/request-2.9.203.tgz"
},
"step": {
"version": "0.0.5",
"version": "0.0.6",
"from": "step@~0.0.5",
"resolved": "https://registry.npmjs.org/step/-/step-0.0.5.tgz"
"resolved": "https://registry.npmjs.org/step/-/step-0.0.6.tgz"
},
"underscore": {
"version": "1.6.0",
@@ -464,9 +485,9 @@
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz"
},
"windshaft": {
"version": "0.43.0",
"from": "windshaft@0.43.0",
"resolved": "https://registry.npmjs.org/windshaft/-/windshaft-0.43.0.tgz",
"version": "0.48.0",
"from": "windshaft@0.48.0",
"resolved": "https://registry.npmjs.org/windshaft/-/windshaft-0.48.0.tgz",
"dependencies": {
"chronograph": {
"version": "0.1.0",
@@ -474,44 +495,9 @@
"resolved": "git://github.com/CartoDB/chronographjs.git#0b8c35eee510cfa14a16be24d70533b38ecc1d2d"
},
"grainstore": {
"version": "0.23.0",
"from": "grainstore@~0.23.0",
"resolved": "https://registry.npmjs.org/grainstore/-/grainstore-0.23.0.tgz",
"version": "1.0.0",
"from": "grainstore@~1.0.0",
"dependencies": {
"redis-mpool": {
"version": "0.1.0",
"from": "https://github.com/CartoDB/node-redis-mpool/tarball/0.1.0",
"resolved": "https://github.com/CartoDB/node-redis-mpool/tarball/0.1.0",
"dependencies": {
"generic-pool": {
"version": "2.1.1",
"from": "generic-pool@~2.1.1",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.1.1.tgz"
},
"redis": {
"version": "0.12.1",
"from": "redis@~0.12.1",
"resolved": "https://registry.npmjs.org/redis/-/redis-0.12.1.tgz"
},
"hiredis": {
"version": "0.1.17",
"from": "hiredis@~0.1.17",
"resolved": "https://registry.npmjs.org/hiredis/-/hiredis-0.1.17.tgz",
"dependencies": {
"bindings": {
"version": "1.2.1",
"from": "bindings@*",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
},
"nan": {
"version": "1.1.2",
"from": "nan@~1.1.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-1.1.2.tgz"
}
}
}
}
},
"carto": {
"version": "0.9.5-cdb2",
"from": "https://github.com/CartoDB/carto/tarball/0.9.5-cdb2",
@@ -579,9 +565,9 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz"
},
"json-stringify-safe": {
"version": "5.0.0",
"version": "5.0.1",
"from": "json-stringify-safe@~5.0.0",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz"
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
},
"forever-agent": {
"version": "0.5.2",
@@ -594,9 +580,9 @@
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz"
},
"tough-cookie": {
"version": "1.1.0",
"version": "2.0.0",
"from": "tough-cookie@>=0.12.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-1.1.0.tgz"
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.0.0.tgz"
},
"form-data": {
"version": "0.1.4",
@@ -616,9 +602,9 @@
}
},
"async": {
"version": "0.9.0",
"version": "0.9.2",
"from": "async@~0.9.0",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
}
}
},
@@ -2307,8 +2293,8 @@
},
"tilelive-mapnik": {
"version": "0.6.15",
"from": "https://github.com/CartoDB/tilelive-mapnik/tarball/cdb",
"resolved": "https://github.com/CartoDB/tilelive-mapnik/tarball/cdb",
"from": "https://github.com/CartoDB/tilelive-mapnik/tarball/upgrade-mapnik",
"resolved": "https://github.com/CartoDB/tilelive-mapnik/tarball/upgrade-mapnik",
"dependencies": {
"generic-pool": {
"version": "2.1.1",
@@ -2317,15 +2303,15 @@
},
"mime": {
"version": "1.2.11",
"from": "mime@~1.2.9",
"from": "mime@~1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
}
}
},
"mapnik": {
"version": "1.4.15-cdb1",
"from": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb1",
"resolved": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb1",
"version": "1.4.15-cdb2",
"from": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb2",
"resolved": "https://github.com/CartoDB/node-mapnik/tarball/1.4.15-cdb2",
"dependencies": {
"nan": {
"version": "1.2.0",
@@ -2817,16 +2803,16 @@
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
},
"async": {
"version": "0.9.0",
"version": "0.9.2",
"from": "async@~0.9.0",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
}
}
},
"json-stringify-safe": {
"version": "5.0.0",
"version": "5.0.1",
"from": "json-stringify-safe@~5.0.0",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.0.tgz"
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
},
"mime-types": {
"version": "1.0.2",
@@ -2844,14 +2830,14 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz"
},
"tunnel-agent": {
"version": "0.4.0",
"version": "0.4.1",
"from": "tunnel-agent@~0.4.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.0.tgz"
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz"
},
"tough-cookie": {
"version": "1.1.0",
"version": "2.0.0",
"from": "tough-cookie@>=0.12.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-1.1.0.tgz"
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.0.0.tgz"
},
"http-signature": {
"version": "0.10.1",
@@ -2933,8 +2919,8 @@
},
"abaculus": {
"version": "1.1.0",
"from": "https://github.com/CartoDB/abaculus/tarball/cdb",
"resolved": "https://github.com/CartoDB/abaculus/tarball/cdb"
"from": "https://github.com/CartoDB/abaculus/tarball/upgrade-mapnik",
"resolved": "https://github.com/CartoDB/abaculus/tarball/upgrade-mapnik"
},
"sphericalmercator": {
"version": "1.0.2",

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "windshaft-cartodb",
"version": "2.3.0",
"version": "2.9.0",
"description": "A map tile server for CartoDB",
"keywords": [
"cartodb"
@@ -24,14 +24,14 @@
"dependencies": {
"underscore" : "~1.6.0",
"dot": "~1.0.2",
"windshaft": "0.43.0",
"windshaft": "0.48.0",
"step": "~0.0.5",
"queue-async": "~1.0.7",
"request": "~2.9.203",
"cartodb-redis": "~0.13.0",
"cartodb-psql": "~0.4.0",
"fastly-purge": "~1.0.0",
"redis-mpool": "~0.3.0",
"redis-mpool": "~0.4.0",
"lzma": "~1.3.7",
"log4js": "https://github.com/CartoDB/log4js-node/tarball/cdb"
},

View File

@@ -174,7 +174,7 @@ describe('render limits', function() {
},
function(res) {
var parsed = JSON.parse(res.body);
assert.deepEqual(parsed, { error: 'Render timed out' });
assert.deepEqual(parsed, { errors: ['Render timed out'] });
done();
}
);

View File

@@ -69,6 +69,7 @@ suite(suiteName, function() {
assert.equal(parsedBody.last_updated, expected_last_updated);
if ( expected_token ) {
assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch);
assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid);
}
else expected_token = parsedBody.layergroupid.split(':')[0];
next(null, res);
@@ -131,7 +132,7 @@ suite(suiteName, function() {
}, {}, function(res) {
assert.equal(res.statusCode, 403, res.statusCode + ':' + res.body);
var parsed = JSON.parse(res.body);
var msg = parsed.error; // TODO: should it be "errors" ?
var msg = parsed.errors[0];
assert.ok(msg.match(/permission denied/i), msg);
next(err);
});
@@ -1011,6 +1012,7 @@ suite(suiteName, function() {
var parsedBody = JSON.parse(res.body);
if ( expected_token ) {
assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch);
assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid);
}
else {
var token_components = parsedBody.layergroupid.split(':');
@@ -1091,6 +1093,7 @@ suite(suiteName, function() {
var parsedBody = JSON.parse(res.body);
if ( expected_token ) {
assert.equal(parsedBody.layergroupid, expected_token + ':' + expected_last_updated_epoch);
assert.equal(res.headers['x-layergroup-id'], parsedBody.layergroupid);
}
else {
var token_components = parsedBody.layergroupid.split(':');

View File

@@ -108,6 +108,7 @@ describe('tests from old api translated to multilayer', function() {
function(res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
done();
}
);
@@ -128,6 +129,7 @@ describe('tests from old api translated to multilayer', function() {
function(res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
global.environment.postgres.host = backupDBHost;
done();
@@ -150,6 +152,7 @@ describe('tests from old api translated to multilayer', function() {
function(res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
global.environment.postgres_auth_pass = backupDBPass;
done();
@@ -246,6 +249,43 @@ describe('tests from old api translated to multilayer', function() {
assert.ok(res.headers.hasOwnProperty('x-cache-channel'));
assert.equal(res.headers['x-cache-channel'], expectedCacheChannel);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
done();
}
);
});
// https://github.com/CartoDB/cartodb-postgresql/issues/86
it.skip("should not fail with long table names because table name length limit", function(done) {
var tableName = 'long_table_name_with_enough_chars_to_break_querytables_function';
var expectedCacheChannel = _.template('<%= databaseName %>:public.<%= tableName %>', {
databaseName: _.template(global.environment.postgres_auth_user, {user_id:1}) + '_db',
tableName: tableName
});
var layergroup = singleLayergroupConfig('select * from ' + tableName, '#layer { marker-fill: red; }');
assert.response(server,
{
url: layergroupUrl + '?config=' + encodeURIComponent(JSON.stringify(layergroup)),
method: 'GET',
headers: {
host: 'localhost'
}
},
{
status: 200
},
function(res) {
var parsed = JSON.parse(res.body);
assert.ok(parsed.layergroupid);
assert.ok(res.headers.hasOwnProperty('x-cache-channel'));
assert.equal(res.headers['x-cache-channel'], expectedCacheChannel);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
done();
}
);

View File

@@ -44,6 +44,7 @@ describe('named_layers', function() {
},
layergroup: {
layers: [
wadusLayer,
wadusLayer
]
}
@@ -634,6 +635,88 @@ describe('named_layers', function() {
});
it('should return metadata for named layers', function(done) {
var layergroup = {
version: '1.3.0',
layers: [
{
type: 'plain',
options: {
color: '#fabada'
}
},
{
type: 'cartodb',
options: {
sql: 'select * from test_table',
cartocss: '#layer { marker-fill: #cc3300; }',
cartocss_version: '2.3.0'
}
},
{
type: 'named',
options: {
name: templateName
}
},
{
type: 'torque',
options: {
sql: "select * from test_table LIMIT 0",
cartocss: "Map { -torque-frame-count:1; -torque-resolution:1; " +
"-torque-aggregation-function:'count(*)'; -torque-time-attribute:'updated_at'; }"
}
}
]
};
step(
function createLayergroup() {
var next = this;
assert.response(server,
{
url: '/api/v1/map',
method: 'POST',
headers: {
host: 'localhost',
'Content-Type': 'application/json'
},
data: JSON.stringify(layergroup)
},
{
status: 200
},
function(res, err) {
next(err, res);
}
);
},
function checkLayergroup(err, response) {
if (err) {
throw err;
}
var parsedBody = JSON.parse(response.body);
assert.ok(parsedBody.metadata);
assert.ok(parsedBody.metadata.layers);
assert.equal(parsedBody.metadata.layers.length, 5);
assert.equal(parsedBody.metadata.layers[0].type, 'plain');
assert.equal(parsedBody.metadata.layers[1].type, 'mapnik');
assert.equal(parsedBody.metadata.layers[2].type, 'mapnik');
assert.equal(parsedBody.metadata.layers[3].type, 'mapnik');
assert.equal(parsedBody.metadata.layers[4].type, 'torque');
return null;
},
function finish(err) {
done(err);
}
);
});
after(function(done) {
global.environment.enabledFeatures = {cdbQueryTablesFromPostgres: false};

View File

@@ -88,8 +88,8 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 403);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'), res.body);
err = parsed.error;
assert.ok(parsed.hasOwnProperty('errors'), res.body);
err = parsed.errors[0];
assert.ok(err.match(/only.*authenticated.*user/i),
'Unexpected error response: ' + err);
post_request_1.url += '?api_key=1234';
@@ -113,9 +113,9 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 400, res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('error'), res.body);
assert.ok(parsedBody.error.match(/already exists/i),
'Unexpected error for pre-existing template name: ' + parsedBody.error);
assert.ok(parsedBody.hasOwnProperty('errors'), res.body);
assert.ok(parsedBody.errors[0].match(/already exists/i),
'Unexpected error for pre-existing template name: ' + parsedBody.errors);
return null;
},
function finish(err) {
@@ -172,10 +172,10 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 400, res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('error'), res.body);
assert.ok(parsedBody.hasOwnProperty('errors'), res.body);
var re = /invalid.*authentication.*missing/i;
assert.ok(parsedBody.error.match(re),
'Error for invalid authentication does not match ' + re + ': ' + parsedBody.error);
assert.ok(parsedBody.errors[0].match(re),
'Error for invalid authentication does not match ' + re + ': ' + parsedBody.errors);
return null;
},
function postTemplate2(err)
@@ -202,10 +202,10 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 400, res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('error'), res.body);
assert.ok(parsedBody.hasOwnProperty('errors'), res.body);
var re = new RegExp(/invalid.*authentication.*missing/i);
assert.ok(parsedBody.error.match(re),
'Error for invalid authentication does not match ' + re + ': ' + parsedBody.error);
assert.ok(parsedBody.errors[0].match(re),
'Error for invalid authentication does not match ' + re + ': ' + parsedBody.errors);
return null;
},
function postTemplateValid(err)
@@ -253,12 +253,12 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 400, res.statusCode + ": " + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
var re = /invalid.*authentication.*missing/i;
assert.ok(parsed.error.match(re),
assert.ok(parsed.errors[0].match(re),
'Error for invalid authentication on PUT does not match ' +
re + ': ' + parsed.error);
re + ': ' + parsed.errors);
var del_request = {
url: '/api/v1/map/named/' + tpl_id + '?api_key=1234',
method: 'DELETE',
@@ -425,9 +425,9 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 403, res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
assert.ok(parsed.hasOwnProperty('errors'),
'Missing error from response: ' + res.body);
err = parsed.error;
err = parsed.errors[0];
assert.ok(err.match(/authenticated user/), err);
var next = this;
var get_request = {
@@ -523,9 +523,9 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 400, res.statusCode + ": " + res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('error'), res.body);
assert.ok(parsedBody.error.match(/cannot update name/i),
'Unexpected error for invalid update: ' + parsedBody.error);
assert.ok(parsedBody.hasOwnProperty('errors'), res.body);
assert.ok(parsedBody.errors[0].match(/cannot update name/i),
'Unexpected error for invalid update: ' + parsedBody.errors);
var put_request = {
url: '/api/v1/map/named/unexistent/?api_key=1234',
method: 'PUT',
@@ -541,9 +541,9 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 400, res.statusCode + ": " + res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('error'), res.body);
assert.ok(parsedBody.error.match(/cannot update name/i),
'Unexpected error for invalid update: ' + parsedBody.error);
assert.ok(parsedBody.hasOwnProperty('errors'), res.body);
assert.ok(parsedBody.errors[0].match(/cannot update name/i),
'Unexpected error for invalid update: ' + parsedBody.errors);
var put_request = {
url: '/api/v1/map/named/' + tpl_id + '/?api_key=1234',
method: 'PUT',
@@ -630,9 +630,9 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 403, res.statusCode + ": " + res.body);
var parsedBody = JSON.parse(res.body);
assert.ok(parsedBody.hasOwnProperty('error'), res.body);
assert.ok(parsedBody.error.match(/only.*authenticated.*user/i),
'Unexpected error for unauthenticated template get: ' + parsedBody.error);
assert.ok(parsedBody.hasOwnProperty('errors'), res.body);
assert.ok(parsedBody.errors[0].match(/only.*authenticated.*user/i),
'Unexpected error for unauthenticated template get: ' + parsedBody.errors);
var get_request = {
url: '/api/v1/map/named/' + tpl_id + '?api_key=1234',
method: 'GET',
@@ -735,10 +735,10 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 403, res.statusCode + ": " + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/only.*authenticated.*user/i),
'Unexpected error for unauthenticated template get: ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/only.*authenticated.*user/i),
'Unexpected error for unauthenticated template get: ' + parsed.errors);
var del_request = {
url: '/api/v1/map/named/' + tpl_id + '?api_key=1234',
method: 'DELETE',
@@ -767,10 +767,10 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 404, res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/cannot find/i),
'Unexpected error for missing template: ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/cannot find/i),
'Unexpected error for missing template: ' + parsed.errors);
return null;
},
function finish(err) {
@@ -863,10 +863,10 @@ describe('template_api', function() {
assert.equal(res.statusCode, 403,
'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/unauthorized/i),
'Unexpected error for unauthorized instance : ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/unauthorized/i),
'Unexpected error for unauthorized instance : ' + parsed.errors);
var post_request = {
url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2',
method: 'POST',
@@ -882,8 +882,8 @@ describe('template_api', function() {
if ( err ) throw err;
assert.equal(res.statusCode, 404, res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'), "Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/not found/i), 'Unexpected error for forbidden instance : ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'), "Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/not found/i), 'Unexpected error for forbidden instance : ' + parsed.errors);
var post_request = {
url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2',
method: 'POST',
@@ -922,10 +922,10 @@ describe('template_api', function() {
assert.equal(res.statusCode, 403,
'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/permission denied/i),
'Unexpected error for unauthorized instance (expected /permission denied/): ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/permission denied/i),
'Unexpected error for unauthorized instance (expected /permission denied/): ' + parsed.errors);
var get_request = {
url: '/api/v1/map/' + layergroupid + '/0/0/0.png?auth_token=valid1',
method: 'GET',
@@ -962,10 +962,10 @@ describe('template_api', function() {
assert.equal(res.statusCode, 403,
'Unexpected error for authorized instance: ' + res.statusCode + ' -- ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/cannot use/i),
'Unexpected error for unauthorized instance (expected /cannot use/): ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/cannot use/i),
'Unexpected error for unauthorized instance (expected /cannot use/): ' + parsed.errors);
return null;
},
function deleteTemplate(err)
@@ -1089,10 +1089,10 @@ describe('template_api', function() {
assert.equal(res.statusCode, 403,
'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/unauthorized/i),
'Unexpected error for unauthorized instance : ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/unauthorized/i),
'Unexpected error for unauthorized instance : ' + parsed.errors);
var post_request = {
url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2',
method: 'POST',
@@ -1131,10 +1131,10 @@ describe('template_api', function() {
assert.equal(res.statusCode, 403,
'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/permission denied/i),
'Unexpected error for unauthorized instance (expected /permission denied): ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/permission denied/i),
'Unexpected error for unauthorized instance (expected /permission denied): ' + parsed.errors);
var get_request = {
url: '/api/v1/map/' + layergroupid + ':cb1/0/0/0/0.json.torque?auth_token=valid1',
method: 'GET',
@@ -1297,10 +1297,10 @@ describe('template_api', function() {
assert.equal(res.statusCode, 403,
'Unexpected success instanciating template with no auth: ' + res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/unauthorized/i),
'Unexpected error for unauthorized instance : ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/unauthorized/i),
'Unexpected error for unauthorized instance : ' + parsed.errors);
var post_request = {
url: '/api/v1/map/named/' + tpl_id + '?auth_token=valid2',
method: 'POST',
@@ -1321,6 +1321,7 @@ describe('template_api', function() {
layergroupid = parsed.layergroupid;
assert.ok(layergroupid.match(/^localhost@/),
"Returned layergroupid does not start with signer name: " + layergroupid);
assert.equal(res.headers['x-layergroup-id'], parsed.layergroupid);
assert.ok(parsed.hasOwnProperty('last_updated'),
"Missing 'last_updated' from response body: " + res.body);
// TODO: check value of last_updated ?
@@ -1339,10 +1340,10 @@ describe('template_api', function() {
assert.equal(res.statusCode, 403,
'Fetching tile with no auth: ' + res.statusCode + ': ' + res.body);
var parsed = JSON.parse(res.body);
assert.ok(parsed.hasOwnProperty('error'),
"Missing 'error' from response body: " + res.body);
assert.ok(parsed.error.match(/permission denied/i),
'Unexpected error for unauthorized getAttributes (expected /permission denied/): ' + parsed.error);
assert.ok(parsed.hasOwnProperty('errors'),
"Missing 'errors' from response body: " + res.body);
assert.ok(parsed.errors[0].match(/permission denied/i),
'Unexpected error for unauthorized getAttributes (expected /permission denied/): ' + parsed.errors);
var get_request = {
url: '/api/v1/map/' + layergroupid + ':cb1/0/attributes/5?auth_token=valid2',
method: 'GET',
@@ -1608,7 +1609,6 @@ describe('template_api', function() {
function checkInstanciation(err, res)
{
if ( err ) throw err;
console.log(err, res.body, res.headers);
assert.equal(res.statusCode, 200, res.statusCode + ': ' + res.body);
// See https://github.com/CartoDB/Windshaft-cartodb/issues/176
helper.checkCache(res);
@@ -2072,7 +2072,7 @@ describe('template_api', function() {
return done(err);
}
assert.deepEqual(JSON.parse(res.body), {
error: "Invalid or nonexistent map configuration token '" + nonexistentToken + "'"
errors: ["Invalid or nonexistent map configuration token '" + nonexistentToken + "'"]
});
done();

View File

@@ -2,12 +2,12 @@
--
-- Requires PostgreSQL 9.x+
--
CREATE OR REPLACE FUNCTION CDB_QueryTables(query text)
RETURNS name[]
CREATE OR REPLACE FUNCTION CDB_QueryTablesText(query text)
RETURNS text[]
AS $$
DECLARE
exp XML;
tables NAME[];
tables text[];
rec RECORD;
rec2 RECORD;
BEGIN
@@ -41,11 +41,11 @@ BEGIN
xpath('//x:Relation-Name/text()', exp, ARRAY[ARRAY['x', 'http://www.postgresql.org/2009/explain']]) as x,
xpath('//x:Relation-Name/../x:Schema/text()', exp, ARRAY[ARRAY['x', 'http://www.postgresql.org/2009/explain']]) as s
)
SELECT unnest(x)::name as p, unnest(s)::name as sc from inp
SELECT unnest(x) as p, unnest(s) as sc from inp
LOOP
-- RAISE DEBUG 'tab: %', rec2.p;
-- RAISE DEBUG 'sc: %', rec2.sc;
tables := array_append(tables, (rec2.sc || '.' || rec2.p)::name);
tables := array_append(tables, (rec2.sc || '.' || rec2.p));
END LOOP;
-- RAISE DEBUG 'Tables: %', tables;
@@ -65,3 +65,14 @@ BEGIN
return tables;
END
$$ LANGUAGE 'plpgsql' VOLATILE STRICT;
-- Keep CDB_QueryTables with same signature for backwards compatibility.
-- It should probably be removed in the future.
CREATE OR REPLACE FUNCTION CDB_QueryTables(query text)
RETURNS name[]
AS $$
BEGIN
RETURN CDB_QueryTablesText(query)::name[];
END
$$ LANGUAGE 'plpgsql' VOLATILE STRICT;

View File

@@ -189,3 +189,31 @@ INSERT INTO CDB_TableMetadata (tabname, updated_at) VALUES ('test_table_private_
-- GRANT SELECT ON CDB_TableMetadata TO :PUBLICUSER;
GRANT SELECT ON CDB_TableMetadata TO :TESTUSER;
-- long name table
CREATE TABLE
long_table_name_with_enough_chars_to_break_querytables_function
(
updated_at timestamp without time zone DEFAULT now(),
created_at timestamp without time zone DEFAULT now(),
cartodb_id integer NOT NULL,
name character varying,
address character varying,
the_geom geometry,
the_geom_webmercator geometry
);
INSERT INTO long_table_name_with_enough_chars_to_break_querytables_function SELECT * from test_table;
ALTER TABLE ONLY long_table_name_with_enough_chars_to_break_querytables_function
ADD CONSTRAINT long_table_name_with_enough_chars_to_break_querytables_func_pkey PRIMARY KEY (cartodb_id);
CREATE INDEX long_table_name_the_geom_idx
ON long_table_name_with_enough_chars_to_break_querytables_function USING gist (the_geom);
CREATE INDEX long_table_name_the_geom_webmercator_idx
ON long_table_name_with_enough_chars_to_break_querytables_function USING gist (the_geom_webmercator);
GRANT ALL ON TABLE long_table_name_with_enough_chars_to_break_querytables_function TO :TESTUSER;
GRANT SELECT ON TABLE long_table_name_with_enough_chars_to_break_querytables_function TO :PUBLICUSER;
INSERT INTO CDB_TableMetadata (tabname, updated_at) VALUES ('long_table_name_with_enough_chars_to_break_querytables_function'::regclass, '2009-02-13T23:31:30.123Z');

View File

@@ -59,30 +59,50 @@ describe('template_maps', function() {
);
});
it('does not accept template with invalid name', function(done) {
var tmap = new TemplateMaps(redis_pool);
assert.ok(tmap);
var tpl = { version:'0.0.1',
auth: {}, layergroup: {layers:[wadusLayer]} };
var invalidnames = [ "ab|", "a b", "a@b", "1ab", "_x", "", " x", "x " ];
var testNext = function() {
if ( ! invalidnames.length ) { done(); return; }
var n = invalidnames.pop();
tpl.name = n;
tmap.addTemplate('me', tpl, function(err) {
if ( ! err ) {
done(new Error("Unexpected success with invalid name '" + n + "'"));
describe('naming', function() {
function createTemplate(name) {
return {
version:'0.0.1',
name: name,
auth: {},
layergroup: {
layers: [
wadusLayer
]
}
};
}
else if ( ! err.message.match(/template.*name/i) ) {
done(new Error("Unexpected error message with invalid name '" + n + "': " + err));
}
else {
testNext();
}
});
};
testNext();
});
var templateMaps = new TemplateMaps(redis_pool);
var invalidNames = [ "ab|", "a b", "a@b", "-1ab", "_x", "", " x", "x " ];
invalidNames.forEach(function(invalidName) {
it('should NOT accept template with invalid name: ' + invalidName, function(done) {
templateMaps.addTemplate('me', createTemplate(invalidName), function(err) {
assert.ok(err, "Unexpected success with invalid name '" + invalidName + "'");
assert.ok(
err.message.match(/template.*name/i),
"Unexpected error message with invalid name '" + invalidName + "': " + err.message
);
done();
});
});
});
var validNames = [
"AB", "1ab", "DFD19A1A-0AC6-11E5-B0CA-6476BA93D4F6", "25ad8300-0ac7-11e5-b93f-6476ba93d4f6"
];
validNames.forEach(function(validName) {
it('should accept template with valid name: ' + validName, function(done) {
templateMaps.addTemplate('me', createTemplate(validName), function(err) {
assert.ok(!err, "Unexpected error with valid name '" + validName + "': " + err);
done();
});
});
});
});
it('does not accept template with invalid placeholder name', function(done) {
var tmap = new TemplateMaps(redis_pool);

8
tools/README.md Normal file
View File

@@ -0,0 +1,8 @@
Deprecated tools
================
All tools and scripts found in this directory are deprecated and no longer maintained.
Use at your own peril.
In future releases they might get removed.