From 5f0284e9e645e5a4ff59857c86ebf2e455c64990 Mon Sep 17 00:00:00 2001
From: raghu <http://localhost:9000>
Date: Tue, 27 Nov 2018 18:48:03 +0530
Subject: [PATCH] Issue #SB-8572 feat : getorgdetails changes

---
 src/config/constants.json |   4 +-
 src/helpers/orgHelper.js  | 128 +++++++++++++++++++++++++++++---------
 2 files changed, 102 insertions(+), 30 deletions(-)

diff --git a/src/config/constants.json b/src/config/constants.json
index e50dbcd..631f2f8 100644
--- a/src/config/constants.json
+++ b/src/config/constants.json
@@ -1,5 +1,5 @@
 {
-    "orgCacheKeyName": "allRootOrgs",
     "orgCacheExpiryTime": 1800,
-    "orgfieldsAllowedToSend": ["email","orgName"]
+    "orgfieldsAllowedToSend": ["email","orgName"],
+    "orgCacheKeyNamePrefix" : "orgdata-"
 }   
\ No newline at end of file
diff --git a/src/helpers/orgHelper.js b/src/helpers/orgHelper.js
index b9048a1..ff6c794 100644
--- a/src/helpers/orgHelper.js
+++ b/src/helpers/orgHelper.js
@@ -7,6 +7,7 @@ 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
@@ -17,39 +18,46 @@ function getRootOrgs (requestObj, cb) {
   LOG.info(utilsService.getLoggerData({}, 'INFO',
     filename, 'getRootOrgs', 'getRootOrgs called', requestObj))
   contentProvider.getAllRootOrgs(requestObj, (err, res) => {
-    if (!err && res && res.result.response.count > 0 && res.result.response.content) {
+    if (!err) {
       return cb(err, res)
     } else {
       LOG.error(utilsService.getLoggerData({}, 'ERROR',
         filename, 'getRootOrgs', 'error in getting root orgs.', err))
-      process.exit(1)
+      return cb(err)
     }
   })
 }
 
 /**
  * This function tries to get the orgdetails from cache if not exits fetches from api and sets to cache
- * @param requestObj is not needed bec all rootorgdetails are fetched here
+ * @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 (cb) {
-  cacheManager.get(configData.orgCacheKeyName, function (err, cachedata) {
-    if (err || !cachedata) {
-      var inputObj = {
-        'request': {
-          'filters': { 'isRootOrg': true }
-        }
+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 {
+            CBW()
+          }
+        })
+      } else {
+        CBW()
       }
-      getRootOrgs(inputObj, function (err, res) {
+    },
+    function (CBW) {
+      getRootOrgs(orgfetchquery, function (err, res) {
         if (err) {
           return cb(err)
         } else {
-          var cacheinputdata = {
-            key: configData.orgCacheKeyName,
-            value: res.result.response.content,
-            ttl: configData.orgCacheExpiryTime
-          }
-          cacheManager.set(cacheinputdata, function (err, data) {
+          var cacheinputdata = prepareCacheDataToInsert(res.result.response.content)
+          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))
@@ -57,14 +65,12 @@ function getRootOrgsFromCache (cb) {
               LOG.info(utilsService.getLoggerData({}, 'INFO', filename,
                 'Setting allRootOrgs cache data success'))
             }
+            return cb(null, res.result.response.content)
           })
-          return cb(null, res.result.response.content)
         }
       })
-    } else {
-      return cb(null, cachedata)
     }
-  })
+  ])
 }
 
 /**
@@ -76,18 +82,59 @@ function populateOrgDetailsByHasTag (inputdata, inputfields, cb) {
   inputfields = inputfields.split(',')
   var fieldsToPopulate = configData.orgfieldsAllowedToSend.filter(eachfield => inputfields.includes(eachfield))
   if (_.size(fieldsToPopulate) > 0 && _.size(inputdata) > 0) {
-    getRootOrgsFromCache(function (err, orgdata) {
-      if (!err && orgdata) {
-        var orgDetails = _.keyBy(orgdata, 'hashTagId')
+    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, inputdata, function (err, orgdata) {
+          if (!err && orgdata) {
+            orgDetails = orgdata
+            return CBW()
+          } else {
+            return cb(null, inputdata)
+          }
+        })
+      },
+      // fetch the orgs which are not fetched from initial api call
+      function (CBW) {
+        var inputHashTagIds = _.uniq(_.map(inputdata, '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, inputdata, function (err, orgdata) {
+            if (!err && orgdata) {
+              orgDetails = _.concat(orgDetails, orgdata)
+              return CBW()
+            } else {
+              return cb(null, inputdata)
+            }
+          })
+        } else {
+          CBW()
+        }
+      },
+      // mapping channel with orgdetails in inputdata
+      function (CBW) {
+        var orgDetailsWithKey = _.keyBy(orgDetails, 'hashTagId')
         _.forEach(inputdata, (eachcontent, index) => {
           if (eachcontent.channel) {
-            var eachorgdetail = orgDetails[eachcontent.channel]
+            var eachorgdetail = orgDetailsWithKey[eachcontent.channel]
             inputdata[index].orgDetails = eachorgdetail ? _.pick(eachorgdetail, fieldsToPopulate) : {}
           }
         })
-      };
-      return cb(null, inputdata)
-    })
+        return cb(null, inputdata)
+      }
+    ])
   } else {
     return cb(null, inputdata)
   }
@@ -116,6 +163,31 @@ function includeOrgDetails (req, res, cb) {
   }
 }
 
+// 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,
-- 
GitLab