diff --git a/NEWS.md b/NEWS.md index e5ee91f7..3ebb1502 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,13 +1,27 @@ # Changelog -## 5.4.0 +## 5.4.1 Released yyyy-mm-dd - - Upgrades Windshaft to 4.5.6 ([Mapnik top metrics](https://github.com/CartoDB/Windshaft/pull/597), [AttributesBackend allows multiple features if all the attributes are the same](https://github.com/CartoDB/Windshaft/pull/602)) + - Upgrades camshaft to 0.61.8 + + +## 5.4.0 +Released 2018-03-15 + - Upgrades Windshaft to 4.5.7 ([Mapnik top metrics](https://github.com/CartoDB/Windshaft/pull/597), [AttributesBackend allows multiple features if all the attributes are the same](https://github.com/CartoDB/Windshaft/pull/602)) - Implemented middleware to authorize users via new Api Key system - Keep the old authorization system as fallback - Aggregation widget: Remove NULL categories in 'count' aggregations too - Update request to 2.85.0 - - Update camshaft to 0.61.3 (Fixes duplicated cartodb_id in AOI) + - Update camshaft to 0.61.4 (Fixes for AOI and Merge analyses) + - Update windshaft to 4.6.0, which in turn updates @carto/mapnik to 3.6.2-carto.4 and related dependencies. It brings in a cache for rasterized symbols. See https://github.com/CartoDB/node-mapnik/blob/v3.6.2-carto/CHANGELOG.carto.md#362-carto4 + - PostGIS: Variables in postgis SQL queries must now additionally be wrapped in `!` (refs [#29](https://github.com/CartoDB/mapnik/issues/29), [mapnik/#3618](https://github.com/mapnik/mapnik/pull/3618)): +```sql +-- Before +SELECT ... WHERE trait = @variable + +-- Now +SELECT ... WHERE trait = !@variable! +``` ## 5.3.1 Released 2018-02-13 diff --git a/lib/cartodb/controllers/analyses.js b/lib/cartodb/controllers/analyses.js index 38b906b8..3ed0d5a4 100644 --- a/lib/cartodb/controllers/analyses.js +++ b/lib/cartodb/controllers/analyses.js @@ -18,24 +18,24 @@ AnalysesController.prototype.register = function (app) { userMiddleware(), rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.ANALYSIS_CATALOG), this.prepareContext, - this.createPGClient(), - this.getDataFromQuery({ queryTemplate: catalogQueryTpl, key: 'catalog' }), - this.getDataFromQuery({ queryTemplate: tablesQueryTpl, key: 'tables' }), - this.prepareResponse(), - this.setCacheControlHeader(), - this.sendResponse(), - this.unathorizedError() + createPGClient(), + getDataFromQuery({ queryTemplate: catalogQueryTpl, key: 'catalog' }), + getDataFromQuery({ queryTemplate: tablesQueryTpl, key: 'tables' }), + prepareResponse(), + setCacheControlHeader(), + sendResponse(), + unauthorizedError() ); }; -AnalysesController.prototype.createPGClient = function () { +function createPGClient () { return function createPGClientMiddleware (req, res, next) { res.locals.pg = new PSQL(dbParamsFromReqParams(res.locals)); next(); }; -}; +} -AnalysesController.prototype.getDataFromQuery = function ({ queryTemplate, key }) { +function getDataFromQuery({ queryTemplate, key }) { const readOnlyTransactionOn = true; return function getCatalogMiddleware(req, res, next) { @@ -52,9 +52,9 @@ AnalysesController.prototype.getDataFromQuery = function ({ queryTemplate, key } next(); }, readOnlyTransactionOn); }; -}; +} -AnalysesController.prototype.prepareResponse = function () { +function prepareResponse () { return function prepareResponseMiddleware (req, res, next) { const { catalog, tables } = res.locals; @@ -95,16 +95,16 @@ AnalysesController.prototype.prepareResponse = function () { next(); }; -}; +} -AnalysesController.prototype.setCacheControlHeader = function () { +function setCacheControlHeader () { return function setCacheControlHeaderMiddleware (req, res, next) { res.set('Cache-Control', 'public,max-age=10,must-revalidate'); next(); }; -}; +} -AnalysesController.prototype.sendResponse = function() { +function sendResponse () { return function sendResponseMiddleware (req, res) { res.status(200); @@ -114,9 +114,9 @@ AnalysesController.prototype.sendResponse = function() { res.json(res.body); } }; -}; +} -AnalysesController.prototype.unathorizedError = function () { +function unauthorizedError () { return function unathorizedErrorMiddleware(err, req, res, next) { if (err.message.match(/permission\sdenied/)) { err = new Error('Unauthorized'); @@ -125,7 +125,7 @@ AnalysesController.prototype.unathorizedError = function () { next(err); }; -}; +} const catalogQueryTpl = ctx => ` SELECT analysis_def->>'type' as type, * FROM cdb_analysis_catalog WHERE username = '${ctx._username}' diff --git a/lib/cartodb/controllers/named_maps.js b/lib/cartodb/controllers/named_maps.js index 64c1f403..04b80ff4 100644 --- a/lib/cartodb/controllers/named_maps.js +++ b/lib/cartodb/controllers/named_maps.js @@ -52,57 +52,62 @@ function NamedMapsController( module.exports = NamedMapsController; NamedMapsController.prototype.register = function(app) { - const tileOptions = { - label: 'NAMED_MAP_TILE' - }; + const { base_url_mapconfig, base_url_templated } = app; app.get( - app.base_url_templated + '/:template_id/:layer/:z/:x/:y.(:format)', + `${base_url_templated}/:template_id/:layer/:z/:x/:y.(:format)`, cors(), userMiddleware(), rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_TILES), this.prepareContext, - this.getNamedMapProvider(tileOptions), - this.getAffectedTables(), - this.getTile(tileOptions), - this.setSurrogateKey(), - this.setCacheChannelHeader(), - this.setLastModifiedHeader(), - this.setCacheControlHeader(), - this.setContentTypeHeader(), - this.respond(), + getNamedMapProvider({ + namedMapProviderCache: this.namedMapProviderCache, + label: 'NAMED_MAP_TILE' + }), + getAffectedTables(), + getTile({ + tileBackend: this.tileBackend, + label: 'NAMED_MAP_TILE' + }), + setSurrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), + setCacheChannelHeader(), + setLastModifiedHeader(), + setCacheControlHeader(), + setContentTypeHeader(), + sendResponse(), vectorError() ); - const staticOptions = { - forcedFormat: 'png', - label: 'STATIC_VIZ_MAP' - }; - app.get( - app.base_url_mapconfig + '/static/named/:template_id/:width/:height.:format', + `${base_url_mapconfig}/static/named/:template_id/:width/:height.:format`, cors(), userMiddleware(), rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.STATIC_NAMED), allowQueryParams(['layer', 'zoom', 'lon', 'lat', 'bbox']), this.prepareContext, - this.getNamedMapProvider(staticOptions), - this.getAffectedTables(), - this.getTemplate(staticOptions), - this.prepareLayerFilterFromPreviewLayers(staticOptions), - this.getStaticImageOptions(), - this.getImage(staticOptions), - this.incrementMapViews(), - this.setSurrogateKey(), - this.setCacheChannelHeader(), - this.setLastModifiedHeader(), - this.setCacheControlHeader(), - this.setContentTypeHeader(), - this.respond() + getNamedMapProvider({ + namedMapProviderCache: this.namedMapProviderCache, + label: 'STATIC_VIZ_MAP', forcedFormat: 'png' + }), + getAffectedTables(), + getTemplate({ label: 'STATIC_VIZ_MAP' }), + prepareLayerFilterFromPreviewLayers({ + namedMapProviderCache: this.namedMapProviderCache, + label: 'STATIC_VIZ_MAP' + }), + getStaticImageOptions({ tablesExtentApi: this.tablesExtentApi }), + getImage({ previewBackend: this.previewBackend, label: 'STATIC_VIZ_MAP' }), + incrementMapViews({ metadataBackend: this.metadataBackend }), + setSurrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), + setCacheChannelHeader(), + setLastModifiedHeader(), + setCacheControlHeader(), + setContentTypeHeader(), + sendResponse() ); }; -NamedMapsController.prototype.getNamedMapProvider = function ({ label, forcedFormat = null }) { +function getNamedMapProvider ({ namedMapProviderCache, label, forcedFormat = null }) { return function getNamedMapProviderMiddleware (req, res, next) { const { user } = res.locals; const { config, auth_token } = req.query; @@ -115,7 +120,7 @@ NamedMapsController.prototype.getNamedMapProvider = function ({ label, forcedFor const params = getRequestParams(res.locals); - this.namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, namedMapProvider) => { + namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, namedMapProvider) => { if (err) { err.label = label; return next(err); @@ -125,10 +130,10 @@ NamedMapsController.prototype.getNamedMapProvider = function ({ label, forcedFor next(); }); - }.bind(this); -}; + }; +} -NamedMapsController.prototype.getAffectedTables = function () { +function getAffectedTables () { return function getAffectedTables (req, res, next) { const { namedMapProvider } = res.locals; @@ -143,10 +148,10 @@ NamedMapsController.prototype.getAffectedTables = function () { next(); }); - }.bind(this); -}; + }; +} -NamedMapsController.prototype.getTemplate = function ({ label }) { +function getTemplate ({ label }) { return function getTemplateMiddleware (req, res, next) { const { namedMapProvider } = res.locals; @@ -161,9 +166,9 @@ NamedMapsController.prototype.getTemplate = function ({ label }) { next(); }); }; -}; +} -NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function ({ label }) { +function prepareLayerFilterFromPreviewLayers ({ namedMapProviderCache, label }) { return function prepareLayerFilterFromPreviewLayersMiddleware (req, res, next) { const { user, template } = res.locals; const { template_id } = req.params; @@ -192,7 +197,7 @@ NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function ({ params.layer = layerVisibilityFilter.join(','); // recreates the provider - this.namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, provider) => { + namedMapProviderCache.get(user, template_id, config, auth_token, params, (err, provider) => { if (err) { err.label = label; return next(err); @@ -202,14 +207,14 @@ NamedMapsController.prototype.prepareLayerFilterFromPreviewLayers = function ({ next(); }); - }.bind(this); -}; + }; +} -NamedMapsController.prototype.getTile = function ({ label }) { +function getTile ({ tileBackend, label }) { return function getTileMiddleware (req, res, next) { const { namedMapProvider } = res.locals; - this.tileBackend.getTile(namedMapProvider, req.params, (err, tile, headers, stats) => { + tileBackend.getTile(namedMapProvider, req.params, (err, tile, headers, stats) => { req.profiler.add(stats); if (err) { @@ -223,10 +228,10 @@ NamedMapsController.prototype.getTile = function ({ label }) { next(); }); - }.bind(this); -}; + }; +} -NamedMapsController.prototype.getStaticImageOptions = function () { +function getStaticImageOptions ({ tablesExtentApi }) { return function getStaticImageOptionsMiddleware(req, res, next) { const { user, namedMapProvider, template } = res.locals; @@ -250,7 +255,7 @@ NamedMapsController.prototype.getStaticImageOptions = function () { return next(); } - this.tablesExtentApi.getBounds(user, affectedTables, (err, bounds) => { + tablesExtentApi.getBounds(user, affectedTables, (err, bounds) => { if (err) { return next(); } @@ -260,8 +265,8 @@ NamedMapsController.prototype.getStaticImageOptions = function () { return next(); }); }); - }.bind(this); -}; + }; +} function getImageOptions (params, template) { const { zoom, lon, lat, bbox } = params; @@ -328,7 +333,7 @@ function getImageOptionsFromBoundingBox (bbox = '') { } } -NamedMapsController.prototype.getImage = function ({ label }) { +function getImage({ previewBackend, label }) { return function getImageMiddleware (req, res, next) { const { imageOpts, namedMapProvider } = res.locals; const { zoom, center, bounds } = imageOpts; @@ -341,7 +346,7 @@ NamedMapsController.prototype.getImage = function ({ label }) { const format = req.params.format === 'jpg' ? 'jpeg' : 'png'; if (zoom !== undefined && center) { - return this.previewBackend.getImage(namedMapProvider, format, width, height, zoom, center, + return previewBackend.getImage(namedMapProvider, format, width, height, zoom, center, (err, image, headers, stats) => { if (err) { err.label = label; @@ -356,7 +361,7 @@ NamedMapsController.prototype.getImage = function ({ label }) { }); } - this.previewBackend.getImage(namedMapProvider, format, width, height, bounds, (err, image, headers, stats) => { + previewBackend.getImage(namedMapProvider, format, width, height, bounds, (err, image, headers, stats) => { if (err) { err.label = label; return next(err); @@ -368,14 +373,14 @@ NamedMapsController.prototype.getImage = function ({ label }) { next(); }); - }.bind(this); -}; + }; +} function incrementMapViewsError (ctx) { return `ERROR: failed to increment mapview count for user '${ctx.user}': ${ctx.err}`; } -NamedMapsController.prototype.incrementMapViews = function () { +function incrementMapViews ({ metadataBackend }) { return function incrementMapViewsMiddleware(req, res, next) { const { user, namedMapProvider } = res.locals; @@ -387,7 +392,7 @@ NamedMapsController.prototype.incrementMapViews = function () { const statTag = mapConfig.obj().stat_tag; - this.metadataBackend.incMapviewCount(user, statTag, (err) => { + metadataBackend.incMapviewCount(user, statTag, (err) => { if (err) { global.logger.log(incrementMapViewsError({ user, err })); } @@ -395,8 +400,8 @@ NamedMapsController.prototype.incrementMapViews = function () { next(); }); }); - }.bind(this); -}; + }; +} function templateZoomCenter(view) { if (view.zoom !== undefined && view.center) { @@ -428,7 +433,22 @@ function templateBounds(view) { return false; } -NamedMapsController.prototype.setCacheChannelHeader = function () { +function setSurrogateKeyHeader ({ surrogateKeysCache }) { + return function setSurrogateKeyHeaderMiddleware(req, res, next) { + const { user, namedMapProvider, affectedTablesAndLastUpdate } = res.locals; + + surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, namedMapProvider.getTemplateName())); + if (!affectedTablesAndLastUpdate || !!affectedTablesAndLastUpdate.tables) { + if (affectedTablesAndLastUpdate.tables.length > 0) { + surrogateKeysCache.tag(res, affectedTablesAndLastUpdate); + } + } + + next(); + }; +} + +function setCacheChannelHeader () { return function setCacheChannelHeaderMiddleware (req, res, next) { const { affectedTablesAndLastUpdate } = res.locals; @@ -438,24 +458,9 @@ NamedMapsController.prototype.setCacheChannelHeader = function () { next(); }; -}; +} -NamedMapsController.prototype.setSurrogateKey = function () { - return function setSurrogateKeyMiddleware(req, res, next) { - const { user, namedMapProvider, affectedTablesAndLastUpdate } = res.locals; - - this.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, namedMapProvider.getTemplateName())); - if (!affectedTablesAndLastUpdate || !!affectedTablesAndLastUpdate.tables) { - if (affectedTablesAndLastUpdate.tables.length > 0) { - this.surrogateKeysCache.tag(res, affectedTablesAndLastUpdate); - } - } - - next(); - }.bind(this); -}; - -NamedMapsController.prototype.setLastModifiedHeader = function () { +function setLastModifiedHeader () { return function setLastModifiedHeaderMiddleware(req, res, next) { const { affectedTablesAndLastUpdate } = res.locals; @@ -472,9 +477,9 @@ NamedMapsController.prototype.setLastModifiedHeader = function () { next(); }; - }; + } -NamedMapsController.prototype.setCacheControlHeader = function () { +function setCacheControlHeader () { return function setCacheControlHeaderMiddleware(req, res, next) { const { affectedTablesAndLastUpdate } = res.locals; @@ -487,9 +492,9 @@ NamedMapsController.prototype.setCacheControlHeader = function () { next(); }; - }; + } -NamedMapsController.prototype.setContentTypeHeader = function () { +function setContentTypeHeader () { return function setContentTypeHeaderMiddleware(req, res, next) { const { headers = {} } = res.locals; @@ -497,10 +502,10 @@ NamedMapsController.prototype.setContentTypeHeader = function () { next(); }; -}; +} -NamedMapsController.prototype.respond = function () { - return function respondMiddleware (req, res) { +function sendResponse () { + return function sendResponseMiddleware (req, res) { const { body, stats = {}, format } = res.locals; req.profiler.done('render-' + format); @@ -509,4 +514,4 @@ NamedMapsController.prototype.respond = function () { res.status(200); res.send(body); }; -}; +} diff --git a/lib/cartodb/controllers/named_maps_admin.js b/lib/cartodb/controllers/named_maps_admin.js index 74e46639..c9ba652e 100644 --- a/lib/cartodb/controllers/named_maps_admin.js +++ b/lib/cartodb/controllers/named_maps_admin.js @@ -30,9 +30,10 @@ NamedMapsAdminController.prototype.register = function (app) { rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_CREATE), localsMiddleware(), credentialsMiddleware(), - this.checkContentType('POST', 'POST TEMPLATE'), - this.authorizedByAPIKey('create', 'POST TEMPLATE'), - this.create() + checkContentType({ action: 'POST', label: 'POST TEMPLATE' }), + authorizedByAPIKey({ authApi: this.authApi, action: 'create', label: 'POST TEMPLATE' }), + createTemplate({ templateMaps: this.templateMaps }), + sendResponse() ); app.put( @@ -42,9 +43,10 @@ NamedMapsAdminController.prototype.register = function (app) { rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_UPDATE), localsMiddleware(), credentialsMiddleware(), - this.checkContentType('PUT', 'PUT TEMPLATE'), - this.authorizedByAPIKey('update', 'PUT TEMPLATE'), - this.update() + checkContentType({ action: 'PUT', label: 'PUT TEMPLATE' }), + authorizedByAPIKey({ authApi: this.authApi, action: 'update', label: 'PUT TEMPLATE' }), + updateTemplate({ templateMaps: this.templateMaps }), + sendResponse() ); app.get( @@ -54,8 +56,9 @@ NamedMapsAdminController.prototype.register = function (app) { rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_GET), localsMiddleware(), credentialsMiddleware(), - this.authorizedByAPIKey('get', 'GET TEMPLATE'), - this.retrieve() + authorizedByAPIKey({ authApi: this.authApi, action: 'get', label: 'GET TEMPLATE' }), + retrieveTemplate({ templateMaps: this.templateMaps }), + sendResponse() ); app.delete( @@ -65,8 +68,9 @@ NamedMapsAdminController.prototype.register = function (app) { rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_DELETE), localsMiddleware(), credentialsMiddleware(), - this.authorizedByAPIKey('delete', 'DELETE TEMPLATE'), - this.destroy() + authorizedByAPIKey({ authApi: this.authApi, action: 'delete', label: 'DELETE TEMPLATE' }), + destroyTemplate({ templateMaps: this.templateMaps }), + sendResponse() ); app.get( @@ -76,8 +80,9 @@ NamedMapsAdminController.prototype.register = function (app) { rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_LIST), localsMiddleware(), credentialsMiddleware(), - this.authorizedByAPIKey('list', 'GET TEMPLATE LIST'), - this.list() + authorizedByAPIKey({ authApi: this.authApi, action: 'list', label: 'GET TEMPLATE LIST' }), + listTemplates({ templateMaps: this.templateMaps }), + sendResponse() ); app.options( @@ -86,10 +91,23 @@ NamedMapsAdminController.prototype.register = function (app) { ); }; -NamedMapsAdminController.prototype.authorizedByAPIKey = function (action, label) { +function checkContentType ({ action, label }) { + return function checkContentTypeMiddleware (req, res, next) { + if (!req.is('application/json')) { + const error = new Error(`template ${action} data must be of type application/json`); + error.label = label; + return next(error); + } + + next(); + }; +} + +function authorizedByAPIKey ({ authApi, action, label }) { return function authorizedByAPIKeyMiddleware (req, res, next) { const { user } = res.locals; - this.authApi.authorizedByAPIKey(user, res, (err, authenticated) => { + + authApi.authorizedByAPIKey(user, res, (err, authenticated) => { if (err) { return next(err); } @@ -103,65 +121,52 @@ NamedMapsAdminController.prototype.authorizedByAPIKey = function (action, label) next(); }); - }.bind(this); -}; - -NamedMapsAdminController.prototype.checkContentType = function (action, label) { - return function checkContentTypeMiddleware (req, res, next) { - if (!req.is('application/json')) { - const error = new Error(`template ${action} data must be of type application/json`); - error.label = label; - return next(error); - } - next(); }; -}; +} -NamedMapsAdminController.prototype.create = function () { +function createTemplate ({ templateMaps }) { return function createTemplateMiddleware (req, res, next) { const { user } = res.locals; const template = req.body; - this.templateMaps.addTemplate(user, template, (err, templateId) => { + templateMaps.addTemplate(user, template, (err, templateId) => { if (err) { return next(err); } - res.status(200); + res.body = { template_id: templateId }; - const method = req.query.callback ? 'jsonp' : 'json'; - res[method]({ template_id: templateId }); + next(); }); - }.bind(this); -}; + }; +} -NamedMapsAdminController.prototype.update = function () { +function updateTemplate ({ templateMaps }) { return function updateTemplateMiddleware (req, res, next) { const { user } = res.locals; const template = req.body; const templateId = templateName(req.params.template_id); - this.templateMaps.updTemplate(user, templateId, template, (err) => { + templateMaps.updTemplate(user, templateId, template, (err) => { if (err) { return next(err); } - res.status(200); + res.body = { template_id: templateId }; - const method = req.query.callback ? 'jsonp' : 'json'; - res[method]({ template_id: templateId }); + next(); }); - }.bind(this); -}; + }; +} -NamedMapsAdminController.prototype.retrieve = function () { +function retrieveTemplate ({ templateMaps }) { return function retrieveTemplateMiddleware (req, res, next) { req.profiler.start('windshaft-cartodb.get_template'); const { user } = res.locals; const templateId = templateName(req.params.template_id); - this.templateMaps.getTemplate(user, templateId, (err, template) => { + templateMaps.getTemplate(user, templateId, (err, template) => { if (err) { return next(err); } @@ -175,49 +180,56 @@ NamedMapsAdminController.prototype.retrieve = function () { // so we remove it before returning to the user delete template.auth_id; - res.status(200); + res.body = { template }; - const method = req.query.callback ? 'jsonp' : 'json'; - res[method]({ template }); + next(); }); - }.bind(this); -}; + }; +} -NamedMapsAdminController.prototype.destroy = function () { +function destroyTemplate ({ templateMaps }) { return function destroyTemplateMiddleware (req, res, next) { req.profiler.start('windshaft-cartodb.delete_template'); const { user } = res.locals; const templateId = templateName(req.params.template_id); - this.templateMaps.delTemplate(user, templateId, (err/* , tpl_val */) => { + templateMaps.delTemplate(user, templateId, (err/* , tpl_val */) => { if (err) { return next(err); } - res.status(204); + res.statusCode = 204; + res.body = ''; - const method = req.query.callback ? 'jsonp' : 'json'; - res[method](''); + next(); }); - }.bind(this); -}; + }; +} -NamedMapsAdminController.prototype.list = function () { +function listTemplates ({ templateMaps }) { return function listTemplatesMiddleware (req, res, next) { req.profiler.start('windshaft-cartodb.get_template_list'); const { user } = res.locals; - this.templateMaps.listTemplates(user, (err, templateIds) => { + templateMaps.listTemplates(user, (err, templateIds) => { if (err) { return next(err); } - res.status(200); + res.body = { template_ids: templateIds }; - const method = req.query.callback ? 'jsonp' : 'json'; - res[method]({ template_ids: templateIds }); + next(); }); - }.bind(this); -}; + }; +} + +function sendResponse () { + return function sendResponseMiddleware (req, res) { + res.status(res.statusCode || 200); + + const method = req.query.callback ? 'jsonp' : 'json'; + res[method](res.body); + }; +} diff --git a/package.json b/package.json index f46263c0..0fedede5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "windshaft-cartodb", - "version": "5.3.2", + "version": "5.4.1", "description": "A map tile server for CartoDB", "keywords": [ "cartodb" @@ -26,7 +26,7 @@ "dependencies": { "basic-auth": "^2.0.0", "body-parser": "^1.18.2", - "camshaft": "0.61.3", + "camshaft": "0.61.8", "cartodb-psql": "0.10.2", "cartodb-query-tables": "0.3.0", "cartodb-redis": "cartodb/node-cartodb-redis#rateLimits", @@ -48,7 +48,7 @@ "step-profiler": "~0.3.0", "turbo-carto": "0.20.2", "underscore": "~1.6.0", - "windshaft": "4.5.6", + "windshaft": "4.6.0", "yargs": "~5.0.0" }, "devDependencies": { diff --git a/test/fixtures/analysis/basic-source-id-mapnik-layer.png b/test/fixtures/analysis/basic-source-id-mapnik-layer.png index bdb315a9..41ee8fd5 100644 Binary files a/test/fixtures/analysis/basic-source-id-mapnik-layer.png and b/test/fixtures/analysis/basic-source-id-mapnik-layer.png differ diff --git a/yarn.lock b/yarn.lock index cd78577d..b4bf570c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,20 +2,20 @@ # yarn lockfile v1 -"@carto/mapnik@3.6.2-carto.2", "@carto/mapnik@~3.6.2-carto.0": - version "3.6.2-carto.2" - resolved "https://registry.yarnpkg.com/@carto/mapnik/-/mapnik-3.6.2-carto.2.tgz#45a055fd2d39530a873ef9ce5a325baacc81c196" +"@carto/mapnik@3.6.2-carto.4": + version "3.6.2-carto.4" + resolved "https://registry.yarnpkg.com/@carto/mapnik/-/mapnik-3.6.2-carto.4.tgz#54042a5dbea293c54e1bd286b32277694c5dc2d2" dependencies: mapnik-vector-tile "1.5.0" nan "~2.7.0" node-pre-gyp "~0.6.30" protozero "1.5.1" -"@carto/tilelive-bridge@cartodb/tilelive-bridge#2.5.1-cdb3": - version "2.5.1-cdb3" - resolved "https://codeload.github.com/cartodb/tilelive-bridge/tar.gz/e61c7752c033595a273dcd1d4b267252b174bd28" +"@carto/tilelive-bridge@cartodb/tilelive-bridge#2.5.1-cdb4": + version "2.5.1-cdb4" + resolved "https://codeload.github.com/cartodb/tilelive-bridge/tar.gz/3eb554e5109199f50f457cec72ee288cffa5d6b3" dependencies: - "@carto/mapnik" "3.6.2-carto.2" + "@carto/mapnik" "3.6.2-carto.4" "@mapbox/sphericalmercator" "~1.0.1" mapnik-pool "~0.1.3" @@ -23,11 +23,11 @@ version "1.0.5" resolved "https://registry.yarnpkg.com/@mapbox/sphericalmercator/-/sphericalmercator-1.0.5.tgz#70237b9774095ed1cfdbcea7a8fd1fc82b2691f2" -abaculus@cartodb/abaculus#2.0.3-cdb2: - version "2.0.3-cdb2" - resolved "https://codeload.github.com/cartodb/abaculus/tar.gz/6468e0e3fddb2b23f60b9a3156117cff0307f6dc" +abaculus@cartodb/abaculus#2.0.3-cdb5: + version "2.0.3-cdb5" + resolved "https://codeload.github.com/cartodb/abaculus/tar.gz/b899cbea04b3e6093aa3ef32331920acd5f839a1" dependencies: - "@carto/mapnik" "~3.6.2-carto.0" + "@carto/mapnik" "3.6.2-carto.4" d3-queue "^2.0.2" sphericalmercator "1.0.x" @@ -238,16 +238,16 @@ camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" -camshaft@0.61.3: - version "0.61.3" - resolved "https://registry.yarnpkg.com/camshaft/-/camshaft-0.61.3.tgz#a1507f19e39dbf98940298ba1704b742741a5053" +camshaft@0.61.8: + version "0.61.8" + resolved "https://registry.yarnpkg.com/camshaft/-/camshaft-0.61.8.tgz#75669c6c14791a93433e79a8892298e88cb0fce2" dependencies: async "^1.5.2" bunyan "1.8.1" cartodb-psql "^0.10.1" debug "^3.1.0" dot "^1.0.3" - request "^2.69.0" + request "2.85.0" canvas@cartodb/node-canvas#1.6.2-cdb2: version "1.6.2-cdb2" @@ -1912,7 +1912,7 @@ request@2.85.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@2.x, request@^2.55.0, request@^2.69.0: +request@2.x, request@^2.55.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" dependencies: @@ -2239,11 +2239,11 @@ through@2: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" -tilelive-mapnik@cartodb/tilelive-mapnik#0.6.18-cdb7: - version "0.6.18-cdb7" - resolved "https://codeload.github.com/cartodb/tilelive-mapnik/tar.gz/488d2acd65c89cc5382d996eabe8dc1f5051ce0f" +tilelive-mapnik@cartodb/tilelive-mapnik#0.6.18-cdb8: + version "0.6.18-cdb8" + resolved "https://codeload.github.com/cartodb/tilelive-mapnik/tar.gz/9cb4546c8fdd34ced0a41dbf70e143475b4e2067" dependencies: - "@carto/mapnik" "3.6.2-carto.2" + "@carto/mapnik" "3.6.2-carto.4" generic-pool "~2.4.0" mime "~1.6.0" sphericalmercator "~1.0.4" @@ -2400,13 +2400,13 @@ window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" -windshaft@4.5.6: - version "4.5.6" - resolved "https://registry.yarnpkg.com/windshaft/-/windshaft-4.5.6.tgz#566c635f25e4dfc18b46cffe1b22b8c9626f8295" +windshaft@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/windshaft/-/windshaft-4.6.0.tgz#d9394aff73c0aa761207ad2b0f12d1c23ac41244" dependencies: - "@carto/mapnik" "3.6.2-carto.2" - "@carto/tilelive-bridge" cartodb/tilelive-bridge#2.5.1-cdb3 - abaculus cartodb/abaculus#2.0.3-cdb2 + "@carto/mapnik" "3.6.2-carto.4" + "@carto/tilelive-bridge" cartodb/tilelive-bridge#2.5.1-cdb4 + abaculus cartodb/abaculus#2.0.3-cdb5 canvas cartodb/node-canvas#1.6.2-cdb2 carto cartodb/carto#0.15.1-cdb3 cartodb-psql "^0.10.1" @@ -2420,7 +2420,7 @@ windshaft@4.5.6: sphericalmercator "1.0.4" step "~0.0.6" tilelive "5.12.2" - tilelive-mapnik cartodb/tilelive-mapnik#0.6.18-cdb7 + tilelive-mapnik cartodb/tilelive-mapnik#0.6.18-cdb8 torque.js "~2.11.0" underscore "~1.6.0"