Name

sn_gs_config.GuidedSetupDynamicRulesUtil

Description

Script to configure the rules on a guided setup

Script

var GuidedSetupDynamicRulesUtil = Class.create();
GuidedSetupDynamicRulesUtil.prototype = {
  LOG_TYPE: {
      DEACTIVATED: 5,
      REACTIVATED: 6
  },

  STATUS_TYPE: {
      INACTIVE: 3
  },

  GSW_STATUS_OF_CONTENT_TABLE: 'gsw_status_of_content',
  GSW_CHANGE_LOG_TABLE: 'gsw_change_log',
  CONTENT: 'content',
  STATUS: 'status',
  TYPE: 'type',

  initialize: function() {
      this.rootContentId = '';
  },

  getContentIdMap: function(rootContentId) {
      try {
          this.rootContentId = rootContentId;
          var rules = {};
          var responseMap = {};
          var contentIdMap = null;
          var hasResponses = false;
          var configGr = new GlideRecord("guided_setup_configuration");
          configGr.addQuery("parent_guided_setup", rootContentId);
          configGr.query();

          if (!configGr.next())
              return contentIdMap;

          var configId = configGr.getUniqueValue();
          var isLeastAccessibleContentMethod = configGr.getValue("matching_criteria") == "atleast_one";
          /*
          	Atleast One Rule --> Shows content if at least one rule shows the content
          		Step 1. Intersection of all exclude Rules 
          		Step 2. Union of all include Rules
          		Step 3. output = { excludes = Step1 Result - Step 2 Result }

          	All Rules --> Shows content only if all the rules shows the content
          		Step 1. Union of all exclude Rules
          		Step 2. Union of all include Rules
          		Step 3. output = { excludes = Step1 Result, includes = Step2 Result }
          */

          //Load the rules and it's excluded content lists in a map for later use to filter out based on the response values...

          var configRuleGr = new GlideRecord("guided_setup_configuration_rule");
          configRuleGr.addQuery("parent_setup_config", configId);
          configRuleGr.query();
          while (configRuleGr.next()) {
              rules[configRuleGr.getUniqueValue()] = rules[configRuleGr.getUniqueValue()] || {};
              rules[configRuleGr.getUniqueValue()]["contentList"] = configRuleGr.getValue("content_list");
              rules[configRuleGr.getUniqueValue()]["contentListType"] = configRuleGr.getValue("content_list_type");
          }

          var configRuleCategoryGr = new GlideRecord("guided_setup_rule_on_category");
          configRuleCategoryGr.addQuery("parent_rule.parent_setup_config", configId);
          configRuleCategoryGr.query();
          while (configRuleCategoryGr.next()) {
              rules[configRuleCategoryGr.getValue("parent_rule")] = rules[configRuleCategoryGr.getValue("parent_rule")] || {};
              rules[configRuleCategoryGr.getValue("parent_rule")][configRuleCategoryGr.category.category_value] = rules[configRuleCategoryGr.getValue("parent_rule")][configRuleCategoryGr.category.category_value] || [];
              rules[configRuleCategoryGr.getValue("parent_rule")][configRuleCategoryGr.category.category_value].push({
                  "operator": configRuleCategoryGr.getValue("operator"),
                  "value": configRuleCategoryGr.getValue("value")
              });
          }

          if (!rules || Object.keys(rules).length == 0)
              return contentIdMap;

          var responseMapGr = new GlideRecord("guided_setup_configuration_response");

          responseMapGr.addQuery("parent_setup_config", configId);
          responseMapGr.addQuery("active", true);
          responseMapGr.query();

          //If active responses are available then respect them by getting all the excluded contents.
          if (responseMapGr.hasNext()) {
              hasResponses = true;
              contentIdMap = {
                  "exclude": [],
                  "include": []
              };

              while (responseMapGr.next()) {
                  responseMap[responseMapGr.getValue("category")] = responseMap[responseMapGr.getValue("category")] || [];
                  responseMap[responseMapGr.getValue("category")].push(responseMapGr.getValue("value"));
              }

              var intersectionOfExcludedContent = [];
              var unionOfIncludedContent = [];
              var isFirstSeenExcludeRule = true;

              for (var ruleId in rules) {
                  var definedRules = rules[ruleId];
                  var isRuleMatching = true;
                  for (var ruleCategory in definedRules) {
                      if (ruleCategory != "contentList") {
                          if (definedRules[ruleCategory] && definedRules[ruleCategory].length > 0) {
                              for (var definedRulesIndx in definedRules[ruleCategory]) {
                                  var definedRule = definedRules[ruleCategory][definedRulesIndx];
                                  if (definedRule.operator == "contains") {
                                      if (!responseMap || !responseMap[ruleCategory] || responseMap[ruleCategory].indexOf(definedRule.value) == -1) {
                                          isRuleMatching = false;
                                          break;
                                      }
                                  } else if (definedRule.operator == "not_contains") {
                                      if (!responseMap || !responseMap[ruleCategory] || responseMap[ruleCategory].indexOf(definedRule.value) > -1) {
                                          isRuleMatching = false;
                                          break;
                                      }
                                  }
                              }
                          }
                      }
                  }
                  if (isRuleMatching) {
                      if (definedRules.contentList) {
                          var contentIds = definedRules.contentList.split(",");
                          if (contentIds && contentIds.length > 0) {
                              var contentIdIndx;
                              if (isLeastAccessibleContentMethod) {
                                  if (definedRules.contentListType == "include") {
                                      for (contentIdIndx in contentIds) {
                                          unionOfIncludedContent.push(contentIds[contentIdIndx]);
                                      }
                                  } else if (definedRules.contentListType == "exclude") {
                                      if (isFirstSeenExcludeRule) {
                                          for (contentIdIndx in contentIds) {
                                              intersectionOfExcludedContent.push(contentIds[contentIdIndx]);
                                          }
                                          isFirstSeenExcludeRule = false;
                                      } else {
                                          intersectionOfExcludedContent = intersectionOfExcludedContent.filter(function(n) {
                                              return contentIds.indexOf(n) !== -1;
                                          });
                                      }
                                  }

                              } else {
                                  if (definedRules.contentListType == "include") {
                                      for (contentIdIndx in contentIds) {
                                          contentIdMap["include"].push(contentIds[contentIdIndx]);
                                      }
                                  } else if (definedRules.contentListType == "exclude") {
                                      for (contentIdIndx in contentIds) {
                                          contentIdMap["exclude"].push(contentIds[contentIdIndx]);
                                      }
                                  }
                              }
                          }
                      }
                  }
              }
          } else {
              contentIdMap = contentIdMap || { "include": []};
  			contentIdMap["include"].push(configGr.getValue("default_contents"));
          }

          if (isLeastAccessibleContentMethod) {
              if (hasResponses) {
                  var contentsToBeExcluded = intersectionOfExcludedContent.filter(function(n) {
                      return unionOfIncludedContent.indexOf(n) == -1;
                  });
                  return {"exclude": contentsToBeExcluded};
              } else {
                  return contentIdMap;
              }
          } else {
              //This will ensure the default contents are included only if there is any explict include rule available so the pre-requisite content is always visible for doing the survey any number of times. 
              if (contentIdMap && contentIdMap["include"] && contentIdMap["include"].length > 0)
                  contentIdMap["include"].push(configGr.getValue("default_contents"));
          }


          //Fix DEF0129942 : Based on the survey taken, If all the visible tasks are complete for a section in the guided setup, it should as 100% complete
          if (contentIdMap) {
              this._deactivateExcludedContent(contentIdMap);
              this._reactivateIncludedContent(contentIdMap);
          }

          return contentIdMap;

      } catch (e) {
          gs.warn("Error occured in the rule evaluation");
          return null;
      }
  },

  _deactivateExcludedContent: function(contentIdMap) {
      var contentsToBeDeactivated = this._getContentIds(contentIdMap, 'status!=' + this.STATUS_TYPE.INACTIVE, 'contentNOT IN', 'contentIN');
      this._insertChangeLogRecords(contentsToBeDeactivated, this.LOG_TYPE.DEACTIVATED);
  },

  _reactivateIncludedContent: function(contentIdMap) {
      var userSkippedContents = this._getContentIdsSkippedByUser();
      var contentToBeIncluded = this._getContentIds(contentIdMap, 'status=' + this.STATUS_TYPE.INACTIVE, 'contentIN', 'contentNOT IN');
      var contentsToBeReactivated = contentToBeIncluded.filter(function(contentId) {
          return userSkippedContents.indexOf(contentId) == -1;
      });
      this._insertChangeLogRecords(contentsToBeReactivated, this.LOG_TYPE.REACTIVATED);
  },

  _insertChangeLogRecords: function(contentIds, type) {
      var logGr = new GlideRecord(this.GSW_CHANGE_LOG_TABLE);
      contentIds.forEach(function(contentId) {
          logGr.initialize();
          logGr.setValue('content', contentId);
          logGr.setValue('type', type);
          logGr.insert();
      });
  },

  // Getting all the content IDs which are manually skipped by the user
  _getContentIdsSkippedByUser: function() {
      var manuallySkippedIds = [];

      var statusGr = new GlideRecord(this.GSW_STATUS_OF_CONTENT_TABLE);
      var changeLogGr = statusGr.addJoinQuery(this.GSW_CHANGE_LOG_TABLE, this.CONTENT, this.CONTENT);
      statusGr.addQuery('content.supports_child_content', false);
      statusGr.addQuery('content.root_parent', this.rootContentId);
      statusGr.addQuery(this.STATUS, this.STATUS_TYPE.INACTIVE);
      changeLogGr.addCondition('changed_by', '!=', '');
      changeLogGr.addCondition(this.TYPE, this.LOG_TYPE.DEACTIVATED);
      statusGr.query();

      while (statusGr.next())
          manuallySkippedIds.push(statusGr.getValue(this.CONTENT));

      return manuallySkippedIds;
  },

  _getContentIds: function(contentIdMap, statusQuery, includeListQuery, excludeListQuery) {
      var contentIds = [];

      var statusGr = new GlideRecord(this.GSW_STATUS_OF_CONTENT_TABLE);
      statusGr.addQuery('content.supports_child_content', false);
      statusGr.addQuery('content.root_parent', this.rootContentId);
      statusGr.addEncodedQuery(statusQuery);

      if (contentIdMap["include"] && contentIdMap["include"].length > 0) {
          statusGr.addEncodedQuery(includeListQuery + contentIdMap["include"]);
          statusGr.query();
          while (statusGr.next())
              contentIds.push(statusGr.getValue(this.CONTENT));
      }

      statusGr.initialize();
      statusGr.addQuery('content.supports_child_content', false);
      statusGr.addQuery('content.root_parent', this.rootContentId);
      statusGr.addEncodedQuery(statusQuery);

      if (contentIdMap["exclude"] && contentIdMap["exclude"].length > 0) {
          statusGr.addEncodedQuery(excludeListQuery + contentIdMap["exclude"]);
          statusGr.query();
          while (statusGr.next())
              contentIds.push(statusGr.getValue(this.CONTENT));
      }

      return contentIds;
  },

  type: 'GuidedSetupDynamicRulesUtil'
};

Sys ID

613390b753121010af5addeeff7b124e

Offical Documentation

Official Docs: