Extract middlewares from map-controller class

This commit is contained in:
Daniel García Aubert 2018-03-08 12:16:24 +01:00
parent d26910ba9c
commit 363cb0b679

View File

@ -74,26 +74,38 @@ MapController.prototype.composeCreateMapMiddleware = function (useTemplate = fal
this.prepareContext,
initProfiler(isTemplateInstantiation),
checkJsonContentType(),
useTemplate ? this.checkInstantiteLayergroup() : this.checkCreateLayergroup(),
useTemplate ? this.getTemplate() : this.prepareAdapterMapConfig(),
useTemplate ? this.instantiateLayergroup() : this.createLayergroup(),
this.incrementMapViewCount(),
this.augmentLayergroupData(),
this.getAffectedTables(),
this.setCacheChannel(),
this.setLastModified(),
this.setLastUpdatedTimeToLayergroup(),
this.setCacheControl(),
this.setLayerStats(),
this.setLayergroupIdHeader(useTemplateHash),
this.setDataviewsAndWidgetsUrlsToLayergroupMetadata(),
this.setAnalysesMetadataToLayergroup(includeQuery),
this.setTurboCartoMetadataToLayergroup(),
this.setAggregationMetadataToLayergroup(),
this.setTilejsonMetadataToLayergroup(),
this.setSurrogateKeyHeader(),
this.sendResponse(),
this.augmentError({ label, addContext })
useTemplate ?
checkInstantiteLayergroup() :
checkCreateLayergroup(),
useTemplate ?
getTemplate(
this.templateMaps,
this.pgConnection,
this.metadataBackend,
this.userLimitsApi,
this.mapConfigAdapter
) :
prepareAdapterMapConfig(this.mapConfigAdapter),
useTemplate ?
instantiateLayergroup(this.mapBackend, this.userLimitsApi) :
createLayergroup (this.mapBackend, this.userLimitsApi),
incrementMapViewCount(this.metadataBackend),
augmentLayergroupData(),
getAffectedTables(this.pgConnection, this.layergroupAffectedTables),
setCacheChannel(),
setLastModified(),
setLastUpdatedTimeToLayergroup(),
setCacheControl(),
setLayerStats(this.pgConnection, this.statsBackend),
setLayergroupIdHeader(this.templateMaps ,useTemplateHash),
setDataviewsAndWidgetsUrlsToLayergroupMetadata(this.resourceLocator),
setAnalysesMetadataToLayergroup(this.resourceLocator, includeQuery),
setTurboCartoMetadataToLayergroup(),
setAggregationMetadataToLayergroup(),
setTilejsonMetadataToLayergroup(this.resourceLocator),
setSurrogateKeyHeader(this.surrogateKeysCache),
sendResponse(),
augmentError({ label, addContext })
];
};
@ -119,7 +131,7 @@ function checkJsonContentType () {
};
}
MapController.prototype.checkInstantiteLayergroup = function () {
function checkInstantiteLayergroup () {
return function checkInstantiteLayergroupMiddleware(req, res, next) {
if (req.method === 'GET') {
const { callback, config } = req.query;
@ -141,9 +153,9 @@ MapController.prototype.checkInstantiteLayergroup = function () {
return next();
};
};
}
MapController.prototype.checkCreateLayergroup = function () {
function checkCreateLayergroup () {
return function checkCreateLayergroupMiddleware (req, res, next) {
if (req.method === 'GET') {
const { config } = res.locals;
@ -162,19 +174,19 @@ MapController.prototype.checkCreateLayergroup = function () {
req.profiler.done('checkCreateLayergroup');
return next();
};
};
}
MapController.prototype.getTemplate = function () {
function getTemplate (templateMaps, pgConnection, metadataBackend, userLimitsApi, mapConfigAdapter) {
return function getTemplateMiddleware (req, res, next) {
const templateParams = req.body;
const { user } = res.locals;
const mapconfigProvider = new NamedMapMapConfigProvider(
this.templateMaps,
this.pgConnection,
this.metadataBackend,
this.userLimitsApi,
this.mapConfigAdapter,
templateMaps,
pgConnection,
metadataBackend,
userLimitsApi,
mapConfigAdapter,
user,
req.params.template_id,
templateParams,
@ -194,10 +206,10 @@ MapController.prototype.getTemplate = function () {
next();
});
}.bind(this);
};
};
}
MapController.prototype.prepareAdapterMapConfig = function () {
function prepareAdapterMapConfig (mapConfigAdapter) {
return function prepareAdapterMapConfigMiddleware(req, res, next) {
const requestMapConfig = req.body;
const { user, dbhost, dbport, dbname, dbuser, dbpassword, api_key } = res.locals;
@ -219,7 +231,7 @@ MapController.prototype.prepareAdapterMapConfig = function () {
}
};
this.mapConfigAdapter.getMapConfig(user, requestMapConfig, res.locals, context, (err, requestMapConfig) => {
mapConfigAdapter.getMapConfig(user, requestMapConfig, res.locals, context, (err, requestMapConfig) => {
req.profiler.done('anonymous.getMapConfig');
if (err) {
return next(err);
@ -230,22 +242,22 @@ MapController.prototype.prepareAdapterMapConfig = function () {
next();
});
}.bind(this);
};
};
}
MapController.prototype.createLayergroup = function () {
function createLayergroup (mapBackend, userLimitsApi) {
return function createLayergroupMiddleware (req, res, next) {
const requestMapConfig = req.body;
const { context, user } = res.locals;
const datasource = context.datasource || Datasource.EmptyDatasource();
const mapconfig = new MapConfig(requestMapConfig, datasource);
const mapconfigProvider =
new CreateLayergroupMapConfigProvider(mapconfig, user, this.userLimitsApi, res.locals);
new CreateLayergroupMapConfigProvider(mapconfig, user, userLimitsApi, res.locals);
res.locals.mapconfig = mapconfig;
res.locals.analysesResults = context.analysesResults;
this.mapBackend.createLayergroup(mapconfig, res.locals, mapconfigProvider, (err, layergroup) => {
mapBackend.createLayergroup(mapconfig, res.locals, mapconfigProvider, (err, layergroup) => {
req.profiler.done('createLayergroup');
if (err) {
return next(err);
@ -255,16 +267,16 @@ MapController.prototype.createLayergroup = function () {
next();
});
}.bind(this);
};
};
}
MapController.prototype.instantiateLayergroup = function () {
function instantiateLayergroup (mapBackend, userLimitsApi) {
return function instantiateLayergroupMiddleware (req, res, next) {
const { user, mapconfig, rendererParams } = res.locals;
const mapconfigProvider =
new CreateLayergroupMapConfigProvider(mapconfig, user, this.userLimitsApi, rendererParams);
new CreateLayergroupMapConfigProvider(mapconfig, user, userLimitsApi, rendererParams);
this.mapBackend.createLayergroup(mapconfig, rendererParams, mapconfigProvider, (err, layergroup) => {
mapBackend.createLayergroup(mapconfig, rendererParams, mapconfigProvider, (err, layergroup) => {
req.profiler.done('createLayergroup');
if (err) {
return next(err);
@ -281,15 +293,15 @@ MapController.prototype.instantiateLayergroup = function () {
next();
});
}.bind(this);
};
};
}
MapController.prototype.incrementMapViewCount = function () {
function incrementMapViewCount (metadataBackend) {
return function incrementMapViewCountMiddleware(req, res, next) {
const { mapconfig, user } = res.locals;
// Error won't blow up, just be logged.
this.metadataBackend.incMapviewCount(user, mapconfig.obj().stat_tag, (err) => {
metadataBackend.incMapviewCount(user, mapconfig.obj().stat_tag, (err) => {
req.profiler.done('incMapviewCount');
if (err) {
@ -298,10 +310,10 @@ MapController.prototype.incrementMapViewCount = function () {
next();
});
}.bind(this);
};
};
}
MapController.prototype.augmentLayergroupData = function () {
function augmentLayergroupData () {
return function augmentLayergroupDataMiddleware (req, res, next) {
const { layergroup } = res.locals;
@ -312,7 +324,7 @@ MapController.prototype.augmentLayergroupData = function () {
next();
};
};
}
function getTemplateUrl(url) {
return url.https || url.http;
@ -331,72 +343,11 @@ function getTilejson(tiles, grids) {
return tilejson;
}
MapController.prototype.setTilejsonMetadataToLayergroup = function () {
return function augmentLayergroupTilejsonMiddleware (req, res, next) {
const { layergroup, user, mapconfig } = res.locals;
const isVectorOnlyMapConfig = mapconfig.isVectorOnlyMapConfig();
let hasMapnikLayers = false;
layergroup.metadata.layers.forEach((layerMetadata, index) => {
const layerId = mapconfig.getLayerId(index);
const rasterResource = `${layergroup.layergroupid}/${layerId}/{z}/{x}/{y}.png`;
if (mapconfig.layerType(index) === 'mapnik') {
hasMapnikLayers = true;
const vectorResource = `${layergroup.layergroupid}/${layerId}/{z}/{x}/{y}.mvt`;
const layerTilejson = {
vector: getTilejson(this.resourceLocator.getTileUrls(user, vectorResource))
};
if (!isVectorOnlyMapConfig) {
let grids = null;
const layer = mapconfig.getLayer(index);
if (layer.options.interactivity) {
const gridResource = `${layergroup.layergroupid}/${layerId}/{z}/{x}/{y}.grid.json`;
grids = this.resourceLocator.getTileUrls(user, gridResource);
}
layerTilejson.raster = getTilejson(
this.resourceLocator.getTileUrls(user, rasterResource),
grids
);
}
layerMetadata.tilejson = layerTilejson;
} else {
layerMetadata.tilejson = {
raster: getTilejson(this.resourceLocator.getTileUrls(user, rasterResource))
};
}
});
const tilejson = {};
const url = {};
if (hasMapnikLayers) {
const vectorResource = `${layergroup.layergroupid}/{z}/{x}/{y}.mvt`;
tilejson.vector = getTilejson(
this.resourceLocator.getTileUrls(user, vectorResource)
);
url.vector = getTemplateUrl(this.resourceLocator.getTemplateUrls(user, vectorResource));
if (!isVectorOnlyMapConfig) {
const rasterResource = `${layergroup.layergroupid}/{z}/{x}/{y}.png`;
tilejson.raster = getTilejson(
this.resourceLocator.getTileUrls(user, rasterResource)
);
url.raster = getTemplateUrl(this.resourceLocator.getTemplateUrls(user, rasterResource));
}
}
layergroup.metadata.tilejson = tilejson;
layergroup.metadata.url = url;
next();
}.bind(this);
};
MapController.prototype.getAffectedTables = function () {
function getAffectedTables (pgConnection, layergroupAffectedTables) {
return function getAffectedTablesMiddleware (req, res, next) {
const { dbname, layergroup, user, mapconfig } = res.locals;
this.pgConnection.getConnection(user, (err, connection) => {
pgConnection.getConnection(user, (err, connection) => {
if (err) {
return next(err);
}
@ -418,17 +369,17 @@ MapController.prototype.getAffectedTables = function () {
}
// feed affected tables cache so it can be reused from, for instance, layergroup controller
this.layergroupAffectedTables.set(dbname, layergroup.layergroupId, affectedTables);
layergroupAffectedTables.set(dbname, layergroup.layergroupId, affectedTables);
res.locals.affectedTables = affectedTables;
next();
});
});
}.bind(this);
};
};
}
MapController.prototype.setCacheChannel = function () {
function setCacheChannel () {
return function setCacheChannelMiddleware (req, res, next) {
const { affectedTables } = res.locals;
@ -438,9 +389,9 @@ MapController.prototype.setCacheChannel = function () {
next();
};
};
}
MapController.prototype.setLastModified = function () {
function setLastModified () {
return function setLastModifiedMiddleware (req, res, next) {
if (req.method === 'GET') {
res.set('Last-Modified', (new Date()).toUTCString());
@ -448,9 +399,9 @@ MapController.prototype.setLastModified = function () {
next();
};
};
}
MapController.prototype.setLastUpdatedTimeToLayergroup = function () {
function setLastUpdatedTimeToLayergroup () {
return function setLastUpdatedTimeToLayergroupMiddleware (req, res, next) {
const { affectedTables, layergroup, analysesResults } = res.locals;
@ -464,7 +415,7 @@ MapController.prototype.setLastUpdatedTimeToLayergroup = function () {
next();
};
};
}
function getLastUpdatedTime(analysesResults, lastUpdateTime) {
if (!Array.isArray(analysesResults)) {
@ -479,7 +430,7 @@ function getLastUpdatedTime(analysesResults, lastUpdateTime) {
}, lastUpdateTime);
}
MapController.prototype.setCacheControl = function () {
function setCacheControl () {
return function setCacheControlMiddleware (req, res, next) {
if (req.method === 'GET') {
var ttl = global.environment.varnish.layergroupTtl || 86400;
@ -488,18 +439,18 @@ MapController.prototype.setCacheControl = function () {
next();
};
};
}
MapController.prototype.setLayerStats = function () {
function setLayerStats (pgConnection, statsBackend) {
return function setLayerStatsMiddleware(req, res, next) {
const { user, mapconfig, layergroup } = res.locals;
this.pgConnection.getConnection(user, (err, connection) => {
pgConnection.getConnection(user, (err, connection) => {
if (err) {
return next(err);
}
this.statsBackend.getStats(mapconfig, connection, function(err, layersStats) {
statsBackend.getStats(mapconfig, connection, function(err, layersStats) {
if (err) {
return next(err);
}
@ -513,53 +464,54 @@ MapController.prototype.setLayerStats = function () {
next();
});
});
}.bind(this);
};
};
}
MapController.prototype.setLayergroupIdHeader = function (useTemplateHash) {
function setLayergroupIdHeader (templateMaps, useTemplateHash) {
return function setLayergroupIdHeaderMiddleware (req, res, next) {
const { layergroup, user, template } = res.locals;
if (useTemplateHash) {
var templateHash = this.templateMaps.fingerPrint(template).substring(0, 8);
var templateHash = templateMaps.fingerPrint(template).substring(0, 8);
layergroup.layergroupid = `${user}@${templateHash}@${layergroup.layergroupid}`;
}
res.set('X-Layergroup-Id', layergroup.layergroupid);
next();
}.bind(this);
};
};
}
MapController.prototype.setDataviewsAndWidgetsUrlsToLayergroupMetadata = function () {
function setDataviewsAndWidgetsUrlsToLayergroupMetadata (resourceLocator) {
return function setDataviewsAndWidgetsUrlsToLayergroupMetadataMiddleware (req, res, next) {
const { layergroup, user, mapconfig } = res.locals;
this.addDataviewsAndWidgetsUrls(user, layergroup, mapconfig.obj());
addDataviewsAndWidgetsUrls(resourceLocator, user, layergroup, mapconfig.obj());
next();
}.bind(this);
};
};
// TODO this should take into account several URL patterns
MapController.prototype.addDataviewsAndWidgetsUrls = function(username, layergroup, mapConfig) {
this.addDataviewsUrls(username, layergroup, mapConfig);
this.addWidgetsUrl(username, layergroup, mapConfig);
};
function addDataviewsAndWidgetsUrls (resourceLocator, username, layergroup, mapConfig) {
addDataviewsUrls(resourceLocator, username, layergroup, mapConfig);
addWidgetsUrl(resourceLocator, username, layergroup, mapConfig);
}
MapController.prototype.addDataviewsUrls = function(username, layergroup, mapConfig) {
function addDataviewsUrls (resourceLocator, username, layergroup, mapConfig) {
layergroup.metadata.dataviews = layergroup.metadata.dataviews || {};
var dataviews = mapConfig.dataviews || {};
Object.keys(dataviews).forEach(function(dataviewName) {
var resource = layergroup.layergroupid + '/dataview/' + dataviewName;
layergroup.metadata.dataviews[dataviewName] = {
url: this.resourceLocator.getUrls(username, resource)
url: resourceLocator.getUrls(username, resource)
};
}.bind(this));
};
});
}
MapController.prototype.addWidgetsUrl = function(username, layergroup, mapConfig) {
function addWidgetsUrl (resourceLocator, username, layergroup, mapConfig) {
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) {
layergroup.metadata.layers = layergroup.metadata.layers.map(function(layer, layerIndex) {
var mapConfigLayer = mapConfig.layers[layerIndex];
@ -569,26 +521,26 @@ MapController.prototype.addWidgetsUrl = function(username, layergroup, mapConfig
var resource = layergroup.layergroupid + '/' + layerIndex + '/widget/' + widgetName;
layer.widgets[widgetName] = {
type: mapConfigLayer.options.widgets[widgetName].type,
url: this.resourceLocator.getUrls(username, resource)
url: resourceLocator.getUrls(username, resource)
};
}.bind(this));
});
}
return layer;
}.bind(this));
});
}
};
}
MapController.prototype.setAnalysesMetadataToLayergroup = function (includeQuery) {
function setAnalysesMetadataToLayergroup (resourceLocator, includeQuery) {
return function setAnalysesMetadataToLayergroupMiddleware (req, res, next) {
const { layergroup, user, analysesResults = [] } = res.locals;
this.addAnalysesMetadata(user, layergroup, analysesResults, includeQuery);
addAnalysesMetadata(resourceLocator, user, layergroup, analysesResults, includeQuery);
next();
}.bind(this);
};
};
}
MapController.prototype.addAnalysesMetadata = function(username, layergroup, analysesResults, includeQuery) {
function addAnalysesMetadata (resourceLocator, username, layergroup, analysesResults, includeQuery) {
includeQuery = includeQuery || false;
analysesResults = analysesResults || [];
layergroup.metadata.analyses = [];
@ -601,7 +553,7 @@ MapController.prototype.addAnalysesMetadata = function(username, layergroup, ana
var nodeResource = layergroup.layergroupid + '/analysis/node/' + node.id();
var nodeRepr = {
status: node.getStatus(),
url: this.resourceLocator.getUrls(username, nodeResource)
url: resourceLocator.getUrls(username, nodeResource)
};
if (includeQuery) {
nodeRepr.query = node.getQuery();
@ -613,12 +565,12 @@ MapController.prototype.addAnalysesMetadata = function(username, layergroup, ana
}
return nodesIdMap;
}.bind(this), {})
}, {})
});
}.bind(this));
};
});
}
MapController.prototype.setTurboCartoMetadataToLayergroup = function () {
function setTurboCartoMetadataToLayergroup () {
return function setTurboCartoMetadataToLayergroupMiddleware (req, res, next) {
const { layergroup, mapconfig, context } = res.locals;
@ -626,7 +578,7 @@ MapController.prototype.setTurboCartoMetadataToLayergroup = function () {
next();
};
};
}
function addTurboCartoContextMetadata(layergroup, mapConfig, context) {
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) {
@ -640,7 +592,7 @@ function addTurboCartoContextMetadata(layergroup, mapConfig, context) {
}
// TODO: see how evolve this function, it's a good candidate to be refactored
MapController.prototype.setAggregationMetadataToLayergroup = function () {
function setAggregationMetadataToLayergroup () {
return function setAggregationMetadataToLayergroupMiddleware (req, res, next) {
const { layergroup, mapconfig, context } = res.locals;
@ -648,7 +600,7 @@ MapController.prototype.setAggregationMetadataToLayergroup = function () {
next();
};
};
}
function addAggregationContextMetadata(layergroup, mapConfig, context) {
if (layergroup.metadata && Array.isArray(layergroup.metadata.layers) && Array.isArray(mapConfig.layers)) {
@ -661,23 +613,84 @@ function addAggregationContextMetadata(layergroup, mapConfig, context) {
}
}
MapController.prototype.setSurrogateKeyHeader = function () {
function setTilejsonMetadataToLayergroup (resourceLocator) {
return function augmentLayergroupTilejsonMiddleware (req, res, next) {
const { layergroup, user, mapconfig } = res.locals;
const isVectorOnlyMapConfig = mapconfig.isVectorOnlyMapConfig();
let hasMapnikLayers = false;
layergroup.metadata.layers.forEach((layerMetadata, index) => {
const layerId = mapconfig.getLayerId(index);
const rasterResource = `${layergroup.layergroupid}/${layerId}/{z}/{x}/{y}.png`;
if (mapconfig.layerType(index) === 'mapnik') {
hasMapnikLayers = true;
const vectorResource = `${layergroup.layergroupid}/${layerId}/{z}/{x}/{y}.mvt`;
const layerTilejson = {
vector: getTilejson(resourceLocator.getTileUrls(user, vectorResource))
};
if (!isVectorOnlyMapConfig) {
let grids = null;
const layer = mapconfig.getLayer(index);
if (layer.options.interactivity) {
const gridResource = `${layergroup.layergroupid}/${layerId}/{z}/{x}/{y}.grid.json`;
grids = resourceLocator.getTileUrls(user, gridResource);
}
layerTilejson.raster = getTilejson(
resourceLocator.getTileUrls(user, rasterResource),
grids
);
}
layerMetadata.tilejson = layerTilejson;
} else {
layerMetadata.tilejson = {
raster: getTilejson(resourceLocator.getTileUrls(user, rasterResource))
};
}
});
const tilejson = {};
const url = {};
if (hasMapnikLayers) {
const vectorResource = `${layergroup.layergroupid}/{z}/{x}/{y}.mvt`;
tilejson.vector = getTilejson(
resourceLocator.getTileUrls(user, vectorResource)
);
url.vector = getTemplateUrl(resourceLocator.getTemplateUrls(user, vectorResource));
if (!isVectorOnlyMapConfig) {
const rasterResource = `${layergroup.layergroupid}/{z}/{x}/{y}.png`;
tilejson.raster = getTilejson(
resourceLocator.getTileUrls(user, rasterResource)
);
url.raster = getTemplateUrl(resourceLocator.getTemplateUrls(user, rasterResource));
}
}
layergroup.metadata.tilejson = tilejson;
layergroup.metadata.url = url;
next();
};
}
function setSurrogateKeyHeader (surrogateKeysCache) {
return function setSurrogateKeyHeaderMiddleware(req, res, next) {
const { affectedTables, user, templateName } = res.locals;
if (req.method === 'GET' && affectedTables.tables && affectedTables.tables.length > 0) {
this.surrogateKeysCache.tag(res, affectedTables);
surrogateKeysCache.tag(res, affectedTables);
}
if (templateName) {
this.surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, templateName));
surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, templateName));
}
next();
}.bind(this);
};
};
}
MapController.prototype.sendResponse = function () {
function sendResponse () {
return function sendResponseMiddleware (req, res) {
req.profiler.done('res');
const { layergroup } = res.locals;
@ -690,9 +703,9 @@ MapController.prototype.sendResponse = function () {
res.json(layergroup);
}
};
};
}
MapController.prototype.augmentError = function (options) {
function augmentError (options) {
const { addContext = false, label = 'MAPS CONTROLLER' } = options;
return function augmentErrorMiddleware (err, req, res, next) {
@ -707,7 +720,7 @@ MapController.prototype.augmentError = function (options) {
next(err);
};
};
}
function populateError(err, mapConfig) {
var error = new Error(err.message);