2016-07-12 22:08:48 +08:00
|
|
|
var step = require('step');
|
|
|
|
var assert = require('assert');
|
|
|
|
var dot = require('dot');
|
|
|
|
dot.templateSettings.strip = false;
|
|
|
|
var PSQL = require('cartodb-psql');
|
|
|
|
var cors = require('../middleware/cors');
|
|
|
|
var userMiddleware = require('../middleware/user');
|
|
|
|
|
2017-09-26 01:40:27 +08:00
|
|
|
function AnalysesController(prepareContext) {
|
|
|
|
this.prepareContext = prepareContext;
|
2016-07-12 22:08:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = AnalysesController;
|
|
|
|
|
2017-10-05 18:12:21 +08:00
|
|
|
AnalysesController.prototype.register = function(app) {
|
|
|
|
app.get(
|
|
|
|
app.base_url_mapconfig + '/analyses/catalog',
|
2017-09-22 06:42:17 +08:00
|
|
|
cors(),
|
2017-10-05 18:12:21 +08:00
|
|
|
userMiddleware,
|
2017-09-22 23:56:47 +08:00
|
|
|
this.prepareContext,
|
2017-11-14 20:49:12 +08:00
|
|
|
this.catalog.bind(this),
|
2017-11-14 20:53:42 +08:00
|
|
|
this.setCacheControlHeader(),
|
2017-11-14 20:49:12 +08:00
|
|
|
this.sendResponse()
|
2017-09-22 06:42:17 +08:00
|
|
|
);
|
2016-07-12 22:08:48 +08:00
|
|
|
};
|
|
|
|
|
2017-11-14 20:53:42 +08:00
|
|
|
AnalysesController.prototype.setCacheControlHeader = function () {
|
|
|
|
return function setCacheControlHeaderMiddleware (req, res, next) {
|
2017-11-14 20:49:12 +08:00
|
|
|
res.set('Cache-Control', 'public,max-age=10,must-revalidate');
|
2017-11-14 20:53:42 +08:00
|
|
|
next();
|
|
|
|
};
|
|
|
|
};
|
2017-10-31 02:28:40 +08:00
|
|
|
|
2017-11-14 20:53:42 +08:00
|
|
|
AnalysesController.prototype.sendResponse = function() {
|
|
|
|
return function sendResponseMiddleware (req, res) {
|
2017-11-14 20:49:12 +08:00
|
|
|
res.status(200);
|
2017-10-31 02:28:40 +08:00
|
|
|
|
2017-11-14 20:49:12 +08:00
|
|
|
if (req.query && req.query.callback) {
|
|
|
|
res.jsonp(res.body);
|
|
|
|
} else {
|
|
|
|
res.json(res.body);
|
|
|
|
}
|
|
|
|
};
|
2016-07-12 22:08:48 +08:00
|
|
|
};
|
|
|
|
|
2017-09-21 17:46:31 +08:00
|
|
|
AnalysesController.prototype.catalog = function (req, res, next) {
|
2017-10-03 23:47:57 +08:00
|
|
|
var username = res.locals.user;
|
2016-07-12 22:08:48 +08:00
|
|
|
|
|
|
|
step(
|
2017-09-22 06:42:17 +08:00
|
|
|
function catalogQuery() {
|
2017-09-29 17:07:11 +08:00
|
|
|
var pg = new PSQL(dbParamsFromReqParams(res.locals));
|
2016-07-12 22:08:48 +08:00
|
|
|
getMetadata(username, pg, this);
|
|
|
|
},
|
|
|
|
function prepareResponse(err, results) {
|
|
|
|
assert.ifError(err);
|
|
|
|
|
|
|
|
var analysisIdToTable = results.tables.reduce(function(analysisIdToTable, table) {
|
|
|
|
var analysisId = table.relname.split('_')[2];
|
|
|
|
if (analysisId && analysisId.length === 40) {
|
|
|
|
analysisIdToTable[analysisId] = table;
|
|
|
|
}
|
|
|
|
return analysisIdToTable;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
var catalogWithTables = results.catalog.map(function(analysis) {
|
|
|
|
if (analysisIdToTable.hasOwnProperty(analysis.node_id)) {
|
|
|
|
analysis.table = analysisIdToTable[analysis.node_id];
|
|
|
|
}
|
|
|
|
return analysis;
|
|
|
|
});
|
|
|
|
|
|
|
|
return catalogWithTables.sort(function(analysisA, analysisB) {
|
|
|
|
if (!!analysisA.table && !!analysisB.table) {
|
|
|
|
return analysisB.table.size - analysisA.table.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!!analysisA.table) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!!analysisB.table) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
});
|
|
|
|
},
|
2017-11-14 20:49:12 +08:00
|
|
|
function prepareResponse(err, catalogWithTables) {
|
2016-07-12 22:08:48 +08:00
|
|
|
if (err) {
|
|
|
|
if (err.message.match(/permission\sdenied/)) {
|
|
|
|
err = new Error('Unauthorized');
|
|
|
|
err.http_status = 401;
|
|
|
|
}
|
2017-09-21 17:46:31 +08:00
|
|
|
|
2017-11-18 01:07:19 +08:00
|
|
|
return next(err);
|
2016-07-12 22:08:48 +08:00
|
|
|
}
|
2017-11-18 01:07:19 +08:00
|
|
|
|
|
|
|
res.body = { catalog: catalogWithTables };
|
|
|
|
next();
|
2016-07-12 22:08:48 +08:00
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
var catalogQueryTpl = dot.template(
|
2017-11-14 19:01:21 +08:00
|
|
|
'SELECT analysis_def->>\'type\' as type, * FROM cdb_analysis_catalog WHERE username = \'{{=it._username}}\''
|
2016-07-12 22:08:48 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
var tablesQueryTpl = dot.template([
|
|
|
|
"WITH analysis_tables AS (",
|
|
|
|
" SELECT",
|
|
|
|
" n.nspname AS nspname,",
|
|
|
|
" c.relname AS relname,",
|
|
|
|
" pg_total_relation_size(",
|
|
|
|
" format('%s.%s', pg_catalog.quote_ident(n.nspname), pg_catalog.quote_ident(c.relname))",
|
|
|
|
" ) AS size,",
|
|
|
|
" format('%s.%s', pg_catalog.quote_ident(nspname), pg_catalog.quote_ident(relname)) AS fully_qualified_name",
|
|
|
|
" FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n",
|
|
|
|
" WHERE c.relnamespace = n.oid",
|
|
|
|
" AND pg_catalog.quote_ident(c.relname) ~ '^analysis_[a-z0-9]{10}_[a-z0-9]{40}$'",
|
|
|
|
" AND n.nspname IN ('{{=it._username}}', 'public')",
|
|
|
|
")",
|
|
|
|
"SELECT *, pg_size_pretty(size) as size_pretty",
|
|
|
|
"FROM analysis_tables",
|
|
|
|
"ORDER BY size DESC"
|
|
|
|
].join('\n'));
|
|
|
|
|
|
|
|
|
|
|
|
function getMetadata(username, pg, callback) {
|
|
|
|
var results = {
|
|
|
|
catalog: [],
|
|
|
|
tables: []
|
|
|
|
};
|
|
|
|
step(
|
|
|
|
function getCatalog() {
|
|
|
|
pg.query(catalogQueryTpl({_username: username}), this, true); // use read-only transaction
|
|
|
|
},
|
|
|
|
function handleCatalog(err, resultSet) {
|
|
|
|
assert.ifError(err);
|
|
|
|
resultSet = resultSet || {};
|
|
|
|
results.catalog = resultSet.rows || [];
|
|
|
|
this();
|
|
|
|
},
|
|
|
|
function getTables(err) {
|
|
|
|
assert.ifError(err);
|
|
|
|
pg.query(tablesQueryTpl({_username: username}), this, true); // use read-only transaction
|
|
|
|
},
|
|
|
|
function handleTables(err, resultSet) {
|
|
|
|
assert.ifError(err);
|
|
|
|
resultSet = resultSet || {};
|
|
|
|
results.tables = resultSet.rows || [];
|
|
|
|
this();
|
|
|
|
},
|
|
|
|
function finish(err) {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return callback(null, results);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function dbParamsFromReqParams(params) {
|
|
|
|
var dbParams = {};
|
|
|
|
if ( params.dbuser ) {
|
|
|
|
dbParams.user = params.dbuser;
|
|
|
|
}
|
|
|
|
if ( params.dbpassword ) {
|
|
|
|
dbParams.pass = params.dbpassword;
|
|
|
|
}
|
|
|
|
if ( params.dbhost ) {
|
|
|
|
dbParams.host = params.dbhost;
|
|
|
|
}
|
|
|
|
if ( params.dbport ) {
|
|
|
|
dbParams.port = params.dbport;
|
|
|
|
}
|
|
|
|
if ( params.dbname ) {
|
|
|
|
dbParams.dbname = params.dbname;
|
|
|
|
}
|
|
|
|
return dbParams;
|
|
|
|
}
|