2018-10-23 23:45:42 +08:00
|
|
|
'use strict';
|
|
|
|
|
2018-05-31 20:57:34 +08:00
|
|
|
const BaseMapConfigProvider = require('./base-mapconfig-adapter');
|
2018-05-31 01:50:07 +08:00
|
|
|
const crypto = require('crypto');
|
|
|
|
const dot = require('dot');
|
|
|
|
const MapConfig = require('windshaft').model.MapConfig;
|
2019-10-07 16:50:14 +08:00
|
|
|
const templateName = require('../../../backends/template-maps').templateName;
|
2015-07-09 20:39:25 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
// Configure bases for cache keys suitable for string interpolation
|
2018-05-31 20:57:34 +08:00
|
|
|
const baseKey = '{{=it.dbname}}:{{=it.user}}:{{=it.templateName}}';
|
2018-05-31 02:02:38 +08:00
|
|
|
const rendererKey = baseKey + ':{{=it.authToken}}:{{=it.configHash}}:{{=it.format}}:{{=it.layer}}:{{=it.scale_factor}}';
|
2015-07-09 20:39:25 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
const baseKeyTpl = dot.template(baseKey);
|
|
|
|
const rendererKeyTpl = dot.template(rendererKey);
|
2015-07-09 20:39:25 +08:00
|
|
|
|
2018-05-31 20:57:34 +08:00
|
|
|
module.exports = class NamedMapMapConfigProvider extends BaseMapConfigProvider {
|
2018-05-31 02:02:38 +08:00
|
|
|
constructor (
|
|
|
|
templateMaps,
|
|
|
|
pgConnection,
|
|
|
|
metadataBackend,
|
|
|
|
userLimitsBackend,
|
|
|
|
mapConfigAdapter,
|
|
|
|
affectedTablesCache,
|
2018-05-31 20:57:34 +08:00
|
|
|
user,
|
2018-05-31 02:02:38 +08:00
|
|
|
templateId,
|
|
|
|
config,
|
|
|
|
authToken,
|
|
|
|
params
|
|
|
|
) {
|
2018-05-31 20:57:34 +08:00
|
|
|
super();
|
2018-05-31 02:02:38 +08:00
|
|
|
this.templateMaps = templateMaps;
|
|
|
|
this.pgConnection = pgConnection;
|
|
|
|
this.metadataBackend = metadataBackend;
|
|
|
|
this.userLimitsBackend = userLimitsBackend;
|
|
|
|
this.mapConfigAdapter = mapConfigAdapter;
|
|
|
|
|
2018-05-31 20:57:34 +08:00
|
|
|
this.user = user;
|
2018-05-31 02:02:38 +08:00
|
|
|
this.templateName = templateName(templateId);
|
|
|
|
this.config = config;
|
|
|
|
this.authToken = authToken;
|
|
|
|
this.params = params;
|
|
|
|
|
2020-04-29 20:32:08 +08:00
|
|
|
// FIXME: why is this different thah that:
|
|
|
|
// this.cacheBuster = params.cache_buster || 0;
|
|
|
|
// test: "should fail to use template from named map provider after template deletion"
|
|
|
|
// check named-map-provider-cache invalidation
|
2018-05-31 02:02:38 +08:00
|
|
|
this.cacheBuster = Date.now();
|
|
|
|
|
|
|
|
// use template after call to mapConfig
|
|
|
|
this.template = null;
|
|
|
|
|
|
|
|
this.affectedTablesCache = affectedTablesCache;
|
|
|
|
|
|
|
|
// providing
|
|
|
|
this.mapConfig = null;
|
|
|
|
this.rendererParams = null;
|
|
|
|
this.context = {};
|
|
|
|
this.analysesResults = [];
|
2015-07-09 20:39:25 +08:00
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
getMapConfig (callback) {
|
2019-09-12 23:23:19 +08:00
|
|
|
if (this.mapConfig !== null) {
|
|
|
|
return callback(null, this.mapConfig, this.rendererParams, this.context);
|
2018-05-31 01:30:34 +08:00
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.getContext((err, context) => {
|
2018-05-31 01:30:34 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
let templateParams = {};
|
2018-05-31 01:30:34 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
if (this.config) {
|
|
|
|
try {
|
2019-10-22 01:07:24 +08:00
|
|
|
templateParams = Object.prototype.toString.call(this.config) === '[object String]'
|
|
|
|
? JSON.parse(this.config)
|
|
|
|
: this.config;
|
2018-05-31 02:02:38 +08:00
|
|
|
} catch (e) {
|
2019-03-27 18:38:25 +08:00
|
|
|
const err = new Error('malformed config parameter, should be a valid JSON');
|
2018-05-31 02:02:38 +08:00
|
|
|
return callback(err);
|
|
|
|
}
|
2018-05-31 01:30:34 +08:00
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
context.templateParams = templateParams;
|
2018-05-31 01:43:23 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.getTemplate((err, template) => {
|
2018-05-31 01:30:34 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
let requestMapConfig;
|
2018-05-31 01:30:34 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
try {
|
|
|
|
requestMapConfig = this.templateMaps.instance(template, templateParams);
|
|
|
|
} catch (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2018-05-31 01:30:34 +08:00
|
|
|
|
2018-05-31 20:57:34 +08:00
|
|
|
const { user, rendererParams } = this;
|
2018-05-31 02:02:38 +08:00
|
|
|
|
|
|
|
this.mapConfigAdapter.getMapConfig(
|
2018-09-04 22:21:20 +08:00
|
|
|
user, requestMapConfig, rendererParams, context, (err, mapConfig, stats = {}) => {
|
2019-10-22 01:07:24 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2018-05-31 01:30:34 +08:00
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
this.mapConfig = (mapConfig === null) ? null : new MapConfig(mapConfig, context.datasource);
|
|
|
|
this.analysesResults = context.analysesResults || [];
|
2018-05-31 01:07:28 +08:00
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
return callback(null, this.mapConfig, this.rendererParams, this.context, stats);
|
|
|
|
});
|
2018-05-31 02:02:38 +08:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
getContext (callback) {
|
2018-05-31 20:57:34 +08:00
|
|
|
this.getDBParams(this.user, (err, rendererParams) => {
|
2018-05-31 00:15:51 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
2015-07-09 20:39:25 +08:00
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.rendererParams = rendererParams;
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 20:57:34 +08:00
|
|
|
this.metadataBackend.getUserMapKey(this.user, (err, apiKey) => {
|
2018-05-31 01:07:28 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
const context = {};
|
|
|
|
|
|
|
|
context.analysisConfiguration = {
|
2018-05-31 20:57:34 +08:00
|
|
|
user: this.user,
|
2018-05-31 02:02:38 +08:00
|
|
|
db: {
|
|
|
|
host: rendererParams.dbhost,
|
|
|
|
port: rendererParams.dbport,
|
|
|
|
dbname: rendererParams.dbname,
|
|
|
|
user: rendererParams.dbuser,
|
|
|
|
pass: rendererParams.dbpassword
|
|
|
|
},
|
|
|
|
batch: {
|
2018-05-31 20:57:34 +08:00
|
|
|
username: this.user,
|
2019-11-14 18:36:47 +08:00
|
|
|
apiKey
|
2018-05-31 02:02:38 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-05-31 20:57:34 +08:00
|
|
|
this.userLimitsBackend.getRenderLimits(this.user, this.params.api_key, (err, renderLimits) => {
|
2018-05-31 02:02:38 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
context.limits = renderLimits || {};
|
|
|
|
|
|
|
|
this.context = context;
|
|
|
|
|
|
|
|
return callback(null, context);
|
|
|
|
});
|
2018-05-31 00:15:51 +08:00
|
|
|
});
|
|
|
|
});
|
2015-07-10 00:47:21 +08:00
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
getTemplate (callback) {
|
2019-09-12 23:23:19 +08:00
|
|
|
if (this.template !== null) {
|
|
|
|
return callback(null, this.template);
|
2018-05-31 00:15:51 +08:00
|
|
|
}
|
|
|
|
|
2018-05-31 20:57:34 +08:00
|
|
|
this.templateMaps.getTemplate(this.user, this.templateName, (err, tpl) => {
|
2018-05-31 02:02:38 +08:00
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
if (!tpl) {
|
2018-05-31 20:57:34 +08:00
|
|
|
const error = new Error(`Template '${this.templateName}' of user '${this.user}' not found`);
|
2018-05-31 02:02:38 +08:00
|
|
|
error.http_status = 404;
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
return callback(error);
|
|
|
|
}
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
let authorized = false;
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
try {
|
|
|
|
authorized = this.templateMaps.isAuthorized(tpl, this.authToken);
|
|
|
|
} catch (err) {
|
|
|
|
const error = new Error('Failed to authorize template');
|
|
|
|
error.http_status = 403;
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
return callback(error);
|
|
|
|
}
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
if (!authorized) {
|
|
|
|
const error = new Error('Unauthorized template instantiation');
|
|
|
|
error.http_status = 403;
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
return callback(error);
|
|
|
|
}
|
2018-05-31 00:15:51 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.template = tpl;
|
2015-07-10 00:47:21 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
return callback(null, this.template);
|
|
|
|
});
|
|
|
|
}
|
2015-07-09 20:39:25 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
getKey () {
|
|
|
|
return this.createKey(false);
|
|
|
|
}
|
2015-07-09 20:39:25 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
getCacheBuster () {
|
|
|
|
return this.cacheBuster;
|
|
|
|
}
|
2015-09-23 22:45:20 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
reset () {
|
|
|
|
this.template = null;
|
2015-09-23 22:45:20 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.affectedTables = null;
|
2015-09-23 22:45:20 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.mapConfig = null;
|
2015-09-23 22:45:20 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.cacheBuster = Date.now();
|
|
|
|
}
|
2015-07-09 20:39:25 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
filter (key) {
|
|
|
|
const regex = new RegExp('^' + this.createKey(true) + '.*');
|
|
|
|
return key && key.match(regex);
|
|
|
|
}
|
2015-07-10 00:47:21 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
createKey (base) {
|
2018-10-19 17:57:54 +08:00
|
|
|
const {
|
|
|
|
dbname = '',
|
|
|
|
user = this.user,
|
|
|
|
templateName = this.templateName,
|
|
|
|
authToken = this.authToken || '',
|
|
|
|
configHash = createConfigHash(this.config),
|
|
|
|
layer = '',
|
|
|
|
scale_factor = 1
|
|
|
|
} = this.params;
|
|
|
|
const tplValues = { dbname, user, templateName, authToken, configHash, layer, scale_factor };
|
2018-05-31 02:02:38 +08:00
|
|
|
|
|
|
|
return (base) ? baseKeyTpl(tplValues) : rendererKeyTpl(tplValues);
|
|
|
|
}
|
2015-07-10 00:47:21 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
getDBParams (cdbuser, callback) {
|
2018-05-31 20:57:34 +08:00
|
|
|
const dbParams = Object.assign({ user: this.user }, this.params);
|
2015-07-09 20:39:25 +08:00
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
this.pgConnection.getDatabaseParams(cdbuser, (err, databaseParams) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
dbParams.dbuser = databaseParams.dbuser;
|
2019-11-12 20:12:01 +08:00
|
|
|
dbParams.dbpassword = databaseParams.dbpassword;
|
2018-05-31 02:02:38 +08:00
|
|
|
dbParams.dbhost = databaseParams.dbhost;
|
|
|
|
dbParams.dbport = databaseParams.dbport;
|
|
|
|
dbParams.dbname = databaseParams.dbname;
|
|
|
|
|
|
|
|
return callback(null, dbParams);
|
|
|
|
});
|
2015-07-10 01:49:11 +08:00
|
|
|
}
|
|
|
|
|
2018-05-31 02:02:38 +08:00
|
|
|
getTemplateName () {
|
|
|
|
return this.templateName;
|
|
|
|
}
|
2015-07-15 02:10:55 +08:00
|
|
|
};
|
2018-04-06 18:59:53 +08:00
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
function createConfigHash (config) {
|
2018-05-31 02:02:38 +08:00
|
|
|
if (!config) {
|
|
|
|
return '';
|
|
|
|
}
|
2018-04-06 18:59:53 +08:00
|
|
|
|
2019-10-22 01:07:24 +08:00
|
|
|
return crypto.createHash('md5').update(JSON.stringify(config)).digest('hex').substring(0, 8);
|
2018-05-31 02:02:38 +08:00
|
|
|
}
|
2018-04-06 18:59:53 +08:00
|
|
|
|
2018-10-19 17:57:54 +08:00
|
|
|
module.exports.configHash = createConfigHash;
|