Windshaft-cartodb/lib/cartodb/controllers/map/named.js

319 lines
11 KiB
JavaScript
Raw Normal View History

2018-03-10 00:02:13 +08:00
const _ = require('underscore');
const ResourceLocator = require('../../models/resource-locator');
const cleanUpQueryParams = require('../../middleware/clean-up-query-params');
const credentials = require('../../middleware/credentials');
const dbConnSetup = require('../../middleware/db-conn-setup');
const authorize = require('../../middleware/authorize');
2018-03-28 18:45:03 +08:00
const initProfiler = require('./middlewares/init-profiler');
const checkJsonContentType = require('./middlewares/check-json-content-type');
const incrementMapViewCount = require('./middlewares/increment-map-view-count');
const augmentLayergroupData = require('./middlewares/augment-layergroup-data');
const cacheControlHeader = require('../../middleware/cache-control-header');
const cacheChannelHeader = require('../../middleware/cache-channel-header');
const surrogateKeyHeader = require('../../middleware/surrogate-key-header');
const lastModifiedHeader = require('../../middleware/last-modified-header');
const lastUpdatedTimeLayergroup = require('./middlewares/last-updated-time-layergroup');
2018-03-28 19:31:37 +08:00
const layerStats = require('./middlewares/layer-stats');
2018-03-28 19:41:41 +08:00
const layergroupIdHeader = require('./middlewares/layergroup-id-header');
const sendResponse = require('../../middleware/send-response');
const NamedMapMapConfigProvider = require('../../models/mapconfig/provider/named-map-provider');
const CreateLayergroupMapConfigProvider = require('../../models/mapconfig/provider/create-layergroup-provider');
const LayergroupMetadata = require('../../utils/layergroup-metadata');
const rateLimit = require('../../middleware/rate-limit');
const { RATE_LIMIT_ENDPOINTS_GROUPS } = rateLimit;
/**
* @param {AuthApi} authApi
* @param {PgConnection} pgConnection
* @param {TemplateMaps} templateMaps
* @param {MapBackend} mapBackend
* @param metadataBackend
* @param {SurrogateKeysCache} surrogateKeysCache
* @param {UserLimitsApi} userLimitsApi
* @param {LayergroupAffectedTables} layergroupAffectedTables
2016-05-24 05:35:42 +08:00
* @param {MapConfigAdapter} mapConfigAdapter
* @param {StatsBackend} statsBackend
* @constructor
*/
function NamedMapController (
pgConnection,
templateMaps,
mapBackend,
metadataBackend,
surrogateKeysCache,
userLimitsApi,
layergroupAffectedTables,
mapConfigAdapter,
statsBackend,
authApi
) {
this.pgConnection = pgConnection;
this.templateMaps = templateMaps;
this.mapBackend = mapBackend;
this.metadataBackend = metadataBackend;
this.surrogateKeysCache = surrogateKeysCache;
2015-07-11 01:10:55 +08:00
this.userLimitsApi = userLimitsApi;
this.layergroupAffectedTables = layergroupAffectedTables;
2016-05-24 05:35:42 +08:00
this.mapConfigAdapter = mapConfigAdapter;
2018-03-09 19:58:05 +08:00
const resourceLocator = new ResourceLocator(global.environment);
this.layergroupMetadata = new LayergroupMetadata(resourceLocator);
2017-05-09 00:42:40 +08:00
this.statsBackend = statsBackend;
this.authApi = authApi;
}
module.exports = NamedMapController;
2018-03-16 23:42:47 +08:00
NamedMapController.prototype.register = function (templateRouter) {
2018-03-28 00:46:54 +08:00
templateRouter.get(
`/:template_id/jsonp`,
this.composeInstantiateTemplateMiddleware()
);
2018-03-28 00:46:54 +08:00
templateRouter.post(
`/:template_id`,
this.composeInstantiateTemplateMiddleware()
);
};
NamedMapController.prototype.composeInstantiateTemplateMiddleware = function () {
const isTemplateInstantiation = true;
const useTemplateHash = true;
const includeQuery = false;
const label = 'NAMED MAP LAYERGROUP';
const addContext = false;
2017-11-03 02:03:20 +08:00
return [
credentials(),
authorize(this.authApi),
dbConnSetup(this.pgConnection),
rateLimit(this.userLimitsApi, RATE_LIMIT_ENDPOINTS_GROUPS.NAMED),
cleanUpQueryParams(['aggregation']),
initProfiler(isTemplateInstantiation),
checkJsonContentType(),
checkInstantiteLayergroup(),
getTemplate(
this.templateMaps,
this.pgConnection,
this.metadataBackend,
this.userLimitsApi,
this.mapConfigAdapter,
this.layergroupAffectedTables
),
instantiateLayergroup(
this.mapBackend,
this.userLimitsApi,
this.pgConnection,
this.layergroupAffectedTables
),
incrementMapViewCount(this.metadataBackend),
augmentLayergroupData(),
cacheControlHeader({ ttl: global.environment.varnish.layergroupTtl || 86400, revalidate: true }),
cacheChannelHeader(),
surrogateKeyHeader({ surrogateKeysCache: this.surrogateKeysCache }),
lastModifiedHeader({ now: true }),
lastUpdatedTimeLayergroup(),
2018-03-28 19:31:37 +08:00
layerStats(this.pgConnection, this.statsBackend),
2018-03-28 19:41:41 +08:00
layergroupIdHeader(this.templateMaps ,useTemplateHash),
2018-03-09 19:58:05 +08:00
setDataviewsAndWidgetsUrlsToLayergroupMetadata(this.layergroupMetadata),
setAnalysesMetadataToLayergroup(this.layergroupMetadata, includeQuery),
setTurboCartoMetadataToLayergroup(this.layergroupMetadata),
setAggregationMetadataToLayergroup(this.layergroupMetadata),
setTilejsonMetadataToLayergroup(this.layergroupMetadata),
sendResponse(),
augmentError({ label, addContext })
];
};
function checkInstantiteLayergroup () {
2017-11-06 02:13:56 +08:00
return function checkInstantiteLayergroupMiddleware(req, res, next) {
if (req.method === 'GET') {
const { callback, config } = req.query;
if (callback === undefined || callback.length === 0) {
return next(new Error('callback parameter should be present and be a function name'));
}
if (config) {
try {
req.body = JSON.parse(config);
} catch(e) {
return next(new Error('Invalid config parameter, should be a valid JSON'));
}
}
}
2017-11-08 21:27:35 +08:00
req.profiler.done('checkInstantiteLayergroup');
2017-11-06 02:13:56 +08:00
return next();
};
}
2017-11-06 02:13:56 +08:00
function getTemplate (
templateMaps,
pgConnection,
metadataBackend,
userLimitsApi,
mapConfigAdapter,
affectedTablesCache
) {
2017-11-06 02:13:56 +08:00
return function getTemplateMiddleware (req, res, next) {
const templateParams = req.body;
const { user, dbuser, dbname, dbpassword, dbhost, dbport } = res.locals;
const { template_id } = req.params;
const { auth_token } = req.query;
const params = { dbuser, dbname, dbpassword, dbhost, dbport };
2017-11-02 00:57:35 +08:00
const mapConfigProvider = new NamedMapMapConfigProvider(
templateMaps,
pgConnection,
metadataBackend,
userLimitsApi,
mapConfigAdapter,
affectedTablesCache,
2017-11-06 02:13:56 +08:00
user,
template_id,
2017-11-06 02:13:56 +08:00
templateParams,
auth_token,
params
2017-11-06 02:13:56 +08:00
);
2017-11-02 00:57:35 +08:00
mapConfigProvider.getMapConfig((err, mapConfig, rendererParams) => {
req.profiler.done('named.getMapConfig');
2017-11-06 02:13:56 +08:00
if (err) {
return next(err);
2017-11-03 16:37:01 +08:00
}
2017-11-02 00:57:35 +08:00
res.locals.mapConfig = mapConfig;
2017-11-06 02:13:56 +08:00
res.locals.rendererParams = rendererParams;
res.locals.mapConfigProvider = mapConfigProvider;
2017-11-06 02:13:56 +08:00
next();
});
};
}
2017-11-02 00:57:35 +08:00
function instantiateLayergroup (mapBackend, userLimitsApi, pgConnection, affectedTablesCache) {
return function instantiateLayergroupMiddleware (req, res, next) {
const { user, mapConfig, rendererParams } = res.locals;
const mapConfigProvider = new CreateLayergroupMapConfigProvider(
mapConfig,
user,
userLimitsApi,
pgConnection,
affectedTablesCache,
rendererParams
);
mapBackend.createLayergroup(mapConfig, rendererParams, mapConfigProvider, (err, layergroup) => {
2017-11-08 17:52:25 +08:00
req.profiler.done('createLayergroup');
if (err) {
return next(err);
}
res.body = layergroup;
const { mapConfigProvider } = res.locals;
res.locals.analysesResults = mapConfigProvider.analysesResults;
res.locals.template = mapConfigProvider.template;
res.locals.context = mapConfigProvider.context;
next();
});
};
}
2018-03-09 19:58:05 +08:00
function setDataviewsAndWidgetsUrlsToLayergroupMetadata (layergroupMetadata) {
return function setDataviewsAndWidgetsUrlsToLayergroupMetadataMiddleware (req, res, next) {
const { user, mapConfig } = res.locals;
const layergroup = res.body;
layergroupMetadata.addDataviewsAndWidgetsUrls(user, layergroup, mapConfig.obj());
next();
};
}
2018-03-09 19:58:05 +08:00
function setAnalysesMetadataToLayergroup (layergroupMetadata, includeQuery) {
2017-11-06 02:13:56 +08:00
return function setAnalysesMetadataToLayergroupMiddleware (req, res, next) {
const { user, analysesResults = [] } = res.locals;
const layergroup = res.body;
2018-03-09 19:58:05 +08:00
layergroupMetadata.addAnalysesMetadata(user, layergroup, analysesResults, includeQuery);
next();
};
}
2018-03-09 19:58:05 +08:00
function setTurboCartoMetadataToLayergroup (layergroupMetadata) {
2017-11-06 02:13:56 +08:00
return function setTurboCartoMetadataToLayergroupMiddleware (req, res, next) {
const { mapConfig, context } = res.locals;
const layergroup = res.body;
2016-06-02 20:14:11 +08:00
layergroupMetadata.addTurboCartoContextMetadata(layergroup, mapConfig.obj(), context);
2016-03-19 01:09:17 +08:00
2017-11-06 02:13:56 +08:00
next();
};
}
2016-03-19 01:09:17 +08:00
2018-03-09 19:58:05 +08:00
function setAggregationMetadataToLayergroup (layergroupMetadata) {
return function setAggregationMetadataToLayergroupMiddleware (req, res, next) {
const { mapConfig, context } = res.locals;
const layergroup = res.body;
layergroupMetadata.addAggregationContextMetadata(layergroup, mapConfig.obj(), context);
next();
};
}
2018-03-09 19:58:05 +08:00
function setTilejsonMetadataToLayergroup (layergroupMetadata) {
return function augmentLayergroupTilejsonMiddleware (req, res, next) {
const { user, mapConfig } = res.locals;
const layergroup = res.body;
layergroupMetadata.addTileJsonMetadata(layergroup, user, mapConfig);
next();
};
}
function augmentError (options) {
2017-11-03 01:38:34 +08:00
const { addContext = false, label = 'MAPS CONTROLLER' } = options;
return function augmentErrorMiddleware (err, req, res, next) {
2017-11-08 17:52:25 +08:00
req.profiler.done('error');
const { mapConfig } = res.locals;
2017-11-03 15:48:13 +08:00
if (addContext) {
err = Number.isFinite(err.layerIndex) ? populateError(err, mapConfig) : err;
}
err.label = label;
next(err);
};
}
function populateError(err, mapConfig) {
var error = new Error(err.message);
error.http_status = err.http_status;
if (!err.http_status && err.message.indexOf('column "the_geom_webmercator" does not exist') >= 0) {
error.http_status = 400;
}
error.type = 'layer';
error.subtype = err.message.indexOf('Postgis Plugin') >= 0 ? 'query' : undefined;
error.layer = {
id: mapConfig.getLayerId(err.layerIndex),
index: err.layerIndex,
type: mapConfig.layerType(err.layerIndex)
};
return error;
}