openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
357 lines (288 loc) • 11.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getTasks = getTasks;
exports.addTask = addTask;
exports.getTask = getTask;
exports.updateTask = updateTask;
exports.removeTask = removeTask;
var _winston = require('winston');
var _winston2 = _interopRequireDefault(_winston);
var _tasks = require('../model/tasks');
var _transactions = require('../model/transactions');
var _autoRetry = require('../model/autoRetry');
var _channels = require('../model/channels');
var Channels = _interopRequireWildcard(_channels);
var _authorisation = require('./authorisation');
var authorisation = _interopRequireWildcard(_authorisation);
var _utils = require('../utils');
var utils = _interopRequireWildcard(_utils);
var _util = require('util');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const { ChannelModelAPI } = Channels;
/**
* Function to check if rerun task creation is valid
*/
function isRerunPermissionsValid(user, transactions, callback) {
// if 'admin' - set rerun permissions to true
if (authorisation.inGroup('admin', user) === true) {
// admin user allowed to rerun any transactions
return callback(null, true);
} else {
return _transactions.TransactionModelAPI.distinct('channelID', { _id: { $in: transactions.tids } }, (err, transChannels) => {
if (err) {
return callback(err);
}
ChannelModelAPI.distinct('_id', { txRerunAcl: { $in: user.groups } }, (err, allowedChannels) => {
if (err) {
return callback(err);
}
// for each transaction channel found to be rerun
for (const trx of Array.from(transChannels)) {
// assume transaction channnel is not allowed at first
let matchFound = false;
// for each user allowed channel to be rerun
for (const chan of Array.from(allowedChannels)) {
if (trx.equals(chan)) {
matchFound = true;
}
}
// if one channel not allowed then rerun NOT allowed
if (!matchFound) {
return callback(null, false);
}
}
return callback(null, true);
});
});
}
}
/**
* Retrieves the list of active tasks
*/
async function getTasks(ctx) {
// Must be admin
if (!authorisation.inGroup('admin', ctx.authenticated)) {
utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to getTasks denied.`, 'info');
return;
}
try {
const filtersObject = ctx.request.query;
// get limit and page values
const { filterLimit } = filtersObject;
const { filterPage } = filtersObject;
// determine skip amount
const filterSkip = filterPage * filterLimit;
// get filters object
const filters = JSON.parse(filtersObject.filters);
// parse date to get it into the correct format for querying
if (filters.created) {
filters.created = JSON.parse(filters.created);
}
// exclude transactions object from tasks list
const projectionFiltersObject = { transactions: 0
// execute the query
};ctx.body = await _tasks.TaskModelAPI.find(filters, projectionFiltersObject).skip(filterSkip).limit(parseInt(filterLimit, 10)).sort({ created: -1 });
} catch (err) {
utils.logAndSetResponse(ctx, 500, `Could not fetch all tasks via the API: ${err}`, 'error');
}
}
const areTransactionChannelsValid = (transactions, callback) => _transactions.TransactionModelAPI.distinct('channelID', { _id: { $in: transactions.tids } }, (err, trxChannelIDs) => {
if (err) {
return callback(err);
}
return ChannelModelAPI.find({ _id: { $in: trxChannelIDs } }, { status: 1 }, (err, trxChannels) => {
if (err) {
return callback(err);
}
for (const chan of Array.from(trxChannels)) {
if (!Channels.isChannelEnabled(chan)) {
return callback(null, false);
}
}
return callback(null, true);
});
});
/**
* Creates a new Task
*/
async function addTask(ctx) {
// Get the values to use
const transactions = ctx.request.body;
try {
const taskObject = {};
const transactionsArr = [];
taskObject.remainingTransactions = transactions.tids.length;
taskObject.user = ctx.authenticated.email;
if (transactions.batchSize != null) {
if (transactions.batchSize <= 0) {
return utils.logAndSetResponse(ctx, 400, 'Invalid batch size specified', 'info');
}
taskObject.batchSize = transactions.batchSize;
}
if (transactions.paused) {
taskObject.status = 'Paused';
}
// check rerun permission and whether to create the rerun task
const isRerunPermsValid = (0, _util.promisify)(isRerunPermissionsValid);
const allowRerunTaskCreation = await isRerunPermsValid(ctx.authenticated, transactions);
// the rerun task may be created
if (allowRerunTaskCreation === true) {
const areTrxChannelsValid = (0, _util.promisify)(areTransactionChannelsValid);
const trxChannelsValid = await areTrxChannelsValid(transactions);
if (!trxChannelsValid) {
utils.logAndSetResponse(ctx, 400, 'Cannot queue task as there are transactions with disabled or deleted channels', 'info');
return;
}
for (const tid of Array.from(transactions.tids)) {
transactionsArr.push({ tid });
}
taskObject.transactions = transactionsArr;
taskObject.totalTransactions = transactionsArr.length;
const task = await new _tasks.TaskModelAPI(taskObject).save();
// All ok! So set the result
utils.logAndSetResponse(ctx, 201, `User ${ctx.authenticated.email} created task with id ${task.id}`, 'info');
// Clear the transactions out of the auto retry queue, in case they're in there
return _autoRetry.AutoRetryModelAPI.remove({ transactionID: { $in: transactions.tids } }, err => {
if (err) {
return _winston2.default.error(err);
}
});
} else {
// rerun task creation not allowed
utils.logAndSetResponse(ctx, 403, 'Insufficient permissions prevents this rerun task from being created', 'error');
}
} catch (error) {
// Error! So inform the user
const err = error;
utils.logAndSetResponse(ctx, 500, `Could not add Task via the API: ${err}`, 'error');
}
}
/**
* Retrieves the details for a specific Task
*/
function buildFilteredTransactionsArray(filters, transactions) {
// set tempTransactions array to return
const tempTransactions = [];
let i = 0;
while (i < transactions.length) {
// set filter variable to captured failed filters
let filtersFailed = false;
if (filters.tstatus) {
// if tstatus doesnt equal filter then set filter failed to true
if (filters.tstatus !== transactions[i].tstatus) {
filtersFailed = true;
}
}
if (filters.rerunStatus) {
// if rerunStatus doesnt equal filter then set filter failed to true
if (filters.rerunStatus !== transactions[i].rerunStatus) {
filtersFailed = true;
}
}
if (filters.hasErrors) {
// if hasErrors filter 'yes' but no hasErrors exist then set filter failed to true
if (filters.hasErrors === 'yes' && !transactions[i].hasErrors) {
filtersFailed = true;
// if hasErrors filter 'no' but hasErrors does exist then set filter failed to true
} else if (filters.hasErrors === 'no' && transactions[i].hasErrors) {
filtersFailed = true;
}
}
// add transaction if all filters passed successfully
if (filtersFailed === false) {
tempTransactions.push(transactions[i]);
}
// increment counter
i++;
}
return tempTransactions;
}
async function getTask(ctx, taskId) {
// Get the values to use
taskId = unescape(taskId);
try {
const filtersObject = ctx.request.query;
// get limit and page values
const { filterLimit } = filtersObject;
const { filterPage } = filtersObject;
// determine skip amount
const filterSkip = filterPage * filterLimit;
// get filters object
const filters = JSON.parse(filtersObject.filters);
const result = await _tasks.TaskModelAPI.findById(taskId).lean().exec();
let tempTransactions = result.transactions;
// are filters present
if (Object.keys(filters).length > 0) {
tempTransactions = buildFilteredTransactionsArray(filters, result.transactions);
}
// get new transactions filters length
const totalFilteredTransactions = tempTransactions.length;
// assign new transactions filters length to result property
result.totalFilteredTransactions = totalFilteredTransactions;
// work out where to slice from and till where
const sliceFrom = filterSkip;
const sliceTo = filterSkip + parseInt(filterLimit, 10);
// slice the transactions array to return only the correct amount of records at the correct index
result.transactions = tempTransactions.slice(sliceFrom, sliceTo);
// Test if the result if valid
if (result === null) {
// task not found! So inform the user
return utils.logAndSetResponse(ctx, 404, `We could not find a Task with this ID: ${taskId}.`, 'info');
} else {
ctx.body = result;
}
// All ok! So set the result
} catch (err) {
utils.logAndSetResponse(ctx, 500, `Could not fetch Task by ID {taskId} via the API: ${err}`, 'error');
}
}
/**
* Updates the details for a specific Task
*/
async function updateTask(ctx, taskId) {
// Must be admin
if (!authorisation.inGroup('admin', ctx.authenticated)) {
utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to updateTask denied.`, 'info');
return;
}
// Get the values to use
taskId = unescape(taskId);
const taskData = ctx.request.body;
// Ignore _id if it exists, user cannot change the internal id
if (taskData._id != null) {
delete taskData._id;
}
try {
await _tasks.TaskModelAPI.findOneAndUpdate({ _id: taskId }, taskData).exec();
// All ok! So set the result
ctx.body = 'The Task was successfully updated';
_winston2.default.info(`User ${ctx.authenticated.email} updated task with id ${taskId}`);
} catch (err) {
utils.logAndSetResponse(ctx, 500, `Could not update Task by ID {taskId} via the API: ${err}`, 'error');
}
}
/**
* Deletes a specific Tasks details
*/
async function removeTask(ctx, taskId) {
// Must be admin
if (!authorisation.inGroup('admin', ctx.authenticated)) {
utils.logAndSetResponse(ctx, 403, `User ${ctx.authenticated.email} is not an admin, API access to removeTask denied.`, 'info');
return;
}
// Get the values to use
taskId = unescape(taskId);
try {
// Try to get the Task (Call the function that emits a promise and Koa will wait for the function to complete)
await _tasks.TaskModelAPI.remove({ _id: taskId }).exec();
// All ok! So set the result
ctx.body = 'The Task was successfully deleted';
_winston2.default.info(`User ${ctx.authenticated.email} removed task with id ${taskId}`);
} catch (err) {
utils.logAndSetResponse(ctx, 500, `Could not remove Task by ID {taskId} via the API: ${err}`, 'error');
}
}
//# sourceMappingURL=tasks.js.map