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