openhim-core
Version:
The OpenHIM core application that provides logging and routing of http requests
384 lines (296 loc) • 12.2 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 = _interopRequireDefault(require("winston"));
var _tasks = require("../model/tasks");
var _transactions = require("../model/transactions");
var _autoRetry = require("../model/autoRetry");
var Channels = _interopRequireWildcard(require("../model/channels"));
var authorisation = _interopRequireWildcard(require("./authorisation"));
var utils = _interopRequireWildcard(require("../utils"));
var _util = require("util");
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } 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.deleteMany({
transactionID: {
$in: transactions.tids
}
}, err => {
if (err) {
return _winston.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';
_winston.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.deleteOne({
_id: taskId
}).exec(); // All ok! So set the result
ctx.body = 'The Task was successfully deleted';
_winston.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