var CWTKnowledgeUtil = Class.create();
/**
* Class to help with manipulation and information retrieval from Knowledge base records and their related classes, such as Categories and Articles.
*
* Example Uses:
* + var owner = CWTKnowledgeUtil.negotiateCategoryOwnership("35669ac2dbe9bb008408d12c5e961941", gs.getProperty("knowledge_base.managers_group"));
*
* @class CWTKnowledgeUtil
* @constructor
* @module ScriptIncludes
* @author Alexander Anderson (cwt_alexander)
* @see https://scottsdev.service-now.com/sys_script_include.do?sys_id=500d0b44db96b3405cacd7795e9619db
* @param {GlideRecord} knowledge_base
*/
(function() {
/**
* Ordered array indicating the order in which to try to set a field to indicate who should
* be considered the owner of a record.
* @property userFields
* @type Array
*/
var userFields = [
"caller_id",
"opened_by",
"requested_for"
];
/**
* Ordered array indicating the order in which to try to set a field to indicate what group
* is assigned to a record or task
* @property groupFields
* @type Array
*/
var groupFields = [
"assignment_group"
];
/**
* Ordered array indicating the order in which to try to set a field to indicate the summary or
* short description of a record or task.
* @property summaryFields
* @type Array
*/
var summaryFields = [
"short_description",
"title",
"summary",
"label",
"name"
];
/**
* Ordered array indicating the order in which to try to set a field to indicate details for
* a record or task.
* @property descriptionFields
* @type Array
*/
var descriptionFields = [
"description"
];
/**
* Determine if a value should be considered true.
*
* Due to a variety of ways of true/false values being returned by service now, this
* method exists to level set to a JavaScript boolean value for use.
* @method isFalse
* @param {Object | String | Boolean | Number} value
* @return {Boolean} True if the value is considered as trying to be "true", false otherwise.
*/
var isTrue = CWTKnowledgeUtil.isTrue = function(value) {
return value == "1" || value == "true" || value === "t" || value === true;
};
/**
* Determine if a value should be considered false.
*
* Due to a variety of ways of true/false values being returned by service now, this
* method exists to level set to a JavaScript boolean value for use.
* @method isFalse
* @param {Object | String | Boolean | Number} value
* @return {Boolean} True if the value is considered as trying to be "false", false otherwise.
*/
var isFalse = CWTKnowledgeUtil.isFalse = function(value) {
return value == "0" || value == "false" || value === "f" || value === false;
};
CWTKnowledgeUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {
"type": "CWTKnowledgeUtil",
/**
* Reference to the knowledge base record being used.
* @property knowledge_base
* @type GlideRecord
*/
"initialize": function(kb_knowledge_base) {
this.kb = kb_knowledge_base;
}
});
/**
* Used by negotiateCategoryOwnership to perform the recursive lookup.
* @method recurseCategoryOwner
* @private
* @param {GlideRecord} category The category to traverse looking for an active owner
* @param {String} [table] Optional string to specify the table against which the field value
* is defined. Defaults to "sys_user".
* @param {String} [field] Optional string to specify the category value being searched for with
* an active flag. Defaults to "u_owning user.
* @param {String} [field] To handle the transition from "Category" to "Knowledge Base" where field
* names differ for the same class & meaning of property, this serves to indicate the field
* on the kb_knowledge_base table that should be pulled from the knowledge base when reached,
* if any. Defaults to "owner".
* @return {GlideRecord} The user record or null.
*/
var recurseCategoryOwner = function(category, table, field, kb_field) {
field = field || "u_owning_user"; // This is redunant but good for a protective fallback
var kb = new GlideRecord("kb_knowledge_base"),
buffer = new GlideRecord("kb_category"),
record = new GlideRecord(table);
if(record.get(category.getValue(field)) && isTrue(record.getValue("active"))) {
// Owning User exists and is active
return record;
} else {
// No owner or not active
if(buffer.get(category.getValue("parent_id"))) {
return recurseCategoryOwner(buffer, table, field, kb_field);
} else if(kb_field && kb.get(category.getValue("parent_id"))) {
if(record.get(kb.getValue(kb_field)) && isTrue(record.getValue("active"))) {
return record;
} else {
return null;
}
} else {
return null;
}
}
};
/**
* If the category has an owner and that owner is active, that owner is returned. If that
* owner is not active, the Category's parent is checked. This active/parent check continues
* until an active owner is found and returned, or null is returned for no active owner
* could be found.
*
* @method negotiateCategoryOwnership
* @static
* @param {GlideRecord | String} category The record or System ID of the Category to check.
* @param {GlideRecord | String} [notify] Indicates the group to notify, if any, when no owner
* can be determined. Uses the System Property "knowledge_base.notify_table" to determine
* what table the notification is created against.
* @param {String} [table] Optional string to specify the table against which the field value
* is defined. Defaults to "sys_user".
* @param {String} [field] Optional string to specify the category value being searched for with
* an active flag. Defaults to "u_owning user.
* @param {String} [field] To handle the transition from "Category" to "Knowledge Base" where field
* names differ for the same class & meaning of property, this serves to indicate the field
* on the kb_knowledge_base table that should be pulled from the knowledge base when reached,
* if any. Defaults to "owner".
* @return {GlideRecord} Referencing the first active owner found or null if one could not be
* determined or none exists.
*/
CWTKnowledgeUtil.negotiateCategoryOwnership = function(id, notify, table, field, kb_field) {
field = field || "u_owning_user";
table = table || "sys_user";
if(kb_field === undefined) {
kb_field = "owner";
}
var category = new GlideRecord("kb_category"),
buffer,
next,
x;
category.get(id);
if(!category.isValidField(field)) {
// The requested field does not exist in the category table
gs.warn("CWTKnowledgeUtil: The specified field for active flag chain check is not valid: " + field);
return null;
}
// Perform Search
buffer = recurseCategoryOwner(category, table, field, kb_field);
if(buffer === null && notify !== undefined && notify !== null) {
// This method attempts to arbitrarily fill the requested record type based on the fields present
// This is to allow easy configuration at the top level of what table to use
// Note: No need to determine assigned_to as the Knowledge Base has already been deemed inactively owned
gs.log("Notifying " + notify + " of indeterminate category owner from CWTKnowledgeUtil");
buffer = new GlideRecord(gs.getProperty("knowledge_base.notify_table"));
next = true; // More logically clear than using "break"
for(x=0; x<userFields.length && next; x++) {
if(buffer.isValidField(userFields[x])) {
buffer.setValue(userFields[x], gs.getUserID());
next = false;
}
}
next = true;
for(x=0; x<groupFields.length && next; x++) {
if(buffer.isValidField(groupFields[x])) {
buffer.setValue(groupFields[x], notify.toString());
next = false;
}
}
next = true;
for(x=0; x<summaryFields.length && next; x++) {
if(buffer.isValidField(summaryFields[x])) {
buffer.setValue(summaryFields[x], "Indeterminate owner for category \"" + category.getValue("label") + "\"");
next = false;
}
}
next = true;
for(x=0; x<descriptionFields.length && next; x++) {
if(buffer.isValidField(descriptionFields[x])) {
buffer.setValue(descriptionFields[x], "An active owner could not be found for the category \"" + category.getValue("label") + "\" (sys_id: " + category.getValue("sys_id") + ")");
next = false;
}
}
buffer.insert();
return null;
} else {
gs.debug("CWTKnowledgeUtil: Owner lookup finishing [" + (buffer == null) + "|" + (buffer === null) + "]");
return buffer;
}
};
})();