diff --git a/lib/cartodb/models/mapconfig/adapter/mapconfig-named-layers-adapter.js b/lib/cartodb/models/mapconfig/adapter/mapconfig-named-layers-adapter.js index fd00e344..17c2059f 100644 --- a/lib/cartodb/models/mapconfig/adapter/mapconfig-named-layers-adapter.js +++ b/lib/cartodb/models/mapconfig/adapter/mapconfig-named-layers-adapter.js @@ -43,7 +43,6 @@ MapConfigNamedLayersAdapter.prototype.getMapConfig = function (user, requestMapC if (nestedNamedLayers.length > 0) { var nestedNamedMapsError = new Error('Nested named layers are not allowed'); - // nestedNamedMapsError.http_status = 400; return done(nestedNamedMapsError); } diff --git a/lib/cartodb/models/mapconfig/adapter/mapconfig-named-map-adapter.js b/lib/cartodb/models/mapconfig/adapter/mapconfig-named-map-adapter.js new file mode 100644 index 00000000..76e8f3f5 --- /dev/null +++ b/lib/cartodb/models/mapconfig/adapter/mapconfig-named-map-adapter.js @@ -0,0 +1,35 @@ +var _ = require('underscore'); + +function MapConfigNamedMapAdapter() { +} + +module.exports = MapConfigNamedMapAdapter; + +MapConfigNamedMapAdapter.prototype.getMapConfig = function (user, requestMapConfig, params, context, callback) { + if (context.templateParams && + context.templateParams.buffersize && + isValidBufferSize(context.templateParams.buffersize)) { + requestMapConfig.buffersize = context.templateParams.buffersize; + } + + process.nextTick(function () { + callback(null, requestMapConfig); + }); +}; + +function isValidBufferSize (bufferSize) { + var formats = ['png', 'png32', 'mvt', 'grid.json', 'geojson']; + + if (!_.isObject(bufferSize) || (_.isArray(bufferSize) || _.isFunction(bufferSize))) { + return false; + } + + for (var index = 0; index < formats.length; index++) { + var bufferSizeByFormat = bufferSize[formats[index]]; + if (bufferSizeByFormat && !Number.isFinite(bufferSizeByFormat)) { + return false; + } + } + + return true; +} diff --git a/lib/cartodb/models/mapconfig/provider/named-map-provider.js b/lib/cartodb/models/mapconfig/provider/named-map-provider.js index 2439a650..594ec247 100644 --- a/lib/cartodb/models/mapconfig/provider/named-map-provider.js +++ b/lib/cartodb/models/mapconfig/provider/named-map-provider.js @@ -90,6 +90,7 @@ NamedMapMapConfigProvider.prototype.getMapConfig = function(callback) { }, function instantiateTemplate(err, templateParams) { assert.ifError(err); + context.templateParams = templateParams; return self.templateMaps.instance(self.template, templateParams); }, function prepareAdapterMapConfig(err, requestMapConfig) { diff --git a/lib/cartodb/server.js b/lib/cartodb/server.js index b695a367..22b14f5b 100644 --- a/lib/cartodb/server.js +++ b/lib/cartodb/server.js @@ -35,6 +35,7 @@ var timeoutErrorTile = require('fs').readFileSync(timeoutErrorTilePath, {encodin var SqlWrapMapConfigAdapter = require('./models/mapconfig/adapter/sql-wrap-mapconfig-adapter'); var MapConfigNamedLayersAdapter = require('./models/mapconfig/adapter/mapconfig-named-layers-adapter'); +var MapConfigNamedMapAdapter = require('./models/mapconfig/adapter/mapconfig-named-map-adapter'); var AnalysisMapConfigAdapter = require('./models/mapconfig/adapter/analysis-mapconfig-adapter'); var MapConfigOverviewsAdapter = require('./models/mapconfig/adapter/mapconfig-overviews-adapter'); var TurboCartoAdapter = require('./models/mapconfig/adapter/turbo-carto-adapter'); @@ -155,6 +156,7 @@ module.exports = function(serverOptions) { var mapConfigAdapter = new MapConfigAdapter( new MapConfigNamedLayersAdapter(templateMaps, pgConnection), + new MapConfigNamedMapAdapter(), new SqlWrapMapConfigAdapter(), new DataviewsWidgetsAdapter(), new AnalysisMapConfigAdapter(analysisBackend), diff --git a/test/acceptance/buffer-size-format.js b/test/acceptance/buffer-size-format.js index 50a11329..8c8f6f7b 100644 --- a/test/acceptance/buffer-size-format.js +++ b/test/acceptance/buffer-size-format.js @@ -1,7 +1,9 @@ require('../support/test_helper'); +var fs = require('fs'); var assert = require('../support/assert'); var TestClient = require('../support/test-client'); +var mapnik = require('windshaft').mapnik; var IMAGE_TOLERANCE_PER_MIL = 5; var CARTOCSS_LABELS = [ @@ -76,7 +78,7 @@ describe('buffer size per format', function () { desc: 'should get mvt tile using buffer-size 0', coords: { z: 7, x: 64, y: 48 }, format: 'mvt', - fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-0.png', + fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-0.mvt', mapConfig: createMapConfig({ mvt: 0 }), assert: function (tile, callback) { var tileJSON = tile.toJSON(); @@ -89,7 +91,7 @@ describe('buffer size per format', function () { desc: 'should get mvt tile using buffer-size 128', coords: { z: 7, x: 64, y: 48 }, format: 'mvt', - fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.png', + fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.mvt', mapConfig: createMapConfig({ mvt: 128 }), assert: function (tile, callback) { var tileJSON = tile.toJSON(); @@ -140,7 +142,7 @@ describe('buffer size per format for named maps', function () { coords: { z: 7, x: 64, y: 48 }, format: 'png', fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-0.png', - template: createBufferSizeTemplate('named-default-buffer-size', '<%= buffersize %>'), + template: createBufferSizeTemplate('named-default-buffer-size', {png: '<%= buffersize %>'}), assert: function (tile, callback) { assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback); } @@ -151,7 +153,7 @@ describe('buffer size per format for named maps', function () { format: 'png', placeholders: { buffersize: 128 }, fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.png', - template: createBufferSizeTemplate('named-custom-buffer-size', '<%= buffersize %>'), + template: createBufferSizeTemplate('named-custom-buffer-size', { png: '<%= buffersize %>'}), assert: function (tile, callback) { assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback); } @@ -214,3 +216,175 @@ describe('buffer size per format for named maps', function () { }); }); }); + + +describe('buffer size per format for named maps w/o placeholders', function () { + var testCases = [ + { + desc: 'should get png tile using buffer-size 0 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'png', + placeholders: { + buffersize: { + png: 0 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-0.png', + template: createBufferSizeTemplate('named-no-buffer-size-png-0', {}, {}), + assert: function (tile, callback) { + assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback); + } + }, + { + desc: 'should get png tile using buffer-size 128 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'png', + placeholders: { + buffersize: { + png: 128 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.png', + template: createBufferSizeTemplate('named-no-buffer-size-png-128', {}, {}), + assert: function (tile, callback) { + assert.imageIsSimilarToFile(tile, this.fixturePath, IMAGE_TOLERANCE_PER_MIL, callback); + } + }, + { + desc: 'should get mvt tile using buffer-size 0 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'mvt', + placeholders: { + buffersize: { + mvt: 0 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.mvt', + template: createBufferSizeTemplate('named-no-buffer-size-mvt', {}, {}), + assert: function (tile, callback) { + var tileJSON = tile.toJSON(); + var features = tileJSON[0].features; + + var dataFixture = fs.readFileSync(this.fixturePath); + var vtile = new mapnik.VectorTile(this.coords.z, this.coords.x, this.coords.y); + vtile.setDataSync(dataFixture); + var vtileJSON = vtile.toJSON(); + var vtileFeatures = vtileJSON[0].features; + + assert.equal(features.length, vtileFeatures.length); + callback(); + } + }, + { + desc: 'should get mvt tile using buffer-size 128 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'mvt', + placeholders: { + buffersize: { + mvt: 128 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-128.mvt', + template: createBufferSizeTemplate('named-no-buffer-size-mvt-128', {}, {}), + assert: function (tile, callback) { + var tileJSON = tile.toJSON(); + var features = tileJSON[0].features; + + var dataFixture = fs.readFileSync(this.fixturePath); + var vtile = new mapnik.VectorTile(this.coords.z, this.coords.x, this.coords.y); + vtile.setDataSync(dataFixture); + var vtileJSON = vtile.toJSON(); + var vtileFeatures = vtileJSON[0].features; + + assert.equal(features.length, vtileFeatures.length); + callback(); + } + }, + { + desc: 'should get geojson tile using buffer-size 0 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'geojson', + placeholders: { + buffersize: { + geojson: 0 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.geojson', + template: createBufferSizeTemplate('named-no-buffer-size-geojson-0', {}, {}), + assert: function (tile, callback) { + var dataFixture = JSON.parse(fs.readFileSync(this.fixturePath)); + assert.equal(tile.features.length, dataFixture.features.length); + callback(); + } + }, + { + desc: 'should get geojson tile using buffer-size 128 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'geojson', + placeholders: { + buffersize: { + geojson: 128 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.geojson', + template: createBufferSizeTemplate('named-no-buffer-size-geojson-128', {}, {}), + assert: function (tile, callback) { + var dataFixture = JSON.parse(fs.readFileSync(this.fixturePath)); + assert.equal(tile.features.length, dataFixture.features.length); + callback(); + } + }, + { + desc: 'should get grid.json tile using buffer-size 0 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'grid.json', + placeholders: { + buffersize: { + 'grid.json': 0 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-grid.json.7.64.48-buffer-size-0.grid.json', + template: createBufferSizeTemplate('named-no-buffer-size-grid-json-0', {}, {}), + assert: function (tile, callback) { + assert.utfgridEqualsFile(tile, this.fixturePath, 2,callback); + } + }, + { + desc: 'should get grid.json tile using buffer-size 128 overriden by template params', + coords: { z: 7, x: 64, y: 48 }, + format: 'grid.json', + placeholders: { + buffersize: { + 'grid.json': 128 + } + }, + fixturePath: './test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.grid.json', + template: createBufferSizeTemplate('named-no-buffer-size-grid-json-128', {}, {}), + assert: function (tile, callback) { + assert.utfgridEqualsFile(tile, this.fixturePath, 2, callback); + } + }, + ]; + + testCases.forEach(function (test) { + it(test.desc, function (done) { + var testClient = new TestClient(test.template, 1234); + var coords = test.coords; + var options = { + format: test.format, + placeholders: test.placeholders + }; + testClient.getTile(coords.z, coords.x, coords.y, options, function (err, res, tile) { + assert.ifError(err); + // To generate images use: + //tile.save(test.fixturePath); + // require('fs').writeFileSync(test.fixturePath, JSON.stringify(tile)); + // require('fs').writeFileSync(test.fixturePath, tile.getDataSync()); + test.assert(tile, function (err) { + assert.ifError(err); + testClient.drain(done); + }); + }); + }); + }); +}); diff --git a/test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.geojson b/test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.geojson new file mode 100644 index 00000000..e89c71dd --- /dev/null +++ b/test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.geojson @@ -0,0 +1 @@ +{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[-53839,4629161]},"properties":{"name":"Alicante","cartodb_id":1200}},{"type":"Feature","geometry":{"type":"Point","coordinates":[242835,5069332]},"properties":{"name":"Barcelona","cartodb_id":5330}},{"type":"Feature","geometry":{"type":"Point","coordinates":[-5567,4861644]},"properties":{"name":"Castello","cartodb_id":1201}},{"type":"Feature","geometry":{"type":"Point","coordinates":[272735,5092314]},"properties":{"name":"Mataro","cartodb_id":615}},{"type":"Feature","geometry":{"type":"Point","coordinates":[-125787,4576600]},"properties":{"name":"Murcia","cartodb_id":952}},{"type":"Feature","geometry":{"type":"Point","coordinates":[295469,4804267]},"properties":{"name":"Palma","cartodb_id":5500}},{"type":"Feature","geometry":{"type":"Point","coordinates":[139148,5030112]},"properties":{"name":"Tarragona","cartodb_id":616}},{"type":"Feature","geometry":{"type":"Point","coordinates":[-44746,4791667]},"properties":{"name":"Valencia","cartodb_id":5942}},{"type":"Feature","geometry":{"type":"Point","coordinates":[-99072,5108695]},"properties":{"name":"Zaragoza","cartodb_id":5932}}]} \ No newline at end of file diff --git a/test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.grid.json b/test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.grid.json new file mode 100644 index 00000000..c06b8d91 --- /dev/null +++ b/test/fixtures/buffer-size/tile-7.64.48-buffer-size-128.grid.json @@ -0,0 +1 @@ +{"grid":[" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," !! ","!!! !!!!! ","!!!!!!! ! ","!!! !!!!! "," !! ! "," "," "," "," "," "," "," "," ### # "," ####### ###"," ####### ## ","$ ## #### ## ","$$ ","$$ ","$$ "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "],"keys":["","9","2","1"],"data":{"1":{"cartodb_id":5942},"2":{"cartodb_id":5500},"9":{"cartodb_id":1201}}} \ No newline at end of file diff --git a/test/fixtures/buffer-size/tile-grid.json.7.64.48-buffer-size-0.grid.json b/test/fixtures/buffer-size/tile-grid.json.7.64.48-buffer-size-0.grid.json new file mode 100644 index 00000000..24581bc3 --- /dev/null +++ b/test/fixtures/buffer-size/tile-grid.json.7.64.48-buffer-size-0.grid.json @@ -0,0 +1 @@ +{"grid":[" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," !!! ! "," !!!!!!! !!!"," !!!!!!! !! "," !! !!!! !! "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "],"keys":["","1"],"data":{"1":{"cartodb_id":5500}}} \ No newline at end of file diff --git a/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.geojson b/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.geojson new file mode 100644 index 00000000..500fb3ea --- /dev/null +++ b/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.geojson @@ -0,0 +1 @@ +{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[295469,4804267]},"properties":{"name":"Palma","cartodb_id":5500}}]} \ No newline at end of file diff --git a/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.mvt b/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.mvt new file mode 100644 index 00000000..b87f1b9a Binary files /dev/null and b/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-0.mvt differ diff --git a/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-128.mvt b/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-128.mvt new file mode 100644 index 00000000..c6e54212 Binary files /dev/null and b/test/fixtures/buffer-size/tile-mvt-7.64.48-buffer-size-128.mvt differ diff --git a/test/support/test-client.js b/test/support/test-client.js index b2a326b8..bbb32c9d 100644 --- a/test/support/test-client.js +++ b/test/support/test-client.js @@ -545,6 +545,20 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { expectedResponse.headers['Content-Type'] = 'application/x-protobuf'; } + var isGeojson = format.match(/geojson$/); + + if (isGeojson) { + request.encoding = 'utf-8'; + expectedResponse.headers['Content-Type'] = 'application/json; charset=utf-8'; + } + + var isGridJSON = format.match(/grid.json$/); + + if (isGridJSON) { + request.encoding = 'utf-8'; + expectedResponse.headers['Content-Type'] = 'application/json; charset=utf-8'; + } + assert.response(server, request, expectedResponse, function(res, err) { assert.ifError(err); @@ -557,7 +571,6 @@ TestClient.prototype.getTile = function(z, x, y, params, callback) { obj = new mapnik.VectorTile(z, x, y); obj.setDataSync(new Buffer(res.body, 'binary')); } - else { obj = JSON.parse(res.body); }