From 01520d6135e967e03f5e7c68f5b3f1949b804958 Mon Sep 17 00:00:00 2001 From: Ally Shaban Date: Wed, 20 Oct 2021 12:19:42 +0300 Subject: [PATCH] converting rapidpro flow results to fhir QuestionnaireResponse --- server/lib/app.js | 50 +++++++++++++++++++-------------- server/lib/macm.js | 55 +++++++++++++++++++++++++++++++++---- server/lib/prerequisites.js | 3 ++ server/lib/rapidpro.js | 7 +++-- 4 files changed, 85 insertions(+), 30 deletions(-) diff --git a/server/lib/app.js b/server/lib/app.js index 39624e7..414754c 100644 --- a/server/lib/app.js +++ b/server/lib/app.js @@ -84,6 +84,7 @@ function appRoutes() { app.put('/emNutt/optout', (req, res) => { let processingError = false + let responseBody = [] let globalid = req.query.globalid let resourceType = req.query.entitytype if((!globalid || !resourceType) && !Array.isArray(req.body)) { @@ -169,7 +170,10 @@ function appRoutes() { } }) if(bundle.entry.length >= 200) { - macm.saveResource(bundle, (err) => { + macm.saveResource(bundle, (err, response, body) => { + if(body.entry) { + responseBody = responseBody.concat(body.entry) + } if(err) { processingError = true } @@ -181,7 +185,10 @@ function appRoutes() { }, () => { let promise = new Promise((resolve) => { if(bundle.entry.length > 0) { - macm.saveResource(bundle, (err) => { + macm.saveResource(bundle, (err, response, body) => { + if(body.entry) { + responseBody = responseBody.concat(body.entry) + } if(err) { processingError = true } @@ -193,9 +200,9 @@ function appRoutes() { }) promise.then(() => { if(processingError) { - return res.status(500).send() + return res.status(500).json(responseBody) } - return res.status(200).send() + return res.status(200).json(responseBody) }) }) }) @@ -204,6 +211,7 @@ function appRoutes() { app.put('/emNutt/undoOptout', (req, res) => { let processingError = false + let responseBody = [] let globalid = req.query.globalid let resourceType = req.query.entitytype if((!globalid || !resourceType) && !Array.isArray(req.body)) { @@ -233,16 +241,14 @@ function appRoutes() { }] }; async.eachSeries(practitioners, (practitioner, nxt) => { - logger.error(JSON.stringify({ - resourceParameters: parameters, - resourceType: practitioner.entitytype, - resourceID: practitioner.globalid - },0,2)); macm["$meta-delete"]({ resourceParameters: parameters, resourceType: practitioner.entitytype, resourceID: practitioner.globalid - }).then(() => { + }).then((err, response, body) => { + if(body.entry) { + responseBody = responseBody.concat(body.entry) + } return nxt(); }).catch((err) => { logger.error(err); @@ -251,9 +257,9 @@ function appRoutes() { }); }, () => { if(processingError) { - return res.status(500).send() + return res.status(500).json(responseBody) } - return res.status(200).send() + return res.status(200).json(responseBody) }) }) @@ -263,15 +269,17 @@ function appRoutes() { if(requestIDs.parentReqId) { delete processedMessages[requestIDs.parentReqId] } - for(let requestID of requestIDs.childrenReqIDs) { - logger.info(`Clearing progress data for clientID ${requestID}`); - let data = JSON.stringify({}) - redisClient.set(requestID, data, (err, reply) => { - if (err) { - logger.error(err); - logger.error(`An error has occured while clearing progress data for ${type} and requestID ${requestID}`); - } - }); + if(Array.isArray(requestIDs.childrenReqIDs)) { + for(let requestID of requestIDs.childrenReqIDs) { + logger.info(`Clearing progress data for clientID ${requestID}`); + let data = JSON.stringify({}) + redisClient.set(requestID, data, (err, reply) => { + if (err) { + logger.error(err); + logger.error(`An error has occured while clearing progress data for ${type} and requestID ${requestID}`); + } + }); + } } }); diff --git a/server/lib/macm.js b/server/lib/macm.js index 45b28f8..d95d577 100644 --- a/server/lib/macm.js +++ b/server/lib/macm.js @@ -254,9 +254,9 @@ module.exports = function () { }; request.post(options, (err, res, body) => { if(err || !res.statusCode || (res.statusCode < 200 && res.statusCode > 299)) { - return reject(); + return reject(err, res, body); } - return resolve(); + return resolve(err, res, body); }); }); }, @@ -533,6 +533,7 @@ module.exports = function () { } }); } + let dialog = [] for (const path of run.path) { const values = Object.keys(run.values); const texts = []; @@ -554,14 +555,16 @@ module.exports = function () { } } const id = uuid5(path.node, run.uuid); - texts.push({ + let text = { id, nodeUUID: path.node, type: 'reply', inResponseTo, time: run.values[valueKey].time, msg: run.values[valueKey].input - }); + } + texts.push(text); + dialog.push(text) } } if (texts.length === 0) { @@ -572,13 +575,15 @@ module.exports = function () { for (const action of node.actions) { if (action.type === 'send_msg') { id = uuid5(action.uuid, run.uuid); - texts.push({ + let text = { id, nodeUUID: action.uuid, type: 'sent', time: path.time, msg: action.text - }); + } + texts.push(text); + dialog.push(text) } } } @@ -625,6 +630,44 @@ module.exports = function () { }); } } + //create questionnaire response resource + let qnresponse = { + resourceType: "QuestionnaireResponse", + id: run.uuid, + authored: run.created_on, + item: [] + } + if(run.exit_type === 'interrupted' || run.exit_type === 'expired') { + qnresponse.status = 'stopped' + } else if(run.exit_type === 'completed') { + qnresponse.status = 'completed' + } else { + qnresponse.status = 'in-progress' + } + for(let text of dialog) { + if(text.type !== 'sent') { + continue + } + let reply = dialog.find((txt) => { + return txt.type === 'reply' && txt.inResponseTo === text.id + }) + let link = {} + link.linkId = text.nodeUUID + link.text = text.msg + if(reply) { + link.answer = [{ + valueString: reply.msg + }] + } + qnresponse.item.push(link) + } + bundle.entry.push({ + resource: qnresponse, + request: { + method: 'PUT', + url: `${qnresponse.resourceType}/${qnresponse.id}` + } + }); return callback(processingError, bundle); } }; diff --git a/server/lib/prerequisites.js b/server/lib/prerequisites.js index 183c980..6fea558 100644 --- a/server/lib/prerequisites.js +++ b/server/lib/prerequisites.js @@ -40,6 +40,9 @@ const checkDependencies = (callback) => { function isRunning(dependence, callback) { logger.info('Checking if ' + dependence.name + ' is running'); + if(dependence.name === 'kibana') { + return callback(true) + } const options = { url: dependence.url, auth: dependence.auth diff --git a/server/lib/rapidpro.js b/server/lib/rapidpro.js index c86305e..f1fdeb5 100644 --- a/server/lib/rapidpro.js +++ b/server/lib/rapidpro.js @@ -14,6 +14,7 @@ const macm = require('./macm')(); const config = require('./config'); const logger = require('./winston'); const mixin = require('./mixin'); +const fhirAudit = require('./modules/fhirAudit') module.exports = function () { return { /** @@ -536,6 +537,7 @@ module.exports = function () { resourceType: "Practitioner", id: contact.uuid, name: [humanName], + active: true, identifier: [{ system: "http://app.rapidpro.io/contact-uuid", value: contact.uuid @@ -1965,7 +1967,7 @@ module.exports = function () { } redisClient.set(reqID, statusResData); async.eachSeries(commReqBundles, (bundle, nxtBundle) => { - macm.saveResource(bundle, () => { + macm.saveResource(bundle, (error, response, body) => { return nxtBundle() }) }, () => { @@ -2104,7 +2106,7 @@ module.exports = function () { commReq.resource.extension = []; } commReq.resource.status = commReqStatus - let extIndex = 0; + let extIndex = 1; for (const index in commReq.resource.extension) { const ext = commReq.resource.extension[index]; if (ext.url === extUrl) { @@ -2112,7 +2114,6 @@ module.exports = function () { break; } } - if(rpRunStatus && Object.keys(rpRunStatus).length > 0) { commReq.resource.extension[extIndex] = { url: extUrl,