Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd3fdb7f16 | ||
|
|
775af6feee | ||
|
|
adf5c17e0d | ||
|
|
beb2d96a32 | ||
|
|
2a4ae88bc0 | ||
|
|
b76098ba45 | ||
|
|
c095027f8e | ||
|
|
9d1db19907 | ||
|
|
260e321537 | ||
|
|
073603b527 | ||
|
|
17b259cf31 | ||
|
|
8f0f0026e9 | ||
|
|
59dae2b545 | ||
|
|
4670f69ead | ||
|
|
16fbd25a34 | ||
|
|
2d75985cb3 | ||
|
|
f963fb321e | ||
|
|
10feea0d48 | ||
|
|
b6b9b0ac36 | ||
|
|
5551e85853 | ||
|
|
1f0fa5031b | ||
|
|
263294a3f5 | ||
|
|
f9df30f70b | ||
|
|
61d31ec054 | ||
|
|
c8917bfc4c | ||
|
|
36b69a05e5 | ||
|
|
c8d2f66467 | ||
|
|
7416bb0e56 | ||
|
|
9182d0132d | ||
|
|
9be9357ade | ||
|
|
7f414f8adf | ||
|
|
3af9549939 | ||
|
|
41f248d731 | ||
|
|
18a517b7bf | ||
|
|
5150204389 | ||
|
|
3b16e7729d | ||
|
|
76d27c9fce | ||
|
|
4ce6e41000 | ||
|
|
33260cdbd9 | ||
|
|
85d81ba7fd | ||
|
|
7e8a3ca21f | ||
|
|
e9e4dc1f5c | ||
|
|
17c30e165a | ||
|
|
c45c6ceb15 | ||
|
|
d73c2c465f | ||
|
|
d4fc53939b | ||
|
|
4becb65bec | ||
|
|
f64e16c790 | ||
|
|
1772011627 | ||
|
|
5b8f785e2b | ||
|
|
a0e3b77006 | ||
|
|
908070ecd7 | ||
|
|
7c6a58cd30 | ||
|
|
b0990a1132 | ||
|
|
c6988cdb88 | ||
|
|
e0d304b033 | ||
|
|
e4a9f2d64c | ||
|
|
0236fe3ca9 | ||
|
|
1bed8623a2 | ||
|
|
df7d957914 | ||
|
|
30c4b00f33 | ||
|
|
ab27886460 | ||
|
|
31e18d04d7 | ||
|
|
8155484510 | ||
|
|
b61f1d2b53 | ||
|
|
2e274b936a | ||
|
|
bf3e311b57 | ||
|
|
6a7613de6b | ||
|
|
ee46549e04 | ||
|
|
377f3d4aff | ||
|
|
752d47d71e | ||
|
|
367157b80c | ||
|
|
53542f1cd6 | ||
|
|
7a8f156abf | ||
|
|
c60cc57a0d | ||
|
|
8de6ec9a21 | ||
|
|
44b6f4be7e | ||
|
|
280be1751c | ||
|
|
701a73a2c5 | ||
|
|
b578eada07 | ||
|
|
8100f155dc | ||
|
|
9f1a014004 | ||
|
|
e35e0e157c | ||
|
|
3aff328af3 | ||
|
|
ffb086045a | ||
|
|
c0786dfa6f | ||
|
|
ddc33fa52b | ||
|
|
9f2d6a5d41 | ||
|
|
64e884a092 | ||
|
|
17ec174683 | ||
|
|
3666cbee94 | ||
|
|
25de018f7d | ||
|
|
6597851b48 | ||
|
|
0399131968 | ||
|
|
86836e7f89 | ||
|
|
df346b11d3 | ||
|
|
27f74b3fe2 | ||
|
|
87dec64ad1 | ||
|
|
54c787162a | ||
|
|
6e92e699dc | ||
|
|
7950f43db3 | ||
|
|
d300677315 | ||
|
|
bd4d29dd14 | ||
|
|
18a84433f4 | ||
|
|
768ebf0ef2 | ||
|
|
1c20cb5478 | ||
|
|
279587ea11 | ||
|
|
25df193390 | ||
|
|
9ce81693bd | ||
|
|
16765e092f | ||
|
|
237e1257c4 | ||
|
|
b5a6d6974c | ||
|
|
26bab029f4 | ||
|
|
ed7bb07b03 | ||
|
|
c87277ad01 |
17
.travis.yml
@@ -1,24 +1,17 @@
|
||||
dist: trusty # only environment that supports Postgres 9.5 at this time
|
||||
sudo: required
|
||||
addons:
|
||||
postgresql: "9.5"
|
||||
apt:
|
||||
packages:
|
||||
- postgresql-plpython-9.5
|
||||
- pkg-config
|
||||
- libcairo2-dev
|
||||
- libjpeg8-dev
|
||||
- libgif-dev
|
||||
- libpango1.0-dev
|
||||
|
||||
before_install:
|
||||
- npm install -g npm@2
|
||||
- lsb_release -a
|
||||
- sudo mv /etc/apt/sources.list.d/pgdg-source.list* /tmp
|
||||
- sudo apt-get -qq purge postgis* postgresql*
|
||||
- sudo rm -Rf /var/lib/postgresql /etc/postgresql
|
||||
- sudo apt-add-repository --yes ppa:cartodb/postgresql-9.5
|
||||
- sudo apt-add-repository --yes ppa:cartodb/gis
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -q postgresql-9.5-postgis-2.2
|
||||
- sudo apt-get install -q postgresql-plpython-9.5
|
||||
- echo -e "local\tall\tall\ttrust\nhost\tall\tall\t127.0.0.1/32\ttrust\nhost\tall\tall\t::1/128\ttrust" |sudo tee /etc/postgresql/9.5/main/pg_hba.conf
|
||||
- sudo service postgresql restart
|
||||
- createdb template_postgis
|
||||
- createuser publicuser
|
||||
- psql -c "CREATE EXTENSION postgis" template_postgis
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
1. Test (make clean all check), fix if broken before proceeding
|
||||
2. Ensure proper version in package.json
|
||||
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
|
||||
|
||||
159
NEWS.md
@@ -1,5 +1,164 @@
|
||||
# Changelog
|
||||
|
||||
## 2.78.0
|
||||
Released 2016-09-29
|
||||
|
||||
New features:
|
||||
- Add metadata about processed turbo-carto rules.
|
||||
|
||||
Announcements:
|
||||
- Upgrades turbo-carto to [0.17.1](https://github.com/CartoDB/turbo-carto/releases/tag/0.17.1).
|
||||
|
||||
|
||||
## 2.77.1
|
||||
|
||||
Released 2016-09-28
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.44.1](https://github.com/CartoDB/camshaft/releases/tag/0.44.1).
|
||||
|
||||
|
||||
## 2.77.0
|
||||
|
||||
Released 2016-09-26
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.44.0](https://github.com/CartoDB/camshaft/releases/tag/0.44.0).
|
||||
- Adds a new configuration for camshaft: logger stream.
|
||||
|
||||
|
||||
## 2.76.0
|
||||
|
||||
Released 2016-09-15
|
||||
|
||||
New features:
|
||||
- Allow to use `--config /path/to/config.js` to specify configuration file.
|
||||
- Environment will be loaded from config file if `environment` key is present, otherwise it keeps current behaviour.
|
||||
|
||||
Bug fixes:
|
||||
- Allow to use absolute paths for log files #570.
|
||||
|
||||
|
||||
## 2.75.0
|
||||
|
||||
Released 2016-09-14
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.43.0](https://github.com/CartoDB/camshaft/releases/tag/0.43.0).
|
||||
|
||||
|
||||
## 2.74.1
|
||||
|
||||
Released 2016-09-07
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.42.1](https://github.com/CartoDB/camshaft/releases/tag/0.42.1).
|
||||
|
||||
|
||||
## 2.74.0
|
||||
|
||||
Released 2016-09-06
|
||||
|
||||
Enhancements:
|
||||
- Layers in previews can be shown or hidden using `preview_layers` property in template map
|
||||
|
||||
|
||||
## 2.73.1
|
||||
|
||||
Released 2016-09-06
|
||||
|
||||
Bug fixes:
|
||||
- Fixes missing column in fixture table `cdb_analysis_catalog`.
|
||||
|
||||
|
||||
## 2.73.0
|
||||
|
||||
Released 2016-09-06
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.42.0](https://github.com/CartoDB/camshaft/releases/tag/0.42.0).
|
||||
|
||||
|
||||
## 2.72.0
|
||||
|
||||
Released 2016-08-23
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.41.0](https://github.com/CartoDB/camshaft/releases/tag/0.41.0).
|
||||
|
||||
|
||||
## 2.71.0
|
||||
|
||||
Released 2016-08-17
|
||||
|
||||
Announcements:
|
||||
- Upgrades windshaft to [2.5.0](https://github.com/CartoDB/windshaft/releases/tag/2.5.0).
|
||||
|
||||
|
||||
## 2.70.0
|
||||
|
||||
Released 2016-08-16
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.40.0](https://github.com/CartoDB/camshaft/releases/tag/0.40.0).
|
||||
|
||||
|
||||
## 2.69.1
|
||||
|
||||
Released 2016-08-12
|
||||
|
||||
Announcements:
|
||||
- Upgrades windshaft to [2.4.2](https://github.com/CartoDB/windshaft/releases/tag/2.4.2).
|
||||
|
||||
|
||||
## 2.69.0
|
||||
|
||||
Released 2016-08-11
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.39.0](https://github.com/CartoDB/camshaft/releases/tag/0.39.0).
|
||||
|
||||
|
||||
## 2.68.0
|
||||
|
||||
Released 2016-07-21
|
||||
|
||||
Announcements:
|
||||
- Upgrades turbo-carto to [0.16.0](https://github.com/CartoDB/turbo-carto/releases/tag/0.16.0).
|
||||
|
||||
|
||||
## 2.67.1
|
||||
|
||||
Released 2016-07-21
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.38.1](https://github.com/CartoDB/camshaft/releases/tag/0.38.1).
|
||||
|
||||
|
||||
## 2.67.0
|
||||
|
||||
Released 2016-07-21
|
||||
|
||||
Announcements:
|
||||
- Upgrades camshaft to [0.38.0](https://github.com/CartoDB/camshaft/releases/tag/0.38.0).
|
||||
|
||||
|
||||
## 2.66.2
|
||||
|
||||
Released 2016-07-20
|
||||
|
||||
Announcements:
|
||||
- Upgrades turbo-carto to [0.15.1](https://github.com/CartoDB/turbo-carto/releases/tag/0.15.1).
|
||||
|
||||
|
||||
## 2.66.1
|
||||
|
||||
Released 2016-07-20
|
||||
|
||||
Announcements:
|
||||
- Upgrades turbo-carto to [0.15.0](https://github.com/CartoDB/turbo-carto/releases/tag/0.15.0).
|
||||
|
||||
|
||||
## 2.66.0
|
||||
|
||||
Released 2016-07-18
|
||||
|
||||
82
app.js
@@ -5,20 +5,35 @@ 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 argv = require('yargs')
|
||||
.usage('Usage: $0 <environment> [options]')
|
||||
.help('h')
|
||||
.example(
|
||||
'$0 production -c /etc/sql-api/config.js',
|
||||
'start server in production environment with /etc/sql-api/config.js as config file'
|
||||
)
|
||||
.alias('h', 'help')
|
||||
.alias('c', 'config')
|
||||
.nargs('c', 1)
|
||||
.describe('c', 'Load configuration from path')
|
||||
.argv;
|
||||
|
||||
var environmentArg = argv._[0] || process.env.NODE_ENV || 'development';
|
||||
var configurationFile = path.resolve(argv.config || './config/environments/' + environmentArg + '.js');
|
||||
if (!fs.existsSync(configurationFile)) {
|
||||
logError('Configuration file "%s" does not exist', configurationFile);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
global.environment = require(configurationFile);
|
||||
var ENVIRONMENT = argv._[0] || process.env.NODE_ENV || global.environment.environment;
|
||||
process.env.NODE_ENV = ENVIRONMENT;
|
||||
|
||||
var availableEnvironments = {
|
||||
production: true,
|
||||
staging: true,
|
||||
@@ -33,16 +48,6 @@ if (!availableEnvironments[ENVIRONMENT]){
|
||||
}
|
||||
|
||||
process.env.NODE_ENV = ENVIRONMENT;
|
||||
|
||||
// set environment specific variables
|
||||
global.environment = require('./config/environments/' + ENVIRONMENT);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -58,25 +63,31 @@ var agentOptions = _.defaults(global.environment.httpAgent || {}, {
|
||||
http.globalAgent = new http.Agent(agentOptions);
|
||||
https.globalAgent = new https.Agent(agentOptions);
|
||||
|
||||
|
||||
global.log4js = require('log4js');
|
||||
var log4jsConfig = {
|
||||
appenders: [],
|
||||
replaceConsole: true
|
||||
};
|
||||
|
||||
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 }
|
||||
);
|
||||
var logFilename = path.resolve(global.environment.log_filename);
|
||||
var logDirectory = path.dirname(logFilename);
|
||||
if (!fs.existsSync(logDirectory)) {
|
||||
logError("Log filename directory does not exist: " + logDirectory);
|
||||
process.exit(1);
|
||||
}
|
||||
log("Logs will be written to " + logFilename);
|
||||
log4jsConfig.appenders.push(
|
||||
{ type: "file", absolute: true, filename: logFilename }
|
||||
);
|
||||
} else {
|
||||
log4js_config.appenders.push(
|
||||
{ type: "console", layout: { type:'basic' } }
|
||||
);
|
||||
log4jsConfig.appenders.push(
|
||||
{ type: "console", layout: { type:'basic' } }
|
||||
);
|
||||
}
|
||||
|
||||
global.log4js.configure(log4js_config, { cwd: __dirname });
|
||||
global.log4js.configure(log4jsConfig);
|
||||
global.logger = global.log4js.getLogger();
|
||||
|
||||
global.environment.api_hostname = require('os').hostname().split('.')[0];
|
||||
@@ -99,6 +110,7 @@ var listener = server.listen(serverOptions.bind.port, serverOptions.bind.host, b
|
||||
var version = require("./package").version;
|
||||
|
||||
listener.on('listening', function() {
|
||||
log('Using configuration file "%s"', configurationFile);
|
||||
log(
|
||||
"Windshaft tileserver %s started on %s:%s PID=%d (%s)",
|
||||
version, serverOptions.bind.host, serverOptions.bind.port, process.pid, ENVIRONMENT
|
||||
@@ -114,7 +126,7 @@ setInterval(function() {
|
||||
|
||||
process.on('SIGHUP', function() {
|
||||
global.log4js.clearAndShutdownAppenders(function() {
|
||||
global.log4js.configure(log4js_config);
|
||||
global.log4js.configure(log4jsConfig);
|
||||
global.logger = global.log4js.getLogger();
|
||||
log('Log files reloaded');
|
||||
});
|
||||
|
||||
@@ -62,6 +62,7 @@ var config = {
|
||||
extent: "-180,-90,180,90",
|
||||
srid: 4326,
|
||||
*/
|
||||
// max number of rows to return when querying data, 0 means no limit
|
||||
row_limit: 65535,
|
||||
simplify_geometries: true,
|
||||
use_overviews: true, // use overviews to retrieve raster
|
||||
@@ -209,6 +210,12 @@ var config = {
|
||||
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'
|
||||
},
|
||||
logger: {
|
||||
// If filename is given logs comming from analysis client will be written
|
||||
// there, in append mode. Otherwise 'log_filename' is used. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
filename: '/tmp/analysis.log'
|
||||
}
|
||||
}
|
||||
,millstone: {
|
||||
|
||||
@@ -56,6 +56,7 @@ var config = {
|
||||
host: '127.0.0.1',
|
||||
port: 6432,
|
||||
extent: "-20037508.3,-20037508.3,20037508.3,20037508.3",
|
||||
// max number of rows to return when querying data, 0 means no limit
|
||||
row_limit: 65535,
|
||||
/*
|
||||
* Set persist_connection to false if you want
|
||||
@@ -203,6 +204,12 @@ var config = {
|
||||
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'
|
||||
},
|
||||
logger: {
|
||||
// If filename is given logs comming from analysis client will be written
|
||||
// there, in append mode. Otherwise 'log_filename' is used. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
filename: 'logs/analysis.log'
|
||||
}
|
||||
}
|
||||
,millstone: {
|
||||
|
||||
@@ -56,6 +56,7 @@ var config = {
|
||||
host: '127.0.0.1',
|
||||
port: 6432,
|
||||
extent: "-20037508.3,-20037508.3,20037508.3,20037508.3",
|
||||
// max number of rows to return when querying data, 0 means no limit
|
||||
row_limit: 65535,
|
||||
simplify_geometries: true,
|
||||
use_overviews: true, // use overviews to retrieve raster
|
||||
@@ -203,6 +204,12 @@ var config = {
|
||||
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'
|
||||
},
|
||||
logger: {
|
||||
// If filename is given logs comming from analysis client will be written
|
||||
// there, in append mode. Otherwise 'log_filename' is used. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
filename: 'logs/analysis.log'
|
||||
}
|
||||
}
|
||||
,millstone: {
|
||||
|
||||
@@ -56,6 +56,7 @@ var config = {
|
||||
host: '127.0.0.1',
|
||||
port: 5432,
|
||||
extent: "-20037508.3,-20037508.3,20037508.3,20037508.3",
|
||||
// max number of rows to return when querying data, 0 means no limit
|
||||
row_limit: 65535,
|
||||
simplify_geometries: true,
|
||||
use_overviews: true, // use overviews to retrieve raster
|
||||
@@ -204,6 +205,12 @@ var config = {
|
||||
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'
|
||||
},
|
||||
logger: {
|
||||
// If filename is given logs comming from analysis client will be written
|
||||
// there, in append mode. Otherwise 'log_filename' is used. Otherwise stdout is used (default).
|
||||
// Log file will be re-opened on receiving the HUP signal
|
||||
filename: 'node-windshaft.log'
|
||||
}
|
||||
}
|
||||
,millstone: {
|
||||
|
||||
@@ -141,9 +141,6 @@ https://{username}.carto.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.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# 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).
|
||||
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 CARTO servers, to select data from your CARTO user database by using SQL, and specifying the CartoCSS for your map.
|
||||
The Named Map workflow consists of uploading a MapConfig file to CARTO servers, to select data from your CARTO 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.
|
||||
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 CARTO.js. This is achieved by adding the [`namedmap` type](http://docs.carto.com/carto-engine/carto-js/layer-source-object/#named-maps-layer-source-object-type-namedmap) layer source object to draw the Named Map.
|
||||
|
||||
@@ -73,6 +73,10 @@ The `name` argument defines how to name this "template_name".json. Note that the
|
||||
}
|
||||
]
|
||||
},
|
||||
"preview_layers": {
|
||||
"0": true,
|
||||
"layer1": false
|
||||
},
|
||||
"view": {
|
||||
"zoom": 4,
|
||||
"center": {
|
||||
@@ -95,7 +99,7 @@ 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 |
|
||||
auth |
|
||||
--- | ---
|
||||
|_ method | `"token"` or `"open"` (`"open"` is the default if no method is specified. Use `"token"` to password-protect your map)
|
||||
|_ valid_tokens | when `"method"` is set to `"token"`, the values listed here allow you to instantiate the Named Map. See this [example](http://docs.carto.com/faqs/manipulating-your-data/#how-to-create-a-password-protected-named-map) for how to create a password-protected map.
|
||||
@@ -105,12 +109,12 @@ view (optional) | extra keys to specify the view area for the map. It can be use
|
||||
--- | ---
|
||||
|_ zoom | The zoom level to use
|
||||
|
||||
|_ center |
|
||||
|_ center |
|
||||
--- | ---
|
||||
|_ |_ lng | The longitude to use for the center
|
||||
|_ |_ lat | The latitude to use for the center
|
||||
|
||||
|_ bounds |
|
||||
|_ 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)
|
||||
@@ -160,7 +164,7 @@ curl -X POST \
|
||||
|
||||
#### 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.
|
||||
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
|
||||
{
|
||||
@@ -516,7 +520,7 @@ If you are creating a Torque layer in a Named Map without using the Torque.js li
|
||||
})
|
||||
.addTo(map)
|
||||
.done(function(layer) {
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
```
|
||||
@@ -535,7 +539,7 @@ Optionally, authenticated users can fetch projected tiles (XYZ tiles or Mapnik R
|
||||
|
||||
### 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.
|
||||
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:
|
||||
|
||||
|
||||
@@ -1,19 +1,50 @@
|
||||
var camshaft = require('camshaft');
|
||||
var fs = require('fs');
|
||||
|
||||
function AnalysisBackend(options) {
|
||||
var batchConfig = options.batch || {};
|
||||
function AnalysisBackend (options) {
|
||||
options = options || {};
|
||||
this.setBatchConfig(options.batch);
|
||||
this.setLoggerConfig(options.logger);
|
||||
}
|
||||
|
||||
module.exports = AnalysisBackend;
|
||||
|
||||
AnalysisBackend.prototype.setBatchConfig = function (options) {
|
||||
var batchConfig = options || {};
|
||||
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.setLoggerConfig = function (options) {
|
||||
var loggerConfig = options || {};
|
||||
|
||||
loggerConfig.filename = loggerConfig.filename;
|
||||
|
||||
this.loggerConfig = loggerConfig;
|
||||
|
||||
if (this.loggerConfig.filename) {
|
||||
this.stream = fs.createWriteStream(this.loggerConfig.filename, { flags: 'a', encoding: 'utf8' });
|
||||
|
||||
process.on('SIGHUP', function () {
|
||||
if (this.stream) {
|
||||
this.stream.destroy();
|
||||
}
|
||||
|
||||
this.stream = fs.createWriteStream(this.loggerConfig.filename, { flags: 'a', encoding: 'utf8' });
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
analysisConfiguration.logger = {
|
||||
stream: this.stream ? this.stream : process.stdout
|
||||
};
|
||||
|
||||
camshaft.create(analysisConfiguration, analysisDefinition, callback);
|
||||
};
|
||||
|
||||
@@ -6,6 +6,9 @@ dot.templateSettings.strip = false;
|
||||
function createTemplate(method) {
|
||||
return dot.template([
|
||||
'SELECT',
|
||||
'min({{=it._column}}) min_val,',
|
||||
'max({{=it._column}}) max_val,',
|
||||
'avg({{=it._column}}) avg_val,',
|
||||
method,
|
||||
'FROM ({{=it._sql}}) _table_sql WHERE {{=it._column}} IS NOT NULL'
|
||||
].join('\n'));
|
||||
@@ -32,14 +35,9 @@ methodTemplates.category = dot.template([
|
||||
' ORDER BY 2 DESC',
|
||||
'),',
|
||||
'agg_categories AS (',
|
||||
' SELECT \'__other\' category',
|
||||
' SELECT category',
|
||||
' FROM categories',
|
||||
' WHERE rank >= {{=it._buckets}}',
|
||||
' GROUP BY 1',
|
||||
' UNION ALL',
|
||||
' SELECT CAST(category AS text)',
|
||||
' FROM categories',
|
||||
' WHERE rank < {{=it._buckets}}',
|
||||
' WHERE rank <= {{=it._buckets}}',
|
||||
')',
|
||||
'SELECT array_agg(category) AS category FROM agg_categories'
|
||||
].join('\n'));
|
||||
@@ -79,11 +77,14 @@ PostgresDatasource.prototype.getRamp = function (column, buckets, method, callba
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
resultSet = resultSet || {};
|
||||
var result = resultSet.rows || [];
|
||||
|
||||
var result = getResult(resultSet);
|
||||
var strategy = method2strategy[methodName];
|
||||
var ramp = result[0][methodName] || [];
|
||||
var ramp = result[methodName] || [];
|
||||
var stats = {
|
||||
min_val: result.min_val,
|
||||
max_val: result.max_val,
|
||||
avg_val: result.avg_val
|
||||
};
|
||||
// Skip null values from ramp
|
||||
// Generated turbo-carto won't be correct, but better to keep it working than failing
|
||||
// TODO fix cartodb-postgres extension quantification functions
|
||||
@@ -94,8 +95,16 @@ PostgresDatasource.prototype.getRamp = function (column, buckets, method, callba
|
||||
});
|
||||
}
|
||||
|
||||
return callback(null, { ramp: ramp, strategy: strategy });
|
||||
return callback(null, { ramp: ramp, strategy: strategy, stats: stats });
|
||||
}, true); // use read-only transaction
|
||||
};
|
||||
|
||||
function getResult(resultSet) {
|
||||
resultSet = resultSet || {};
|
||||
var result = resultSet.rows || [];
|
||||
result = result[0] || {};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = PostgresDatasource;
|
||||
|
||||
@@ -171,6 +171,7 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
|
||||
var analysesResults = context.analysesResults || [];
|
||||
addDataviewsAndWidgetsUrls(req.context.user, layergroup, mapConfig.obj());
|
||||
addAnalysesMetadata(req.context.user, layergroup, analysesResults, true);
|
||||
addContextMetadata(layergroup, mapConfig.obj(), context);
|
||||
res.set('X-Layergroup-Id', layergroup.layergroupid);
|
||||
self.send(req, res, layergroup, 200);
|
||||
}
|
||||
@@ -178,6 +179,17 @@ MapController.prototype.create = function(req, res, prepareConfigFn) {
|
||||
);
|
||||
};
|
||||
|
||||
function addContextMetadata(layergroup, mapConfig, context) {
|
||||
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) {
|
||||
layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) {
|
||||
if (context.turboCarto && Array.isArray(context.turboCarto.layers)) {
|
||||
layer.meta.cartocss_meta = context.turboCarto.layers[layerIndex];
|
||||
}
|
||||
return layer;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn) {
|
||||
var self = this;
|
||||
|
||||
@@ -229,8 +241,10 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
|
||||
var templateHash = self.templateMaps.fingerPrint(mapConfigProvider.template).substring(0, 8);
|
||||
layergroup.layergroupid = cdbuser + '@' + templateHash + '@' + layergroup.layergroupid;
|
||||
|
||||
addDataviewsAndWidgetsUrls(cdbuser, layergroup, mapConfig.obj());
|
||||
var _mapConfig = mapConfig.obj();
|
||||
addDataviewsAndWidgetsUrls(cdbuser, layergroup, _mapConfig);
|
||||
addAnalysesMetadata(cdbuser, layergroup, mapConfigProvider.analysesResults);
|
||||
addContextMetadata(layergroup, _mapConfig, mapConfigProvider.context);
|
||||
|
||||
res.set('X-Layergroup-Id', layergroup.layergroupid);
|
||||
self.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(cdbuser, mapConfigProvider.getTemplateName()));
|
||||
|
||||
@@ -137,9 +137,15 @@ NamedMapsController.prototype.staticMap = function(req, res) {
|
||||
this
|
||||
);
|
||||
},
|
||||
function prepareImageOptions(err, _namedMapProvider) {
|
||||
function prepareLayerVisibility(err, _namedMapProvider) {
|
||||
assert.ifError(err);
|
||||
|
||||
namedMapProvider = _namedMapProvider;
|
||||
|
||||
self.prepareLayerFilterFromPreviewLayers(cdbUser, req, namedMapProvider, this);
|
||||
},
|
||||
function prepareImageOptions(err) {
|
||||
assert.ifError(err);
|
||||
self.getStaticImageOptions(cdbUser, req.params, namedMapProvider, this);
|
||||
},
|
||||
function getImage(err, imageOpts) {
|
||||
@@ -184,6 +190,45 @@ NamedMapsController.prototype.staticMap = function(req, res) {
|
||||
);
|
||||
};
|
||||
|
||||
NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function (user, req, namedMapProvider, callback) {
|
||||
var self = this;
|
||||
namedMapProvider.getTemplate(function (err, template) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!template || !template.view || !template.view.preview_layers) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
var previewLayers = template.view.preview_layers;
|
||||
var layerVisibilityFilter = [];
|
||||
|
||||
template.layergroup.layers.forEach(function (layer, index) {
|
||||
if (previewLayers[''+index] !== false && previewLayers[layer.id] !== false) {
|
||||
layerVisibilityFilter.push(''+index);
|
||||
}
|
||||
});
|
||||
|
||||
if (!layerVisibilityFilter.length) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// overwrites 'all' default filter
|
||||
req.params.layer = layerVisibilityFilter.join(',');
|
||||
|
||||
// recreates the provider
|
||||
self.namedMapProviderCache.get(
|
||||
user,
|
||||
req.params.template_id,
|
||||
req.query.config,
|
||||
req.query.auth_token,
|
||||
req.params,
|
||||
callback
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
var DEFAULT_ZOOM_CENTER = {
|
||||
zoom: 1,
|
||||
center: {
|
||||
|
||||
@@ -48,6 +48,11 @@ TurboCartoAdapter.prototype.getMapConfig = function (user, requestMapConfig, par
|
||||
}
|
||||
|
||||
requestMapConfig.layers = results.map(function(result) { return result.layer; });
|
||||
context.turboCarto = {
|
||||
layers: results.map(function(result) {
|
||||
return result.meta;
|
||||
})
|
||||
};
|
||||
|
||||
return callback(null, requestMapConfig);
|
||||
});
|
||||
@@ -84,7 +89,7 @@ TurboCartoAdapter.prototype._parseCartoCss = function (username, params, layer,
|
||||
}
|
||||
|
||||
var pg = new PSQL(dbParamsFromReqParams(params));
|
||||
function processCallback(err, cartocss) {
|
||||
function processCallback(err, cartocss, meta) {
|
||||
// Only return turbo-carto errors
|
||||
if (err && err.name === 'TurboCartoError') {
|
||||
var error = new Error(err.message);
|
||||
@@ -105,7 +110,7 @@ TurboCartoAdapter.prototype._parseCartoCss = function (username, params, layer,
|
||||
if (cartocss) {
|
||||
layer.options.cartocss = cartocss;
|
||||
}
|
||||
return callback(null, { layer: layer });
|
||||
return callback(null, { layer: layer, meta: meta });
|
||||
}
|
||||
|
||||
var layerSql = layer.options.sql;
|
||||
|
||||
@@ -120,6 +120,7 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) {
|
||||
self.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource);
|
||||
self.analysesResults = context.analysesResults || [];
|
||||
self.rendererParams = rendererParams;
|
||||
self.context = context;
|
||||
self.context.limits = renderLimits || {};
|
||||
return callback(self.err, self.mapConfig, self.rendererParams, self.context);
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@ module.exports = function(serverOptions) {
|
||||
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();
|
||||
|
||||
@@ -36,6 +36,9 @@ var analysisConfig = _.defaults(global.environment.analysis || {}, {
|
||||
inlineExecution: false,
|
||||
endpoint: 'http://127.0.0.1:8080/api/v2/sql/job',
|
||||
hostHeaderTemplate: '{{=it.username}}.localhost.lan'
|
||||
},
|
||||
logger: {
|
||||
filename: undefined
|
||||
}
|
||||
});
|
||||
|
||||
@@ -95,6 +98,9 @@ module.exports = {
|
||||
inlineExecution: analysisConfig.batch.inlineExecution,
|
||||
endpoint: analysisConfig.batch.endpoint,
|
||||
hostHeaderTemplate: analysisConfig.batch.hostHeaderTemplate
|
||||
},
|
||||
logger: {
|
||||
filename: analysisConfig.logger.filename
|
||||
}
|
||||
},
|
||||
// Do not send unwatch on release. See http://github.com/CartoDB/Windshaft-cartodb/issues/161
|
||||
|
||||
1317
npm-shrinkwrap.json
generated
11
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "windshaft-cartodb",
|
||||
"version": "2.66.0",
|
||||
"version": "2.78.0",
|
||||
"description": "A map tile server for CartoDB",
|
||||
"keywords": [
|
||||
"cartodb"
|
||||
@@ -20,7 +20,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"body-parser": "~1.14.0",
|
||||
"camshaft": "0.37.1",
|
||||
"camshaft": "0.44.1",
|
||||
"cartodb-psql": "~0.6.1",
|
||||
"cartodb-query-tables": "~0.1.0",
|
||||
"cartodb-redis": "0.13.1",
|
||||
@@ -28,7 +28,7 @@
|
||||
"dot": "~1.0.2",
|
||||
"express": "~4.13.3",
|
||||
"fastly-purge": "~1.0.1",
|
||||
"log4js": "https://github.com/CartoDB/log4js-node/tarball/cdb",
|
||||
"log4js": "cartodb/log4js-node#cdb",
|
||||
"lru-cache": "2.6.5",
|
||||
"lzma": "~2.3.2",
|
||||
"node-statsd": "~0.0.7",
|
||||
@@ -37,9 +37,10 @@
|
||||
"request": "~2.62.0",
|
||||
"step": "~0.0.6",
|
||||
"step-profiler": "~0.3.0",
|
||||
"turbo-carto": "0.14.0",
|
||||
"turbo-carto": "0.17.1",
|
||||
"underscore": "~1.6.0",
|
||||
"windshaft": "2.4.0"
|
||||
"windshaft": "2.5.0",
|
||||
"yargs": "~5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"istanbul": "~0.4.3",
|
||||
|
||||
210
test/acceptance/named_layers_visibility.js
Normal file
@@ -0,0 +1,210 @@
|
||||
var step = require('step');
|
||||
var test_helper = require('../support/test_helper');
|
||||
|
||||
var assert = require('../support/assert');
|
||||
var CartodbWindshaft = require(__dirname + '/../../lib/cartodb/server');
|
||||
var serverOptions = require(__dirname + '/../../lib/cartodb/server_options');
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
|
||||
var RedisPool = require('redis-mpool');
|
||||
var TemplateMaps = require('../../lib/cartodb/backends/template_maps.js');
|
||||
var mapnik = require('windshaft').mapnik;
|
||||
|
||||
var IMAGE_TOLERANCE = 20;
|
||||
|
||||
describe('layers visibility for previews', function() {
|
||||
// configure redis pool instance to use in tests
|
||||
var redisPool = new RedisPool(global.environment.redis);
|
||||
var templateMaps = new TemplateMaps(redisPool, {
|
||||
max_user_templates: global.environment.maxUserTemplates
|
||||
});
|
||||
|
||||
var username = 'localhost';
|
||||
|
||||
function createLayer (color, layerId) {
|
||||
var mod;
|
||||
|
||||
if (color === 'red') {
|
||||
mod = 0;
|
||||
} else if (color === 'orange') {
|
||||
mod = 1;
|
||||
} else if (color === 'blue') {
|
||||
mod = 2;
|
||||
} else {
|
||||
mod = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'mapnik',
|
||||
id: layerId,
|
||||
options: {
|
||||
sql: 'select * from populated_places_simple_reduced where cartodb_id % 3 = ' + mod,
|
||||
cartocss: '#layer { marker-fill: ' + color + '; }',
|
||||
cartocss_version: '2.3.0'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createTemplate(scenario) {
|
||||
return {
|
||||
version: '0.0.1',
|
||||
name: scenario.name,
|
||||
auth: {
|
||||
method: 'open'
|
||||
},
|
||||
view: {
|
||||
bounds: {
|
||||
west: 0,
|
||||
south: 0,
|
||||
east: 45,
|
||||
north: 45
|
||||
},
|
||||
zoom: 4,
|
||||
center: {
|
||||
lng: 40,
|
||||
lat: 20
|
||||
},
|
||||
preview_layers: scenario.layerPerview
|
||||
},
|
||||
layergroup: {
|
||||
layers: scenario.layers
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(function (done) {
|
||||
test_helper.deleteRedisKeys({
|
||||
'user:localhost:mapviews:global': 5
|
||||
}, done);
|
||||
});
|
||||
|
||||
function previewFixture(version) {
|
||||
return './test/fixtures/previews/populated_places_simple_reduced-' + version + '.png';
|
||||
}
|
||||
|
||||
var threeLayerPointDistintColor = [
|
||||
createLayer('red'),
|
||||
createLayer('orange'),
|
||||
createLayer('blue', 'layer2')
|
||||
];
|
||||
|
||||
var scenarios = [{
|
||||
name: 'preview_layers_red',
|
||||
layerPerview: {
|
||||
'0': true,
|
||||
'1': false,
|
||||
'layer2': false
|
||||
},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_orange',
|
||||
layerPerview: {
|
||||
'0': false,
|
||||
'1': true,
|
||||
'layer2': false
|
||||
},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_blue',
|
||||
layerPerview: {
|
||||
'0': false,
|
||||
'1': false,
|
||||
'layer2': true
|
||||
},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_red_orange',
|
||||
layerPerview: {
|
||||
'0': true,
|
||||
'1': true,
|
||||
'layer2': false
|
||||
},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_red_blue',
|
||||
layerPerview: {
|
||||
'0': true,
|
||||
'1': false,
|
||||
'layer2': true
|
||||
},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_orange_blue',
|
||||
layerPerview: {
|
||||
'0': false,
|
||||
'1': true,
|
||||
'layer2': true
|
||||
},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_red_orange_blue',
|
||||
layerPerview: {
|
||||
'0': true,
|
||||
'1': true,
|
||||
'layer2': true
|
||||
},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_all',
|
||||
layerPerview: {},
|
||||
layers: threeLayerPointDistintColor
|
||||
}, {
|
||||
name: 'preview_layers_undefined',
|
||||
layerPerview: undefined,
|
||||
layers: threeLayerPointDistintColor
|
||||
}];
|
||||
|
||||
scenarios.forEach(function (scenario) {
|
||||
it('should filter layers for template: ' + scenario.name, function (done) {
|
||||
step(
|
||||
function addTemplate () {
|
||||
var next = this;
|
||||
var template = createTemplate(scenario);
|
||||
|
||||
templateMaps.addTemplate(username, template, next);
|
||||
},
|
||||
function requestPreview (err) {
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
|
||||
assert.response(server, {
|
||||
url: '/api/v1/map/static/named/' + scenario.name + '/640/480.png',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: 'localhost'
|
||||
},
|
||||
encoding: 'binary'
|
||||
}, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'content-type': 'image/png'
|
||||
}
|
||||
}, function (res, err) {
|
||||
next(err, res);
|
||||
});
|
||||
},
|
||||
function checkPreview (err, res) {
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
var img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
|
||||
var previewFixturePath = previewFixture(scenario.name);
|
||||
|
||||
assert.imageIsSimilarToFile(img, previewFixturePath, IMAGE_TOLERANCE, next);
|
||||
},
|
||||
function deleteTemplate(err) {
|
||||
assert.ifError(err);
|
||||
|
||||
var next = this;
|
||||
|
||||
templateMaps.delTemplate(username, scenario.name, next);
|
||||
},
|
||||
function finish (err) {
|
||||
done(err);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -50,14 +50,14 @@ describe('turbo-carto error cases', function() {
|
||||
});
|
||||
|
||||
it('should return invalid number of ramp error', function(done) {
|
||||
this.testClient = new TestClient(makeMapconfig('ramp([pop_max], (8,24,96), (8,24,96,128))'));
|
||||
this.testClient = new TestClient(makeMapconfig('ramp([pop_max], 8, 96, 3, (8,24,96,128))'));
|
||||
this.testClient.getLayergroup(ERROR_RESPONSE, function(err, layergroup) {
|
||||
assert.ok(!err, err);
|
||||
|
||||
assert.ok(layergroup.hasOwnProperty('errors'));
|
||||
assert.equal(layergroup.errors.length, 1);
|
||||
assert.ok(layergroup.errors[0].match(/^Failed\sto\sprocess/));
|
||||
assert.ok(layergroup.errors[0].match(/invalid\sramp\slength/i));
|
||||
assert.ok(layergroup.errors[0].match(/^Failed\sto\sprocess/), layergroup.errors[0]);
|
||||
assert.ok(layergroup.errors[0].match(/invalid\sramp\slength/i), layergroup.errors[0]);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -287,4 +287,97 @@ describe('turbo-carto regressions', function() {
|
||||
});
|
||||
});
|
||||
|
||||
var scenarios = [
|
||||
{
|
||||
desc: 'numeric datasource',
|
||||
cartocss: [
|
||||
"#points {",
|
||||
" marker-fill: ramp([scalerank], colorbrewer(Reds), category);",
|
||||
"}"
|
||||
].join('\n'),
|
||||
expected: [
|
||||
'#points {',
|
||||
' marker-fill: #fee5d9;',
|
||||
' [ scalerank = 6 ] {',
|
||||
' marker-fill: #fcae91',
|
||||
' }',
|
||||
' [ scalerank = 8 ] {',
|
||||
' marker-fill: #fb6a4a',
|
||||
' }',
|
||||
' [ scalerank = 4 ] {',
|
||||
' marker-fill: #de2d26',
|
||||
' }',
|
||||
' [ scalerank = 10 ] {',
|
||||
' marker-fill: #a50f15',
|
||||
' }',
|
||||
'}',
|
||||
].join('\n')
|
||||
},
|
||||
{
|
||||
desc: 'string datasource',
|
||||
cartocss: [
|
||||
"#points {",
|
||||
" marker-fill: ramp([adm0name], colorbrewer(Reds), category);",
|
||||
"}"
|
||||
].join('\n'),
|
||||
expected: [
|
||||
'#points {',
|
||||
' marker-fill: #fee5d9;',
|
||||
' [ adm0name = "Russia" ] {',
|
||||
' marker-fill: #fcae91',
|
||||
' }',
|
||||
' [ adm0name = "China" ] {',
|
||||
' marker-fill: #fb6a4a',
|
||||
' }',
|
||||
' [ adm0name = "Brazil" ] {',
|
||||
' marker-fill: #de2d26',
|
||||
' }',
|
||||
' [ adm0name = "Canada" ] {',
|
||||
' marker-fill: #a50f15',
|
||||
' }',
|
||||
'}',
|
||||
].join('\n')
|
||||
},
|
||||
{
|
||||
desc: 'numeric manual',
|
||||
cartocss: [
|
||||
"#points {",
|
||||
" marker-fill: ramp([scalerank], colorbrewer(Reds), (-1, 6, 8, 4, 10), category);",
|
||||
"}"
|
||||
].join('\n'),
|
||||
expected: [
|
||||
'#points {',
|
||||
' marker-fill: #fee5d9;',
|
||||
' [ scalerank = 6 ] {',
|
||||
' marker-fill: #fcae91',
|
||||
' }',
|
||||
' [ scalerank = 8 ] {',
|
||||
' marker-fill: #fb6a4a',
|
||||
' }',
|
||||
' [ scalerank = 4 ] {',
|
||||
' marker-fill: #de2d26',
|
||||
' }',
|
||||
' [ scalerank = 10 ] {',
|
||||
' marker-fill: #a50f15',
|
||||
' }',
|
||||
'}',
|
||||
].join('\n')
|
||||
}
|
||||
];
|
||||
|
||||
scenarios.forEach(function(scenario) {
|
||||
it('category ramps should use original type: ' + scenario.desc, function(done) {
|
||||
var mapConfig = makeMapconfig('SELECT * FROM populated_places_simple_reduced', scenario.cartocss);
|
||||
this.testClient = new TestClient(mapConfig);
|
||||
this.testClient.getLayergroup(function(err, layergroup) {
|
||||
assert.ok(!err, err);
|
||||
|
||||
assert.ok(layergroup.hasOwnProperty('layergroupid'));
|
||||
assert.deepEqual(layergroup.metadata.layers[0].meta.cartocss, scenario.expected);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_all.png
vendored
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_blue.png
vendored
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_orange.png
vendored
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_orange_blue.png
vendored
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_red.png
vendored
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_red_blue.png
vendored
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_red_orange.png
vendored
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_red_orange_blue.png
vendored
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
test/fixtures/previews/populated_places_simple_reduced-preview_layers_undefined.png
vendored
Normal file
|
After Width: | Height: | Size: 59 KiB |
@@ -26,5 +26,7 @@ CREATE TABLE IF NOT EXISTS
|
||||
-- last job modifying the node
|
||||
last_modified_by uuid,
|
||||
-- store error message for failures
|
||||
last_error_message text
|
||||
last_error_message text,
|
||||
-- cached tables involved in the analysis
|
||||
cache_tables regclass[] NOT NULL DEFAULT '{}'
|
||||
);
|
||||
|
||||