Merge branch 'master' into fix-image-format-png

This commit is contained in:
Simon Martín 2018-05-16 14:40:59 +02:00
commit 04e00bb834
16 changed files with 484 additions and 441 deletions

View File

@ -191,7 +191,7 @@ module.exports = class ApiRouter {
Object.keys(this.serverOptions.routes).forEach(apiVersion => { Object.keys(this.serverOptions.routes).forEach(apiVersion => {
const routes = this.serverOptions.routes[apiVersion]; const routes = this.serverOptions.routes[apiVersion];
const apiRouter = router(); const apiRouter = router({ mergeParams: true });
apiRouter.use(logger(this.serverOptions)); apiRouter.use(logger(this.serverOptions));
apiRouter.use(initializeStatusCode()); apiRouter.use(initializeStatusCode());

View File

@ -8,29 +8,32 @@ const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
const cacheControlHeader = require('../middlewares/cache-control-header'); const cacheControlHeader = require('../middlewares/cache-control-header');
const dbParamsFromResLocals = require('../../utils/database-params'); const dbParamsFromResLocals = require('../../utils/database-params');
function AnalysesController(pgConnection, authBackend, userLimitsBackend) { module.exports = class AnalysesController {
this.pgConnection = pgConnection; constructor (pgConnection, authBackend, userLimitsBackend) {
this.authBackend = authBackend; this.pgConnection = pgConnection;
this.userLimitsBackend = userLimitsBackend; this.authBackend = authBackend;
} this.userLimitsBackend = userLimitsBackend;
}
module.exports = AnalysesController; register (mapRouter) {
mapRouter.get('/analyses/catalog', this.middlewares());
}
AnalysesController.prototype.register = function (mapRouter) { middlewares () {
mapRouter.get( return [
`/analyses/catalog`, credentials(),
credentials(), authorize(this.authBackend),
authorize(this.authBackend), dbConnSetup(this.pgConnection),
dbConnSetup(this.pgConnection), rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ANALYSIS_CATALOG),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ANALYSIS_CATALOG), cleanUpQueryParams(),
cleanUpQueryParams(), createPGClient(),
createPGClient(), getDataFromQuery({ queryTemplate: catalogQueryTpl, key: 'catalog' }),
getDataFromQuery({ queryTemplate: catalogQueryTpl, key: 'catalog' }), getDataFromQuery({ queryTemplate: tablesQueryTpl, key: 'tables' }),
getDataFromQuery({ queryTemplate: tablesQueryTpl, key: 'tables' }), prepareResponse(),
prepareResponse(), cacheControlHeader({ ttl: 10, revalidate: true }),
cacheControlHeader({ ttl: 10, revalidate: true }), unauthorizedError()
unauthorizedError() ];
); }
}; };
function createPGClient () { function createPGClient () {

View File

@ -16,8 +16,11 @@ module.exports = class AnalysisLayergroupController {
} }
register (mapRouter) { register (mapRouter) {
mapRouter.get( mapRouter.get('/:token/analysis/node/:nodeId', this.middlewares());
`/:token/analysis/node/:nodeId`, }
middlewares () {
return [
layergroupToken(), layergroupToken(),
credentials(), credentials(),
authorize(this.authBackend), authorize(this.authBackend),
@ -25,8 +28,7 @@ module.exports = class AnalysisLayergroupController {
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ANALYSIS), rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ANALYSIS),
cleanUpQueryParams(), cleanUpQueryParams(),
analysisNodeStatus(this.analysisStatusBackend) analysisNodeStatus(this.analysisStatusBackend)
); ];
} }
}; };

View File

@ -22,88 +22,88 @@ const CreateLayergroupMapConfigProvider = require('../../models/mapconfig/provid
const rateLimit = require('../middlewares/rate-limit'); const rateLimit = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit; const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
/** module.exports = class AnonymousMapController {
* @param {AuthBackend} authBackend /**
* @param {PgConnection} pgConnection * @param {AuthBackend} authBackend
* @param {TemplateMaps} templateMaps * @param {PgConnection} pgConnection
* @param {MapBackend} mapBackend * @param {TemplateMaps} templateMaps
* @param metadataBackend * @param {MapBackend} mapBackend
* @param {SurrogateKeysCache} surrogateKeysCache * @param metadataBackend
* @param {UserLimitsBackend} userLimitsBackend * @param {SurrogateKeysCache} surrogateKeysCache
* @param {LayergroupAffectedTables} layergroupAffectedTables * @param {UserLimitsBackend} userLimitsBackend
* @param {MapConfigAdapter} mapConfigAdapter * @param {LayergroupAffectedTables} layergroupAffectedTables
* @param {StatsBackend} statsBackend * @param {MapConfigAdapter} mapConfigAdapter
* @constructor * @param {StatsBackend} statsBackend
*/ * @constructor
function AnonymousMapController ( */
pgConnection, constructor (
templateMaps, pgConnection,
mapBackend, templateMaps,
metadataBackend, mapBackend,
surrogateKeysCache, metadataBackend,
userLimitsBackend, surrogateKeysCache,
layergroupAffectedTables, userLimitsBackend,
mapConfigAdapter, layergroupAffectedTables,
statsBackend, mapConfigAdapter,
authBackend, statsBackend,
layergroupMetadata authBackend,
) { layergroupMetadata
this.pgConnection = pgConnection; ) {
this.templateMaps = templateMaps; this.pgConnection = pgConnection;
this.mapBackend = mapBackend; this.templateMaps = templateMaps;
this.metadataBackend = metadataBackend; this.mapBackend = mapBackend;
this.surrogateKeysCache = surrogateKeysCache; this.metadataBackend = metadataBackend;
this.userLimitsBackend = userLimitsBackend; this.surrogateKeysCache = surrogateKeysCache;
this.layergroupAffectedTables = layergroupAffectedTables; this.userLimitsBackend = userLimitsBackend;
this.mapConfigAdapter = mapConfigAdapter; this.layergroupAffectedTables = layergroupAffectedTables;
this.statsBackend = statsBackend; this.mapConfigAdapter = mapConfigAdapter;
this.authBackend = authBackend; this.statsBackend = statsBackend;
this.layergroupMetadata = layergroupMetadata; this.authBackend = authBackend;
} this.layergroupMetadata = layergroupMetadata;
}
module.exports = AnonymousMapController; register (mapRouter) {
mapRouter.options('/');
mapRouter.get('/', this.middlewares());
mapRouter.post('/', this.middlewares());
}
AnonymousMapController.prototype.register = function (mapRouter) { middlewares () {
mapRouter.options('/'); const isTemplateInstantiation = false;
mapRouter.get('/', this.composeCreateMapMiddleware()); const useTemplateHash = false;
mapRouter.post('/', this.composeCreateMapMiddleware()); const includeQuery = true;
}; const label = 'ANONYMOUS LAYERGROUP';
const addContext = true;
AnonymousMapController.prototype.composeCreateMapMiddleware = function () { return [
const isTemplateInstantiation = false; credentials(),
const useTemplateHash = false; authorize(this.authBackend),
const includeQuery = true; dbConnSetup(this.pgConnection),
const label = 'ANONYMOUS LAYERGROUP'; rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS),
const addContext = true; cleanUpQueryParams(['aggregation']),
initProfiler(isTemplateInstantiation),
return [ checkJsonContentType(),
credentials(), checkCreateLayergroup(),
authorize(this.authBackend), prepareAdapterMapConfig(this.mapConfigAdapter),
dbConnSetup(this.pgConnection), createLayergroup (
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.ANONYMOUS), this.mapBackend,
cleanUpQueryParams(['aggregation']), this.userLimitsBackend,
initProfiler(isTemplateInstantiation), this.pgConnection,
checkJsonContentType(), this.layergroupAffectedTables
checkCreateLayergroup(), ),
prepareAdapterMapConfig(this.mapConfigAdapter), incrementMapViewCount(this.metadataBackend),
createLayergroup ( augmentLayergroupData(),
this.mapBackend, cacheControlHeader({ ttl: global.environment.varnish.layergroupTtl || 86400, revalidate: true }),
this.userLimitsBackend, cacheChannelHeader(),
this.pgConnection, surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
this.layergroupAffectedTables lastModifiedHeader({ now: true }),
), lastUpdatedTimeLayergroup(),
incrementMapViewCount(this.metadataBackend), layerStats(this.pgConnection, this.statsBackend),
augmentLayergroupData(), layergroupIdHeader(this.templateMaps, useTemplateHash),
cacheControlHeader({ ttl: global.environment.varnish.layergroupTtl || 86400, revalidate: true }), layergroupMetadata(this.layergroupMetadata, includeQuery),
cacheChannelHeader(), mapError({ label, addContext })
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), ];
lastModifiedHeader({ now: true }), }
lastUpdatedTimeLayergroup(),
layerStats(this.pgConnection, this.statsBackend),
layergroupIdHeader(this.templateMaps, useTemplateHash),
layergroupMetadata(this.layergroupMetadata, includeQuery),
mapError({ label, addContext })
];
}; };
function checkCreateLayergroup () { function checkCreateLayergroup () {

View File

@ -31,8 +31,11 @@ module.exports = class AttributesLayergroupController {
} }
register (mapRouter) { register (mapRouter) {
mapRouter.get( mapRouter.get('/:token/:layer/attributes/:fid', this.middlewares());
`/:token/:layer/attributes/:fid`, }
middlewares () {
return [
layergroupToken(), layergroupToken(),
credentials(), credentials(),
authorize(this.authBackend), authorize(this.authBackend),
@ -50,7 +53,7 @@ module.exports = class AttributesLayergroupController {
cacheChannelHeader(), cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader() lastModifiedHeader()
); ];
} }
}; };

View File

@ -49,76 +49,34 @@ module.exports = class DataviewLayergroupController {
// Undocumented/non-supported API endpoint methods. // Undocumented/non-supported API endpoint methods.
// Use at your own peril. // Use at your own peril.
mapRouter.get( mapRouter.get('/:token/dataview/:dataviewName', this.middlewares({
`/:token/dataview/:dataviewName`, action: 'get',
layergroupToken(), rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW
credentials(), }));
authorize(this.authBackend),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW),
cleanUpQueryParams(ALLOWED_DATAVIEW_QUERY_PARAMS),
createMapStoreMapConfigProvider(
this.mapStore,
this.userLimitsBackend,
this.pgConnection,
this.layergroupAffectedTablesCache
),
getDataview(this.dataviewBackend),
cacheControlHeader(),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader()
);
mapRouter.get( mapRouter.get('/:token/:layer/widget/:dataviewName', this.middlewares({
`/:token/:layer/widget/:dataviewName`, action: 'get',
layergroupToken(), rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW
credentials(), }));
authorize(this.authBackend),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW),
cleanUpQueryParams(ALLOWED_DATAVIEW_QUERY_PARAMS),
createMapStoreMapConfigProvider(
this.mapStore,
this.userLimitsBackend,
this.pgConnection,
this.layergroupAffectedTablesCache
),
getDataview(this.dataviewBackend),
cacheControlHeader(),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader()
);
mapRouter.get( mapRouter.get('/:token/dataview/:dataviewName/search', this.middlewares({
`/:token/dataview/:dataviewName/search`, action: 'search',
layergroupToken(), rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW_SEARCH
credentials(), }));
authorize(this.authBackend),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW_SEARCH),
cleanUpQueryParams(ALLOWED_DATAVIEW_QUERY_PARAMS),
createMapStoreMapConfigProvider(
this.mapStore,
this.userLimitsBackend,
this.pgConnection,
this.layergroupAffectedTablesCache
),
dataviewSearch(this.dataviewBackend),
cacheControlHeader(),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader()
);
mapRouter.get( mapRouter.get('/:token/:layer/widget/:dataviewName/search', this.middlewares({
`/:token/:layer/widget/:dataviewName/search`, action: 'search',
rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW_SEARCH
}));
}
middlewares ({ action, rateLimitGroup }) {
return [
layergroupToken(), layergroupToken(),
credentials(), credentials(),
authorize(this.authBackend), authorize(this.authBackend),
dbConnSetup(this.pgConnection), dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.DATAVIEW_SEARCH), rateLimit(this.userLimitsBackend, rateLimitGroup),
cleanUpQueryParams(ALLOWED_DATAVIEW_QUERY_PARAMS), cleanUpQueryParams(ALLOWED_DATAVIEW_QUERY_PARAMS),
createMapStoreMapConfigProvider( createMapStoreMapConfigProvider(
this.mapStore, this.mapStore,
@ -126,12 +84,12 @@ module.exports = class DataviewLayergroupController {
this.pgConnection, this.pgConnection,
this.layergroupAffectedTablesCache this.layergroupAffectedTablesCache
), ),
dataviewSearch(this.dataviewBackend), action === 'search' ? dataviewSearch(this.dataviewBackend) : getDataview(this.dataviewBackend),
cacheControlHeader(), cacheControlHeader(),
cacheChannelHeader(), cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader() lastModifiedHeader()
); ];
} }
}; };

View File

@ -113,7 +113,7 @@ module.exports = class MapRouter {
} }
register (apiRouter, mapPaths) { register (apiRouter, mapPaths) {
const mapRouter = router(); const mapRouter = router({ mergeParams: true });
this.analysisLayergroupController.register(mapRouter); this.analysisLayergroupController.register(mapRouter);
this.attributesLayergroupController.register(mapRouter); this.attributesLayergroupController.register(mapRouter);

View File

@ -2,6 +2,7 @@ const layergroupToken = require('../middlewares/layergroup-token');
const coordinates = require('../middlewares/coordinates'); const coordinates = require('../middlewares/coordinates');
const cleanUpQueryParams = require('../middlewares/clean-up-query-params'); const cleanUpQueryParams = require('../middlewares/clean-up-query-params');
const credentials = require('../middlewares/credentials'); const credentials = require('../middlewares/credentials');
const noop = require('../middlewares/noop');
const dbConnSetup = require('../middlewares/db-conn-setup'); const dbConnSetup = require('../middlewares/db-conn-setup');
const authorize = require('../middlewares/authorize'); const authorize = require('../middlewares/authorize');
const rateLimit = require('../middlewares/rate-limit'); const rateLimit = require('../middlewares/rate-limit');
@ -33,35 +34,33 @@ module.exports = class PreviewLayergroupController {
} }
register (mapRouter) { register (mapRouter) {
mapRouter.get('/static/center/:token/:z/:lat/:lng/:width/:height.:format', this.middlewares({
validateZoom: true,
previewType: 'centered'
}));
mapRouter.get('/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format', this.middlewares({
validateZoom: false,
previewType: 'bbox'
}));
}
middlewares ({ validateZoom, previewType }) {
const forcedFormat = 'png'; const forcedFormat = 'png';
mapRouter.get( let getPreviewImage;
`/static/center/:token/:z/:lat/:lng/:width/:height.:format`,
layergroupToken(),
coordinates({ z: true, x: false, y: false }),
credentials(),
authorize(this.authBackend),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.STATIC),
cleanUpQueryParams(['layer']),
checkStaticImageFormat(),
createMapStoreMapConfigProvider(
this.mapStore,
this.userLimitsBackend,
this.pgConnection,
this.layergroupAffectedTablesCache,
forcedFormat
),
getPreviewImageByCenter(this.previewBackend),
cacheControlHeader(),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader()
);
mapRouter.get( if (previewType === 'centered') {
`/static/bbox/:token/:west,:south,:east,:north/:width/:height.:format`, getPreviewImage = getPreviewImageByCenter;
}
if (previewType === 'bbox') {
getPreviewImage = getPreviewImageByBoundingBox;
}
return [
layergroupToken(), layergroupToken(),
validateZoom ? coordinates({ z: true, x: false, y: false }) : noop(),
credentials(), credentials(),
authorize(this.authBackend), authorize(this.authBackend),
dbConnSetup(this.pgConnection), dbConnSetup(this.pgConnection),
@ -75,12 +74,12 @@ module.exports = class PreviewLayergroupController {
this.layergroupAffectedTablesCache, this.layergroupAffectedTablesCache,
forcedFormat forcedFormat
), ),
getPreviewImageByBoundingBox(this.previewBackend), getPreviewImage(this.previewBackend),
cacheControlHeader(), cacheControlHeader(),
cacheChannelHeader(), cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader() lastModifiedHeader()
); ];
} }
}; };

View File

@ -23,55 +23,58 @@ function numMapper(n) {
return +n; return +n;
} }
function PreviewTemplateController ( module.exports = class PreviewTemplateController {
namedMapProviderCache, constructor (
previewBackend, namedMapProviderCache,
surrogateKeysCache, previewBackend,
tablesExtentBackend, surrogateKeysCache,
metadataBackend, tablesExtentBackend,
pgConnection, metadataBackend,
authBackend, pgConnection,
userLimitsBackend authBackend,
) { userLimitsBackend
this.namedMapProviderCache = namedMapProviderCache; ) {
this.previewBackend = previewBackend; this.namedMapProviderCache = namedMapProviderCache;
this.surrogateKeysCache = surrogateKeysCache; this.previewBackend = previewBackend;
this.tablesExtentBackend = tablesExtentBackend; this.surrogateKeysCache = surrogateKeysCache;
this.metadataBackend = metadataBackend; this.tablesExtentBackend = tablesExtentBackend;
this.pgConnection = pgConnection; this.metadataBackend = metadataBackend;
this.authBackend = authBackend; this.pgConnection = pgConnection;
this.userLimitsBackend = userLimitsBackend; this.authBackend = authBackend;
} this.userLimitsBackend = userLimitsBackend;
}
module.exports = PreviewTemplateController; register (mapRouter) {
mapRouter.get('/static/named/:template_id/:width/:height.:format', this.middlewares());
}
PreviewTemplateController.prototype.register = function (mapRouter) { middlewares () {
mapRouter.get( return [
`/static/named/:template_id/:width/:height.:format`, credentials(),
credentials(), authorize(this.authBackend),
authorize(this.authBackend), dbConnSetup(this.pgConnection),
dbConnSetup(this.pgConnection), rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.STATIC_NAMED),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.STATIC_NAMED), cleanUpQueryParams(['layer', 'zoom', 'lon', 'lat', 'bbox']),
cleanUpQueryParams(['layer', 'zoom', 'lon', 'lat', 'bbox']), checkStaticImageFormat(),
checkStaticImageFormat(), namedMapProvider({
namedMapProvider({ namedMapProviderCache: this.namedMapProviderCache,
namedMapProviderCache: this.namedMapProviderCache, label: 'STATIC_VIZ_MAP', forcedFormat: 'png'
label: 'STATIC_VIZ_MAP', forcedFormat: 'png' }),
}), getTemplate({ label: 'STATIC_VIZ_MAP' }),
getTemplate({ label: 'STATIC_VIZ_MAP' }), prepareLayerFilterFromPreviewLayers({
prepareLayerFilterFromPreviewLayers({ namedMapProviderCache: this.namedMapProviderCache,
namedMapProviderCache: this.namedMapProviderCache, label: 'STATIC_VIZ_MAP'
label: 'STATIC_VIZ_MAP' }),
}), getStaticImageOptions({ tablesExtentBackend: this.tablesExtentBackend }),
getStaticImageOptions({ tablesExtentBackend: this.tablesExtentBackend }), getImage({ previewBackend: this.previewBackend, label: 'STATIC_VIZ_MAP' }),
getImage({ previewBackend: this.previewBackend, label: 'STATIC_VIZ_MAP' }), setContentTypeHeader(),
setContentTypeHeader(), incrementMapViews({ metadataBackend: this.metadataBackend }),
incrementMapViews({ metadataBackend: this.metadataBackend }), cacheControlHeader(),
cacheControlHeader(), cacheChannelHeader(),
cacheChannelHeader(), surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), lastModifiedHeader()
lastModifiedHeader() ];
); }
}; };
function getTemplate ({ label }) { function getTemplate ({ label }) {

View File

@ -42,14 +42,21 @@ module.exports = class TileLayergroupController {
} }
register (mapRouter) { register (mapRouter) {
// REGEXP doesn't match with `val` // REGEXP: doesn't match with `val`
const not = (val) => `(?!${val})([^\/]+?)`; const not = (val) => `(?!${val})([^\/]+?)`;
// Sadly the path that matches 1 also matches with 2 so we need to tell to express
// that performs only the middlewares of the first path that matches
// for that we use one array to group all paths.
mapRouter.get([ mapRouter.get([
`/:token/:z/:x/:y@:scale_factor?x.:format`, `/:token/:z/:x/:y@:scale_factor?x.:format`, // 1
`/:token/:z/:x/:y.:format`, `/:token/:z/:x/:y.:format`, // 2
`/:token${not('static')}/:layer/:z/:x/:y.(:format)` `/:token${not('static')}/:layer/:z/:x/:y.(:format)`
], ], this.middlewares());
}
middlewares () {
return [
layergroupToken(), layergroupToken(),
coordinates(), coordinates(),
credentials(), credentials(),
@ -72,7 +79,7 @@ module.exports = class TileLayergroupController {
incrementErrorMetrics(global.statsClient), incrementErrorMetrics(global.statsClient),
tileError(), tileError(),
vectorError() vectorError()
); ];
} }
}; };

View File

@ -0,0 +1,5 @@
module.exports = function noop () {
return function noopMiddleware (req, res, next) {
next();
};
};

View File

@ -3,70 +3,90 @@ const credentials = require('../middlewares/credentials');
const rateLimit = require('../middlewares/rate-limit'); const rateLimit = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit; const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
/** module.exports = class AdminTemplateController {
* @param {AuthBackend} authBackend /**
* @param {PgConnection} pgConnection * @param {AuthBackend} authBackend
* @param {TemplateMaps} templateMaps * @param {PgConnection} pgConnection
* @constructor * @param {TemplateMaps} templateMaps
*/ * @constructor
function AdminTemplateController(authBackend, templateMaps, userLimitsBackend) { */
this.authBackend = authBackend; constructor (authBackend, templateMaps, userLimitsBackend) {
this.templateMaps = templateMaps; this.authBackend = authBackend;
this.userLimitsBackend = userLimitsBackend; this.templateMaps = templateMaps;
} this.userLimitsBackend = userLimitsBackend;
}
module.exports = AdminTemplateController; register (templateRouter) {
templateRouter.options(`/:template_id`);
AdminTemplateController.prototype.register = function (templateRouter) { templateRouter.post('/', this.middlewares({
templateRouter.options(`/:template_id`); action: 'create',
label: 'POST TEMPLATE',
rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_CREATE
}));
templateRouter.post( templateRouter.put('/:template_id', this.middlewares({
`/`, action: 'update',
credentials(), label: 'PUT TEMPLATE',
authorizedByAPIKey({ authBackend: this.authBackend, action: 'create', label: 'POST TEMPLATE' }), rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_UPDATE
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_CREATE), }));
checkContentType({ action: 'POST', label: 'POST TEMPLATE' }),
createTemplate({ templateMaps: this.templateMaps })
);
templateRouter.put( templateRouter.get('/:template_id', this.middlewares({
`/:template_id`, action: 'get',
credentials(), label: 'GET TEMPLATE',
authorizedByAPIKey({ authBackend: this.authBackend, action: 'update', label: 'PUT TEMPLATE' }), rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_GET
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_UPDATE), }));
checkContentType({ action: 'PUT', label: 'PUT TEMPLATE' }),
updateTemplate({ templateMaps: this.templateMaps })
);
templateRouter.get( templateRouter.delete('/:template_id', this.middlewares({
`/:template_id`, action: 'delete',
credentials(), label: 'DELETE TEMPLATE',
authorizedByAPIKey({ authBackend: this.authBackend, action: 'get', label: 'GET TEMPLATE' }), rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_DELETE
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_GET), }));
retrieveTemplate({ templateMaps: this.templateMaps })
);
templateRouter.delete( templateRouter.get('/', this.middlewares({
`/:template_id`, action: 'list',
credentials(), label: 'GET TEMPLATE LIST',
authorizedByAPIKey({ authBackend: this.authBackend, action: 'delete', label: 'DELETE TEMPLATE' }), rateLimitGroup: RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_LIST
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_DELETE), }));
destroyTemplate({ templateMaps: this.templateMaps }) }
);
templateRouter.get( middlewares ({ action, label, rateLimitGroup }) {
`/`, let template;
credentials(),
authorizedByAPIKey({ authBackend: this.authBackend, action: 'list', label: 'GET TEMPLATE LIST' }), if (action === 'create') {
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_LIST), template = createTemplate;
listTemplates({ templateMaps: this.templateMaps }) }
);
if (action === 'update') {
template = updateTemplate;
}
if (action === 'get') {
template = retrieveTemplate;
}
if (action === 'delete') {
template = destroyTemplate;
}
if (action === 'list') {
template = listTemplates;
}
return [
credentials(),
authorizedByAPIKey({ authBackend: this.authBackend, action, label }),
rateLimit(this.userLimitsBackend, rateLimitGroup),
checkContentType({ action: 'POST', label: 'POST TEMPLATE' }),
template({ templateMaps: this.templateMaps })
];
}
}; };
function checkContentType ({ action, label }) { function checkContentType ({ label }) {
return function checkContentTypeMiddleware (req, res, next) { return function checkContentTypeMiddleware (req, res, next) {
if (!req.is('application/json')) { if ((req.method === 'POST' || req.method === 'PUT') && !req.is('application/json')) {
const error = new Error(`template ${action} data must be of type application/json`); const error = new Error(`${req.method} template data must be of type application/json`);
error.label = label; error.label = label;
return next(error); return next(error);
} }

View File

@ -20,101 +20,95 @@ const CreateLayergroupMapConfigProvider = require('../../models/mapconfig/provid
const rateLimit = require('../middlewares/rate-limit'); const rateLimit = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit; const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
/** module.exports = class NamedMapController {
* @param {AuthBackend} authBackend /**
* @param {PgConnection} pgConnection * @param {PgConnection} pgConnection
* @param {TemplateMaps} templateMaps * @param {TemplateMaps} templateMaps
* @param {MapBackend} mapBackend * @param {MapBackend} mapBackend
* @param metadataBackend * @param metadataBackend
* @param {SurrogateKeysCache} surrogateKeysCache * @param {SurrogateKeysCache} surrogateKeysCache
* @param {UserLimitsBackend} userLimitsBackend * @param {UserLimitsBackend} userLimitsBackend
* @param {LayergroupAffectedTables} layergroupAffectedTables * @param {LayergroupAffectedTables} layergroupAffectedTables
* @param {MapConfigAdapter} mapConfigAdapter * @param {MapConfigAdapter} mapConfigAdapter
* @param {StatsBackend} statsBackend * @param {StatsBackend} statsBackend
* @constructor * @param {AuthBackend} authBackend
*/ * @param layergroupMetadata
function NamedMapController ( * @constructor
pgConnection, */
templateMaps, constructor (
mapBackend, pgConnection,
metadataBackend, templateMaps,
surrogateKeysCache, mapBackend,
userLimitsBackend, metadataBackend,
layergroupAffectedTables, surrogateKeysCache,
mapConfigAdapter, userLimitsBackend,
statsBackend, layergroupAffectedTables,
authBackend, mapConfigAdapter,
layergroupMetadata statsBackend,
) { authBackend,
this.pgConnection = pgConnection; layergroupMetadata
this.templateMaps = templateMaps; ) {
this.mapBackend = mapBackend; this.pgConnection = pgConnection;
this.metadataBackend = metadataBackend; this.templateMaps = templateMaps;
this.surrogateKeysCache = surrogateKeysCache; this.mapBackend = mapBackend;
this.userLimitsBackend = userLimitsBackend; this.metadataBackend = metadataBackend;
this.layergroupAffectedTables = layergroupAffectedTables; this.surrogateKeysCache = surrogateKeysCache;
this.mapConfigAdapter = mapConfigAdapter; this.userLimitsBackend = userLimitsBackend;
this.statsBackend = statsBackend; this.layergroupAffectedTables = layergroupAffectedTables;
this.authBackend = authBackend; this.mapConfigAdapter = mapConfigAdapter;
this.layergroupMetadata = layergroupMetadata; this.statsBackend = statsBackend;
} this.authBackend = authBackend;
this.layergroupMetadata = layergroupMetadata;
}
module.exports = NamedMapController; register (templateRouter) {
templateRouter.get('/:template_id/jsonp', this.middlewares());
templateRouter.post('/:template_id', this.middlewares());
}
NamedMapController.prototype.register = function (templateRouter) { middlewares () {
templateRouter.get( const isTemplateInstantiation = true;
`/:template_id/jsonp`, const useTemplateHash = true;
this.composeInstantiateTemplateMiddleware() const includeQuery = false;
); const label = 'NAMED MAP LAYERGROUP';
const addContext = false;
templateRouter.post( return [
`/:template_id`, credentials(),
this.composeInstantiateTemplateMiddleware() authorize(this.authBackend),
); dbConnSetup(this.pgConnection),
}; rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED),
cleanUpQueryParams(['aggregation']),
NamedMapController.prototype.composeInstantiateTemplateMiddleware = function () { initProfiler(isTemplateInstantiation),
const isTemplateInstantiation = true; checkJsonContentType(),
const useTemplateHash = true; checkInstantiteLayergroup(),
const includeQuery = false; getTemplate(
const label = 'NAMED MAP LAYERGROUP'; this.templateMaps,
const addContext = false; this.pgConnection,
this.metadataBackend,
return [ this.userLimitsBackend,
credentials(), this.mapConfigAdapter,
authorize(this.authBackend), this.layergroupAffectedTables
dbConnSetup(this.pgConnection), ),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED), instantiateLayergroup(
cleanUpQueryParams(['aggregation']), this.mapBackend,
initProfiler(isTemplateInstantiation), this.userLimitsBackend,
checkJsonContentType(), this.pgConnection,
checkInstantiteLayergroup(), this.layergroupAffectedTables
getTemplate( ),
this.templateMaps, incrementMapViewCount(this.metadataBackend),
this.pgConnection, augmentLayergroupData(),
this.metadataBackend, cacheControlHeader({ ttl: global.environment.varnish.layergroupTtl || 86400, revalidate: true }),
this.userLimitsBackend, cacheChannelHeader(),
this.mapConfigAdapter, surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
this.layergroupAffectedTables lastModifiedHeader({ now: true }),
), lastUpdatedTimeLayergroup(),
instantiateLayergroup( layerStats(this.pgConnection, this.statsBackend),
this.mapBackend, layergroupIdHeader(this.templateMaps ,useTemplateHash),
this.userLimitsBackend, layergroupMetadata(this.layergroupMetadata, includeQuery),
this.pgConnection, mapError({ label, addContext })
this.layergroupAffectedTables ];
), }
incrementMapViewCount(this.metadataBackend),
augmentLayergroupData(),
cacheControlHeader({ ttl: global.environment.varnish.layergroupTtl || 86400, revalidate: true }),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader({ now: true }),
lastUpdatedTimeLayergroup(),
layerStats(this.pgConnection, this.statsBackend),
layergroupIdHeader(this.templateMaps ,useTemplateHash),
layergroupMetadata(this.layergroupMetadata, includeQuery),
mapError({ label, addContext })
];
}; };
function checkInstantiteLayergroup () { function checkInstantiteLayergroup () {

View File

@ -53,7 +53,7 @@ module.exports = class TemplateRouter {
} }
register (apiRouter, templatePaths) { register (apiRouter, templatePaths) {
const templateRouter = router(); const templateRouter = router({ mergeParams: true });
this.namedMapController.register(templateRouter); this.namedMapController.register(templateRouter);
this.tileTemplateController.register(templateRouter); this.tileTemplateController.register(templateRouter);

View File

@ -12,48 +12,51 @@ const vectorError = require('../middlewares/vector-error');
const rateLimit = require('../middlewares/rate-limit'); const rateLimit = require('../middlewares/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit; const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
function TileTemplateController ( module.exports = class TileTemplateController {
namedMapProviderCache, constructor (
tileBackend, namedMapProviderCache,
surrogateKeysCache, tileBackend,
pgConnection, surrogateKeysCache,
authBackend, pgConnection,
userLimitsBackend authBackend,
) { userLimitsBackend
this.namedMapProviderCache = namedMapProviderCache; ) {
this.tileBackend = tileBackend; this.namedMapProviderCache = namedMapProviderCache;
this.surrogateKeysCache = surrogateKeysCache; this.tileBackend = tileBackend;
this.pgConnection = pgConnection; this.surrogateKeysCache = surrogateKeysCache;
this.authBackend = authBackend; this.pgConnection = pgConnection;
this.userLimitsBackend = userLimitsBackend; this.authBackend = authBackend;
} this.userLimitsBackend = userLimitsBackend;
}
module.exports = TileTemplateController; register (templateRouter) {
templateRouter.get('/:template_id/:layer/:z/:x/:y.(:format)', this.middlewares());
}
TileTemplateController.prototype.register = function (templateRouter) { middlewares () {
templateRouter.get( return [
`/:template_id/:layer/:z/:x/:y.(:format)`, coordinates(),
coordinates(), credentials(),
credentials(), authorize(this.authBackend),
authorize(this.authBackend), dbConnSetup(this.pgConnection),
dbConnSetup(this.pgConnection), rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_TILES),
rateLimit(this.userLimitsBackend, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED_TILES), cleanUpQueryParams(),
cleanUpQueryParams(), namedMapProvider({
namedMapProvider({ namedMapProviderCache: this.namedMapProviderCache,
namedMapProviderCache: this.namedMapProviderCache, label: 'NAMED_MAP_TILE'
label: 'NAMED_MAP_TILE' }),
}), getTile({
getTile({ tileBackend: this.tileBackend,
tileBackend: this.tileBackend, label: 'NAMED_MAP_TILE'
label: 'NAMED_MAP_TILE' }),
}), setContentTypeHeader(),
setContentTypeHeader(), cacheControlHeader(),
cacheControlHeader(), cacheChannelHeader(),
cacheChannelHeader(), surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }), lastModifiedHeader(),
lastModifiedHeader(), vectorError()
vectorError() ];
); }
}; };
function getTile ({ tileBackend, label }) { function getTile ({ tileBackend, label }) {

View File

@ -1,7 +1,10 @@
require('../support/test_helper'); require('../support/test_helper');
var assert = require('../support/assert'); var assert = require('../support/assert');
const helper = require('../support/test_helper');
var TestClient = require('../support/test-client'); var TestClient = require('../support/test-client');
const LayergroupToken = require('../../lib/cartodb/models/layergroup-token'); const LayergroupToken = require('../../lib/cartodb/models/layergroup-token');
const CartodbWindshaft = require(__dirname + '/../../lib/cartodb/server');
const serverOptions = require(__dirname + '/../../lib/cartodb/server_options');
describe('regressions', function() { describe('regressions', function() {
@ -38,6 +41,49 @@ describe('regressions', function() {
}); });
}); });
// See: https://github.com/CartoDB/Windshaft-cartodb/pull/956
it('"/user/localhost/api/v1/map" should create an anonymous map', function (done) {
const server = new CartodbWindshaft(serverOptions);
const layergroup = {
version: '1.7.0',
layers: [
{
type: 'mapnik',
options: {
sql: TestClient.SQL.ONE_POINT,
cartocss: TestClient.CARTOCSS.POINTS,
cartocss_version: '2.3.0'
}
}
]
};
const keysToDelete = {};
assert.response(server,
{
url: '/user/localhost/api/v1/map',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify(layergroup)
},
function(res, err) {
if (err) {
return done(err);
}
const body = JSON.parse(res.body);
assert.ok(body.layergroupid);
keysToDelete['map_cfg|' + LayergroupToken.parse(body.layergroupid).token] = 0;
keysToDelete['user:localhost:mapviews:global'] = 5;
helper.deleteRedisKeys(keysToDelete, done);
}
);
});
describe('map instantiation', function () { describe('map instantiation', function () {
const apikeyToken = 'regular1'; const apikeyToken = 'regular1';
const mapConfig = { const mapConfig = {