openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
425 lines (382 loc) • 16.6 kB
JavaScript
var Channel, Client, Q, application, authorisation, config, domain, getChannelIDsArray, getProjectionObject, logger, os, sdc, statsd_client, statsd_server, timer, transactions, utils,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
transactions = require('../model/transactions');
Channel = require('../model/channels').Channel;
Client = require('../model/clients').Client;
Q = require('q');
logger = require('winston');
authorisation = require('./authorisation');
utils = require("../utils");
config = require('../config/config');
statsd_client = require("statsd-client");
statsd_server = config.get('statsd');
sdc = new statsd_client(statsd_server);
application = config.get('application');
os = require("os");
timer = new Date();
domain = os.hostname() + '.' + application.name;
getChannelIDsArray = function(channels) {
var channel, channelIDs, i, len;
channelIDs = [];
for (i = 0, len = channels.length; i < len; i++) {
channel = channels[i];
channelIDs.push(channel._id.toString());
}
return channelIDs;
};
getProjectionObject = function(filterRepresentation) {
switch (filterRepresentation) {
case "simpledetails":
return {
"request.body": 0,
"response.body": 0,
"routes.request.body": 0,
"routes.response.body": 0,
"orchestrations.request.body": 0,
"orchestrations.response.body": 0
};
case "full":
return {};
case "bulkrerun":
return {
"_id": 1,
"childIDs": 1,
"canRerun": 1,
"channelID": 1
};
default:
return {
"request.body": 0,
"request.headers": 0,
"response.body": 0,
"response.headers": 0,
orchestrations: 0,
routes: 0
};
}
};
/*
* Retrieves the list of transactions
*/
exports.getTransactions = function*() {
var channels, e, filterLimit, filterPage, filterRepresentation, filterSkip, filters, filtersObject, key, projectionFiltersObject, ref;
try {
filtersObject = this.request.query;
filterLimit = filtersObject.filterLimit;
filterPage = filtersObject.filterPage;
filterRepresentation = filtersObject.filterRepresentation;
delete filtersObject.filterLimit;
delete filtersObject.filterPage;
delete filtersObject.filterRepresentation;
filterSkip = filterPage * filterLimit;
filters = filtersObject.filters != null ? JSON.parse(filtersObject.filters) : {};
if (!authorisation.inGroup('admin', this.authenticated)) {
channels = (yield authorisation.getUserViewableChannels(this.authenticated));
if (!filtersObject.channelID) {
filters.channelID = {
$in: getChannelIDsArray(channels)
};
} else if (ref = filtersObject.channelID, indexOf.call(getChannelIDsArray(channels), ref) < 0) {
return utils.logAndSetResponse(this, 403, "Forbidden: Unauthorized channel " + filtersObject.channelID, 'info');
}
filterRepresentation = '';
}
projectionFiltersObject = getProjectionObject(filterRepresentation);
if (filtersObject.channelID) {
filters.channelID = filtersObject.channelID;
}
if (filters['request.timestamp']) {
filters['request.timestamp'] = JSON.parse(filters['request.timestamp']);
}
/* Transaction Filters */
if (filters['request.path']) {
filters['request.path'] = new RegExp(filters['request.path'], "i");
}
if (filters['request.querystring']) {
filters['request.querystring'] = new RegExp(filters['request.querystring'], "i");
}
if (filters['response.status'] && utils.statusCodePatternMatch(filters['response.status'])) {
filters['response.status'] = {
"$gte": filters['response.status'][0] * 100,
"$lt": filters['response.status'][0] * 100 + 100
};
}
if (filters['properties']) {
key = Object.keys(filters['properties'])[0];
filters['properties.' + key] = filters['properties'][key];
if (filters['properties'][key] === null) {
filters['properties.' + key] = {
'$exists': true
};
}
delete filters['properties'];
}
if (filters['childIDs.0']) {
filters['childIDs.0'] = JSON.parse(filters['childIDs.0']);
}
/* Route Filters */
if (filters['routes.request.path']) {
filters['routes.request.path'] = new RegExp(filters['routes.request.path'], "i");
}
if (filters['routes.request.querystring']) {
filters['routes.request.querystring'] = new RegExp(filters['routes.request.querystring'], "i");
}
if (filters['routes.response.status'] && utils.statusCodePatternMatch(filters['routes.response.status'])) {
filters['routes.response.status'] = {
"$gte": filters['routes.response.status'][0] * 100,
"$lt": filters['routes.response.status'][0] * 100 + 100
};
}
/* orchestration Filters */
if (filters['orchestrations.request.path']) {
filters['orchestrations.request.path'] = new RegExp(filters['orchestrations.request.path'], "i");
}
if (filters['orchestrations.request.querystring']) {
filters['orchestrations.request.querystring'] = new RegExp(filters['orchestrations.request.querystring'], "i");
}
if (filters['orchestrations.response.status'] && utils.statusCodePatternMatch(filters['orchestrations.response.status'])) {
filters['orchestrations.response.status'] = {
"$gte": filters['orchestrations.response.status'][0] * 100,
"$lt": filters['orchestrations.response.status'][0] * 100 + 100
};
}
return this.body = (yield transactions.Transaction.find(filters, projectionFiltersObject).skip(filterSkip).limit(filterLimit).sort({
'request.timestamp': -1
}).exec());
} catch (_error) {
e = _error;
return utils.logAndSetResponse(this, 500, "Could not retrieve transactions via the API: " + e, 'error');
}
};
/*
* Adds an transaction
*/
exports.addTransaction = function*() {
var e, transactionData, tx;
if (!authorisation.inGroup('admin', this.authenticated)) {
utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to addTransaction denied.", 'info');
return;
}
transactionData = this.request.body;
tx = new transactions.Transaction(transactionData);
try {
(yield Q.ninvoke(tx, "save"));
this.status = 201;
return logger.info("User " + this.authenticated.email + " created transaction with id " + tx.id);
} catch (_error) {
e = _error;
return utils.logAndSetResponse(this, 500, "Could not add a transaction via the API: " + e, 'error');
}
};
/*
* Retrieves the details for a specific transaction
*/
exports.getTransactionById = function*(transactionId) {
var channel, channels, e, filterRepresentation, filtersObject, group, i, len, projectionFiltersObject, ref, result, txChannelID;
transactionId = unescape(transactionId);
try {
filtersObject = this.request.query;
filterRepresentation = filtersObject.filterRepresentation;
delete filtersObject.filterRepresentation;
if (!filterRepresentation) {
filterRepresentation = 'full';
}
if (!authorisation.inGroup('admin', this.authenticated)) {
txChannelID = (yield transactions.Transaction.findById(transactionId, {
channelID: 1,
_id: 0
}).exec());
if ((txChannelID != null ? txChannelID.length : void 0) === 0) {
this.body = "Could not find transaction with ID: " + transactionId;
this.status = 404;
return;
} else {
filterRepresentation = 'simpledetails';
channel = (yield Channel.findById(txChannelID.channelID, {
txViewFullAcl: 1,
_id: 0
}).exec());
ref = this.authenticated.groups;
for (i = 0, len = ref.length; i < len; i++) {
group = ref[i];
if (channel.txViewFullAcl.indexOf(group) >= 0) {
filterRepresentation = 'full';
break;
}
}
}
}
projectionFiltersObject = getProjectionObject(filterRepresentation);
result = (yield transactions.Transaction.findById(transactionId, projectionFiltersObject).exec());
if (!result) {
this.body = "Could not find transaction with ID: " + transactionId;
return this.status = 404;
} else if (!authorisation.inGroup('admin', this.authenticated)) {
channels = (yield authorisation.getUserViewableChannels(this.authenticated));
if (getChannelIDsArray(channels).indexOf(result.channelID.toString()) >= 0) {
return this.body = result;
} else {
return utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not authenticated to retrieve transaction " + transactionId, 'info');
}
} else {
return this.body = result;
}
} catch (_error) {
e = _error;
return utils.logAndSetResponse(this, 500, "Could not get transaction by ID via the API: " + e, 'error');
}
};
/*
* Retrieves all transactions specified by clientId
*/
exports.findTransactionByClientId = function*(clientId) {
var channels, e, filterRepresentation, filtersObject, projectionFiltersObject;
clientId = unescape(clientId);
try {
filtersObject = this.request.query;
filterRepresentation = filtersObject.filterRepresentation;
projectionFiltersObject = getProjectionObject(filterRepresentation);
filtersObject = {};
filtersObject.clientID = clientId;
if (!authorisation.inGroup('admin', this.authenticated)) {
channels = (yield authorisation.getUserViewableChannels(this.authenticated));
filtersObject.channelID = {
$in: getChannelIDsArray(channels)
};
filterRepresentation = '';
}
return this.body = (yield transactions.Transaction.find(filtersObject, projectionFiltersObject).sort({
'request.timestamp': -1
}).exec());
} catch (_error) {
e = _error;
return utils.logAndSetResponse(this, 500, "Could not get transaction by clientID via the API: " + e, 'error');
}
};
/*
* Updates a transaction record specified by transactionId
*/
exports.updateTransaction = function*(transactionId) {
var e, that, updates;
if (!authorisation.inGroup('admin', this.authenticated)) {
utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to updateTransaction denied.", 'info');
return;
}
transactionId = unescape(transactionId);
updates = this.request.body;
that = this;
try {
(yield transactions.Transaction.findByIdAndUpdate(transactionId, updates).exec());
that.body = "Transaction with ID: " + transactionId + " successfully updated";
that.status = 200;
logger.info("User " + that.authenticated.email + " updated transaction with id " + transactionId);
/*
* Update transaction metrics
*/
return transactions.Transaction.findById(transactionId, function(err, doc) {
var k, ref, ref1, results, route;
if (((ref = updates['$push']) != null ? ref.routes : void 0) != null) {
ref1 = updates['$push'];
results = [];
for (k in ref1) {
route = ref1[k];
results.push((function(route) {
var i, j, len, len1, metric, orchestration, ref2, ref3, results1;
if (route.metrics != null) {
ref2 = route.metrics;
for (i = 0, len = ref2.length; i < len; i++) {
metric = ref2[i];
if (metric.type === 'counter') {
logger.info("incrementing mediator counter " + metric.name);
sdc.increment(domain + ".channels." + doc.channelID + "." + route.name + ".mediator_metrics." + metric.name);
}
if (metric.type === 'timer') {
logger.info("incrementing mediator timer " + metric.name);
sdc.timing(domain + ".channels." + doc.channelID + "." + route.name + ".mediator_metrics." + metric.name, metric.value);
}
if (metric.type === 'gauge') {
logger.info("incrementing mediator gauge " + metric.name);
sdc.gauge(domain + ".channels." + doc.channelID + "." + route.name + ".mediator_metrics." + metric.name, metric.value);
}
}
}
ref3 = route.orchestrations;
results1 = [];
for (j = 0, len1 = ref3.length; j < len1; j++) {
orchestration = ref3[j];
results1.push((function(orchestration) {
var l, len2, orchestrationDuration, orchestrationName, orchestrationStatus, ref4, results2;
orchestrationDuration = orchestration.response.timestamp - orchestration.request.timestamp;
orchestrationStatus = orchestration.response.status;
orchestrationName = orchestration.name;
if (orchestration.group) {
orchestrationName = orchestration.group + "." + orchestration.name;
}
/*
* Update timers
*/
logger.info('updating async route timers');
sdc.timing(domain + ".channels." + doc.channelID + "." + route.name + ".orchestrations." + orchestrationName, orchestrationDuration);
sdc.timing(domain + ".channels." + doc.channelID + "." + route.name + ".orchestrations." + orchestrationName + ".statusCodes." + orchestrationStatus, orchestrationDuration);
/*
* Update counters
*/
logger.info('updating async route counters');
sdc.increment(domain + ".channels." + doc.channelID + "." + route.name + ".orchestrations." + orchestrationName);
sdc.increment(domain + ".channels." + doc.channelID + "." + route.name + ".orchestrations." + orchestrationName + ".statusCodes." + orchestrationStatus);
if (orchestration.metrics != null) {
ref4 = orchestration.metrics;
results2 = [];
for (l = 0, len2 = ref4.length; l < len2; l++) {
metric = ref4[l];
if (metric.type === 'counter') {
logger.info("incrementing " + route.name + " orchestration counter " + metric.name);
sdc.increment(domain + ".channels." + doc.channelID + "." + route.name + ".orchestrations." + orchestrationName + "." + metric.name, metric.value);
}
if (metric.type === 'timer') {
logger.info("incrementing " + route.name + " orchestration timer " + metric.name);
sdc.timing(domain + ".channels." + doc.channelID + "." + route.name + ".orchestrations." + orchestrationName + "." + metric.name, metric.value);
}
if (metric.type === 'gauge') {
logger.info("incrementing " + route.name + " orchestration gauge " + metric.name);
results2.push(sdc.gauge(domain + ".channels." + doc.channelID + "." + route.name + ".orchestrations." + orchestrationName + "." + metric.name, metric.value));
} else {
results2.push(void 0);
}
}
return results2;
}
})(orchestration));
}
return results1;
})(route));
}
return results;
}
});
} catch (_error) {
e = _error;
return utils.logAndSetResponse(this, 500, "Could not update transaction via the API: " + e, 'error');
}
};
/*
#Removes a transaction
*/
exports.removeTransaction = function*(transactionId) {
var e;
if (!authorisation.inGroup('admin', this.authenticated)) {
utils.logAndSetResponse(this, 403, "User " + this.authenticated.email + " is not an admin, API access to removeTransaction denied.", 'info');
return;
}
transactionId = unescape(transactionId);
try {
(yield transactions.Transaction.findByIdAndRemove(transactionId).exec());
this.body = 'Transaction successfully deleted';
this.status = 200;
return logger.info("User " + this.authenticated.email + " removed transaction with id " + transactionId);
} catch (_error) {
e = _error;
return utils.logAndSetResponse(this, 500, "Could not remove transaction via the API: " + e, 'error');
}
};
//# sourceMappingURL=transactions.js.map