diff --git a/dhis2sync/loadDHIS2MetadataConfig.json b/dhis2sync/loadDHIS2MetadataConfig.json index daad86689..dfa29de63 100644 --- a/dhis2sync/loadDHIS2MetadataConfig.json +++ b/dhis2sync/loadDHIS2MetadataConfig.json @@ -1,15 +1,15 @@ { "ilr": { - "url": "", + "url": "http://localhost:3447/fhir", "user": "", "pass": "", "doc": "" }, "dhis2": { - "url": "", - "user": "", - "pass": "", + "url": "https://play.dhis2.org/2.30", + "user": "admin", + "pass": "district", "dousers": false, "doservices": true } -} +} \ No newline at end of file diff --git a/facility-recon-backend/config/default.json b/facility-recon-backend/config/default.json index 4ea797451..b5b016c86 100755 --- a/facility-recon-backend/config/default.json +++ b/facility-recon-backend/config/default.json @@ -60,11 +60,11 @@ }, "dictionary": { "HC": "Health Center", - "HOSP": "Hospital", + "Health Centre": "Health Center", "H/C": "Health Center", + "HOSP": "Hospital", "St": "Saint", "ST.": "Saint", - "Health Centre": "Health Center", "HP": "Health Post", "HP.": "Health Post", "DISP": "Dispensary", diff --git a/facility-recon-backend/lib/dhis.js b/facility-recon-backend/lib/dhis.js new file mode 100644 index 000000000..b894cb722 --- /dev/null +++ b/facility-recon-backend/lib/dhis.js @@ -0,0 +1,410 @@ +require('./init'); +const config = require('./config'); +const winston = require('winston'); +const http = require('http') +const https = require('https') +const url = require('url') +const isJSON = require('is-json') +const redis = require('redis') +const redisClient = redis.createClient() + +var thisRunTime = new Date().toISOString() +var credentials = { + dhis2URL: '', + username: '', + password: '', + name: '' +} + +module.exports = function () { + return { + sync(host, username, password, name, clientId, reset, full, dousers, doservices) { + const dhis2URL = url.parse(host) + const auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64') + credentials.dhis2URL = dhis2URL + credentials.clientId = clientId + credentials.auth = auth + credentials.name = name + + if (reset) { + + process.stdout.write("Attempting to reset time on " + host + "\n") + + let req = (dhis2URL.protocol == 'https:' ? https : http).request({ + hostname: dhis2URL.hostname, + port: dhis2URL.port, + path: dhis2URL.path + '/api/dataStore/CSD-Loader-Last-Export/' + toTitleCase(name), + headers: { + Authorization: auth + }, + method: 'DELETE' + }, (res) => { + console.log('STATUS: ' + res.statusCode) + console.log('HEADERS: ' + JSON.stringify(res.headers, null, 2)) + res.on('end', () => {}) + res.on('error', (e) => { + console.log('ERROR: ' + e.message) + }) + }).end() + + } else { + + processMetaData(full, dousers, doservices); + + } + } + } +} + +async function processMetaData(full, dousers, doservices) { + var clientId = credentials.clientId + var dhisSyncRequestId = `dhisSyncRequest${clientId}` + dhisSyncRequest = JSON.stringify({ + status: `1/2 - Loading all DHIS2 data from host`, + error: null, + percent: null + }) + redisClient.set(dhisSyncRequestId, dhisSyncRequest) + + let hasKey = await checkLoaderDataStore() + let lastUpdate = false + if (full && hasKey) { + lastUpdate = await getLastUpdate() + // Convert to yyyy-mm-dd format (dropping time as it is ignored by DHIS2) + lastUpdate = new Date(Date.parse(lastUpdate)).toISOString().substr(0, 10) + } + + let uflag = 'false' + if (dousers) { + uflag = 'true' + } + let sflag = 'false' + if (doservices) { + sflag = 'true' + } + + const metadataOpts = [ + 'assumeTrue=false', + 'organisationUnits=true', + 'organisationUnitGroups=true', + 'organisationUnitLevels=true', + 'organisationUnitGroupSets=true', + "categoryOptions=" + sflag, + "optionSets=" + sflag, + "dataElementGroupSets=" + sflag, + "categoryOptionGroupSets=" + sflag, + "categoryCombos=" + sflag, + "options=" + sflag, + "categoryOptionCombos=" + sflag, + "dataSets=" + sflag, + "dataElementGroups=" + sflag, + "dataElements=" + sflag, + "categoryOptionGroups=" + sflag, + "categories=" + sflag, + "users=" + uflag, + "userGroups=" + uflag, + "userRoles=" + uflag, + ] + + if (lastUpdate) { + metadataOpts.push("filter=lastUpdated:gt:" + lastUpdate) + } + const dhis2URL = credentials.dhis2URL + const auth = credentials.auth + console.log("GETTING " + dhis2URL.protocol + "//" + dhis2URL.hostname + ":" + dhis2URL.port + dhis2URL.path + "/api/metadata.json?" + + metadataOpts.join('&')) + let req = (dhis2URL.protocol == 'https:' ? https : http).request({ + hostname: dhis2URL.hostname, + port: dhis2URL.port, + path: dhis2URL.path + '/api/metadata.json?' + metadataOpts.join('&'), + headers: { + Authorization: auth + }, + method: 'GET' + }, (res) => { + console.log('STATUS: ' + res.statusCode) + console.log('HEADERS: ' + JSON.stringify(res.headers, null, 2)) + var body = '' + res.on('data', (chunk) => { + body += chunk + }) + res.on('end', () => { + if (!isJSON(body)) { + winston.error('Non JSON response received while getting DHIS2 data') + var dhisSyncRequestId = `dhisSyncRequest${clientId}` + dhisSyncRequest = JSON.stringify({ + status: '1/2 - Getting DHIS2 Data', + error: 'Invalid response received while getting DHIS2 data,cross check the host name,username and password', + percent: null + }) + redisClient.set(dhisSyncRequestId, dhisSyncRequest) + } + let metadata = JSON.parse(body); + processOrgUnit(metadata, 0, metadata.organisationUnits.length - 1, hasKey) + }) + res.on('error', (e) => { + winston.error('ERROR: ' + e.message) + }) + }).end() +} + +function processOrgUnit(metadata, i, max, hasKey) { + var name = credentials.name + const clientId = credentials.clientId + var database = toTitleCase(name) + org = metadata.organisationUnits[i] + let percent = parseFloat((i * 100 / max).toFixed(2)) + winston.error(percent) + var status = '2/2 - Saving DHIS2 locations into FHIR server' + if (i == max) { + status = 'Done' + } + const dhisSyncRequestId = `dhisSyncRequest${clientId}` + dhisSyncRequest = JSON.stringify({ + status: status, + error: null, + percent: percent + }) + redisClient.set(dhisSyncRequestId, dhisSyncRequest) + + console.log("Processing (" + i + "/" + max + ") " + org.id) + let fhir = { + resourceType: 'Location', + id: org.id, + status: "active", + mode: "instance" + } + fhir.identifier = [{ + system: "http://dhis2.org/code", + value: org.code + }, + { + system: "http://dhis2.org/id", + value: org.id + } + ] + fhir.meta = { + lastUpdated: org.lastUpdated + } + let path = org.path.split('/') + let level = metadata.organisationUnitLevels.find(x => x.level == path.length - 1) + fhir.meta.tag = [{ + system: "http://test.geoalign.datim.org/organistionUnitLevels", + code: level.id, + display: level.name + }] + fhir.name = org.name + fhir.alias = [org.shortName] + if (metadata.organisationUnits.find(x => x.parent && x.parent.id && x.parent.id == org.id)) { + fhir.physicalType = { + coding: [{ + system: "http://hl7.org/fhir/location-physical-type", + code: "area", + display: "Area", + }], + text: "Administrative Area" + } + } else { + fhir.physicalType = { + coding: [{ + system: "http://hl7.org/fhir/location-physical-type", + code: "bu", + display: "Building", + }], + text: "Facility" + } + } + + if (org.featureType == 'POINT' && org.coordinates) { + try { + coords = JSON.parse(org.coordinates) + fhir.position = { + longitude: coords[1], + latitude: coords[0] + } + } catch (e) { + console.log("Failed to load coordinates. " + e.message) + } + } + if (org.parent) { + fhir.partOf = { + reference: "Location/" + org.parent.id + } + } + if (org.attributeValues) { + for (let attr of org.attributeValues) { + if (attr.attribute.id == 'XxZsKNpu4nB') { + fhir.identifier.push({ + system: `http://dhis2.org/id`, + value: attr.value + }) + } + if (attr.attribute.id == 'Ed6SCy0OXfx') { + fhir.identifier.push({ + system: "http://dhis2.org/code", + value: attr.value + }) + } + } + } + + const ilrURL = url.parse(config.getConf('mCSD:url')) + const ilrAuth = 'Basic ' + Buffer.from(config.getConf('ilr:username') + ':' + config.getConf('ilr:password')).toString('base64') + + console.log("Sending FHIR to " + ilrURL.hostname + " " + ilrURL.port + " " + ilrURL.path + `/${database}/fhir/Location/` + fhir.id) + let req = (ilrURL.protocol == 'https:' ? https : http).request({ + hostname: ilrURL.hostname, + port: ilrURL.port, + path: ilrURL.path + `${database}/fhir/Location/` + fhir.id, + headers: { + 'Content-Type': 'application/fhir+json' + //Authorization: ilrAuth + }, + method: 'PUT' + }, (res) => { + console.log('STATUS: ' + res.statusCode) + console.log('HEADERS: ' + JSON.stringify(res.headers)) + var body = '' + res.on('data', (chunk) => { + body += chunk + }) + res.on('end', () => { + console.log(body) + }) + res.on('error', (e) => { + console.log('ERROR: ' + e.message) + }) + }) + req.on('error', (e) => { + console.log("REQ ERROR: " + e.message) + }) + req.write(JSON.stringify(fhir)) + req.end() + + if (++i <= max) { + // Had to do it this way to free up the event loop + // so the request can go out before the entire + // data set is processed. + setTimeout(() => { + processOrgUnit(metadata, i, max, hasKey) + }, 0) + } else { + setLastUpdate(hasKey, thisRunTime) + } + +} + + +function checkLoaderDataStore() { + var name = credentials.name + const dhis2URL = credentials.dhis2URL + const auth = credentials.auth + return new Promise((resolve, reject) => { + let req = (dhis2URL.protocol == 'https:' ? https : http).request({ + hostname: dhis2URL.hostname, + port: dhis2URL.port, + path: dhis2URL.path + '/api/dataStore/CSD-Loader-Last-Export/' + toTitleCase(name), + headers: { + Authorization: auth + }, + method: 'GET' + }) + req.on('response', (res) => { + console.log('STATUS: ' + res.statusCode) + console.log('HEADERS: ' + JSON.stringify(res.headers, null, 2)) + if (res.statusCode == 200 || res.statusCode == 201) { + resolve(true) + } else { + resolve(false) + } + }) + req.on('error', (err) => { + reject(err) + }) + req.end() + }) +} + +function getLastUpdate() { + var name = credentials.name + var dhis2URL = credentials.dhis2URL + const auth = credentials.auth + return new Promise((resolve, reject) => { + let req = (dhis2URL.protocol == 'https:' ? https : http).request({ + hostname: dhis2URL.hostname, + port: dhis2URL.port, + path: dhis2URL.path + '/api/dataStore/CSD-Loader-Last-Export/' + toTitleCase(name), + headers: { + Authorization: auth + }, + method: 'GET' + }) + req.on('response', (res) => { + console.log('STATUS: ' + res.statusCode) + console.log('HEADERS: ' + JSON.stringify(res.headers, null, 2)) + let body = '' + res.on('data', (chunk) => { + body += chunk + }) + res.on('end', () => { + let dataStore = JSON.parse(body); + console.log(dataStore) + resolve(dataStore.value) + }) + res.on('error', (e) => { + console.log('ERROR: ' + e.message) + reject(e) + }) + }) + req.on('error', (err) => { + reject(err) + }) + req.end() + }) +} + +function setLastUpdate(hasKey, lastUpdate) { + var name = credentials.name + const auth = credentials.auth + //const dhis2URL = credentials.dhis2URL + let req = (dhis2URL.protocol == 'https:' ? https : http).request({ + hostname: dhis2URL.hostname, + port: dhis2URL.port, + path: dhis2URL.path + '/api/dataStore/CSD-Loader-Last-Export/' + toTitleCase(name), + headers: { + Authorization: auth, + "Content-Type": "application/json" + }, + method: (hasKey ? 'PUT' : 'POST') + }, (res) => { + console.log('STATUS: ' + res.statusCode) + console.log('HEADERS: ' + JSON.stringify(res.headers, null, 2)) + if (res.statusCode == 200 || res.statusCode == 201) { + console.log("Last update dataStore set.") + } else { + console.log("Last update dataStore FAILED.") + } + let body = '' + res.on('data', (chunk) => { + body += chunk + }) + res.on('end', () => { + let dataStore = JSON.parse(body); + console.log(dataStore) + }) + res.on('error', (e) => { + console.log('ERROR: ' + e.message) + }) + }) + let payload = { + value: lastUpdate + } + req.write(JSON.stringify(payload)) + req.end() +} + +function toTitleCase(str) { + return str.toLowerCase().split(' ').map(function (word) { + return word.replace(word[0], word[0].toUpperCase()); + }).join(''); +} \ No newline at end of file diff --git a/facility-recon-backend/lib/index.js b/facility-recon-backend/lib/index.js index 0ce78adfe..a72f029ad 100755 --- a/facility-recon-backend/lib/index.js +++ b/facility-recon-backend/lib/index.js @@ -1,4 +1,3 @@ - require('./init'); const cluster = require('cluster'); const express = require('express'); @@ -10,21 +9,24 @@ const formidable = require('formidable'); const winston = require('winston'); const https = require('https'); const http = require('http'); -const redis = require('redis') +const redis = require('redis'); const request = require('request'); const URI = require('urijs'); -const isJSON = require('is-json') -const async = require('async') -const mongoose = require('mongoose') -const redisClient = redis.createClient() +const isJSON = require('is-json'); +const async = require('async'); +const mongoose = require('mongoose'); +const redisClient = redis.createClient(); const config = require('./config'); const mcsd = require('./mcsd')(); +const dhis = require('./dhis')(); const scores = require('./scores')(); const app = express(); -var server = require('http').createServer(app); +let server = require('http').createServer(app); -app.use(bodyParser.urlencoded({ extended: true })); +app.use(bodyParser.urlencoded({ + extended: true +})); app.use(bodyParser.json()); // socket config - large documents can cause machine to max files open @@ -54,232 +56,223 @@ app.post('/oauth/registerUser', (req, res) => { }); */ -if(cluster.isMaster) { - var numWorkers = require('os').cpus().length; - console.log('Master cluster setting up ' + numWorkers + ' workers...'); +if (cluster.isMaster) { + let numWorkers = require('os').cpus().length; + console.log(`Master cluster setting up ${ numWorkers } workers...`); - for(var i = 0; i < numWorkers; i++) { - cluster.fork(); - } + for (let i = 0; i < numWorkers; i++) { + cluster.fork(); + } - cluster.on('online', function(worker) { - console.log('Worker ' + worker.process.pid + ' is online'); - }); + cluster.on('online', (worker) => { + console.log('Worker ' + worker.process.pid + ' is online'); + }); - cluster.on('exit', function(worker, code, signal) { - console.log('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal); - console.log('Starting a new worker'); - cluster.fork(); - }); + cluster.on('exit', (worker, code, signal) => { + console.log('Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal); + console.log('Starting a new worker'); + cluster.fork(); + }); } else { -app.get('/countLevels/:orgid', (req, res) => { - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - } else { - const orgid = req.params.orgid; - winston.info(`Getting total levels for ${orgid}`); - mcsd.countLevels('DATIM', orgid, (err, totalLevels) => { + app.get('/countLevels/:orgid', (req, res) => { + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' + }); res.set('Access-Control-Allow-Origin', '*'); - if (err) { - winston.error(err); - res.status(401).json({ error: 'Missing Orgid' }); - } else { - const recoLevel = 2; - winston.info(`Received total levels of ${totalLevels} for ${orgid}`); - res.status(200).json({ totalLevels, recoLevel }); - } - }); - } -}); - -app.get('/uploadAvailable/:orgid', (req, res) => { - if (!req.params.orgid) { - winston.error({ - error: 'Missing Orgid' - }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ - error: 'Missing Orgid' - }); - } else { - const orgid = req.params.orgid; - winston.info(`Checking if data uploaded ${orgid}`); - mcsd.getLocations (orgid, (mohData)=>{ - if (mohData.hasOwnProperty('entry') && mohData.entry.length > 0) { - res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json({ - dataUploaded: true - }); - } - else { + res.status(401).json({ + error: 'Missing Orgid' + }); + } else { + const orgid = req.params.orgid; + winston.info(`Getting total levels for ${orgid}`); + mcsd.countLevels('DATIM', orgid, (err, totalLevels) => { res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json({ - dataUploaded: false - }); - } - }) - } -}); + if (err) { + winston.error(err); + res.status(401).json({ + error: 'Missing Orgid' + }); + } else { + const recoLevel = 2; + winston.info(`Received total levels of ${totalLevels} for ${orgid}`); + res.status(200).json({ + totalLevels, + recoLevel + }); + } + }); + } + }); -app.get('/getArchives/:orgid', (req, res) => { - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - } else { - const orgid = req.params.orgid; - winston.info(`Getting archived DB for ${orgid}`); - mcsd.getArchives(orgid,(err,archives)=>{ + app.get('/uploadAvailable/:orgid', (req, res) => { + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid', + }); res.set('Access-Control-Allow-Origin', '*'); - if(err) { - winston.error({ error: 'Unexpected error has occured' }); - res.status(400).json({ error: 'Unexpected error'}); - return - } - res.status(200).json(archives) - }) - } -}); - -app.post('/restoreArchive/:orgid', (req,res) => { - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - } else { - const orgid = req.params.orgid; - winston.info(`Restoring archive DB for ${orgid}`); - const form = new formidable.IncomingForm(); - form.parse(req, (err, fields, files) => { - mcsd.restoreDB(fields.archive,orgid,(err) => { - res.set('Access-Control-Allow-Origin', '*'); - if(err) { - winston.error(err) - res.status(401).json({ error: 'Unexpected error occured while restoring the database,please retry' }); + res.status(401).json({ + error: 'Missing Orgid', + }); + } else { + const orgid = req.params.orgid; + winston.info(`Checking if data uploaded ${orgid}`); + mcsd.getLocations(orgid, (mohData) => { + if (mohData.hasOwnProperty('entry') && mohData.entry.length > 0) { + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).json({ + dataUploaded: true, + }); + } else { + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).json({ + dataUploaded: false, + }); } - res.status(200).send(); - }) - }) - } -}); - -app.get('/hierarchy/:source', (req, res) => { - if (!req.query.OrgId || !req.query.OrgName || !req.params.source) { - winston.error({ error: 'Missing Orgid or source' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid or source' }); - } else { - const orgid = req.query.OrgId; - const source = req.params.source.toUpperCase(); - if (source == 'DATIM') var database = config.getConf('mCSD:database'); - else if (source == 'MOH') var database = orgid; - - winston.info(`Fetching ${source} Locations For ${orgid}`); - if (source == 'MOH') { - var database = orgid; - const namespace = config.getConf('UUID:namespace'); - var id = uuid5(orgid, `${namespace}000`); - var locationReceived = new Promise((resolve,reject)=>{ - mcsd.getLocations(database,(mcsdData)=>{ - winston.info(`Done Fetching ${source} Locations`); - resolve(mcsdData) - }) - }) - } else if (source == 'DATIM') { - var id = orgid; - var database = config.getConf('mCSD:database'); - var locationReceived = new Promise((resolve,reject)=>{ - mcsd.getLocationChildren(database, id, (mcsdData) => { - winston.info(`Done Fetching ${source} Locations`); - resolve(mcsdData) - }) - }) + }); } + }); - locationReceived.then((mcsdData)=>{ - winston.info(`Creating ${source} Tree`); - mcsd.createTree(mcsdData, source, database, orgid, (tree) => { - winston.info(`Done Creating ${source} Tree`); + app.get('/getArchives/:orgid', (req, res) => { + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing Orgid' + }); + } else { + const orgid = req.params.orgid; + winston.info(`Getting archived DB for ${orgid}`); + mcsd.getArchives(orgid, (err, archives) => { res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json(tree); + if (err) { + winston.error({ + error: 'Unexpected error has occured' + }); + res.status(400).json({ + error: 'Unexpected error' + }); + return; + } + res.status(200).json(archives); }); - }).catch((err)=>{ - winston.error(err) - }) - } -}); + } + }); -app.get('/mappingStatus/:orgid/:level/:clientId', (req,res)=>{ - winston.info('Getting mapping status'); - const orgid = req.params.orgid; - const mohDB = orgid; - const datimTopId = orgid; - const datimDB = config.getConf('mCSD:database'); - const recoLevel = req.params.level; - const namespace = config.getConf('UUID:namespace'); - const mohTopId = uuid5(orgid, `${namespace}000`); - const clientId = req.params.clientId; - - let statusRequestId = `mappingStatus${datimTopId}${clientId}` - statusResData = JSON.stringify({status: '1/2 - Loading DATIM and MOH Data', error: null, percent: null}) - redisClient.set(statusRequestId,statusResData) - - const datimLocationReceived = new Promise((resolve, reject) => { - mcsd.getLocationChildren(datimDB, datimTopId, (mcsdDATIM) => { - mcsdDatimAll = mcsdDATIM; - mcsd.filterLocations(mcsdDATIM, datimTopId, 0, recoLevel, 0, (mcsdDatimTotalLevels, mcsdDatimLevel, mcsdDatimBuildings) => { - resolve(mcsdDatimLevel); + app.post('/restoreArchive/:orgid', (req, res) => { + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' }); - }); - }); - const mohLocationReceived = new Promise((resolve, reject) => { - mcsd.getLocations(mohDB, (mcsdMOH) => { - mcsd.filterLocations(mcsdMOH, mohTopId, 0, recoLevel, 0, (mcsdMohTotalLevels, mcsdMohLevel, mcsdMohBuildings) => { - resolve(mcsdMohLevel); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing Orgid' }); - }); - }); - const mappingDB = config.getConf('mapping:dbPrefix') + orgid; - const mappingLocationReceived = new Promise((resolve, reject) => { - mcsd.getLocationByID(mappingDB, false, false, (mcsdMapped) => { - resolve(mcsdMapped); - }); + } else { + const orgid = req.params.orgid; + winston.info(`Restoring archive DB for ${orgid}`); + const form = new formidable.IncomingForm(); + form.parse(req, (err, fields, files) => { + mcsd.restoreDB(fields.archive, orgid, (err) => { + res.set('Access-Control-Allow-Origin', '*'); + if (err) { + winston.error(err); + res.status(401).json({ + error: 'Unexpected error occured while restoring the database,please retry' + }); + } + res.status(200).send(); + }); + }); + } }); - Promise.all([datimLocationReceived, mohLocationReceived, mappingLocationReceived]).then((locations) => { - var datimLocations = locations[0] - var mohLocations = locations[1] - var mappedLocations = locations[2] - scores.getMappingStatus(mohLocations,datimLocations,mappedLocations,datimTopId,clientId,(mappingStatus)=>{ - res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json(mappingStatus) + + app.post('/dhisSync', (req, res) => { + winston.info('received request to sync DHIS2 data') + const form = new formidable.IncomingForm(); + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).end(); + form.parse(req, (err, fields, files) => { + var host = fields.host + var username = fields.username + var password = fields.password + var name = fields.name + var clientId = fields.clientId + dhis.sync(host, username, password, name, clientId, false, false, false, true) }) }) -}) -app.get('/reconcile/:orgid/:totalLevels/:recoLevel/:clientId', (req, res) => { - if (!req.params.orgid || !req.params.recoLevel) { - winston.error({ error: 'Missing Orgid or reconciliation Level' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid or reconciliation Level' }); - } else { - winston.info('Getting scores'); + app.get('/hierarchy/:source', (req, res) => { + if (!req.query.OrgId || !req.query.OrgName || !req.params.source) { + winston.error({ + error: 'Missing Orgid or source' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing Orgid or source' + }); + } else { + const orgid = req.query.OrgId; + const source = req.params.source.toUpperCase(); + if (source == 'DATIM') var database = config.getConf('mCSD:database'); + else if (source == 'MOH') var database = orgid; + + winston.info(`Fetching ${source} Locations For ${orgid}`); + if (source == 'MOH') { + var database = orgid; + const namespace = config.getConf('UUID:namespace'); + var id = uuid5(orgid, `${namespace}000`); + var locationReceived = new Promise((resolve, reject) => { + mcsd.getLocations(database, (mcsdData) => { + winston.info(`Done Fetching ${source} Locations`); + resolve(mcsdData); + }); + }); + } else if (source == 'DATIM') { + var id = orgid; + var database = config.getConf('mCSD:database'); + var locationReceived = new Promise((resolve, reject) => { + mcsd.getLocationChildren(database, id, (mcsdData) => { + winston.info(`Done Fetching ${source} Locations`); + resolve(mcsdData); + }); + }); + } + + locationReceived.then((mcsdData) => { + winston.info(`Creating ${source} Tree`); + mcsd.createTree(mcsdData, source, database, orgid, (tree) => { + winston.info(`Done Creating ${source} Tree`); + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).json(tree); + }); + }).catch((err) => { + winston.error(err); + }); + } + }); + + app.get('/mappingStatus/:orgid/:level/:clientId', (req, res) => { + winston.info('Getting mapping status'); const orgid = req.params.orgid; - const recoLevel = req.params.recoLevel; - const totalLevels = req.params.totalLevels; - const clientId = req.params.clientId; - const datimDB = config.getConf('mCSD:database'); const mohDB = orgid; + const datimTopId = orgid; + const datimDB = config.getConf('mCSD:database'); + const recoLevel = req.params.level; const namespace = config.getConf('UUID:namespace'); const mohTopId = uuid5(orgid, `${namespace}000`); - const datimTopId = orgid; - let mcsdDatimAll = null; - let mcsdMohAll = null; + const clientId = req.params.clientId; + + const statusRequestId = `mappingStatus${datimTopId}${clientId}`; + statusResData = JSON.stringify({ + status: '1/2 - Loading DATIM and MOH Data', + error: null, + percent: null + }); + redisClient.set(statusRequestId, statusResData); - let scoreRequestId = `scoreResults${datimTopId}${clientId}` - scoreResData = JSON.stringify({status: '1/3 - Loading DATIM and MOH Data', error: null, percent: null}) - redisClient.set(scoreRequestId,scoreResData) const datimLocationReceived = new Promise((resolve, reject) => { mcsd.getLocationChildren(datimDB, datimTopId, (mcsdDATIM) => { mcsdDatimAll = mcsdDATIM; @@ -288,16 +281,13 @@ app.get('/reconcile/:orgid/:totalLevels/:recoLevel/:clientId', (req, res) => { }); }); }); - const mohLocationReceived = new Promise((resolve, reject) => { mcsd.getLocations(mohDB, (mcsdMOH) => { - mcsdMohAll = mcsdMOH; mcsd.filterLocations(mcsdMOH, mohTopId, 0, recoLevel, 0, (mcsdMohTotalLevels, mcsdMohLevel, mcsdMohBuildings) => { resolve(mcsdMohLevel); }); }); }); - const mappingDB = config.getConf('mapping:dbPrefix') + orgid; const mappingLocationReceived = new Promise((resolve, reject) => { mcsd.getLocationByID(mappingDB, false, false, (mcsdMapped) => { @@ -305,586 +295,816 @@ app.get('/reconcile/:orgid/:totalLevels/:recoLevel/:clientId', (req, res) => { }); }); Promise.all([datimLocationReceived, mohLocationReceived, mappingLocationReceived]).then((locations) => { - if (recoLevel == totalLevels) { - scores.getBuildingsScores(locations[1], locations[0], locations[2], mcsdDatimAll, mcsdMohAll, mohDB, datimDB, mohTopId, datimTopId, recoLevel, totalLevels, clientId, (scoreResults) => { - res.set('Access-Control-Allow-Origin', '*'); - recoStatus (orgid,(totalAllMapped,totalAllNoMatch,totalAllFlagged)=>{ - var mohTotalAllNotMapped = (mcsdMohAll.entry.length - 1) - totalAllMapped - res.status(200).json({ scoreResults, - recoLevel, - datimTotalRecords: locations[0].entry.length, - datimTotalAllRecords: mcsdDatimAll.entry.length, - totalAllMapped: totalAllMapped, - totalAllFlagged: totalAllFlagged, - totalAllNoMatch: totalAllNoMatch, - mohTotalAllNotMapped: mohTotalAllNotMapped, - mohTotalAllRecords: mcsdMohAll.entry.length-1 - }); - winston.info('Score results sent back'); - }) + let datimLocations = locations[0]; + let mohLocations = locations[1]; + let mappedLocations = locations[2]; + scores.getMappingStatus(mohLocations, datimLocations, mappedLocations, datimTopId, clientId, (mappingStatus) => { + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).json(mappingStatus); + }); + }); + }); + + app.get('/reconcile/:orgid/:totalLevels/:recoLevel/:clientId', (req, res) => { + if (!req.params.orgid || !req.params.recoLevel) { + winston.error({ + error: 'Missing Orgid or reconciliation Level' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing Orgid or reconciliation Level' + }); + } else { + winston.info('Getting scores'); + const orgid = req.params.orgid; + const recoLevel = req.params.recoLevel; + const totalLevels = req.params.totalLevels; + const clientId = req.params.clientId; + const datimDB = config.getConf('mCSD:database'); + const mohDB = orgid; + const namespace = config.getConf('UUID:namespace'); + const mohTopId = uuid5(orgid, `${namespace}000`); + const datimTopId = orgid; + let mcsdDatimAll = null; + let mcsdMohAll = null; + + const scoreRequestId = `scoreResults${datimTopId}${clientId}`; + scoreResData = JSON.stringify({ + status: '1/3 - Loading DATIM and MOH Data', + error: null, + percent: null + }); + redisClient.set(scoreRequestId, scoreResData); + const datimLocationReceived = new Promise((resolve, reject) => { + mcsd.getLocationChildren(datimDB, datimTopId, (mcsdDATIM) => { + mcsdDatimAll = mcsdDATIM; + mcsd.filterLocations(mcsdDATIM, datimTopId, 0, recoLevel, 0, (mcsdDatimTotalLevels, mcsdDatimLevel, mcsdDatimBuildings) => { + resolve(mcsdDatimLevel); + }); }); - } else { - scores.getJurisdictionScore(locations[1], locations[0], locations[2], mcsdDatimAll, mcsdMohAll,mohDB, datimDB, mohTopId, datimTopId, recoLevel, totalLevels, clientId, (scoreResults) => { - res.set('Access-Control-Allow-Origin', '*'); - recoStatus (orgid,(totalAllMapped,totalAllNoMatch,totalAllFlagged)=>{ - var mohTotalAllNotMapped = (mcsdMohAll.entry.length - 1) - totalAllMapped - res.status(200).json({ scoreResults, - recoLevel, - datimTotalRecords: locations[0].entry.length, - datimTotalAllRecords: mcsdDatimAll.entry.length, - totalAllMapped: totalAllMapped, - totalAllFlagged: totalAllFlagged, - totalAllNoMatch: totalAllNoMatch, - mohTotalAllNotMapped: mohTotalAllNotMapped, - mohTotalAllRecords: mcsdMohAll.entry.length-1 - }); - winston.info('Score results sent back'); - }) + }); + + const mohLocationReceived = new Promise((resolve, reject) => { + mcsd.getLocations(mohDB, (mcsdMOH) => { + mcsdMohAll = mcsdMOH; + mcsd.filterLocations(mcsdMOH, mohTopId, 0, recoLevel, 0, (mcsdMohTotalLevels, mcsdMohLevel, mcsdMohBuildings) => { + resolve(mcsdMohLevel); + }); }); - } - }).catch((err)=>{ - winston.error(err) - }); - } + }); - function recoStatus (orgid,callback) { - //getting total Mapped - var database = config.getConf('mapping:dbPrefix') + orgid; - var url = URI(config.getConf('mCSD:url')).segment(database).segment('fhir').segment('Location') + const mappingDB = config.getConf('mapping:dbPrefix') + orgid; + const mappingLocationReceived = new Promise((resolve, reject) => { + mcsd.getLocationByID(mappingDB, false, false, (mcsdMapped) => { + resolve(mcsdMapped); + }); + }); + Promise.all([datimLocationReceived, mohLocationReceived, mappingLocationReceived]).then((locations) => { + if (recoLevel == totalLevels) { + scores.getBuildingsScores(locations[1], locations[0], locations[2], mcsdDatimAll, mcsdMohAll, mohDB, datimDB, mohTopId, datimTopId, recoLevel, totalLevels, clientId, (scoreResults) => { + res.set('Access-Control-Allow-Origin', '*'); + recoStatus(orgid, (totalAllMapped, totalAllNoMatch, totalAllFlagged) => { + let mohTotalAllNotMapped = (mcsdMohAll.entry.length - 1) - totalAllMapped; + res.status(200).json({ + scoreResults, + recoLevel, + datimTotalRecords: locations[0].entry.length, + datimTotalAllRecords: mcsdDatimAll.entry.length, + totalAllMapped, + totalAllFlagged, + totalAllNoMatch, + mohTotalAllNotMapped, + mohTotalAllRecords: mcsdMohAll.entry.length - 1, + }); + winston.info('Score results sent back'); + }); + }); + } else { + scores.getJurisdictionScore(locations[1], locations[0], locations[2], mcsdDatimAll, mcsdMohAll, mohDB, datimDB, mohTopId, datimTopId, recoLevel, totalLevels, clientId, (scoreResults) => { + res.set('Access-Control-Allow-Origin', '*'); + recoStatus(orgid, (totalAllMapped, totalAllNoMatch, totalAllFlagged) => { + let mohTotalAllNotMapped = (mcsdMohAll.entry.length - 1) - totalAllMapped; + res.status(200).json({ + scoreResults, + recoLevel, + datimTotalRecords: locations[0].entry.length, + datimTotalAllRecords: mcsdDatimAll.entry.length, + totalAllMapped, + totalAllFlagged, + totalAllNoMatch, + mohTotalAllNotMapped, + mohTotalAllRecords: mcsdMohAll.entry.length - 1, + }); + winston.info('Score results sent back'); + }); + }); + } + }).catch((err) => { + winston.error(err); + }); + } + + function recoStatus(orgid, callback) { + // getting total Mapped + let database = config.getConf('mapping:dbPrefix') + orgid; + let url = URI(config.getConf('mCSD:url')).segment(database).segment('fhir').segment('Location') .toString(); - const options = { - url, - }; - var totalAllMapped = 0 - var totalAllNoMatch = 0 - var totalAllFlagged = 0 - var mohTotalAllNotMapped = 0 - const noMatchCode = config.getConf('mapping:noMatchCode'); - const flagCode = config.getConf('mapping:flagCode'); - setTimeout(()=>{ - mcsd.getLocations(database, (body) => { - if (!body.hasOwnProperty('entry') || body.length === 0) { - totalAllNoMatch = 0 - totalAllMapped = 0 - return callback (totalAllMapped,mohTotalAllNotMapped,totalAllNoMatch,totalAllFlagged) - } - async.each(body.entry,(entry,nxtEntry)=>{ - if (entry.resource.hasOwnProperty('tag')) { - var nomatch = entry.resource.tag.find((tag)=>{ - return tag.code === noMatchCode - }) - var flagged = entry.resource.tag.find((tag)=>{ - return tag.code === flagCode - }) - if (nomatch) { - totalAllNoMatch++ - } - if (flagged) { - totalAllFlagged++ + const options = { + url, + }; + let totalAllMapped = 0; + let totalAllNoMatch = 0; + let totalAllFlagged = 0; + let mohTotalAllNotMapped = 0; + const noMatchCode = config.getConf('mapping:noMatchCode'); + const flagCode = config.getConf('mapping:flagCode'); + setTimeout(() => { + mcsd.getLocations(database, (body) => { + if (!body.hasOwnProperty('entry') || body.length === 0) { + totalAllNoMatch = 0; + totalAllMapped = 0; + return callback(totalAllMapped, mohTotalAllNotMapped, totalAllNoMatch, totalAllFlagged); } - return nxtEntry () - } - else { - return nxtEntry() - } - },()=>{ - totalAllMapped = body.entry.length - totalAllNoMatch - totalAllFlagged - return callback (totalAllMapped,totalAllNoMatch,totalAllFlagged) - //res.set('Access-Control-Allow-Origin', '*'); - //res.status(200).json({totalAllMapped,totalAllNoMatch,totalAllFlagged}) - }) - }) - },1000) - } + async.each(body.entry, (entry, nxtEntry) => { + if (entry.resource.hasOwnProperty('tag')) { + var nomatch = entry.resource.tag.find((tag) => { + return tag.code === noMatchCode + }) + var flagged = entry.resource.tag.find((tag) => { + return tag.code === flagCode + }) + if (nomatch) { + totalAllNoMatch++ + } + if (flagged) { + totalAllFlagged++ + } + return nxtEntry() + } -}); + return nxtEntry() -app.get('/getUnmatched/:orgid/:source/:recoLevel', (req, res) => { - winston.info(`Getting DATIM Unmatched Orgs for ${req.params.orgid}`); - if (!req.params.orgid || !req.params.source) { - winston.error({ error: 'Missing Orgid or Source' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid or Source' }); - return; - } - const orgid = req.params.orgid; - const source = req.params.source.toUpperCase(); - const recoLevel = req.params.recoLevel; - const datimDB = config.getConf('mCSD:database'); - mcsd.getLocationChildren(datimDB, orgid, (locations) => { - mcsd.filterLocations(locations, orgid, 0, recoLevel, 0, (mcsdLevels, mcsdLevel, mcsdBuildings) => { - scores.getUnmatched(locations,mcsdLevel, orgid, (unmatched) => { - winston.info(`sending back DATIM unmatched Orgs for ${req.params.orgid}`); - res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json(unmatched); + }, () => { + totalAllMapped = body.entry.length - totalAllNoMatch - totalAllFlagged; + return callback(totalAllMapped, totalAllNoMatch, totalAllFlagged); + // res.set('Access-Control-Allow-Origin', '*'); + // res.status(200).json({totalAllMapped,totalAllNoMatch,totalAllFlagged}) + }); + }); + }, 1000); + } + }); + + app.get('/getUnmatched/:orgid/:source/:recoLevel', (req, res) => { + winston.info(`Getting DATIM Unmatched Orgs for ${req.params.orgid}`); + if (!req.params.orgid || !req.params.source) { + winston.error({ + error: 'Missing Orgid or Source' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing Orgid or Source' + }); + return; + } + const orgid = req.params.orgid; + const source = req.params.source.toUpperCase(); + const recoLevel = req.params.recoLevel; + const datimDB = config.getConf('mCSD:database'); + mcsd.getLocationChildren(datimDB, orgid, (locations) => { + mcsd.filterLocations(locations, orgid, 0, recoLevel, 0, (mcsdLevels, mcsdLevel, mcsdBuildings) => { + scores.getUnmatched(locations, mcsdLevel, orgid, (unmatched) => { + winston.info(`sending back DATIM unmatched Orgs for ${req.params.orgid}`); + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).json(unmatched); + }); }); }); }); -}); -app.post('/match/:type/:orgid', (req, res) => { - winston.info('Received data for matching'); - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - return; - } - const orgid = req.params.orgid; - const type = req.params.type; - const form = new formidable.IncomingForm(); - form.parse(req, (err, fields, files) => { - let mohId = fields.mohId; - const datimId = fields.datimId; - const recoLevel = fields.recoLevel; - const totalLevels = fields.totalLevels; - if (!mohId || !datimId) { - winston.error({ error: 'Missing either MOHID or DATIMID or both' }); + app.post('/match/:type/:orgid', (req, res) => { + winston.info('Received data for matching'); + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' + }); res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing either MOHID or DATIMID or both' }); + res.status(401).json({ + error: 'Missing Orgid' + }); return; } - if (recoLevel == totalLevels) { - const namespace = config.getConf('UUID:namespace'); - mohId = uuid5(mohId, `${namespace}100`); - } - mcsd.saveMatch(mohId, datimId, orgid, recoLevel, totalLevels, type, (err) => { - winston.info('Done matching'); - res.set('Access-Control-Allow-Origin', '*'); - if (err) res.status(401).send({ error: err }); - else res.status(200).send(); + const orgid = req.params.orgid; + const type = req.params.type; + const form = new formidable.IncomingForm(); + form.parse(req, (err, fields, files) => { + let mohId = fields.mohId; + const datimId = fields.datimId; + const recoLevel = fields.recoLevel; + const totalLevels = fields.totalLevels; + if (!mohId || !datimId) { + winston.error({ + error: 'Missing either MOHID or DATIMID or both' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing either MOHID or DATIMID or both' + }); + return; + } + if (recoLevel == totalLevels) { + const namespace = config.getConf('UUID:namespace'); + mohId = uuid5(mohId, `${namespace}100`); + } + mcsd.saveMatch(mohId, datimId, orgid, recoLevel, totalLevels, type, (err) => { + winston.info('Done matching'); + res.set('Access-Control-Allow-Origin', '*'); + if (err) res.status(401).send({ + error: err + }); + else res.status(200).send(); + }); }); }); -}); -app.post('/acceptFlag/:orgid', (req, res) => { - winston.info('Received data for marking flag as a match'); - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - return; - } - const orgid = req.params.orgid; - const form = new formidable.IncomingForm(); - form.parse(req, (err, fields, files) => { - const datimId = fields.datimId; - const recoLevel = fields.recoLevel; - const totalLevels = fields.totalLevels; - if (!datimId) { - winston.error({ error: 'Missing DATIMID' }); + app.post('/acceptFlag/:orgid', (req, res) => { + winston.info('Received data for marking flag as a match'); + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' + }); res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing DATIMID' }); + res.status(401).json({ + error: 'Missing Orgid' + }); return; } - if (recoLevel == totalLevels) { - const namespace = config.getConf('UUID:namespace'); - mohId = uuid5(orgid, `${namespace}100`); - } - mcsd.acceptFlag(datimId, orgid, (err) => { - winston.info('Done marking flag as a match'); - res.set('Access-Control-Allow-Origin', '*'); - if (err) res.status(401).send({ error: err }); - else res.status(200).send(); + const orgid = req.params.orgid; + const form = new formidable.IncomingForm(); + form.parse(req, (err, fields, files) => { + const datimId = fields.datimId; + const recoLevel = fields.recoLevel; + const totalLevels = fields.totalLevels; + if (!datimId) { + winston.error({ + error: 'Missing DATIMID' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing DATIMID' + }); + return; + } + if (recoLevel == totalLevels) { + const namespace = config.getConf('UUID:namespace'); + mohId = uuid5(orgid, `${namespace}100`); + } + mcsd.acceptFlag(datimId, orgid, (err) => { + winston.info('Done marking flag as a match'); + res.set('Access-Control-Allow-Origin', '*'); + if (err) res.status(401).send({ + error: err + }); + else res.status(200).send(); + }); }); }); -}); -app.post('/noMatch/:orgid', (req, res) => { - winston.info('Received data for matching'); - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - return; - } - const orgid = req.params.orgid; - const form = new formidable.IncomingForm(); - form.parse(req, (err, fields, files) => { - let mohId = fields.mohId; - const recoLevel = fields.recoLevel; - const totalLevels = fields.totalLevels; - if (!mohId) { - winston.error({ error: 'Missing either MOHID' }); + app.post('/noMatch/:orgid', (req, res) => { + winston.info('Received data for matching'); + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' + }); res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing either MOHID' }); + res.status(401).json({ + error: 'Missing Orgid' + }); return; } - if (recoLevel == totalLevels) { - const namespace = config.getConf('UUID:namespace'); - mohId = uuid5(mohId, `${namespace}100`); - } - mcsd.saveNoMatch(mohId, orgid, recoLevel, totalLevels, (err) => { - winston.info('Done matching'); + const orgid = req.params.orgid; + const form = new formidable.IncomingForm(); + form.parse(req, (err, fields, files) => { + let mohId = fields.mohId; + const recoLevel = fields.recoLevel; + const totalLevels = fields.totalLevels; + if (!mohId) { + winston.error({ + error: 'Missing either MOHID' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing either MOHID' + }); + return; + } + if (recoLevel == totalLevels) { + const namespace = config.getConf('UUID:namespace'); + mohId = uuid5(mohId, `${namespace}100`); + } + mcsd.saveNoMatch(mohId, orgid, recoLevel, totalLevels, (err) => { + winston.info('Done matching'); + res.set('Access-Control-Allow-Origin', '*'); + if (err) res.status(401).send({ + error: err + }); + else res.status(200).send(); + }); + }); + }); + + app.post('/breakMatch/:orgid', (req, res) => { + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' + }); res.set('Access-Control-Allow-Origin', '*'); - if (err) res.status(401).send({ error: err }); - else res.status(200).send(); + res.status(401).json({ + error: 'Missing Orgid' + }); + return; + } + const form = new formidable.IncomingForm(); + form.parse(req, (err, fields, files) => { + winston.info(`Received break match request for ${fields.datimId}`); + const datimId = fields.datimId; + const database = config.getConf('mapping:dbPrefix') + req.params.orgid; + mcsd.breakMatch(datimId, database, req.params.orgid, (err, results) => { + winston.info(`break match done for ${fields.datimId}`); + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).send(err); + }); }); }); -}); -app.post('/breakMatch/:orgid', (req, res) => { - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - return; - } - const form = new formidable.IncomingForm(); - form.parse(req, (err, fields, files) => { - winston.info(`Received break match request for ${fields.datimId}`); - const datimId = fields.datimId; - const database = config.getConf('mapping:dbPrefix') + req.params.orgid; - mcsd.breakMatch(datimId, database, req.params.orgid, (err,results) => { - winston.info(`break match done for ${fields.datimId}`); + app.post('/breakNoMatch/:orgid', (req, res) => { + if (!req.params.orgid) { + winston.error({ + error: 'Missing Orgid' + }); res.set('Access-Control-Allow-Origin', '*'); - res.status(200).send(err); + res.status(401).json({ + error: 'Missing Orgid' + }); + return; + } + const form = new formidable.IncomingForm(); + form.parse(req, (err, fields, files) => { + winston.info(`Received break no match request for ${fields.mohId}`); + let mohId = fields.mohId; + if (!mohId) { + winston.error({ + error: 'Missing MOH ID' + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Missing MOH ID' + }); + return; + } + const recoLevel = fields.recoLevel; + const totalLevels = fields.totalLevels; + const database = config.getConf('mapping:dbPrefix') + req.params.orgid; + if (recoLevel == totalLevels) { + const namespace = config.getConf('UUID:namespace'); + mohId = uuid5(mohId, `${namespace}100`); + } + mcsd.breakNoMatch(mohId, database, (err) => { + winston.info(`break no match done for ${fields.mohId}`); + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).send(err); + }); }); }); -}); -app.post('/breakNoMatch/:orgid', (req, res) => { - if (!req.params.orgid) { - winston.error({ error: 'Missing Orgid' }); - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - return; - } - const form = new formidable.IncomingForm(); - form.parse(req, (err, fields, files) => { - winston.info(`Received break no match request for ${fields.mohId}`); - var mohId = fields.mohId; - if (!mohId) { - winston.error({'error': 'Missing MOH ID'}) - res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing MOH ID' }); - return + app.get('/markRecoUnDone/:orgid', (req, res) => { + winston.info(`received a request to mark reconciliation for ${req.params.orgid} as undone`); + const mongoUser = config.getConf('mCSD:databaseUser'); + const mongoPasswd = config.getConf('mCSD:databasePassword'); + const mongoHost = config.getConf('mCSD:databaseHost'); + const mongoPort = config.getConf('mCSD:databasePort'); + const orgid = req.params.orgid; + const database = config.getConf('mapping:dbPrefix') + orgid; + if (mongoUser && mongoPasswd) { + var uri = `mongodb://${mongoUser}:${mongoPasswd}@${mongoHost}:${mongoPort}/${database}`; + } else { + var uri = `mongodb://${mongoHost}:${mongoPort}/${database}`; } - const recoLevel = fields.recoLevel; - const totalLevels = fields.totalLevels; - const database = config.getConf('mapping:dbPrefix') + req.params.orgid; - if (recoLevel == totalLevels) { - const namespace = config.getConf('UUID:namespace'); - mohId = uuid5(mohId, `${namespace}100`); + mongoose.connect(uri); + const Schema = mongoose.Schema; + let ReconciliationStatusModel; + try { + ReconciliationStatusModel = mongoose.model('ReconciliationStatus'); + } catch (e) { + mongoose.model('ReconciliationStatus', new Schema({ + status: { + type: Object + }, + })); + ReconciliationStatusModel = mongoose.model('ReconciliationStatus'); } - mcsd.breakNoMatch(mohId, database, (err) => { - winston.info(`break no match done for ${fields.mohId}`); + + const recoStatusCode = config.getConf('mapping:recoStatusCode'); + const query = { + status: { + code: recoStatusCode, + text: 'Done' + } + }; + const update = { + status: { + code: recoStatusCode, + text: 'on-progress' + } + }; + ReconciliationStatusModel.findOneAndUpdate(query, update, (err, data) => { res.set('Access-Control-Allow-Origin', '*'); - res.status(200).send(err); + if (err) { + res.status(500).json({ + error: 'An error occured while processing request' + }); + } else { + res.status(200).json({ + status: 'on-progresss' + }); + } }); }); -}); -app.get('/markRecoUnDone/:orgid',(req,res)=>{ - winston.info (`received a request to mark reconciliation for ${req.params.orgid} as undone`) - const mongoUser = config.getConf('mCSD:databaseUser') - const mongoPasswd = config.getConf('mCSD:databasePassword') - const mongoHost = config.getConf('mCSD:databaseHost') - const mongoPort = config.getConf('mCSD:databasePort') - const orgid = req.params.orgid - const database = config.getConf('mapping:dbPrefix') + orgid - if(mongoUser && mongoPasswd) { - var uri = `mongodb://${mongoUser}:${mongoPasswd}@${mongoHost}:${mongoPort}/${database}` - } - else { - var uri = `mongodb://${mongoHost}:${mongoPort}/${database}` - } - mongoose.connect(uri) - const Schema = mongoose.Schema - let ReconciliationStatusModel - try { - ReconciliationStatusModel = mongoose.model('ReconciliationStatus') - } catch(e) { - mongoose.model('ReconciliationStatus', new Schema({ - status: { type: Object } - })) - ReconciliationStatusModel = mongoose.model('ReconciliationStatus') - } - - const recoStatusCode = config.getConf('mapping:recoStatusCode'); - const query = {status: {code: recoStatusCode,text: 'Done'}} - const update = {status: {code: recoStatusCode,text: 'on-progress'}} - ReconciliationStatusModel.findOneAndUpdate(query,update,(err,data)=>{ - res.set('Access-Control-Allow-Origin', '*'); - if(err) { - res.status(500).json({error: 'An error occured while processing request'}); + app.get('/markRecoDone/:orgid', (req, res) => { + winston.info(`received a request to mark reconciliation for ${req.params.orgid} as done`); + const mongoUser = config.getConf('mCSD:databaseUser'); + const mongoPasswd = config.getConf('mCSD:databasePassword'); + const mongoHost = config.getConf('mCSD:databaseHost'); + const mongoPort = config.getConf('mCSD:databasePort'); + const orgid = req.params.orgid; + const database = config.getConf('mapping:dbPrefix') + orgid; + if (mongoUser && mongoPasswd) { + var uri = `mongodb://${mongoUser}:${mongoPasswd}@${mongoHost}:${mongoPort}/${database}`; + } else { + var uri = `mongodb://${mongoHost}:${mongoPort}/${database}`; } - else { - res.status(200).json({status: 'on-progresss'}); + mongoose.connect(uri); + const Schema = mongoose.Schema; + let ReconciliationStatusModel; + try { + ReconciliationStatusModel = mongoose.model('ReconciliationStatus'); + } catch (e) { + mongoose.model('ReconciliationStatus', new Schema({ + status: { + type: Object + }, + })); + ReconciliationStatusModel = mongoose.model('ReconciliationStatus'); } - }) -}) - -app.get('/markRecoDone/:orgid',(req,res)=>{ - winston.info (`received a request to mark reconciliation for ${req.params.orgid} as done`) - const mongoUser = config.getConf('mCSD:databaseUser') - const mongoPasswd = config.getConf('mCSD:databasePassword') - const mongoHost = config.getConf('mCSD:databaseHost') - const mongoPort = config.getConf('mCSD:databasePort') - const orgid = req.params.orgid - const database = config.getConf('mapping:dbPrefix') + orgid - if(mongoUser && mongoPasswd) { - var uri = `mongodb://${mongoUser}:${mongoPasswd}@${mongoHost}:${mongoPort}/${database}` - } - else { - var uri = `mongodb://${mongoHost}:${mongoPort}/${database}` - } - mongoose.connect(uri) - const Schema = mongoose.Schema - let ReconciliationStatusModel - try { - ReconciliationStatusModel = mongoose.model('ReconciliationStatus') - } catch(e) { - mongoose.model('ReconciliationStatus', new Schema({ - status: { type: Object } - })) - ReconciliationStatusModel = mongoose.model('ReconciliationStatus') - } - - const recoStatusCode = config.getConf('mapping:recoStatusCode'); - ReconciliationStatusModel.findOne({status: {code: recoStatusCode,text: 'on-progress'}},(err,data)=>{ - if (err) { - winston.error('Unexpected error occured,please retry') - res.status(500).json({error: 'Unexpected error occured,please retry'}); - return - } - if (!data) { - var recoStatus = new ReconciliationStatusModel({ - status: {code: recoStatusCode, text: 'Done'} - }) - recoStatus.save(function(err,data){ - if (err) { - winston.error('Unexpected error occured,please retry') + const recoStatusCode = config.getConf('mapping:recoStatusCode'); + + ReconciliationStatusModel.findOne({ + status: { + code: recoStatusCode, + text: 'on-progress' + } + }, (err, data) => { + if (err) { + winston.error('Unexpected error occured,please retry'); + res.status(500).json({ + error: 'Unexpected error occured,please retry' + }); + return; + } + if (!data) { + let recoStatus = new ReconciliationStatusModel({ + status: { + code: recoStatusCode, + text: 'Done' + }, + }); + recoStatus.save((err, data) => { + if (err) { + winston.error('Unexpected error occured,please retry') + res.set('Access-Control-Allow-Origin', '*'); + res.status(500).json({ + error: 'Unexpected error occured,please retry' + }); + } + winston.info(`${orgid} marked as done with reconciliation`) res.set('Access-Control-Allow-Origin', '*'); - res.status(500).json({error: 'Unexpected error occured,please retry'}); - } - winston.info(`${orgid} marked as done with reconciliation`) - res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json({status: 'done'}); - }) - } - else { - ReconciliationStatusModel.findByIdAndUpdate(data.id,{status: {code: recoStatusCode, text: 'Done'}},(err,data)=>{ - if(err) { - winston.error('Unexpected error occured,please retry') + res.status(200).json({ + status: 'done' + }); + }); + } else { + ReconciliationStatusModel.findByIdAndUpdate(data.id, { + status: { + code: recoStatusCode, + text: 'Done' + } + }, (err, data) => { + if (err) { + winston.error('Unexpected error occured,please retry'); + res.set('Access-Control-Allow-Origin', '*'); + res.status(500).json({ + error: 'Unexpected error occured,please retry' + }); + return; + } + winston.info(`${orgid} already marked as done with reconciliation`); res.set('Access-Control-Allow-Origin', '*'); - res.status(500).json({error: 'Unexpected error occured,please retry'}); - return - } - winston.info(`${orgid} already marked as done with reconciliation`) - res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json({status: 'done'}); - }) - } - }) -}) - -app.get('/recoStatus/:orgid',(req,res)=>{ - const mongoUser = config.getConf('mCSD:databaseUser') - const mongoPasswd = config.getConf('mCSD:databasePassword') - const mongoHost = config.getConf('mCSD:databaseHost') - const mongoPort = config.getConf('mCSD:databasePort') - const orgid = req.params.orgid - const database = config.getConf('mapping:dbPrefix') + orgid - if(mongoUser && mongoPasswd) { - var uri = `mongodb://${mongoUser}:${mongoPasswd}@${mongoHost}:${mongoPort}/${database}` - } - else { - var uri = `mongodb://${mongoHost}:${mongoPort}/${database}` - } - mongoose.connect(uri) - const Schema = mongoose.Schema - - const recoStatusCode = config.getConf('mapping:recoStatusCode'); - let ReconciliationStatusModel - try { - ReconciliationStatusModel = mongoose.model('ReconciliationStatus') - } catch(e) { - mongoose.model('ReconciliationStatus', new Schema({ - status: { type: Object } - })) - ReconciliationStatusModel = mongoose.model('ReconciliationStatus') - } + res.status(200).json({ + status: 'done' + }); + }); + } + }); + }); - res.set('Access-Control-Allow-Origin', '*'); - ReconciliationStatusModel.findOne({status: {code: recoStatusCode,text: 'Done'}},(err,data)=>{ - if (err) { - res.status(500).json({error: 'Unexpected error occured,please retry'}); - return - } - if (data) { - res.status(200).json({status: 'done'}); - } - else { - res.status(200).json({status: 'on-progress'}); + app.get('/recoStatus/:orgid', (req, res) => { + const mongoUser = config.getConf('mCSD:databaseUser'); + const mongoPasswd = config.getConf('mCSD:databasePassword'); + const mongoHost = config.getConf('mCSD:databaseHost'); + const mongoPort = config.getConf('mCSD:databasePort'); + const orgid = req.params.orgid; + const database = config.getConf('mapping:dbPrefix') + orgid; + if (mongoUser && mongoPasswd) { + var uri = `mongodb://${mongoUser}:${mongoPasswd}@${mongoHost}:${mongoPort}/${database}`; + } else { + var uri = `mongodb://${mongoHost}:${mongoPort}/${database}`; } - }) + mongoose.connect(uri); + const Schema = mongoose.Schema; -}) - -app.get('/uploadProgress/:orgid/:clientId', (req,res)=>{ - const orgid = req.params.orgid - const clientId = req.params.clientId - redisClient.get(`uploadProgress${orgid}${clientId}`,(error,results)=>{ - results = JSON.parse(results) - //reset progress - if (results && (results.error !== null || results.status === 'Done')) { - var uploadRequestId = `uploadProgress${orgid}${clientId}` - let uploadReqPro = JSON.stringify({status:null, error: null, percent: null}) - redisClient.set(uploadRequestId,uploadReqPro) + const recoStatusCode = config.getConf('mapping:recoStatusCode'); + let ReconciliationStatusModel; + try { + ReconciliationStatusModel = mongoose.model('ReconciliationStatus'); + } catch (e) { + mongoose.model('ReconciliationStatus', new Schema({ + status: { + type: Object + }, + })); + ReconciliationStatusModel = mongoose.model('ReconciliationStatus'); } - res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json(results) - }) -}); -app.get('/mappingStatusProgress/:orgid/:clientId', (req,res)=>{ - const orgid = req.params.orgid - const clientId = req.params.clientId - redisClient.get(`mappingStatus${orgid}${clientId}`,(error,results)=>{ - results = JSON.parse(results) - //reset progress - if (results && (results.error !== null || results.status === 'Done')) { - var statusRequestId = `mappingStatus${orgid}${clientId}` - let statusResData = JSON.stringify({status:null, error: null, percent: null}) - redisClient.set(statusRequestId,statusResData) - } res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json(results) - }) -}); + ReconciliationStatusModel.findOne({ + status: { + code: recoStatusCode, + text: 'Done' + } + }, (err, data) => { + if (err) { + res.status(500).json({ + error: 'Unexpected error occured,please retry' + }); + return; + } + if (data) { + res.status(200).json({ + status: 'done' + }); + } else { + res.status(200).json({ + status: 'on-progress' + }); + } + }); + }); -app.get('/scoreProgress/:orgid/:clientId', (req,res)=>{ - const orgid = req.params.orgid - const clientId = req.params.clientId - redisClient.get(`scoreResults${orgid}${clientId}`,(error,results)=>{ - results = JSON.parse(results) - //reset progress - if (results && (results.error !== null || results.status === 'Done')) { - const scoreRequestId = `scoreResults${orgid}${clientId}` - let uploadReqPro = JSON.stringify({status:null, error: null, percent: null}) - redisClient.set(scoreRequestId,uploadReqPro) - } - res.set('Access-Control-Allow-Origin', '*'); - res.status(200).json(results) + app.get('/progress/:type/:clientId', (req, res) => { + const clientId = req.params.clientId; + const type = req.params.type + let progressRequestId = `${type}${clientId}`; + redisClient.get(progressRequestId, (error, results) => { + results = JSON.parse(results); + // reset progress + if (results && (results.error !== null || results.status === 'Done')) { + const uploadReqRes = JSON.stringify({ + status: null, + error: null, + percent: null + }); + redisClient.set(progressRequestId, uploadReqRes); + } + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).json(results); + }); }) -}); + app.get('/uploadProgress/:orgid/:clientId', (req, res) => { + const orgid = req.params.orgid; + const clientId = req.params.clientId; + redisClient.get(`uploadProgress${orgid}${clientId}`, (error, results) => { + results = JSON.parse(results); + // reset progress + if (results && (results.error !== null || results.status === 'Done')) { + let uploadRequestId = `uploadProgress${orgid}${clientId}`; + const uploadReqPro = JSON.stringify({ + status: null, + error: null, + percent: null + }); + redisClient.set(uploadRequestId, uploadReqPro); + } + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).json(results); + }); + }); -app.post('/uploadCSV', (req, res) => { - const form = new formidable.IncomingForm(); - form.parse(req, (err, fields, files) => { - winston.info(`Received MOH Data with fields Mapping ${JSON.stringify(fields)}`); - if (!fields.orgid) { - winston.error({ error: 'Missing Orgid' }); + app.get('/mappingStatusProgress/:orgid/:clientId', (req, res) => { + const orgid = req.params.orgid; + const clientId = req.params.clientId; + redisClient.get(`mappingStatus${orgid}${clientId}`, (error, results) => { + results = JSON.parse(results); + // reset progress + if (results && (results.error !== null || results.status === 'Done')) { + let statusRequestId = `mappingStatus${orgid}${clientId}`; + const statusResData = JSON.stringify({ + status: null, + error: null, + percent: null + }); + redisClient.set(statusRequestId, statusResData); + } res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Missing Orgid' }); - return; - } - const orgid = fields.orgid; - const orgname = fields.orgname; - const database = config.getConf('mCSD:database'); - const expectedLevels = config.getConf('levels'); - const clientId = fields.clientId - var uploadRequestId = `uploadProgress${orgid}${clientId}` - let uploadReqPro = JSON.stringify({status:'Request received by server', error: null, percent: null}) - redisClient.set(uploadRequestId,uploadReqPro) - if (!Array.isArray(expectedLevels)) { - winston.error('Invalid config data for key Levels '); + res.status(200).json(results); + }); + }); + + app.get('/scoreProgress/:orgid/:clientId', (req, res) => { + const orgid = req.params.orgid; + const clientId = req.params.clientId; + redisClient.get(`scoreResults${orgid}${clientId}`, (error, results) => { + results = JSON.parse(results); + // reset progress + if (results && (results.error !== null || results.status === 'Done')) { + const scoreRequestId = `scoreResults${orgid}${clientId}`; + const uploadReqPro = JSON.stringify({ + status: null, + error: null, + percent: null + }); + redisClient.set(scoreRequestId, uploadReqPro); + } res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Un expected error occured while processing this request' }); - res.end(); - return; - } - if (Object.keys(files).length == 0) { - winston.error('No file submitted for reconciliation'); - res.status(401).json({ error: 'Please submit CSV file for facility reconciliation' }); - res.end(); - return; - } - const fileName = Object.keys(files)[0]; - winston.info('validating CSV File'); - validateCSV(fields, (valid, missing) => { - if (!valid) { - winston.error({ MissingHeaders: missing }); + res.status(200).json(results); + }); + }); + + app.post('/uploadCSV', (req, res) => { + const form = new formidable.IncomingForm(); + form.parse(req, (err, fields, files) => { + winston.info(`Received MOH Data with fields Mapping ${JSON.stringify(fields)}`); + if (!fields.orgid) { + winston.error({ + error: 'Missing Orgid' + }); res.set('Access-Control-Allow-Origin', '*'); - res.status(401).json({ error: 'Some Headers are Missing' }); - res.end(); + res.status(401).json({ + error: 'Missing Orgid' + }); return; } - else { + const orgid = fields.orgid; + const orgname = fields.orgname; + const database = config.getConf('mCSD:database'); + const expectedLevels = config.getConf('levels'); + const clientId = fields.clientId; + let uploadRequestId = `uploadProgress${orgid}${clientId}`; + const uploadReqPro = JSON.stringify({ + status: 'Request received by server', + error: null, + percent: null + }); + redisClient.set(uploadRequestId, uploadReqPro); + if (!Array.isArray(expectedLevels)) { + winston.error('Invalid config data for key Levels '); res.set('Access-Control-Allow-Origin', '*'); - res.status(200).end(); + res.status(401).json({ + error: 'Un expected error occured while processing this request' + }); + res.end(); + return; + } + if (Object.keys(files).length == 0) { + winston.error('No file submitted for reconciliation'); + res.status(401).json({ + error: 'Please submit CSV file for facility reconciliation' + }); + res.end(); + return; } - winston.info('CSV File Passed Validation'); - //archive existing DB first - let uploadReqPro = JSON.stringify({status:'2/4 Archiving Old DB', error: null, percent: null}) - redisClient.set(uploadRequestId,uploadReqPro) - mcsd.archiveDB(orgid,(err)=>{ - if(err) { - let uploadReqPro = JSON.stringify({status:'1/3 Archiving Old DB',error: 'An error occured while archiving Database,retry', percent: null}) - redisClient.set(uploadRequestId,uploadReqPro) - winston.error('An error occured while Archiving existing DB,Upload of new dataset was stopped') - return + const fileName = Object.keys(files)[0]; + winston.info('validating CSV File'); + validateCSV(fields, (valid, missing) => { + if (!valid) { + winston.error({ + MissingHeaders: missing + }); + res.set('Access-Control-Allow-Origin', '*'); + res.status(401).json({ + error: 'Some Headers are Missing' + }); + res.end(); + return; } - //ensure old archives are deleted - let uploadReqPro = JSON.stringify({status:'3/4 Deleting Old DB', error: null, percent: null}) - redisClient.set(uploadRequestId,uploadReqPro) - mcsd.cleanArchives(orgid,()=>{}) - //delete existing db - mcsd.deleteDB(orgid,(err)=>{ - if(!err){ - winston.info(`Uploading data for ${orgid} now`) - let uploadReqPro = JSON.stringify({status:'4/4 Uploading of DB started', error: null, percent: null}) - redisClient.set(uploadRequestId,uploadReqPro) - mcsd.CSVTomCSD(files[fileName].path, fields, orgid, clientId, () => { - winston.info(`Data upload for ${orgid} is done`) - let uploadReqPro = JSON.stringify({status:'Done', error: null, percent: 100}) - redisClient.set(uploadRequestId,uploadReqPro) - }); - } - else { - winston.error('An error occured while dropping existing DB,Upload of new dataset was stopped') - let uploadReqPro = JSON.stringify({status:'3/4 Deleting Old DB',error: 'An error occured while dropping existing Database,retry', percent: null}) - redisClient.set(uploadRequestId,uploadReqPro) + + res.set('Access-Control-Allow-Origin', '*'); + res.status(200).end(); + + winston.info('CSV File Passed Validation'); + //archive existing DB first + let uploadReqPro = JSON.stringify({ + status: '2/4 Archiving Old DB', + error: null, + percent: null + }) + redisClient.set(uploadRequestId, uploadReqPro) + mcsd.archiveDB(orgid, (err) => { + if (err) { + let uploadReqPro = JSON.stringify({ + status: '1/3 Archiving Old DB', + error: 'An error occured while archiving Database,retry', + percent: null + }) + redisClient.set(uploadRequestId, uploadReqPro) + winston.error('An error occured while Archiving existing DB,Upload of new dataset was stopped') + return } + //ensure old archives are deleted + let uploadReqPro = JSON.stringify({ + status: '3/4 Deleting Old DB', + error: null, + percent: null + }) + redisClient.set(uploadRequestId, uploadReqPro) + mcsd.cleanArchives(orgid, () => {}) + //delete existing db + mcsd.deleteDB(orgid, (err) => { + if (!err) { + winston.info(`Uploading data for ${orgid} now`) + let uploadReqPro = JSON.stringify({ + status: '4/4 Uploading of DB started', + error: null, + percent: null + }) + redisClient.set(uploadRequestId, uploadReqPro) + mcsd.CSVTomCSD(files[fileName].path, fields, orgid, clientId, () => { + winston.info(`Data upload for ${orgid} is done`) + let uploadReqPro = JSON.stringify({ + status: 'Done', + error: null, + percent: 100 + }) + redisClient.set(uploadRequestId, uploadReqPro) + }); + } else { + winston.error('An error occured while dropping existing DB,Upload of new dataset was stopped') + let uploadReqPro = JSON.stringify({ + status: '3/4 Deleting Old DB', + error: 'An error occured while dropping existing Database,retry', + percent: null + }) + redisClient.set(uploadRequestId, uploadReqPro) + } + }) }) - }) + }); }); - }); - function validateCSV(cols, callback) { - const missing = []; - if (!cols.hasOwnProperty('facility') || cols.facility === null || cols.facility === undefined || cols.facility === false) { - missing.push('facility'); - } - if (!cols.hasOwnProperty('code') || cols.code === null || cols.code === undefined || cols.code === false) { - missing.push('code'); - } - if (!cols.hasOwnProperty('lat') || cols.lat === null || cols.lat === undefined || cols.lat === false) { - missing.push('lat'); - } - if (!cols.hasOwnProperty('long') || cols.long === null || cols.long === undefined || cols.long === false) { - missing.push('long'); - } - if (!cols.hasOwnProperty('level1') || cols.level1 === null || cols.level1 === undefined || cols.facility === false) { - missing.push('level1'); - } - if (!cols.hasOwnProperty('level2') || cols.level2 === null || cols.level2 === undefined || cols.level2 === false) { - missing.push('level2'); - } - if (!cols.hasOwnProperty('level3') || cols.level3 === null || cols.level3 === undefined || cols.level3 === false) { - missing.push('level3'); - } - if (!cols.hasOwnProperty('level4') || cols.level4 === null || cols.level4 === undefined || cols.level4 === false) { - missing.push('level4'); + function validateCSV(cols, callback) { + const missing = []; + if (!cols.hasOwnProperty('facility') || cols.facility === null || cols.facility === undefined || cols.facility === false) { + missing.push('facility'); + } + if (!cols.hasOwnProperty('code') || cols.code === null || cols.code === undefined || cols.code === false) { + missing.push('code'); + } + if (!cols.hasOwnProperty('lat') || cols.lat === null || cols.lat === undefined || cols.lat === false) { + missing.push('lat'); + } + if (!cols.hasOwnProperty('long') || cols.long === null || cols.long === undefined || cols.long === false) { + missing.push('long'); + } + if (!cols.hasOwnProperty('level1') || cols.level1 === null || cols.level1 === undefined || cols.facility === false) { + missing.push('level1'); + } + if (!cols.hasOwnProperty('level2') || cols.level2 === null || cols.level2 === undefined || cols.level2 === false) { + missing.push('level2'); + } + if (!cols.hasOwnProperty('level3') || cols.level3 === null || cols.level3 === undefined || cols.level3 === false) { + missing.push('level3'); + } + if (!cols.hasOwnProperty('level4') || cols.level4 === null || cols.level4 === undefined || cols.level4 === false) { + missing.push('level4'); + } + if (missing.length > 0) { + return callback(false, missing); + } + return callback(true, missing); } - if (missing.length > 0) { - return callback(false, missing); - } return callback(true, missing); - } -}); + }); -server.listen(config.getConf('server:port')); -winston.info(`Server is running and listening on port ${config.getConf('server:port')}`); + server.listen(config.getConf('server:port')); + winston.info(`Server is running and listening on port ${config.getConf('server:port')}`); } \ No newline at end of file diff --git a/facility-recon-backend/lib/mcsd.js b/facility-recon-backend/lib/mcsd.js index 4a01bd1ea..88256a43f 100755 --- a/facility-recon-backend/lib/mcsd.js +++ b/facility-recon-backend/lib/mcsd.js @@ -51,12 +51,10 @@ module.exports = function () { }, ); }, - getLocationByID(database, id, getCached, callback) { if (id) { var url = `${URI(config.getConf('mCSD:url')).segment(database).segment('fhir').segment('Location')}?_id=${id.toString()}`; - } - else { + } else { var url = URI(config.getConf('mCSD:url')).segment(database).segment('fhir').segment('Location') .toString(); } @@ -96,9 +94,9 @@ module.exports = function () { const locations = {}; locations.entry = []; if (identifier) { - var url = `${URI(config.getConf('mCSD:url')).segment(database).segment('fhir').segment('Location')}?identifier=${identifier}`.toString() + var url = `${URI(config.getConf('mCSD:url')).segment(database).segment('fhir').segment('Location')}?identifier=${identifier}`.toString(); } else { - return callback(locations) + return callback(locations); } async.doWhilst( (callback) => { @@ -147,12 +145,12 @@ module.exports = function () { getLocationParentsFromDB(source, database, entityParent, topOrg, details, callback) { const parents = []; - if (entityParent == null - || entityParent == false - || entityParent == undefined - || !topOrg - || !database - || !source + if (entityParent == null || + entityParent == false || + entityParent == undefined || + !topOrg || + !database || + !source ) { return callback(parents); } @@ -268,10 +266,10 @@ module.exports = function () { // if this is a topOrg then end here,we dont need to fetch the upper org which is continent i.e Africa else if (topOrg && sourceEntityID.endsWith(topOrg)) { return callback(parents); - } else if (body.entry[0].resource.hasOwnProperty('partOf') - && body.entry[0].resource.partOf.reference != false - && body.entry[0].resource.partOf.reference != null - && body.entry[0].resource.partOf.reference != undefined) { + } else if (body.entry[0].resource.hasOwnProperty('partOf') && + body.entry[0].resource.partOf.reference != false && + body.entry[0].resource.partOf.reference != null && + body.entry[0].resource.partOf.reference != undefined) { var entityParent = body.entry[0].resource.partOf.reference; getPar(entityParent, (parents) => { callback(parents); @@ -323,10 +321,10 @@ module.exports = function () { else if (details == 'names') parents.push(entry.resource.name); else winston.error('parent details (either id,names or all) to be returned not specified'); - if (entry.resource.hasOwnProperty('partOf') - && entry.resource.partOf.reference != false - && entry.resource.partOf.reference != null - && entry.resource.partOf.reference != undefined) { + if (entry.resource.hasOwnProperty('partOf') && + entry.resource.partOf.reference != false && + entry.resource.partOf.reference != null && + entry.resource.partOf.reference != undefined) { entityParent = entry.resource.partOf.reference; filter(entityParent, parents => callback(parents)); } else { @@ -464,10 +462,10 @@ module.exports = function () { } totalLevels++; counter++; - if (entry.resource.hasOwnProperty('id') - && entry.resource.id != false - && entry.resource.id != null - && entry.resource.id != undefined) { + if (entry.resource.hasOwnProperty('id') && + entry.resource.id != false && + entry.resource.id != null && + entry.resource.id != undefined) { const reference = entry.resource.id; if (source == 'MOH') { @@ -508,50 +506,48 @@ module.exports = function () { const datimSystem = 'http://geoalign.datim.org/DATIM'; // check if its already mapped and inore const mappingDB = config.getConf('mapping:dbPrefix') + topOrgId; - - var me = this - async.parallel( - { - datimMapped: function(callback) { - const datimIdentifier = URI(config.getConf('mCSD:url')). - segment(database). - segment('fhir'). - segment('Location'). - segment(datimId). - toString(); + + const me = this; + async.parallel({ + datimMapped(callback) { + const datimIdentifier = URI(config.getConf('mCSD:url')) + .segment(database) + .segment('fhir') + .segment('Location') + .segment(datimId) + .toString(); me.getLocationByIdentifier(mappingDB, datimIdentifier, (mapped) => { if (mapped.entry.length > 0) { - winston.error("Attempting to map already mapped location") - return callback(null,'This location was already mapped, recalculate scores to update the level you are working on') - } - else { - return callback(null,null) + winston.error('Attempting to map already mapped location'); + return callback(null, 'This location was already mapped, recalculate scores to update the level you are working on'); } - }) + + return callback(null, null); + }); }, - mohMapped: function(callback) { - const mohIdentifier = URI(config.getConf('mCSD:url')). - segment(topOrgId). - segment('fhir'). - segment('Location'). - segment(mohId). - toString(); + mohMapped(callback) { + const mohIdentifier = URI(config.getConf('mCSD:url')) + .segment(topOrgId) + .segment('fhir') + .segment('Location') + .segment(mohId) + .toString(); me.getLocationByIdentifier(mappingDB, mohIdentifier, (mapped) => { if (mapped.entry.length > 0) { - winston.error("Attempting to map already mapped location") - return callback(null,'This location was already mapped, recalculate scores to update the level you are working on') + winston.error('Attempting to map already mapped location'); + return callback(null, 'This location was already mapped, recalculate scores to update the level you are working on'); } - else { - return callback(null, null) - } - }) - } + + return callback(null, null); + }); + }, }, - function (err,res) { - if(res.mohMapped !== null) { - return callback(res.mohMapped) - } else if (res.datimMapped !== null) { - return callback(res.datimMapped) + (err, res) => { + if (res.mohMapped !== null) { + return callback(res.mohMapped); + } + if (res.datimMapped !== null) { + return callback(res.datimMapped); } me.getLocationByID(database, datimId, false, (mcsd) => { @@ -619,8 +615,8 @@ module.exports = function () { callback(err); }); }); - } - ) + }, + ); }, acceptFlag(datimId, topOrgId, callback) { const database = config.getConf('mapping:dbPrefix') + topOrgId; @@ -667,30 +663,28 @@ module.exports = function () { const mohSystem = 'http://geoalign.datim.org/MOH'; const noMatchCode = config.getConf('mapping:noMatchCode'); - var me = this - async.parallel( - { - mohMapped: function (callback) { - const mohIdentifier = URI(config.getConf('mCSD:url')). - segment(topOrgId). - segment('fhir'). - segment('Location'). - segment(mohId). - toString(); + const me = this; + async.parallel({ + mohMapped(callback) { + const mohIdentifier = URI(config.getConf('mCSD:url')) + .segment(topOrgId) + .segment('fhir') + .segment('Location') + .segment(mohId) + .toString(); const mappingDB = config.getConf('mapping:dbPrefix') + topOrgId; me.getLocationByIdentifier(mappingDB, mohIdentifier, (mapped) => { if (mapped.entry.length > 0) { - winston.error("Attempting to mark an already mapped location as no match") - return callback(null, 'This location was already mapped, recalculate scores to update the level you are working on') - } else { - return callback(null, null) + winston.error('Attempting to mark an already mapped location as no match'); + return callback(null, 'This location was already mapped, recalculate scores to update the level you are working on'); } - }) - } + return callback(null, null); + }); + }, }, - function (err, res) { + (err, res) => { if (res.mohMapped !== null) { - return callback(res.mohMapped) + return callback(res.mohMapped); } me.getLocationByID(database, mohId, false, (mcsd) => { const fhir = {}; @@ -723,7 +717,8 @@ module.exports = function () { }], }; resource.identifier = []; - const mohURL = URI(config.getConf('mCSD:url')).segment(topOrgId).segment('fhir').segment('Location').segment(mohId) + const mohURL = URI(config.getConf('mCSD:url')).segment(topOrgId).segment('fhir').segment('Location') + .segment(mohId) .toString(); resource.identifier.push({ system: mohSystem, @@ -748,8 +743,8 @@ module.exports = function () { callback(err); }); }); - } - ) + }, + ); }, breakMatch(id, database, topOrgId, callback) { const url = URI(config.getConf('mCSD:url')).segment(database).segment('fhir').segment('Location') @@ -835,7 +830,7 @@ module.exports = function () { let countRow = 0; let totalRows = 0; - exec.exec(`wc -l ${ filePath}`, (err, stdout, stderr) => { + exec.exec(`wc -l ${filePath}`, (err, stdout, stderr) => { if (err) { // node couldn't execute the command winston.error(err); @@ -869,8 +864,8 @@ module.exports = function () { } const UUID = uuid5(name, namespaceMod); - const topLevels = Array.apply(null, { - length: levelNumber + const topLevels = Array({ + length: levelNumber, }).map(Number.call, Number); // removing zero as levels starts from 1 topLevels.splice(0, 1); @@ -988,11 +983,11 @@ module.exports = function () { value: jurisdiction.uuid, }); if (jurisdiction.parentUUID) { - resource.partOf = { - display: jurisdiction.parent, - reference: `Location/${jurisdiction.parentUUID}`, - }; -} + resource.partOf = { + display: jurisdiction.parent, + reference: `Location/${jurisdiction.parentUUID}`, + }; + } resource.physicalType = { coding: [{ code: 'jdn', @@ -1093,7 +1088,7 @@ module.exports = function () { if (lookup[id]) { lookup[id].children.push(...addLater[id]); } else { - winston.error(`Couldn't find ${id } in tree.`); + winston.error(`Couldn't find ${id} in tree.`); } } } @@ -1130,7 +1125,7 @@ module.exports = function () { filesDelete.push(file); return nxtFile(); } - let replaceDel = filesDelete.find((fDelete) => { + const replaceDel = filesDelete.find((fDelete) => { fDelete = fDelete.replace(`${__dirname}/dbArchives/${db}_`, '').replace('.tar', ''); fDelete = moment(fDelete); searchFile = file.replace(`${__dirname}/dbArchives/${db}_`, '').replace('.tar', ''); @@ -1138,7 +1133,7 @@ module.exports = function () { return fDelete > searchFile; }); if (replaceDel) { - let index = filesDelete.indexOf(replaceDel); + const index = filesDelete.indexOf(replaceDel); filesDelete.splice(index, 1); filesDelete.push(file); } @@ -1170,7 +1165,7 @@ module.exports = function () { const mongoPasswd = config.getConf('mCSD:databasePassword'); const mongoHost = config.getConf('mCSD:databaseHost'); const mongoPort = config.getConf('mCSD:databasePort'); - const name = `${db }_${ moment().format()}`; + const name = `${db}_${moment().format()}`; const dbList = []; dbList.push({ name, @@ -1184,7 +1179,7 @@ module.exports = function () { async.eachSeries(dbList, (list, nxtList) => { const db = list.db; const name = list.name; - winston.info(`Archiving DB ${ db}`); + winston.info(`Archiving DB ${db}`); if (mongoUser && mongoPasswd) { var uri = `mongodb://${mongoUser}:${mongoPasswd}@${mongoHost}:${mongoPort}/${db}`; } else { @@ -1194,11 +1189,11 @@ module.exports = function () { const dir = `${__dirname}/dbArchives`; const tmpDir = tmp.dirSync(); - exec.execSync(`mongodump --uri=${ uri} -o ${tmpDir.name}`, { + exec.execSync(`mongodump --uri=${uri} -o ${tmpDir.name}`, { cwd: tmpDir.name, }); tar.c({ - file: `${dir }/${name}.tar`, + file: `${dir}/${name}.tar`, cwd: tmpDir.name, sync: true, }, [db]); @@ -1317,7 +1312,7 @@ module.exports = function () { error = err; throw err; } else { - winston.info(`${db } Dropped`); + winston.info(`${db} Dropped`); } return nxtList(); }); @@ -1344,4 +1339,4 @@ module.exports = function () { }); }, }; -}; +}; \ No newline at end of file diff --git a/facility-recon-gui/src/App.vue b/facility-recon-gui/src/App.vue index 85cf09635..f357f8829 100755 --- a/facility-recon-gui/src/App.vue +++ b/facility-recon-gui/src/App.vue @@ -9,6 +9,9 @@ cloud_uploadUpload + + syncData Sync + archive Archived Uploads @@ -52,7 +55,7 @@ - Last GeoAlign Data Sync: {{datimUpdateTime | moment("dddd, MMMM Do YYYY, h:mm:ss a")}} + @@ -64,7 +67,6 @@ import { uuid } from 'vue-uuid' const config = require('../config') const isProduction = process.env.NODE_ENV === 'production' const backendServer = (isProduction ? config.build.backend : config.dev.backend) -const updateTimeURL = (isProduction ? config.build.updateTimeURL : config.dev.updateTimeURL) export default { mixins: [scoresMixin], @@ -72,8 +74,7 @@ export default { return { initializingApp: false, fixed: false, - title: 'Facility Reconciliation', - datimUpdateTime: 'Loading...' + title: 'Facility Reconciliation' } }, computed: { @@ -150,14 +151,6 @@ export default { }) } }, - mounted () { - axios.get(updateTimeURL).then((update) => { - this.datimUpdateTime = update.data.value - }).catch((error) => { - console.log('Failed to get last update time.', error) - this.datimUpdateTime = 'Failed' - }) - }, created () { this.$store.state.clientId = uuid.v4() this.initializingApp = true diff --git a/facility-recon-gui/src/components/DataSync/FacilityReconDHIS.vue b/facility-recon-gui/src/components/DataSync/FacilityReconDHIS.vue new file mode 100644 index 000000000..c43d70f14 --- /dev/null +++ b/facility-recon-gui/src/components/DataSync/FacilityReconDHIS.vue @@ -0,0 +1,158 @@ + + + + + + {{syncStatus}} + + + + + + + + + {{syncStatus}} + + + + {{ syncPercent }}% + + + + + + + + + + + + + + + + DHIS2 Credentials + + + + + + + + + + + Clear + + + Sync + + + + + + + + diff --git a/facility-recon-gui/src/components/FacilityReconUpload.vue b/facility-recon-gui/src/components/DataSync/FacilityReconUpload.vue similarity index 98% rename from facility-recon-gui/src/components/FacilityReconUpload.vue rename to facility-recon-gui/src/components/DataSync/FacilityReconUpload.vue index 17be3d794..93b263b40 100755 --- a/facility-recon-gui/src/components/FacilityReconUpload.vue +++ b/facility-recon-gui/src/components/DataSync/FacilityReconUpload.vue @@ -44,7 +44,7 @@ - + {{uploadStatus}} @@ -52,7 +52,7 @@ - + @@ -187,10 +187,10 @@ \ No newline at end of file diff --git a/facility-recon-gui/src/components/FacilityReconView.vue b/facility-recon-gui/src/components/FacilityReconView.vue index b99502735..888616cac 100755 --- a/facility-recon-gui/src/components/FacilityReconView.vue +++ b/facility-recon-gui/src/components/FacilityReconView.vue @@ -6,6 +6,38 @@ + + + + + + + + + close + + + + title + + + + + + + + + + + + thumb_upSave + + + cancelCancel + + + + @@ -58,7 +90,12 @@ - {{props.item[header.value]}} + {{props.item[header.value].name}} + {{props.item[header.value]}} + + edit + delete + @@ -83,7 +120,7 @@ - {{props.item[header.value]}} + {{props.item[header.value] | formatGridData}} @@ -114,7 +151,7 @@ import LiquorTree from 'liquor-tree' const addChildren = (treeData, results, filter, ...rest) => { for (const node of treeData) { if (node.children && node.children.length > 0) { - addChildren(node.children, results, filter, node.text, ...rest) + addChildren(node.children, results, filter, { name: node.text, id: node.id }, ...rest) } else { let row = {} for (let i = rest.length - 1, level = 1; i >= 0; i = i - 1, level++) { @@ -123,7 +160,7 @@ const addChildren = (treeData, results, filter, ...rest) => { } row['level' + level] = rest[i] } - row.facility = node.text + row.facility = { name: node.text, id: node.id } row.latitude = node.lat row.longitude = node.long // Do nothing for level1 since that's the whole country @@ -137,6 +174,8 @@ const addChildren = (treeData, results, filter, ...rest) => { export default { data () { return { + editDialog: false, + locationDetails: {}, headerText: { level2: 'Level 1', level3: 'Level 2', @@ -168,6 +207,23 @@ export default { mohPagination: { rowsPerPage: 20 } } }, + filters: { + formatGridData (data) { + if (data === '' || data === undefined || data === null || !data) { + return data + } else if (data.hasOwnProperty('id')) { + return data.name + } else { + return data + } + } + }, + methods: { + editLocation (item) { + this.editDialog = true + this.locationDetails = item + } + }, computed: { datimGridData () { var results = [] @@ -204,6 +260,12 @@ export default { header.push({ text: this.headerText[key], value: key }) } } + if (header.length > 0) { + header.push({ + text: 'Action', + value: 'action' + }) + } return header }, datimPages () { diff --git a/facility-recon-gui/src/main.js b/facility-recon-gui/src/main.js index a37edd6e6..3ce033a94 100755 --- a/facility-recon-gui/src/main.js +++ b/facility-recon-gui/src/main.js @@ -10,7 +10,6 @@ import { store } from './store/store' -Vue.use(require('vue-moment')) Vue.use(Vuelidate) Vue.use(Vuetify, { theme: { diff --git a/facility-recon-gui/src/router/index.js b/facility-recon-gui/src/router/index.js index 6bf983d86..d319e7490 100755 --- a/facility-recon-gui/src/router/index.js +++ b/facility-recon-gui/src/router/index.js @@ -1,45 +1,51 @@ import Vue from 'vue' import Router from 'vue-router' import FacilityReconHome from '@/components/FacilityReconHome' -import FacilityReconUpload from '@/components/FacilityReconUpload' +import FacilityReconUpload from '@/components/DataSync/FacilityReconUpload' import FacilityReconView from '@/components/FacilityReconView' import FacilityReconScores from '@/components/FacilityReconScores' import FacilityRecoStatus from '@/components/FacilityRecoStatus' import FacilityReconDbAdmin from '@/components/FacilityReconDbAdmin' +import FacilityReconDataSource from '@/components/FacilityReconDataSource' Vue.use(Router) export default new Router({ routes: [{ - path: '/', - name: 'FacilityReconHome', - component: FacilityReconHome + path: '/', + name: 'FacilityReconHome', + component: FacilityReconHome - }, - { - path: '/upload', - name: 'FacilityReconUpload', - component: FacilityReconUpload - }, - { - path: '/view', - name: 'FacilityReconView', - component: FacilityReconView - }, - { - path: '/scores', - name: 'FacilityReconScores', - component: FacilityReconScores - }, - { - path: '/recoStatus', - name: 'FacilityRecoStatus', - component: FacilityRecoStatus - }, - { - path: '/dbAdmin', - name: 'FacilityReconDbAdmin', - component: FacilityReconDbAdmin - } + }, + { + path: '/upload', + name: 'FacilityReconUpload', + component: FacilityReconUpload + }, + { + path: '/source', + name: 'FacilityReconDataSource', + component: FacilityReconDataSource + }, + { + path: '/view', + name: 'FacilityReconView', + component: FacilityReconView + }, + { + path: '/scores', + name: 'FacilityReconScores', + component: FacilityReconScores + }, + { + path: '/recoStatus', + name: 'FacilityRecoStatus', + component: FacilityRecoStatus + }, + { + path: '/dbAdmin', + name: 'FacilityReconDbAdmin', + component: FacilityReconDbAdmin + } ] })