Name

sn_cd.cd_Audience

Description

API for using audiences.

Script

var cd_Audience = Class.create();
cd_Audience.prototype = {
  initialize: function() {
      this.NULL_QUERY = "sys_id=null";
      this.hrPluginActive = GlidePluginManager.isActive('com.sn_hr_core');
      this.blockCriteriaFieldList = {
          'name': true,
          'active': true,
          'script': true,
          'match_all': true,
          'tags': true
      };
  },

  /** Return an array of users described by any of the audience records
   * @param audienceIds string Comma separated string of sn_cd_audience sys_id's
   * @return array User sys_id's
   */
  getAudience: function(audienceIds) {
      var userMap = this.getAudienceMap(audienceIds, false);

      var userArray = [];
      for (var key in userMap)
          userArray.push(key);

      return userArray;
  },

  /** Return an object with keys equal to language codes and values equal to arrays of user
   * sys_ids, where each user in an array has their preferred_language equal to the key language
   * @param audienceIds string Comma seperated string of sn_cd_audience sys_ids
   * @return object with key = string, language code and value = [string], user sys_ids
   */
  getAudienceByLanguage: function(audienceIds) {
      var userMap = this.getAudienceMap(audienceIds, true);

      var languageToUsers = {};
      for (var userSysId in userMap) {
          if (!languageToUsers.hasOwnProperty(userMap[userSysId]))
              languageToUsers[userMap[userSysId]] = [];
          languageToUsers[userMap[userSysId]].push(userSysId);
      }

      return languageToUsers;
  },

  /** Return a Map of users described by any of the audience records
   * @param audienceIds string Comma separated string of sn_cd_audience sys_id's
   * @param getUserLanguages boolean If true, set value in return object to users' preferred language instead of true
   * @return object key = string, user sys_ids, value = bool, unless getUserLanguages is set to true, then value = language string
   */
  getAudienceMap: function(audienceIds, getUserLanguages) {
      var userMap = {};

      var systemLanguage = gs.getProperty("glide.sys.language");
      var userLanguage;
      var grAudience = new GlideRecord("sn_cd_audience");
      grAudience.addQuery("sys_id", "IN", audienceIds);
      grAudience.addNotNullQuery("audience_type");
      grAudience.query();
      while (grAudience.next()) {
          var audienceType = grAudience.getValue("audience_type");
          var audienceQuery = grAudience.getValue("audience_query");

          if (audienceType == "upload_file") {
              var grAudienceData = new GlideRecord("sn_cd_audience_data");
              grAudienceData.addQuery("audience", grAudience.sys_id);
              grAudienceData.addNotNullQuery("user");
              grAudienceData.query();
              while (grAudienceData.next())
                  if (getUserLanguages) {
                      userLanguage = grAudienceData.getElement('user.preferred_language').toString() || systemLanguage;
                      userMap[grAudienceData.getValue("user")] = userLanguage;
                  } else
                      userMap[grAudienceData.getValue("user")] = true;

          } else if (audienceType == "sn_hr_core_criteria" && this.hrPluginActive && !gs.nil(audienceQuery)) {
              var hrCriteriaUsers = new sn_hr_core.hr_Criteria().getUsersForHRCriteria(audienceQuery);
              if (getUserLanguages && hrCriteriaUsers.length) {
                  // Must query to get user language preferences
                  var grUsers = new GlideRecord("sys_user");
                  grUsers.addEncodedQuery("sys_idIN" + hrCriteriaUsers.join(","));
                  grUsers.query();
                  while (grUsers.next()) {
                      userLanguage = grUsers.getValue("preferred_language");
                      userMap[grUsers.getUniqueValue()] = userLanguage ? userLanguage : systemLanguage;
                  }
              } else
                  for (var i = 0; i < hrCriteriaUsers.length; i++)
                      userMap[hrCriteriaUsers[i]] = true;

          } else if (audienceType == "user_criteria" && !gs.nil(audienceQuery)) {
              var grUserCriteria = new GlideRecord("sys_user");
              grUserCriteria.addEncodedQuery(this.getUserCriteriaQuery(audienceQuery));
              grUserCriteria.query();
              while (grUserCriteria.next())
                  if (getUserLanguages) {
                      userLanguage = grUserCriteria.getValue("preferred_language");
                      userMap[grUserCriteria.getUniqueValue()] = userLanguage ? userLanguage : systemLanguage;
                  } else
                      userMap[grUserCriteria.getUniqueValue()] = true;

          } else if (audienceType == "sn_hr_core_profile" && this.hrPluginActive && !gs.nil(audienceQuery)) {
              var grHrProfile = new GlideRecord("sn_hr_core_profile");
              grHrProfile.addEncodedQuery(audienceQuery);
              grHrProfile.query();
              while (grHrProfile.next())
                  if (getUserLanguages) {
                      userLanguage = grHrProfile.getElement('user.preferred_language').toString() || systemLanguage;
                      userMap[grHrProfile.getValue("user")] = userLanguage;
                  } else
                      userMap[grHrProfile.getValue("user")] = true;

          } else if (audienceType == "sys_user" && !gs.nil(audienceQuery)) {
              var grUser = new GlideRecord("sys_user");
              grUser.addEncodedQuery(audienceQuery);
              grUser.query();
              while (grUser.next())
                  if (getUserLanguages) {
                      userLanguage = grUser.getValue("preferred_language");
                      userMap[grUser.getUniqueValue()] = userLanguage || systemLanguage;
                  } else
                      userMap[grUser.getUniqueValue()] = true;
          }
      }

      return userMap;
  },

  /** Determine whether a user is in any of the audiences
   * @param audienceIds string Comma separated string of sn_cd_audience sys_id's
   * @param userId string sys_id of user
   * @param caseId (optional) String LE case sys_id to add the right survey instance to hr_condition
   * @param simulation (optional) Boolean
   * @param useCache (optional) Boolean Try to use scoped cache to retrieve / store result. Not all audience types support caching.
   * @return boolean Whether the user is in any of the audience records
   */
  isUserInAudience: function(audienceIds, userId, simulation, caseId, useCache) {
      if (!audienceIds || !userId)
          return false;

      var grAudience = new GlideRecord("sn_cd_audience");
      grAudience.addQuery("sys_id", "IN", audienceIds);
      grAudience.addNotNullQuery("audience_type");
      grAudience.query();
      while (grAudience.next()) {
          var audienceType = grAudience.getValue("audience_type");
          var audienceQuery = grAudience.getValue("audience_query");

          if (audienceType == "upload_file") {
              var grAudienceData = new GlideRecord("sn_cd_audience_data");
              grAudienceData.addQuery("audience", grAudience.sys_id);
              grAudienceData.addQuery("user", userId);
              grAudienceData.addNotNullQuery("user");
              grAudienceData.query();
              if (grAudienceData.hasNext())
                  return true;

          } else if (audienceType == "sn_hr_core_criteria" && this.hrPluginActive && !gs.nil(audienceQuery)) {
              var hrCriteriaIds = audienceQuery.split(",");
              for (var i = 0; i < hrCriteriaIds.length; i++)
                  if (new sn_hr_core.hr_Criteria().evaluateById(hrCriteriaIds[i], userId, simulation, caseId, useCache))
                      return true;

          } else if (audienceType == "user_criteria" && !gs.nil(audienceQuery)) {
              var grUserCheck = new GlideRecord('sys_user');
              if (!grUserCheck.get(userId))
                  return false;
              if (sn_uc.UserCriteriaLoader.userMatches(userId, audienceQuery.split(',')))
                  return true;

          } else if (audienceType == "sn_hr_core_profile" && this.hrPluginActive && !gs.nil(audienceQuery)) {
              var grHrProfile = new GlideRecord("sn_hr_core_profile");
              grHrProfile.addEncodedQuery(this._addUserToQuery(audienceQuery, "user", userId));
              grHrProfile.query();
              if (grHrProfile.hasNext())
                  return true;

          } else if (audienceType == "sys_user" && !gs.nil(audienceQuery)) {
              var grUser = new GlideRecord("sys_user");
              grUser.addEncodedQuery(this._addUserToQuery(audienceQuery, "sys_id", userId));
              grUser.query();
              if (grUser.hasNext())
                  return true;
          }
      }

      return false;
  },

  /* Get audience name
   * @param audienceId string sys_id of a audience record
   * @return string audience name
   */
  getAudienceName: function(audienceId) {
      if (!audienceId)
          return '';

      var grAudience = new GlideRecord('sn_cd_audience');
      grAudience.get(audienceId);

      return grAudience.getValue('name');
  },

  /* Get audience type. Returns an empty string if no audience is found
   * @param audienceId string sys_id of a audience record
   * @return string audience type
   */
  getAudienceType: function(audienceId) {
      if (!audienceId)
          return '';

      var grAudience = new GlideRecord('sn_cd_audience');

      return grAudience.get(audienceId) ?
          grAudience.getValue('audience_type') :
          '';
  },

  /* Add a user query to an encoded query
   * @param encodedQuery string Encoded query to modify
   * @param userColumn string Name of column to query user
   * @param userId string sys_id of a user record
   * @return string Encoded query with @param userId added in to limit condition to a specific user
   */
  _addUserToQuery: function(encodedQuery, userColumn, userId) {
      var conditions = encodedQuery.split("^NQ");
      for (var i = 0; i < conditions.length; i++)
          conditions[i] = userColumn + '=' + userId + "^" + conditions[i];
      return conditions.join("^NQ");
  },

  /** Return the count and url for an audience
   * @param audienceType string The type of audience
   * @param audienceQuery string The query for an audience: sys_id or encoded query
   * @param audienceSysId string The sys_id for the audience (only used with uploads)
   * @return object {count: number, url: string}
   */
  getAudienceCount: function(audienceType, audienceQuery, audienceSysId) {
      var gaAudience = this._createAudienceGA(audienceType, audienceQuery, audienceSysId);
      var result = {
      	url: this._getAudienceUrl(gaAudience)
      };
  	if (audienceType == "sn_hr_core_criteria" && this.hrPluginActive) {
  		result.count = new sn_hr_core.hr_Criteria().getUserCountForHRCriteria(audienceQuery);
  	} else {
  		result.count = this._getAudienceCount(gaAudience);
  	}
      return result;
  },

  /** Return ONLY the url for an audience
   * @param audienceType string The type of audience
   * @param audienceQuery string The query for an audience: sys_id or encoded query
   * @param audienceSysId string The sys_id for the audience (only used with uploads)
   * @return object {url: string}
   */
  getAudienceUrl: function(audienceType, audienceQuery, audienceSysId) {
      var gaAudience = this._createAudienceGA(audienceType, audienceQuery, audienceSysId);
      return {
          url: this._getAudienceUrl(gaAudience)
      };
  },

  /** Get query describing users matching hr criteria
   * @param hrCriteriaIds string Comma separated string of hr criteria sys_id's
   * @return string Encoded query describing users matching hr criteria
   */
  getHrCriteriaQuery: function(hrCriteriaIds) {
      // Ensure @param hrCriteriaIds is string of comma separated sys_id's
      if (!this.hrPluginActive || !hrCriteriaIds || !hrCriteriaIds.match(/^[a-f\d]{32}(?:,[a-f\d]{32})*$/))
          return this.NULL_QUERY;
      return "sys_idINjavascript:new sn_cd.cd_AudienceAJAX().getUsersForHrCriteria('" + hrCriteriaIds + "')";
  },

  /** Get query describing users matching a user criteria
   * @param userCriteriaId string User criteria sys_id
   * @param userId string (optional) sys_id of user to limit query to
   * @return string Encoded query describing users matching a user_criteria
   */
  getUserCriteriaQuery: function(userCriteriaId, userId) {
      var grUserCriteria = new GlideRecord("user_criteria");
      grUserCriteria.addActiveQuery();
      grUserCriteria.addQuery("sys_id", userCriteriaId);
      grUserCriteria.addQuery("advanced", false);
      grUserCriteria.query();
      if (!userCriteriaId || !grUserCriteria.next())
          return this.NULL_QUERY;

      var criteriaConditions = [];

      // Simple reference fields on user_criteria
      var criteriaFieldMap = this._getUserCriteriaFieldMap();
      for (var key in criteriaFieldMap)
          if (grUserCriteria.getValue(key))
              criteriaConditions.push(criteriaFieldMap[key] + "IN" + grUserCriteria.getValue(key));

      // 'role' field on user_criteria
      if (grUserCriteria.getValue("role")) {
          var roles = grUserCriteria.getValue("role").split(",");
          for (var j = 0; j < roles.length; j++)
              roles[j] = "roles=" + roles[j];
          criteriaConditions.push(roles.join("^OR"));
      }

      // 'group' field on user_criteria
      if (grUserCriteria.getValue("group")) {
          var users = [];
          var gaGrMember = new GlideAggregate("sys_user_grmember");
          gaGrMember.addQuery("group", "IN", grUserCriteria.getValue("group"));
          if (userId)
              gaGrMember.addQuery("user", userId);
          gaGrMember.groupBy("user");
          gaGrMember.query();
          while (gaGrMember.next())
              users.push(gaGrMember.getValue("user"));

          if (!users.length)
              criteriaConditions.push(this.NULL_QUERY);
          else
              criteriaConditions.push("sys_idIN" + users.join(","));
      }

      return (userId ? ("sys_id=" + userId + "^") : '') + criteriaConditions.join(grUserCriteria.match_all ? "^" : "^OR");
  },

  /**
   * Returns a map of user criteria columns to their corresponding sys_user column
   **/
  _getUserCriteriaFieldMap: function() {
      var criteriaFieldMap = {};
      var userFields = {};
      var _this = this;
      new GlideRecord('sys_user').getElements().forEach(function(item) {
          userFields[item.getName()] = true;
      });
      new GlideRecord('user_criteria').getElements().forEach(function(item) {
          var colName = item.getName();
          if (!colName || _this.blockCriteriaFieldList.hasOwnProperty(colName) || colName.startsWith('sys_'))
              return;
          colName = colName.toLowerCase();
          if (colName === 'user')
              criteriaFieldMap[colName] = 'sys_id';
          else if (colName === 'group' || colName === 'role')
              return; // These fields are specially handled elsewhere
          if (userFields.hasOwnProperty(colName))
              criteriaFieldMap[colName] = colName;
          else if (colName.startsWith('u_')) {
              if (userFields.hasOwnProperty(colName.substring(2)))
                  criteriaFieldMap[colName] = colName.substring(2);
          } else if (userFields.hasOwnProperty('u_' + colName))
              criteriaFieldMap[colName] = 'u_' + colName;
      });
      return criteriaFieldMap;
  },

  /** Create audience data based on search terms and update tracker (used by upload_file in audience directive)
   * @param firstHeader string Column used to search for users (limited to 'user_name' and 'email')
   * @param searchList string Comma separated list of search terms (e.g 'abel.tuter,abraham.lincoln')
   * @param audienceSysId string sys id of sn_cd_audience table
   */
  uploadOperation: function(firstHeader, searchList, audienceSysId) {
      var tracker = GlideExecutionTracker.getLastRunning();
      tracker.run();
      if (searchList.length != 0)
          searchList = searchList.split(",");
      else
          searchList = [];

      var identifierMap = {};
      var usersFound = 0;
      var usersNotFound = 0;
      var processId = tracker.getSysID();
      var totalRows = searchList.length;
      var totalPercent = 0;
      var percentPerRow = 100 / totalRows;

      // remove audience from old records
      var grAudienceData = new GlideRecord('sn_cd_audience_data');
      grAudienceData.addQuery("audience", audienceSysId);
      grAudienceData.setValue("audience", "");
      grAudienceData.updateMultiple();

      // Import uploaded data to bulk case data table
      if (firstHeader == "user_name" || firstHeader == "email") {
          for (var i = 0; i < totalRows; i++) {
              // Increment percent complete
              var percentComplete = (i + 1) * percentPerRow;
              var percentIncrease = percentComplete - totalPercent;
              if (percentIncrease >= 1) {
                  var percentIncreaseFloor = Math.floor(percentIncrease);
                  totalPercent += percentIncreaseFloor;
                  tracker.incrementPercentComplete(percentIncreaseFloor);
              }

              // Skip duplicates
              if (identifierMap.hasOwnProperty(searchList[i]))
                  continue;

              // Create audience data record and increment userFound/usersNotFound
              grAudienceData = new GlideRecord("sn_cd_audience_data");
              grAudienceData.setValue("process_id", processId);
              grAudienceData.setValue("identifier", searchList[i]);
              grAudienceData.setValue("audience", audienceSysId);
              var sysUserGR = new GlideRecord("sys_user");
              if (sysUserGR.get(firstHeader, searchList[i])) {
                  grAudienceData.setValue("user", sysUserGR.getUniqueValue());
                  if (!identifierMap[searchList[i]]) // Only count users that were not already found
                      usersFound++;
                  identifierMap[searchList[i]] = true;
              } else {
                  usersNotFound++;
                  identifierMap[searchList[i]] = false;
              }

              grAudienceData.insert();
          }
      }

      tracker.updateResult({
          recordCount: totalRows,
          processId: processId,
          usersFound: usersFound,
          usersNotFound: usersNotFound
      });
  },

  _createAudienceGA: function(audienceType, audienceQuery, audienceSysId) {
      var gaAudience;
      if (audienceType == "upload_file") {
          gaAudience = new GlideAggregate("sn_cd_audience_data");
          gaAudience.addQuery("audience", audienceSysId);
          gaAudience.addNotNullQuery("user");

      } else if (audienceType == "sn_hr_core_criteria" && this.hrPluginActive) {
          gaAudience = new GlideAggregate("sys_user");
          gaAudience.addEncodedQuery(this.getHrCriteriaQuery(audienceQuery));

      } else if (audienceType == "user_criteria") {
          gaAudience = new GlideAggregate("sys_user");
          gaAudience.addEncodedQuery(this.getUserCriteriaQuery(audienceQuery));

      } else if (audienceType == "sn_hr_core_profile" && this.hrPluginActive) {
          gaAudience = new GlideAggregate("sn_hr_core_profile");
          gaAudience.addEncodedQuery(audienceQuery);

      } else if (audienceType == "sys_user") {
          gaAudience = new GlideAggregate("sys_user");
          gaAudience.addEncodedQuery(audienceQuery);

      } else
          return null;

      // Can return null to signal to users of the internal function that they cannot use the GA
      // which can only happen if we have an unsupported combination of type, query and sys_id.
      // The function that use this are only _getAudienceCount and _getAudienceUrl which return -1
      // and "" respectively when there is a null gaAudience object given to them
      return gaAudience;
  },

  _getAudienceCount: function(gaAudience) {
      if (gaAudience === null)
          return -1;
      gaAudience.addAggregate("COUNT");
      gaAudience.query();
      if (gaAudience.next())
          return gaAudience.getAggregate("COUNT");
      else
          return -1;
  },

  _getAudienceUrl: function(gaAudience) {
      if (gaAudience === null)
          return "";
  var resultUrl = "/" + gaAudience.getTableName() + "_list.do?v=1&sysparm_query=" + gaAudience.getEncodedQuery() + "&sysparm_preview=true&sysparm_view=audience";
  return resultUrl.trim();
  },

  type: 'cd_Audience'
};

Sys ID

102630a6eb230300a9e7e26ac106fe4f

Offical Documentation

Official Docs: