UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

384 lines (296 loc) 12.2 kB
"use strict"; 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