var path = require('path') var filename = path.basename(__filename) var utilsService = require('../service/utilsService') var LOG = require('sb_logger_util') const contentProvider = require('sb_content_provider_util') var _ = require('lodash') var CacheManager = require('sb_cache_manager') var cacheManager = new CacheManager({}) var configData = require('../config/constants') var async = require('async') /** * This function executes the org search lms API to get all orgs * @param requestObj js object which contains the search request with filters,offset,limit,query etc * @param cb callback after success or error */ function getRootOrgs (requestObj, cb, noExitOnError) { LOG.info(utilsService.getLoggerData({}, 'INFO', filename, 'getRootOrgs', 'getRootOrgs called', requestObj)) contentProvider.getAllRootOrgs(requestObj, (err, res) => { if (!err) { return cb(err, res) } else { LOG.error(utilsService.getLoggerData({}, 'ERROR', filename, 'getRootOrgs', 'error in getting root orgs.', err)) if (!noExitOnError) process.exit(1) } }) } /** * This function tries to get the orgdetails from cache if not exits fetches from api and sets to cache * @param requestObj is filter query that is sent to fetch org api call, tryfromcache is a boolean flag, inputdata is array of contents that needs org data * @param CBW callback after success or error */ function getRootOrgsFromCache (orgfetchquery, tryfromcache, inputdata, cb) { async.waterfall([ function (CBW) { if (tryfromcache) { var keyNames = getKeyNames(inputdata) cacheManager.mget(keyNames, function (err, cacheresponse) { var cachedata = _.compact(cacheresponse) if (!err && _.size(cachedata) > 0) { return cb(null, cachedata) } else { if (err) { LOG.error(utilsService.getLoggerData({}, 'ERROR', filename, 'getRootOrgsFromCache', 'Feching Org details from cache failed.', err)) } CBW() } }) } else { CBW() } }, function (CBW) { getRootOrgs(orgfetchquery, function (err, res) { if (err) { return cb(err) } else { if (_.get(res, 'result.response') && _.get(res.result, 'response.content')) { var cacheinputdata = prepareCacheDataToInsert(res.result.response.content) insertDataToCache(cacheinputdata) return cb(null, res.result.response.content) } else { return cb(null, []) } } }, true) } ]) } function insertDataToCache (cacheinputdata) { cacheManager.mset({ data: cacheinputdata, ttl: configData.orgCacheExpiryTime }, function (err, data) { if (err) { LOG.error(utilsService.getLoggerData({}, 'ERROR', filename, 'Setting allRootOrgs cache failed', 'Setting allRootOrgs cache data failed', err)) } else { LOG.info(utilsService.getLoggerData({}, 'INFO', filename, 'Setting allRootOrgs cache data success')) } }) } /** * This function loops each object from the input and maps channel id with hasTagId from orgdetails and prepares orgDetails obj for each obj in the array * @param inputdata is array of objects, it might be content or course * @param cb callback after success or error */ function populateOrgDetailsByHasTag (contents, inputfields, cb) { var orgDetails = [] var orgFetchQuery = { 'request': { 'filters': { 'isRootOrg': true } } } var tryFromCache = true async.waterfall([ // intially fetch all the orgs till the default limit function (CBW) { getRootOrgsFromCache(orgFetchQuery, tryFromCache, contents, function (err, orgdata) { if (!err && orgdata) { orgDetails = orgdata return CBW() } else { return cb(null, contents) } }) }, // fetch the orgs which are not fetched from initial api call function (CBW) { var inputHashTagIds = _.uniq(_.map(contents, 'channel')) var fetchedhashTagIds = _.uniq(_.map(orgDetails, 'hashTagId')) // diff of channels which doesnt exists in inital fetch var hasTagIdsNeedToFetch = _.difference(inputHashTagIds, fetchedhashTagIds) orgFetchQuery.request.filters.hashTagId = hasTagIdsNeedToFetch if (hasTagIdsNeedToFetch.length) { // fetch directly from api , as hashTagIdsNeedToFetch are the data which are not found from first api query tryFromCache = false getRootOrgsFromCache(orgFetchQuery, tryFromCache, contents, function (err, orgdata) { if (!err && orgdata) { orgDetails = _.concat(orgDetails, orgdata) return CBW() } else { return cb(null, contents) } }) } else { CBW() } }, // mapping channel with orgdetails in contents function (CBW) { var orgDetailsWithKey = _.keyBy(orgDetails, 'hashTagId') _.forEach(contents, (eachcontent, index) => { if (eachcontent.channel) { var eachorgdetail = orgDetailsWithKey[eachcontent.channel] contents[index].orgDetails = eachorgdetail ? _.pick(eachorgdetail, inputfields) : {} } }) return cb(null, contents) } ]) } /** * This function loops each object from the input and includes org details in it * @param inputdata is req object and res object * @param cb there will be no error callback , always returns success */ function includeOrgDetails (req, res, cb) { if (_.get(req, 'query.orgdetails') && _.get(res, 'result.content')) { var inputfields = req.query.orgdetails.split(',') var fieldsToPopulate = configData.orgfieldsAllowedToSend.filter(eachfield => inputfields.includes(eachfield)) var inputContentIsArray = _.isArray(res.result.content) // contents need to send as array bec populateOrgDetailsByHasTag expects data as array var contents = inputContentIsArray ? res.result.content : [res.result.content] if (_.size(fieldsToPopulate) && _.size(contents)) { populateOrgDetailsByHasTag(contents, fieldsToPopulate, function (err, contentwithorgdetails) { if (!err) { res.result.content = inputContentIsArray ? contentwithorgdetails : contentwithorgdetails[0] } return cb(null, res) }) } else { return cb(null, res) } } else { return cb(null, res) } } // prepares the set data for inserting in cache function prepareCacheDataToInsert (data) { var cacheKeyValuePairs = [] _.forEach(data, function (eachdata) { if (eachdata.hashTagId) { var keyname = configData.orgCacheKeyNamePrefix + eachdata.hashTagId cacheKeyValuePairs.push(keyname) cacheKeyValuePairs.push(eachdata) } }) return cacheKeyValuePairs } // prepares the get data for fetching from cache function getKeyNames (data) { var keyNames = [] _.forEach(data, function (eachdata) { if (eachdata.channel) { var keyname = configData.orgCacheKeyNamePrefix + eachdata.channel keyNames.push(keyname) } }) return _.uniq(keyNames) } module.exports = { getRootOrgs: getRootOrgs, includeOrgDetails: includeOrgDetails, populateOrgDetailsByHasTag: populateOrgDetailsByHasTag }