From ad0b2ffc8e77982dbb4cc7cb9f089bebd6c6782e Mon Sep 17 00:00:00 2001 From: javi Date: Wed, 29 Jan 2014 13:11:37 +0100 Subject: [PATCH] added support for template instanciation with jsonp closes #116 --- lib/cartodb/cartodb_windshaft.js | 67 ++++++++++++--- test/acceptance/templates.js | 139 +++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 13 deletions(-) diff --git a/lib/cartodb/cartodb_windshaft.js b/lib/cartodb/cartodb_windshaft.js index 079c7588..ca77df79 100644 --- a/lib/cartodb/cartodb_windshaft.js +++ b/lib/cartodb/cartodb_windshaft.js @@ -393,7 +393,7 @@ var CartodbWindshaft = function(serverOptions) { }); // Instantiate a template - ws.post(template_baseurl + '/:template_id', function(req, res) { + function instanciate(req, res, template_params, callback) { ws.doCORS(res); var that = this; var response = {}; @@ -437,9 +437,10 @@ var CartodbWindshaft = function(serverOptions) { err.http_status = 401; throw err; } - if ( ! req.headers['content-type'] || req.headers['content-type'].split(';')[0] != 'application/json' ) + /*if ( (! req.headers['content-type'] || req.headers['content-type'].split(';')[0] != 'application/json') && req.query.callback === undefined) { throw new Error('template POST data must be of type application/json, it is instead '); - var template_params = req.body; + }*/ + //var template_params = req.body; return templateMaps.instance(template, template_params); }, function prepareParams(err, instance){ @@ -481,17 +482,57 @@ var CartodbWindshaft = function(serverOptions) { response.layergroupid = cdbuser + '@' + response.layergroupid; return response; }, - function finish(err, response){ - if (err){ - var statusCode = 400; - response = { error: ''+err }; - if ( ! _.isUndefined(err.http_status) ) { - statusCode = err.http_status; - } - ws.sendError(res, response, statusCode, 'POST INSTANCE TEMPLATE', err.message); - } else { - res.send(response, 200); + callback + ); + } + + function finish_instanciation(err, response, res) { + if (err) { + var statusCode = 400; + response = { error: ''+err }; + if ( ! _.isUndefined(err.http_status) ) { + statusCode = err.http_status; } + ws.sendError(res, response, statusCode, 'POST INSTANCE TEMPLATE', err.message); + } else { + res.send(response, 200); + } + } + + ws.post(template_baseurl + '/:template_id', function(req, res) { + Step( + function() { + if ( ! req.headers['content-type'] || req.headers['content-type'].split(';')[0] != 'application/json') { + throw new Error('template POST data must be of type application/json, it is instead '); + } + instanciate(req, res, req.body, this); + }, function(err, response) { + finish_instanciation(err, response, res); + } + ); + }); + + /** + * jsonp endpoint, allows to instanciate a template with a json call. + * callback query argument is mandartoy + */ + ws.get(template_baseurl + '/:template_id/jsonp', function(req, res) { + Step( + function() { + if ( req.query.callback === undefined || req.query.callback.length === 0) { + throw new Error('callback parameter should be present and be a function name'); + } + var config = {}; + if(req.query.config) { + try { + config = JSON.parse(req.query.config); + } catch(e) { + throw new Error('badformed config parameter, should be a valid JSON'); + } + } + instanciate(req, res, config, this); + }, function(err, response) { + finish_instanciation(err, response, res); } ); }); diff --git a/test/acceptance/templates.js b/test/acceptance/templates.js index 6d7a14de..08938b41 100644 --- a/test/acceptance/templates.js +++ b/test/acceptance/templates.js @@ -871,6 +871,145 @@ suite('template_api', function() { ); }); + test("can instanciate a template using jsonp", function(done) { + + // This map fetches data from a private table + var template_acceptance_open = { + version: '0.0.1', + name: 'acceptance_open_jsonp', + auth: { method: 'open' }, + layergroup: { + version: '1.0.0', + layers: [ + { options: { + sql: "select * from test_table_private_1 LIMIT 0", + cartocss: '#layer { marker-fill:blue; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } } + ] + } + }; + + var template_params = {}; + + var errors = []; + var expected_failure = false; + var tpl_id; + var layergroupid; + Step( + function postTemplate(err, res) + { + var next = this; + var post_request = { + url: '/tiles/template?api_key=1234', + method: 'POST', + headers: {host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(template_acceptance_open) + } + assert.response(server, post_request, {}, + function(res) { next(null, res); }); + }, + function instanciateNoAuth(err, res) + { + if ( err ) throw err; + assert.equal(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.hasOwnProperty('template_id'), + "Missing 'template_id' from response body: " + res.body); + tpl_id = parsed.template_id; + var post_request = { + url: '/tiles/template/' + tpl_id + "/jsonp?callback=test", + method: 'GET', + headers: {host: 'localhost' } + } + var next = this; + assert.response(server, post_request, {}, + function(res) { next(null, res); }); + }, + function instanciateAuth(err, res) + { + if ( err ) throw err; + assert.equal(res.statusCode, 200, + 'Unexpected success instanciating template with no auth: ' + + res.statusCode + ': ' + res.body); + done(); + } + ); + }); + + test("can instanciate a template using jsonp with params", function(done) { + + // This map fetches data from a private table + var template_acceptance_open = { + version: '0.0.1', + name: 'acceptance_open_jsonp_params', + auth: { method: 'open' }, + /* + placeholders: { + color: { type: "css_color", default: "red" } + },*/ + layergroup: { + version: '1.0.0', + layers: [ + { options: { + sql: "select * from test_table_private_1 LIMIT 0", + cartocss: '#layer { marker-fill: <%= color %>; marker-allow-overlap:true; }', + cartocss_version: '2.0.2', + interactivity: 'cartodb_id' + } } + ] + } + }; + + var template_params = {}; + + var errors = []; + var expected_failure = false; + var tpl_id; + var layergroupid; + Step( + function postTemplate(err, res) + { + var next = this; + var post_request = { + url: '/tiles/template?api_key=1234', + method: 'POST', + headers: {host: 'localhost', 'Content-Type': 'application/json' }, + data: JSON.stringify(template_acceptance_open) + } + assert.response(server, post_request, {}, + function(res) { next(null, res); }); + }, + function instanciateNoAuth(err, res) + { + if ( err ) throw err; + assert.equal(res.statusCode, 200, res.body); + var parsed = JSON.parse(res.body); + assert.ok(parsed.hasOwnProperty('template_id'), + "Missing 'template_id' from response body: " + res.body); + tpl_id = parsed.template_id; + var post_request = { + url: '/tiles/template/' + tpl_id + "/jsonp?callback=test%config=" + JSON.stringify('{color:blue}'), + method: 'GET', + headers: {host: 'localhost' } + } + var next = this; + assert.response(server, post_request, {}, + function(res) { next(null, res); }); + }, + function instanciateAuth(err, res) + { + if ( err ) throw err; + assert.equal(res.statusCode, 200, + 'Unexpected success instanciating template with no auth: ' + + res.statusCode + ': ' + res.body); + done(); + } + ); + }); + + test("template instantiation raises mapviews counter", function(done) { var layergroup = {