Implemented integration of turbo-cartocss for named maps

This commit is contained in:
Daniel García Aubert 2016-03-10 20:45:00 +01:00
parent 46b212b2cd
commit dab4b6d56b
6 changed files with 210 additions and 22 deletions

View File

@ -255,22 +255,6 @@ MapController.prototype.instantiateTemplate = function(req, res, prepareParamsFn
}
);
},
function parseTurboCartoCss(err, requestMapConfig, datasource) {
assert.ifError(err);
var next = this;
self.turboCartoCssAdapter.getLayers(req.context.user, requestMapConfig.layers, function (err, layers) {
if (err) {
return next(err);
}
if (layers) {
requestMapConfig.layers = layers;
}
return next(null, requestMapConfig, datasource);
});
},
function createLayergroup(err, mapConfig_, rendererParams) {
assert.ifError(err);
mapConfig = mapConfig_;

View File

@ -15,11 +15,12 @@ var userMiddleware = require('../middleware/user');
* @param {TemplateMaps} templateMaps
* @constructor
*/
function NamedMapsAdminController(authApi, pgConnection, templateMaps) {
function NamedMapsAdminController(authApi, pgConnection, templateMaps, turboCartoCssAdapter) {
BaseController.call(this, authApi, pgConnection);
this.authApi = authApi;
this.templateMaps = templateMaps;
this.turboCartoCssAdapter = turboCartoCssAdapter;
}
util.inherits(NamedMapsAdminController, BaseController);
@ -44,11 +45,30 @@ NamedMapsAdminController.prototype.create = function(req, res) {
function checkPerms(){
self.authApi.authorizedByAPIKey(cdbuser, req, this);
},
function addTemplate(err, authenticated) {
function parseTurboCartoCss(err, authenticated) {
assert.ifError(err);
ifUnauthenticated(authenticated, 'Only authenticated users can get template maps');
ifInvalidContentType(req, 'template POST data must be of type application/json');
var next = this;
var cfg = req.body;
self.turboCartoCssAdapter.getLayers(req.context.user, cfg.layergroup.layers, function (err, layers) {
if (err) {
return next(err);
}
if (layers) {
cfg.layergroup.layers = layers;
}
return next(null, cfg);
});
},
function addTemplate(err, cfg) {
assert.ifError(err);
self.templateMaps.addTemplate(cdbuser, cfg, this);
},
function prepareResponse(err, tpl_id){

View File

@ -196,7 +196,7 @@ module.exports = function(serverOptions) {
metadataBackend
).register(app);
new controller.NamedMapsAdmin(authApi, pgConnection, templateMaps).register(app);
new controller.NamedMapsAdmin(authApi, pgConnection, templateMaps, turboCartocssAdapter).register(app);
new controller.ServerInfo().register(app);

View File

@ -32,7 +32,9 @@ TurboCartocssAdapter.prototype.getLayers = function (username, layers, callback)
TurboCartocssAdapter.prototype._parseCartoCss = function (username, layer, callback) {
if (isNotLayerToParseCartocss(layer)) {
return callback(null, layer);
return process.nextTick(function () {
callback(null, layer);
});
}
this.turboCartocssParser.process(username, layer.options.cartocss, layer.options.sql, function (err, cartocss) {
@ -46,7 +48,7 @@ TurboCartocssAdapter.prototype._parseCartoCss = function (username, layer, callb
};
function isNotLayerToParseCartocss(layer) {
if ( layer.type !== 'mapnik' && layer.type !== 'cartodb' && layer.type !== 'torque' ) {
if (!layer || !layer.options || !layer.options.cartocss || !layer.options.sql) {
return true;
}

View File

@ -38,7 +38,7 @@ function makeMapconfig(cartocss) {
};
}
describe('turbo-cartocss', function() {
describe('turbo-cartocss for anonymous maps', function() {
describe('parsing ramp function with colorbrewer for greens and mapnik renderer', function () {
beforeEach(function () {
var turboCartocss = '#layer { marker-fill: ramp([price], colorbrewer(Greens)); }';

View File

@ -0,0 +1,182 @@
var assert = require('../support/assert');
var step = require('step');
var LayergroupToken = require('../../lib/cartodb/models/layergroup_token');
var testHelper = require(__dirname + '/../support/test_helper');
var CartodbWindshaft = require(__dirname + '/../../lib/cartodb/server');
var serverOptions = require(__dirname + '/../../lib/cartodb/server_options');
var server = new CartodbWindshaft(serverOptions);
describe('turbo-cartocss for named maps', function() {
var keysToDelete;
beforeEach(function() {
keysToDelete = {};
});
afterEach(function(done) {
testHelper.deleteRedisKeys(keysToDelete, done);
});
var expectedCartocss = [
'#layer {',
' marker-allow-overlap:true;',
' marker-fill:#fee5d9;',
' [ price > 10.25 ] { marker-fill:#fcae91}',
' [ price > 10.75 ] { marker-fill:#fb6a4a}',
' [ price > 11.5 ] { marker-fill:#de2d26}',
' [ price > 16.5 ] { marker-fill:#a50f15}',
'}'
].join('');
var templateId = 'turbo-cartocss-template-1';
var template = {
version: '0.0.1',
name: templateId,
auth: { method: 'open' },
layergroup: {
version: '1.0.0',
layers: [{
options: {
sql: [
'SELECT test_table.*, _prices.price FROM test_table JOIN (' +
' SELECT 1 AS cartodb_id, 10.00 AS price',
' UNION',
' SELECT 2, 10.50',
' UNION',
' SELECT 3, 11.00',
' UNION',
' SELECT 4, 12.00',
' UNION',
' SELECT 5, 21.00',
') _prices ON _prices.cartodb_id = test_table.cartodb_id'
].join('\n'),
cartocss: [
'#layer {' +
' marker-fill: ramp([price], colorbrewer(Reds));' +
' marker-allow-overlap:true;' +
'}'
].join(''),
cartocss_version: '2.0.2'
}
}
]
}
};
var layergroup = {
version: '1.3.0',
layers: [{
type: 'named',
options: {
name: templateId,
}
}]
};
it('should create a template with turbo-cartocss parsed properly', function (done) {
step(
function postTemplate() {
var next = this;
assert.response(server, {
url: '/api/v1/map/named?api_key=1234',
method: 'POST',
headers: { host: 'localhost', 'Content-Type': 'application/json' },
data: JSON.stringify(template)
}, {},
function (res, err) {
next(err, res);
});
},
function checkTemplate(err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert.deepEqual(JSON.parse(res.body), {
template_id: templateId
});
return null;
},
function createLayergroup(err) {
assert.ifError(err);
var next = this;
assert.response(server, {
url: '/api/v1/map',
method: 'POST',
headers: { host: 'localhost', 'Content-Type': 'application/json' },
data: JSON.stringify(layergroup)
}, {},
function (res, err) {
next(err, res);
});
},
function checkLayergroup(err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
var parsedBody = JSON.parse(res.body);
keysToDelete['map_cfg|' + LayergroupToken.parse(parsedBody.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
assert.ok(parsedBody.layergroupid);
assert.ok(parsedBody.last_updated);
assert.deepEqual(parsedBody.metadata.layers[0].meta.cartocss, expectedCartocss);
return parsedBody.layergroupid;
},
function requestTile(err, layergroupId) {
assert.ifError(err);
var next = this;
assert.response(server, {
url: '/api/v1/map/' + layergroupId + '/0/0/0.png',
method: 'GET',
headers: { host: 'localhost' },
encoding: 'binary'
}, {},
function(res, err) {
next(err, res);
});
},
function checkTile(err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert.equal(res.headers['content-type'], 'image/png');
testHelper.checkCache(res);
return null;
},
function deleteTemplate(err) {
assert.ifError(err);
var next = this;
assert.response(server, {
url: '/api/v1/map/named/' + templateId + '?api_key=1234',
method: 'DELETE',
headers: { host: 'localhost' }
}, {}, function (res, err) {
next(err, res);
});
},
function checkDeleteTemplate(err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 204);
assert.ok(!res.body);
return null;
},
function finish(err) {
done(err);
}
);
});
});