2015-07-10 17:24:32 +08:00
|
|
|
var _ = require('underscore');
|
|
|
|
var windshaft = require('windshaft');
|
2016-02-23 02:11:54 +08:00
|
|
|
var QueryTables = require('cartodb-query-tables');
|
2015-07-05 02:41:22 +08:00
|
|
|
|
2017-03-23 01:58:37 +08:00
|
|
|
var ResourceLocator = require('../models/resource-locator');
|
|
|
|
|
2015-07-08 19:27:56 +08:00
|
|
|
var cors = require('../middleware/cors');
|
2015-09-30 23:17:01 +08:00
|
|
|
var userMiddleware = require('../middleware/user');
|
2017-12-05 19:59:32 +08:00
|
|
|
const allowQueryParams = require('../middleware/allow-query-params');
|
2015-07-08 19:27:56 +08:00
|
|
|
|
2015-07-10 07:30:38 +08:00
|
|
|
var MapConfig = windshaft.model.MapConfig;
|
|
|
|
var Datasource = windshaft.model.Datasource;
|
|
|
|
|
2015-07-10 17:24:32 +08:00
|
|
|
var NamedMapsCacheEntry = require('../cache/model/named_maps_entry');
|
|
|
|
|
2016-05-23 19:32:28 +08:00
|
|
|
var NamedMapMapConfigProvider = require('../models/mapconfig/provider/named-map-provider');
|
2016-05-23 19:28:11 +08:00
|
|
|
var CreateLayergroupMapConfigProvider = require('../models/mapconfig/provider/create-layergroup-provider');
|
2018-03-09 19:58:05 +08:00
|
|
|
const LayergroupMetadata = require('../utils/layergroup-metadata');
|
2017-05-10 23:17:01 +08:00
|
|
|
|
2015-07-05 02:41:22 +08:00
|
|
|
/**
|
2015-09-16 22:18:26 +08:00
|
|
|
* @param {AuthApi} authApi
|
2015-07-10 07:30:38 +08:00
|
|
|
* @param {PgConnection} pgConnection
|
|
|
|
* @param {TemplateMaps} templateMaps
|
2015-07-05 02:41:22 +08:00
|
|
|
* @param {MapBackend} mapBackend
|
2015-07-10 17:24:32 +08:00
|
|
|
* @param metadataBackend
|
|
|
|
* @param {SurrogateKeysCache} surrogateKeysCache
|
2015-07-14 19:40:41 +08:00
|
|
|
* @param {UserLimitsApi} userLimitsApi
|
|
|
|
* @param {LayergroupAffectedTables} layergroupAffectedTables
|
2016-05-24 05:35:42 +08:00
|
|
|
* @param {MapConfigAdapter} mapConfigAdapter
|
2017-05-09 18:31:16 +08:00
|
|
|
* @param {StatsBackend} statsBackend
|
2015-07-05 02:41:22 +08:00
|
|
|
* @constructor
|
|
|
|
*/
|
2017-09-26 01:40:27 +08:00
|
|
|
function MapController(prepareContext, pgConnection, templateMaps, mapBackend, metadataBackend,
|
2017-05-09 00:42:40 +08:00
|
|
|
surrogateKeysCache, userLimitsApi, layergroupAffectedTables, mapConfigAdapter,
|
2017-05-09 18:31:16 +08:00
|
|
|
statsBackend) {
|
2015-07-10 07:30:38 +08:00
|
|
|
this.pgConnection = pgConnection;
|
|
|
|
this.templateMaps = templateMaps;
|
2015-07-09 02:51:36 +08:00
|
|
|
this.mapBackend = mapBackend;
|
2015-07-10 17:24:32 +08:00
|
|
|
this.metadataBackend = metadataBackend;
|
|
|
|
this.surrogateKeysCache = surrogateKeysCache;
|
2015-07-11 01:10:55 +08:00
|
|
|
this.userLimitsApi = userLimitsApi;
|
2015-07-14 19:40:41 +08:00
|
|
|
this.layergroupAffectedTables = layergroupAffectedTables;
|
2015-07-14 17:55:49 +08:00
|
|
|
|
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
|
|
|
|
2017-05-09 18:31:16 +08:00
|
|
|
this.statsBackend = statsBackend;
|
2017-09-26 01:40:27 +08:00
|
|
|
this.prepareContext = prepareContext;
|
2015-07-05 02:41:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = MapController;
|
|
|
|
|
|
|
|
MapController.prototype.register = function(app) {
|
2017-11-06 01:55:23 +08:00
|
|
|
const { base_url_mapconfig, base_url_templated } = app;
|
|
|
|
const useTemplate = true;
|
2017-11-03 02:03:20 +08:00
|
|
|
|
2017-11-06 01:55:23 +08:00
|
|
|
app.get(base_url_mapconfig, this.composeCreateMapMiddleware());
|
|
|
|
app.post(base_url_mapconfig, this.composeCreateMapMiddleware());
|
|
|
|
app.get(`${base_url_templated}/:template_id/jsonp`, this.composeCreateMapMiddleware(useTemplate));
|
|
|
|
app.post(`${base_url_templated}/:template_id`, this.composeCreateMapMiddleware(useTemplate));
|
2015-07-10 17:24:32 +08:00
|
|
|
app.options(app.base_url_mapconfig, cors('Content-Type'));
|
2015-07-05 02:41:22 +08:00
|
|
|
};
|
|
|
|
|
2017-11-06 01:55:23 +08:00
|
|
|
MapController.prototype.composeCreateMapMiddleware = function (useTemplate = false) {
|
|
|
|
const isTemplateInstantiation = useTemplate;
|
2017-11-03 16:37:01 +08:00
|
|
|
const useTemplateHash = useTemplate;
|
|
|
|
const includeQuery = !useTemplate;
|
|
|
|
const label = useTemplate ? 'NAMED MAP LAYERGROUP' : 'ANONYMOUS LAYERGROUP';
|
|
|
|
const addContext = !useTemplate;
|
2017-11-03 02:03:20 +08:00
|
|
|
|
|
|
|
return [
|
|
|
|
cors(),
|
2018-03-01 22:42:03 +08:00
|
|
|
userMiddleware(),
|
2017-12-05 19:59:32 +08:00
|
|
|
allowQueryParams(['aggregation']),
|
2017-11-03 02:03:20 +08:00
|
|
|
this.prepareContext,
|
2018-03-08 02:09:52 +08:00
|
|
|
initProfiler(isTemplateInstantiation),
|
2018-03-08 02:11:03 +08:00
|
|
|
checkJsonContentType(),
|
2018-03-09 22:49:03 +08:00
|
|
|
this.getCreateMapMiddlewares(useTemplate),
|
2018-03-08 19:16:24 +08:00
|
|
|
incrementMapViewCount(this.metadataBackend),
|
|
|
|
augmentLayergroupData(),
|
|
|
|
getAffectedTables(this.pgConnection, this.layergroupAffectedTables),
|
|
|
|
setCacheChannel(),
|
|
|
|
setLastModified(),
|
|
|
|
setLastUpdatedTimeToLayergroup(),
|
|
|
|
setCacheControl(),
|
|
|
|
setLayerStats(this.pgConnection, this.statsBackend),
|
|
|
|
setLayergroupIdHeader(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),
|
2018-03-08 19:16:24 +08:00
|
|
|
setSurrogateKeyHeader(this.surrogateKeysCache),
|
|
|
|
sendResponse(),
|
|
|
|
augmentError({ label, addContext })
|
2017-11-03 02:24:33 +08:00
|
|
|
];
|
|
|
|
};
|
|
|
|
|
2018-03-09 22:49:03 +08:00
|
|
|
MapController.prototype.getCreateMapMiddlewares = function (useTemplate) {
|
|
|
|
if (useTemplate) {
|
|
|
|
return [
|
|
|
|
checkInstantiteLayergroup(),
|
|
|
|
getTemplate(
|
|
|
|
this.templateMaps,
|
|
|
|
this.pgConnection,
|
|
|
|
this.metadataBackend,
|
|
|
|
this.userLimitsApi,
|
|
|
|
this.mapConfigAdapter
|
|
|
|
),
|
|
|
|
instantiateLayergroup(this.mapBackend, this.userLimitsApi)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
return [
|
|
|
|
checkCreateLayergroup(),
|
|
|
|
prepareAdapterMapConfig(this.mapConfigAdapter),
|
|
|
|
createLayergroup (this.mapBackend, this.userLimitsApi)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2018-03-08 02:09:52 +08:00
|
|
|
function initProfiler (isTemplateInstantiation) {
|
2017-11-06 01:55:23 +08:00
|
|
|
const operation = isTemplateInstantiation ? 'instance_template' : 'createmap';
|
2017-11-03 02:03:20 +08:00
|
|
|
|
2017-11-06 01:55:23 +08:00
|
|
|
return function initProfilerMiddleware (req, res, next) {
|
|
|
|
req.profiler.start(`windshaft-cartodb.${operation}_${req.method.toLowerCase()}`);
|
2017-11-08 21:27:35 +08:00
|
|
|
req.profiler.done(`${operation}.initProfilerMiddleware`);
|
2017-11-06 01:55:23 +08:00
|
|
|
next();
|
|
|
|
};
|
2018-03-08 02:09:52 +08:00
|
|
|
}
|
2017-11-02 00:57:35 +08:00
|
|
|
|
2018-03-08 02:11:03 +08:00
|
|
|
function checkJsonContentType () {
|
2017-11-06 01:55:23 +08:00
|
|
|
return function checkJsonContentTypeMiddleware(req, res, next) {
|
2017-11-03 22:06:15 +08:00
|
|
|
if (req.method === 'POST' && !req.is('application/json')) {
|
2017-11-06 01:55:23 +08:00
|
|
|
return next(new Error('POST data must be of type application/json'));
|
2017-11-03 16:37:01 +08:00
|
|
|
}
|
2017-11-02 17:22:30 +08:00
|
|
|
|
2017-11-08 21:27:35 +08:00
|
|
|
req.profiler.done('checkJsonContentTypeMiddleware');
|
|
|
|
|
2017-11-06 01:55:23 +08:00
|
|
|
next();
|
|
|
|
};
|
2018-03-08 02:11:03 +08:00
|
|
|
}
|
2017-11-06 01:55:23 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
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();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-11-06 02:13:56 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function checkCreateLayergroup () {
|
2017-11-06 01:55:23 +08:00
|
|
|
return function checkCreateLayergroupMiddleware (req, res, next) {
|
2017-11-03 22:06:15 +08:00
|
|
|
if (req.method === 'GET') {
|
|
|
|
const { config } = res.locals;
|
|
|
|
|
|
|
|
if (!config) {
|
|
|
|
return next(new Error('layergroup GET needs a "config" parameter'));
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
req.body = JSON.parse(config);
|
|
|
|
} catch (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
2017-11-03 16:37:01 +08:00
|
|
|
}
|
2017-11-02 00:57:35 +08:00
|
|
|
|
2017-11-08 21:27:35 +08:00
|
|
|
req.profiler.done('checkCreateLayergroup');
|
2017-11-03 22:06:15 +08:00
|
|
|
return next();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-11-02 00:57:35 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function getTemplate (templateMaps, pgConnection, metadataBackend, userLimitsApi, mapConfigAdapter) {
|
2017-11-06 02:13:56 +08:00
|
|
|
return function getTemplateMiddleware (req, res, next) {
|
|
|
|
const templateParams = req.body;
|
|
|
|
const { user } = res.locals;
|
2017-11-02 00:57:35 +08:00
|
|
|
|
2017-11-06 02:13:56 +08:00
|
|
|
const mapconfigProvider = new NamedMapMapConfigProvider(
|
2018-03-08 19:16:24 +08:00
|
|
|
templateMaps,
|
|
|
|
pgConnection,
|
|
|
|
metadataBackend,
|
|
|
|
userLimitsApi,
|
|
|
|
mapConfigAdapter,
|
2017-11-06 02:13:56 +08:00
|
|
|
user,
|
|
|
|
req.params.template_id,
|
|
|
|
templateParams,
|
|
|
|
res.locals.auth_token,
|
|
|
|
res.locals
|
|
|
|
);
|
2017-11-02 00:57:35 +08:00
|
|
|
|
2017-11-06 02:13:56 +08:00
|
|
|
mapconfigProvider.getMapConfig((err, mapconfig, rendererParams) => {
|
2017-11-08 21:08:27 +08:00
|
|
|
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
|
|
|
|
2017-11-06 02:13:56 +08:00
|
|
|
res.locals.mapconfig = mapconfig;
|
|
|
|
res.locals.rendererParams = rendererParams;
|
|
|
|
res.locals.mapconfigProvider = mapconfigProvider;
|
|
|
|
|
|
|
|
next();
|
|
|
|
});
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-11-02 00:57:35 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function prepareAdapterMapConfig (mapConfigAdapter) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function prepareAdapterMapConfigMiddleware(req, res, next) {
|
|
|
|
const requestMapConfig = req.body;
|
|
|
|
const { user, dbhost, dbport, dbname, dbuser, dbpassword, api_key } = res.locals;
|
|
|
|
|
|
|
|
const context = {
|
|
|
|
analysisConfiguration: {
|
|
|
|
user,
|
|
|
|
db: {
|
|
|
|
host: dbhost,
|
|
|
|
port: dbport,
|
|
|
|
dbname: dbname,
|
|
|
|
user: dbuser,
|
|
|
|
pass: dbpassword
|
|
|
|
},
|
|
|
|
batch: {
|
|
|
|
username: user,
|
|
|
|
apiKey: api_key
|
|
|
|
}
|
2017-11-02 02:02:07 +08:00
|
|
|
}
|
2017-11-03 22:06:15 +08:00
|
|
|
};
|
2017-11-02 02:02:07 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
mapConfigAdapter.getMapConfig(user, requestMapConfig, res.locals, context, (err, requestMapConfig) => {
|
2017-11-08 21:08:27 +08:00
|
|
|
req.profiler.done('anonymous.getMapConfig');
|
2017-11-03 22:06:15 +08:00
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
2017-11-02 02:02:07 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
req.body = requestMapConfig;
|
|
|
|
res.locals.context = context;
|
2015-07-05 02:41:22 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
});
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function createLayergroup (mapBackend, userLimitsApi) {
|
2017-11-03 22:06:15 +08:00
|
|
|
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);
|
2017-11-06 01:55:23 +08:00
|
|
|
const mapconfigProvider =
|
2018-03-08 19:16:24 +08:00
|
|
|
new CreateLayergroupMapConfigProvider(mapconfig, user, userLimitsApi, res.locals);
|
2016-05-23 22:20:42 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
res.locals.mapconfig = mapconfig;
|
|
|
|
res.locals.analysesResults = context.analysesResults;
|
2017-11-02 02:57:20 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
mapBackend.createLayergroup(mapconfig, res.locals, mapconfigProvider, (err, layergroup) => {
|
2017-11-08 17:52:25 +08:00
|
|
|
req.profiler.done('createLayergroup');
|
2017-11-03 22:06:15 +08:00
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
2017-11-02 02:57:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
res.locals.layergroup = layergroup;
|
2017-11-01 03:10:37 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
});
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-11-02 02:02:07 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function instantiateLayergroup (mapBackend, userLimitsApi) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function instantiateLayergroupMiddleware (req, res, next) {
|
|
|
|
const { user, mapconfig, rendererParams } = res.locals;
|
|
|
|
const mapconfigProvider =
|
2018-03-08 19:16:24 +08:00
|
|
|
new CreateLayergroupMapConfigProvider(mapconfig, user, userLimitsApi, rendererParams);
|
2015-07-05 02:41:22 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
mapBackend.createLayergroup(mapconfig, rendererParams, mapconfigProvider, (err, layergroup) => {
|
2017-11-08 17:52:25 +08:00
|
|
|
req.profiler.done('createLayergroup');
|
2017-11-03 22:06:15 +08:00
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
2017-11-02 02:02:07 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
res.locals.layergroup = layergroup;
|
2017-10-31 20:36:17 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
const { mapconfigProvider } = res.locals;
|
2017-11-02 02:02:07 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
res.locals.analysesResults = mapconfigProvider.analysesResults;
|
|
|
|
res.locals.template = mapconfigProvider.template;
|
|
|
|
res.locals.templateName = mapconfigProvider.getTemplateName();
|
|
|
|
res.locals.context = mapconfigProvider.context;
|
2017-11-02 02:27:01 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
});
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-11-02 02:02:07 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function incrementMapViewCount (metadataBackend) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function incrementMapViewCountMiddleware(req, res, next) {
|
|
|
|
const { mapconfig, user } = res.locals;
|
2015-07-09 02:51:36 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
// Error won't blow up, just be logged.
|
2018-03-08 19:16:24 +08:00
|
|
|
metadataBackend.incMapviewCount(user, mapconfig.obj().stat_tag, (err) => {
|
2017-11-03 22:06:15 +08:00
|
|
|
req.profiler.done('incMapviewCount');
|
2017-11-01 00:29:55 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
if (err) {
|
|
|
|
global.logger.log(`ERROR: failed to increment mapview count for user '${user}': ${err.message}`);
|
|
|
|
}
|
2017-10-31 21:47:29 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
});
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function augmentLayergroupData () {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function augmentLayergroupDataMiddleware (req, res, next) {
|
|
|
|
const { layergroup } = res.locals;
|
2017-10-31 20:46:03 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
// include in layergroup response the variables in serverMedata
|
|
|
|
// those variables are useful to send to the client information
|
|
|
|
// about how to reach this server or information about it
|
|
|
|
_.extend(layergroup, global.environment.serverMetadata);
|
2017-10-31 20:46:03 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-10-31 20:46:03 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function getAffectedTables (pgConnection, layergroupAffectedTables) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function getAffectedTablesMiddleware (req, res, next) {
|
|
|
|
const { dbname, layergroup, user, mapconfig } = res.locals;
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
pgConnection.getConnection(user, (err, connection) => {
|
2017-10-31 20:13:20 +08:00
|
|
|
if (err) {
|
2017-11-02 18:29:43 +08:00
|
|
|
return next(err);
|
2015-07-09 02:51:36 +08:00
|
|
|
}
|
2015-07-10 17:24:32 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
const sql = [];
|
|
|
|
mapconfig.getLayers().forEach(function(layer) {
|
|
|
|
sql.push(layer.options.sql);
|
|
|
|
if (layer.options.affected_tables) {
|
|
|
|
layer.options.affected_tables.map(function(table) {
|
|
|
|
sql.push('SELECT * FROM ' + table + ' LIMIT 0');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
QueryTables.getAffectedTablesFromQuery(connection, sql.join(';'), (err, affectedTables) => {
|
2017-11-08 17:52:25 +08:00
|
|
|
req.profiler.done('getAffectedTablesFromQuery');
|
2017-11-03 22:06:15 +08:00
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
// feed affected tables cache so it can be reused from, for instance, layergroup controller
|
2018-03-08 19:16:24 +08:00
|
|
|
layergroupAffectedTables.set(dbname, layergroup.layergroupId, affectedTables);
|
2017-11-03 22:06:15 +08:00
|
|
|
|
|
|
|
res.locals.affectedTables = affectedTables;
|
|
|
|
|
|
|
|
next();
|
|
|
|
});
|
2017-11-02 18:29:43 +08:00
|
|
|
});
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2015-10-26 21:35:51 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function setCacheChannel () {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function setCacheChannelMiddleware (req, res, next) {
|
|
|
|
const { affectedTables } = res.locals;
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
if (req.method === 'GET') {
|
|
|
|
res.set('X-Cache-Channel', affectedTables.getCacheChannel());
|
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function setLastModified () {
|
2017-11-07 16:50:52 +08:00
|
|
|
return function setLastModifiedMiddleware (req, res, next) {
|
|
|
|
if (req.method === 'GET') {
|
|
|
|
res.set('Last-Modified', (new Date()).toUTCString());
|
|
|
|
}
|
|
|
|
|
|
|
|
next();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-11-07 16:50:52 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function setLastUpdatedTimeToLayergroup () {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function setLastUpdatedTimeToLayergroupMiddleware (req, res, next) {
|
|
|
|
const { affectedTables, layergroup, analysesResults } = res.locals;
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
var lastUpdateTime = affectedTables.getLastUpdatedAt();
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
lastUpdateTime = getLastUpdatedTime(analysesResults, lastUpdateTime) || lastUpdateTime;
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
// last update for layergroup cache buster
|
|
|
|
layergroup.layergroupid = layergroup.layergroupid + ':' + lastUpdateTime;
|
|
|
|
layergroup.last_updated = new Date(lastUpdateTime).toISOString();
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-06 02:13:56 +08:00
|
|
|
function getLastUpdatedTime(analysesResults, lastUpdateTime) {
|
|
|
|
if (!Array.isArray(analysesResults)) {
|
|
|
|
return lastUpdateTime;
|
|
|
|
}
|
|
|
|
return analysesResults.reduce(function(lastUpdateTime, analysis) {
|
|
|
|
return analysis.getNodes().reduce(function(lastNodeUpdatedAtTime, node) {
|
|
|
|
var nodeUpdatedAtDate = node.getUpdatedAt();
|
|
|
|
var nodeUpdatedTimeAt = (nodeUpdatedAtDate && nodeUpdatedAtDate.getTime()) || 0;
|
|
|
|
return nodeUpdatedTimeAt > lastNodeUpdatedAtTime ? nodeUpdatedTimeAt : lastNodeUpdatedAtTime;
|
|
|
|
}, lastUpdateTime);
|
|
|
|
}, lastUpdateTime);
|
|
|
|
}
|
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function setCacheControl () {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function setCacheControlMiddleware (req, res, next) {
|
|
|
|
if (req.method === 'GET') {
|
|
|
|
var ttl = global.environment.varnish.layergroupTtl || 86400;
|
|
|
|
res.set('Cache-Control', 'public,max-age='+ttl+',must-revalidate');
|
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function setLayerStats (pgConnection, statsBackend) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function setLayerStatsMiddleware(req, res, next) {
|
|
|
|
const { user, mapconfig, layergroup } = res.locals;
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
pgConnection.getConnection(user, (err, connection) => {
|
2017-10-31 20:13:20 +08:00
|
|
|
if (err) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return next(err);
|
2017-10-31 20:13:20 +08:00
|
|
|
}
|
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
statsBackend.getStats(mapconfig, connection, function(err, layersStats) {
|
2017-11-03 22:06:15 +08:00
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layersStats.length > 0) {
|
|
|
|
layergroup.metadata.layers.forEach(function (layer, index) {
|
|
|
|
layer.meta.stats = layersStats[index];
|
|
|
|
});
|
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
|
|
|
});
|
2017-10-31 20:13:20 +08:00
|
|
|
});
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-10-31 20:13:20 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function setLayergroupIdHeader (templateMaps, useTemplateHash) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function setLayergroupIdHeaderMiddleware (req, res, next) {
|
2017-11-01 01:54:32 +08:00
|
|
|
const { layergroup, user, template } = res.locals;
|
|
|
|
|
|
|
|
if (useTemplateHash) {
|
2018-03-08 19:16:24 +08:00
|
|
|
var templateHash = templateMaps.fingerPrint(template).substring(0, 8);
|
2017-11-01 01:54:32 +08:00
|
|
|
layergroup.layergroupid = `${user}@${templateHash}@${layergroup.layergroupid}`;
|
|
|
|
}
|
2017-11-01 01:02:23 +08:00
|
|
|
|
2017-11-01 01:54:32 +08:00
|
|
|
res.set('X-Layergroup-Id', layergroup.layergroupid);
|
2017-11-01 01:02:23 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-11-01 01:02:23 +08:00
|
|
|
|
2018-03-09 19:58:05 +08:00
|
|
|
function setDataviewsAndWidgetsUrlsToLayergroupMetadata (layergroupMetadata) {
|
2017-11-03 22:06:15 +08:00
|
|
|
return function setDataviewsAndWidgetsUrlsToLayergroupMetadataMiddleware (req, res, next) {
|
|
|
|
const { layergroup, user, mapconfig } = res.locals;
|
2017-11-01 01:02:23 +08:00
|
|
|
|
2018-03-09 19:58:05 +08:00
|
|
|
layergroupMetadata.addDataviewsAndWidgetsUrls(user, layergroup, mapconfig.obj());
|
2017-11-01 01:02:23 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-11-01 01:02:23 +08:00
|
|
|
|
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 { layergroup, user, analysesResults = [] } = res.locals;
|
2017-11-01 02:49:12 +08:00
|
|
|
|
2018-03-09 19:58:05 +08:00
|
|
|
layergroupMetadata.addAnalysesMetadata(user, layergroup, analysesResults, includeQuery);
|
2017-11-01 02:49:12 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
next();
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-11-01 02:49:12 +08:00
|
|
|
|
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 { layergroup, mapconfig, context } = res.locals;
|
2016-06-02 20:14:11 +08:00
|
|
|
|
2018-03-09 19:58:05 +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();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2016-03-19 01:09:17 +08:00
|
|
|
|
2018-03-09 19:58:05 +08:00
|
|
|
function setAggregationMetadataToLayergroup (layergroupMetadata) {
|
2017-12-04 19:40:53 +08:00
|
|
|
return function setAggregationMetadataToLayergroupMiddleware (req, res, next) {
|
|
|
|
const { layergroup, mapconfig, context } = res.locals;
|
|
|
|
|
2018-03-09 19:58:05 +08:00
|
|
|
layergroupMetadata.addAggregationContextMetadata(layergroup, mapconfig.obj(), context);
|
2017-12-04 19:40:53 +08:00
|
|
|
|
|
|
|
next();
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-12-04 19:40:53 +08:00
|
|
|
|
2018-03-09 19:58:05 +08:00
|
|
|
function setTilejsonMetadataToLayergroup (layergroupMetadata) {
|
2018-03-08 19:16:24 +08:00
|
|
|
return function augmentLayergroupTilejsonMiddleware (req, res, next) {
|
|
|
|
const { layergroup, user, mapconfig } = res.locals;
|
|
|
|
|
2018-03-09 19:58:05 +08:00
|
|
|
layergroupMetadata.addTileJsonMetadata(layergroup, user, mapconfig);
|
2018-03-08 19:16:24 +08:00
|
|
|
|
|
|
|
next();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function setSurrogateKeyHeader (surrogateKeysCache) {
|
2017-11-06 02:13:56 +08:00
|
|
|
return function setSurrogateKeyHeaderMiddleware(req, res, next) {
|
|
|
|
const { affectedTables, user, templateName } = res.locals;
|
|
|
|
|
|
|
|
if (req.method === 'GET' && affectedTables.tables && affectedTables.tables.length > 0) {
|
2018-03-08 19:16:24 +08:00
|
|
|
surrogateKeysCache.tag(res, affectedTables);
|
2017-11-06 02:13:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (templateName) {
|
2018-03-08 19:16:24 +08:00
|
|
|
surrogateKeysCache.tag(res, new NamedMapsCacheEntry(user, templateName));
|
2017-11-06 02:13:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
next();
|
2018-03-08 19:16:24 +08:00
|
|
|
};
|
|
|
|
}
|
2017-11-06 02:13:56 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function sendResponse () {
|
2017-11-06 02:13:56 +08:00
|
|
|
return function sendResponseMiddleware (req, res) {
|
2017-11-08 17:52:25 +08:00
|
|
|
req.profiler.done('res');
|
2017-11-06 02:13:56 +08:00
|
|
|
const { layergroup } = res.locals;
|
|
|
|
|
|
|
|
res.status(200);
|
|
|
|
|
|
|
|
if (req.query && req.query.callback) {
|
|
|
|
res.jsonp(layergroup);
|
|
|
|
} else {
|
|
|
|
res.json(layergroup);
|
|
|
|
}
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-11-01 03:49:26 +08:00
|
|
|
|
2018-03-08 19:16:24 +08:00
|
|
|
function augmentError (options) {
|
2017-11-03 01:38:34 +08:00
|
|
|
const { addContext = false, label = 'MAPS CONTROLLER' } = options;
|
2017-11-01 03:49:26 +08:00
|
|
|
|
2017-11-03 22:06:15 +08:00
|
|
|
return function augmentErrorMiddleware (err, req, res, next) {
|
2017-11-08 17:52:25 +08:00
|
|
|
req.profiler.done('error');
|
2017-11-01 03:49:26 +08:00
|
|
|
const { mapconfig } = res.locals;
|
|
|
|
|
2017-11-03 15:48:13 +08:00
|
|
|
if (addContext) {
|
2017-11-01 03:49:26 +08:00
|
|
|
err = Number.isFinite(err.layerIndex) ? populateError(err, mapconfig) : err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err.label = label;
|
|
|
|
|
|
|
|
next(err);
|
|
|
|
};
|
2018-03-08 19:16:24 +08:00
|
|
|
}
|
2017-11-01 03:49:26 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|