Compare commits

...

13 Commits
3.2.0 ... 3.3.0

Author SHA1 Message Date
Raul Ochoa
508d495a23 Release 3.3.0 2017-04-03 13:07:05 +02:00
Raul Ochoa
06427dc009 Bump version and add news 2017-04-03 13:06:37 +02:00
Raul Ochoa
c325df1414 Merge pull request #655 from CartoDB/static-maps-layers-filter
Static maps layers filter
2017-04-03 12:07:38 +02:00
Raul Ochoa
07447160e3 Merge pull request #654 from CartoDB/non-conditional-profiler
Remove all conditional branches to call req.profiler
2017-04-03 11:58:38 +02:00
Raul Ochoa
ededc73fd7 Throw on invalid params argument 2017-03-31 18:39:29 +02:00
Raul Ochoa
cad02bfad7 Remove all conditional branches to call req.profiler
req.profiler is created in a middleware for all requests.
2017-03-30 20:31:53 +02:00
Raul Ochoa
94299f0452 Configure extra allowed params per endpoint via middleware
Instead of making all params available in all endpoints, we control
what endpoints allow what extra params.

Dataviews endpoints should be migrated to this.
2017-03-30 20:12:55 +02:00
Raul Ochoa
ae5d82c41d Add test to go red 2017-03-30 20:12:20 +02:00
Raul Ochoa
6468822295 Remove layer param before creating a better solution 2017-03-30 20:08:45 +02:00
Raul Ochoa
777ae31426 Merge branch 'master' into static-maps-layers-filter 2017-03-30 19:33:59 +02:00
Raul Ochoa
1ca56fb81c Update news 2017-03-30 17:52:25 +02:00
Raul Ochoa
5d74e1eafe Stubs next version 2017-03-30 14:33:41 +02:00
Raul Ochoa
8694c120bc Allow to overwrite layers filter in static maps images 2017-03-15 11:00:10 +01:00
11 changed files with 97 additions and 62 deletions

View File

@@ -1,11 +1,18 @@
# Changelog
## 3.3.0
Released 2017-04-03
New features:
- Static map endpoints allow specifying the layers to render #653.
## 3.2.0
Released 2017-03-30
Announcements:
- Upgrades windshaft to [3.1.0](https://github.com/CartoDB/windshaft/releases/tag/3.1.0).
- Active GC interval.
## 3.1.1

View File

@@ -95,9 +95,7 @@ AuthApi.prototype.authorize = function(req, callback) {
self.authorizedByAPIKey(user, req, this);
},
function checkApiKey(err, authorized){
if (req.profiler) {
req.profiler.done('authorizedByAPIKey');
}
req.profiler.done('authorizedByAPIKey');
assert.ifError(err);
// if not authorized by api_key, continue
@@ -131,9 +129,7 @@ AuthApi.prototype.authorize = function(req, callback) {
}
self.pgConnection.setDBAuth(user, req.params, function(err) {
if (req.profiler) {
req.profiler.done('setDBAuth');
}
req.profiler.done('setDBAuth');
callback(err, true); // authorized (or error)
});
}

View File

@@ -36,7 +36,7 @@ function BaseController(authApi, pgConnection) {
module.exports = BaseController;
// jshint maxcomplexity:9
// jshint maxcomplexity:10
/**
* Whitelist input and get database name & default geometry type from
* subdomain/user metadata held in CartoDB Redis
@@ -61,9 +61,7 @@ BaseController.prototype.req2params = function(req, callback){
lzmaWorker.decompress(
lzma,
function(result) {
if (req.profiler) {
req.profiler.done('lzma');
}
req.profiler.done('lzma');
try {
delete req.query.lzma;
_.extend(req.query, JSON.parse(result));
@@ -77,7 +75,11 @@ BaseController.prototype.req2params = function(req, callback){
return;
}
req.query = _.pick(req.query, REQUEST_QUERY_PARAMS_WHITELIST);
var allowedQueryParams = REQUEST_QUERY_PARAMS_WHITELIST;
if (Array.isArray(req.context.allowedQueryParams)) {
allowedQueryParams = allowedQueryParams.concat(req.context.allowedQueryParams);
}
req.query = _.pick(req.query, allowedQueryParams);
req.params = _.extend({}, req.params); // shuffle things as request is a strange array/object
var user = req.context.user;
@@ -115,18 +117,14 @@ BaseController.prototype.req2params = function(req, callback){
// bring all query values onto req.params object
_.extend(req.params, req.query);
if (req.profiler) {
req.profiler.done('req2params.setup');
}
req.profiler.done('req2params.setup');
step(
function getPrivacy(){
self.authApi.authorize(req, this);
},
function validateAuthorization(err, authorized) {
if (req.profiler) {
req.profiler.done('authorize');
}
req.profiler.done('authorize');
assert.ifError(err);
if(!authorized) {
err = new Error("Sorry, you are unauthorized (permission denied)");
@@ -167,9 +165,7 @@ BaseController.prototype.send = function(req, res, body, status, headers) {
res.set('X-Served-By-DB-Host', req.params.dbhost);
}
if (req.profiler) {
res.set('X-Tiler-Profiler', req.profiler.toJSONString());
}
res.set('X-Tiler-Profiler', req.profiler.toJSONString());
if (headers) {
res.set(headers);
@@ -187,14 +183,12 @@ BaseController.prototype.send = function(req, res, body, status, headers) {
res.send(body);
}
if (req.profiler) {
try {
// May throw due to dns, see
// See http://github.com/CartoDB/Windshaft/issues/166
req.profiler.sendStats();
} catch (err) {
debug("error sending profiling stats: " + err);
}
try {
// May throw due to dns, see
// See http://github.com/CartoDB/Windshaft/issues/166
req.profiler.sendStats();
} catch (err) {
debug("error sending profiling stats: " + err);
}
};
// jshint maxcomplexity:6

View File

@@ -6,6 +6,7 @@ var BaseController = require('./base');
var cors = require('../middleware/cors');
var userMiddleware = require('../middleware/user');
var allowQueryParams = require('../middleware/allow-query-params');
var DataviewBackend = require('../backends/dataview');
var AnalysisStatusBackend = require('../backends/analysis-status');
@@ -67,11 +68,13 @@ LayergroupController.prototype.register = function(app) {
this.attributes.bind(this));
app.get(app.base_url_mapconfig +
'/static/center/:token/:z/:lat/:lng/:width/:height.:format', cors(), userMiddleware,
'/static/center/:token/:z/:lat/:lng/:width/:height.:format',
cors(), userMiddleware, allowQueryParams(['layer']),
this.center.bind(this));
app.get(app.base_url_mapconfig +
'/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format', cors(), userMiddleware,
'/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format',
cors(), userMiddleware, allowQueryParams(['layer']),
this.bbox.bind(this));
// Undocumented/non-supported API endpoint methods.

View File

@@ -87,9 +87,7 @@ MapController.prototype.createPost = function(req, res) {
};
MapController.prototype.instantiate = function(req, res) {
if (req.profiler) {
req.profiler.start('windshaft-cartodb.instance_template_post');
}
req.profiler.start('windshaft-cartodb.instance_template_post');
this.instantiateTemplate(req, res, function prepareTemplateParams(callback) {
if (!req.is('application/json')) {
@@ -100,9 +98,7 @@ MapController.prototype.instantiate = function(req, res) {
};
MapController.prototype.jsonp = function(req, res) {
if (req.profiler) {
req.profiler.start('windshaft-cartodb.instance_template_get');
}
req.profiler.start('windshaft-cartodb.instance_template_get');
this.instantiateTemplate(req, res, function prepareJsonTemplateParams(callback) {
var err = null;
@@ -303,9 +299,7 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, la
// take place before proceeding. Error will be logged
// asynchronously
this.metadataBackend.incMapviewCount(username, mapconfig.obj().stat_tag, function(err) {
if (req.profiler) {
req.profiler.done('incMapviewCount');
}
req.profiler.done('incMapviewCount');
if ( err ) {
global.logger.log("ERROR: failed to increment mapview count for user '" + username + "': " + err);
}
@@ -328,9 +322,7 @@ MapController.prototype.afterLayergroupCreate = function(req, res, mapconfig, la
QueryTables.getAffectedTablesFromQuery(connection, sql, this);
},
function handleAffectedTablesAndLastUpdatedTime(err, result) {
if (req.profiler) {
req.profiler.done('queryTablesAndLastUpdated');
}
req.profiler.done('queryTablesAndLastUpdated');
assert.ifError(err);
// feed affected tables cache so it can be reused from, for instance, layergroup controller
self.layergroupAffectedTables.set(dbName, layergroupId, result);

View File

@@ -8,6 +8,7 @@ var BaseController = require('./base');
var cors = require('../middleware/cors');
var userMiddleware = require('../middleware/user');
var allowQueryParams = require('../middleware/allow-query-params');
function NamedMapsController(authApi, pgConnection, namedMapProviderCache, tileBackend, previewBackend,
surrogateKeysCache, tablesExtentApi, metadataBackend) {
@@ -31,7 +32,7 @@ NamedMapsController.prototype.register = function(app) {
this.tile.bind(this));
app.get(app.base_url_mapconfig +
'/static/named/:template_id/:width/:height.:format', cors(), userMiddleware,
'/static/named/:template_id/:width/:height.:format', cors(), userMiddleware, allowQueryParams(['layer']),
this.staticMap.bind(this));
};
@@ -100,9 +101,7 @@ NamedMapsController.prototype.tile = function(req, res) {
self.tileBackend.getTile(namedMapProvider, req.params, this);
},
function handleImage(err, tile, headers, stats) {
if (req.profiler) {
req.profiler.add(stats);
}
req.profiler.add(stats);
if (err) {
self.sendError(req, res, err, 'NAMED_MAP_TILE');
} else {
@@ -176,10 +175,8 @@ NamedMapsController.prototype.staticMap = function(req, res) {
});
},
function handleImage(err, image, headers, stats) {
if (req.profiler) {
req.profiler.done('render-' + format);
req.profiler.add(stats || {});
}
req.profiler.done('render-' + format);
req.profiler.add(stats || {});
if (err) {
self.sendError(req, res, err, 'STATIC_VIZ_MAP');

View File

@@ -91,9 +91,7 @@ NamedMapsAdminController.prototype.update = function(req, res) {
NamedMapsAdminController.prototype.retrieve = function(req, res) {
var self = this;
if (req.profiler) {
req.profiler.start('windshaft-cartodb.get_template');
}
req.profiler.start('windshaft-cartodb.get_template');
var cdbuser = req.context.user;
var tpl_id;
@@ -127,9 +125,7 @@ NamedMapsAdminController.prototype.retrieve = function(req, res) {
NamedMapsAdminController.prototype.destroy = function(req, res) {
var self = this;
if (req.profiler) {
req.profiler.start('windshaft-cartodb.delete_template');
}
req.profiler.start('windshaft-cartodb.delete_template');
var cdbuser = req.context.user;
var tpl_id;
@@ -154,9 +150,7 @@ NamedMapsAdminController.prototype.destroy = function(req, res) {
NamedMapsAdminController.prototype.list = function(req, res) {
var self = this;
if ( req.profiler ) {
req.profiler.start('windshaft-cartodb.get_template_list');
}
req.profiler.start('windshaft-cartodb.get_template_list');
var cdbuser = req.context.user;

View File

@@ -0,0 +1,9 @@
module.exports = function allowQueryParams(params) {
if (!Array.isArray(params)) {
throw new Error('allowQueryParams must receive an Array of params');
}
return function allowQueryParamsMiddleware(req, res, next) {
req.context.allowedQueryParams = params;
next();
};
};

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "windshaft-cartodb",
"version": "3.2.0",
"version": "3.3.0",
"description": "A map tile server for CartoDB",
"keywords": [
"cartodb"

View File

@@ -21,7 +21,7 @@ describe('named maps static view', function() {
var IMAGE_TOLERANCE = 20;
function createTemplate(view) {
function createTemplate(view, layers) {
return {
version: '0.0.1',
name: templateName,
@@ -36,7 +36,7 @@ describe('named maps static view', function() {
},
view: view,
layergroup: {
layers: [
layers: layers || [
{
type: 'mapnik',
options: {
@@ -198,4 +198,43 @@ describe('named maps static view', function() {
});
});
it('should allow to select the layers to render', function (done) {
var view = {
bounds: {
west: 0,
south: 0,
east: 45,
north: 45
}
};
var layers = [
{
type: 'mapnik',
options: {
sql: 'select * from populated_places_simple_reduced',
cartocss: '#layer { marker-fill: <%= color %>; }',
cartocss_version: '2.3.0'
}
},
{
type: 'mapnik',
options: {
sql: 'select ST_Transform(ST_MakeEnvelope(-45, -45, 45, 45, 4326), 3857) the_geom_webmercator',
cartocss: '#layer { polygon-fill: <%= color %>; }',
cartocss_version: '2.3.0'
}
}
];
templateMaps.addTemplate(username, createTemplate(view, layers), function (err) {
if (err) {
return done(err);
}
getStaticMap({ layer: 0 }, function(err, img) {
assert.ok(!err);
assert.imageIsSimilarToFile(img, previewFixture('bounds'), IMAGE_TOLERANCE, done);
});
});
});
});

View File

@@ -26,12 +26,14 @@ describe('tile stats', function() {
var layergroupController = new LayergroupController();
var reqMock = {
profiler: { toJSONString:function() {} },
params: {
format: invalidFormat
}
};
var resMock = {
status: function() { return this; },
set: function() {},
json: function() {},
jsonp: function() {},
send: function() {}
@@ -54,12 +56,14 @@ describe('tile stats', function() {
}
});
var reqMock = {
profiler: { toJSONString:function() {} },
params: {
format: validFormat
}
};
var resMock = {
status: function() { return this; },
set: function() {},
json: function() {},
jsonp: function() {},
send: function() {}