logo

NJP

Leveraging User Criteria in your custom applications

Import · Jun 03, 2024 · article

Home » Leveraging User Criteria in your custom applications

var user = gs.getUserId();
var uc_array = [“”, “”, “”];
var ret = sn_uc.UserCriteriaLoader.userMatches( user, uc_array);

The above is a great start as it gives you the base capability to evaluate a user’s inclusion in a set of UCs, but what we really want is a utility that wrappers the above to give us a generic way of evaluating users against UCs in the way that UCs tend to be applied to records.

The script include below gives us a reusable utility to do this in the two primary ways we found UCs to be applied to a record:

  • A glidelist directly on the record
  • A related list with references to the record and to UC’s

UserCriteriaLoader.userMatches() requires the user’s sys_user record sys_id and an array of UC record sys_ids. The ‘trick’ to the utility is converting either the glidelist or a list of related records into that array of UC record sys_ids. Let’s look at some specific examples of how to use each function.

//'UserCriteriaLoader.userMatches()' Sample Usage
var gr = new GlideRecord("my_custom_table"); //Table name of record for which are evaluating access
gr.get(""); //sys_id of record for which you are evaluating access
var user_can_read = new UserCriteria(gs.getUserID(), gr).evalUCGlideList("my_can_read", "my_cannot_read");
The above would return true/false depending on the user’s inclusion in the can/cannot read UCs. A couple of things to note:

  • The cannot read parameter on the function is optional. If not included it is assumed that the user is NOT part of any cannot read UCs.
  • If given a cannot read parameter, the function will take it into account by determining if the given user is part of the cannot read UC(s) and if they are returning false as the ‘answer’ as being included in any can read UCs would no longer matter for functionality to be consistent with the way OOB applications us UCs.
  • The above is somewhat contrived as one of the biggest use cases is where you’d already HAVE a glide record to work with as part of the platform (BRs & ACLs mainly).

Usage when the UCs are associated via a related list is a bit more complicated….but just because data model is a more complicated. The overall approach is the same in that we want to build an array of UCs for the can read and cannot read related lists and feed them to base function.

var gr = new GlideRecord("my_custom_table");
gr.get("");
var user_can_read = new UserCriteria(gs.getUserID(), gr).evalUCRelatedList("m2mCanTable", "canGrRefFieldName", "canUCRefFieldName", "m2mCannotTable", "cannotGrRefFieldName", "cannotUCRefFieldName");

//m2mCanTable: name of the table that contains the list of can read UCs related to the record in my_custom_table.
//canGrRefFieldName: reference to a record on my_custom_table.
//canUCRefFieldName: reference to a UC record
//m2mCannotTable: name of the table that contains the list of cannot read UCs related to the record in my_custom_table.
//cannotGrRefFieldName: reference to a record on my_custom_table
//cannotUCRefFieldName: reference to a UC record

Hopefully, this is helpful and gives the ServiceNow community an extra tool in their toolbox to solve their problems with the power of the ServiceNow platform!

NOTE:

  • UserCriteriaLoader is NOT documented on docs.servicenow.com or in developer.servicenow.com. However, if you search in OOB script includes you will see it being used. So a bit of ‘buyer beware’ but we believe it’s relatively safe to use….i.e. while not formally documented it seems unlikely that ServiceNow would deprecate the object/functions.
  • The script include given was factored for the use case/need we had at the time, it can certainly be reworked to fit your needs…but the building blocks are there for most use cases.

var UserCriteria = Class.create();
UserCriteria.prototype = {
/**
name: initialize
description: Initializes the UserCriteria object by setting the user sys_id and the GlideRecord.
param: {String} [userSysId] - sys_id of the user we want to check.
param: {GlideRecord} [grToCheck] - GlideRecord of the record we want to check against.
example:
var matches = new UserCriteria(userSysID, grToCheck)
returns: {UserCriteria} returns a initialized UserCriteria Object.
*/
initialize: function(userSysId, grToCheck) {
this.userSysId = userSysId;
this.grToCheck = grToCheck;
},

/**
name: evalUCGlideList
description: Takes the field names on the table/GlideRecord that are GlideList(s) pointing too User Criteria for "Can" & "Cannot".
param: {String} [ucCanField] - The field name of the GlideList for the "Can" User Criteria.
param: {String} [ucCannotField] - The field name of the GlideList for the "Cannot" User Criteria.
example:
var matches = new UserCriteria(userSysID, grToCheck).evalUCGlideList("<can_read_uc_glidelist_field>", "<cannot_read_uc_glidelist_field>");
returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
*/
evalUCGlideList: function(ucCanField, ucCannotField) {
    var ret = false;
    if (ucCannotField)
        ret = (!this._matchesUCListField(ucCannotField, false) && this._matchesUCListField(ucCanField, true));
    else
        ret = (this._matchesUCListField(ucCanField, true));

    return ret;

},

/**
name: evalUCRelatedList
description: Takes m2m tables for can and can't mappings, with ref field names of "connectors", that connects a record to User Criteria and returns true/false indicating a users access depending on related lists.
param: {String} [m2mCanTable] - Name of the m2m table connecting the record with User Criteria 'can' access.
param: {String} [canGrRefFieldName] - Name of the field on the m2m table that points to the GlideRecord (can access).
param: {String} [canUCRefFieldName] - Name of the field on the m2m table that points to the User Criteria (can access).
param: {String} [m2mCannotTable] - Name of the m2m table connecting the record with User Criteria for can't access
param: {String} [cannotGrRefFieldName] - Name of the field on the m2m table that points to the GlideRecord (can't access).
param: {String} [cannotUCRefFieldName] - Name of the field on the m2m table that points to the User Criteria (can't access).
example:
var matches = new UserCriteria(userSysID, grToCheck).evalUCRelatedList(m2mCanTable, canGrRefFieldName, canUCRefFieldName, m2mCannotTable, cannotGrRefFieldName, cannotUCRefFieldName)
returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
*/
evalUCRelatedList: function(m2mCanTable, canGrRefFieldName, canUCRefFieldName, m2mCannotTable, cannotGrRefFieldName, cannotUCRefFieldName) {

    var ret = false;
    if (m2mCannotTable)
        ret = (!this._matchesUCListTable(m2mCannotTable, cannotGrRefFieldName, cannotUCRefFieldName, false) && this._matchesUCListTable(m2mCanTable, canGrRefFieldName, canUCRefFieldName, true));
    else
        ret = this._matchesUCListTable(m2mCanTable, canGrRefFieldName, canUCRefFieldName, true);
    return ret;

},

/**
name: _matchesUCListField
description: Takes the field name on the table/GlideRecord that is a GlideList pointing too User Criteria.
param: {String} [ucField] - The field name of the GlideList for the User Criteria.
param: {boolean} [emptyListReturn] - What to return in case the list of criteria is empty (false: for cannot read; true: for can read).

returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
*/
_matchesUCListField: function(ucField, emptyListReturn) {

    var ucArray = [];
    var ucFieldValue = this.grToCheck.getValue(ucField);
    if (ucFieldValue != null)
        ucArray = ucFieldValue.split(",");

    return (ucFieldValue && !gs.isLoggedIn()) ? !emptyListReturn : this._matchesUCList(ucArray, emptyListReturn);

},

/**
name: _matchesUCListTable
description: Takes a m2m table, with ref field names of "connectors", that connects a record to User Criteria and returns true/false indicating if the user is in any of the User Criteria.
param: {String} [m2mTable] - Name of the m2m table connecting the record with User Criteria
param: {String} [grRefFieldName] - Name of the field on the m2m table that points to the GlideRecord.
param: {String} [ucRefFieldName] - Name of the field on the m2m table that points to the User Criteria.
param: {boolean} [emptyListReturn] - What to return in case the list of criteria is empty.

returns: {boolean} Returns true if user passed in is part of any of the user criteria in the GlideList. 
*/
_matchesUCListTable: function(m2mTable, grRefFieldName, ucRefFieldName, emptyListReturn) {

    //var ret = false;
    var ucArray = this._glideQuerytoArray(m2mTable, grRefFieldName, ucRefFieldName);
    return (ucArray.length > 0 && !gs.isLoggedIn()) ? !emptyListReturn : this._matchesUCList(ucArray, emptyListReturn);

},


/**
name: individualUserCriteriaCheck
description: Used to check the includance of a user in a single User Criteria. 
param: {String} [uc] - Sys_id of a single User Criteria
example:
var matches = new UserCriteria(userSysID, grToCheck).individualUserCriteriaCheck("<uc_sys_id>")
returns: {boolean} Returns true if user passed in is part of any of the user criteria. 
*/
individualUserCriteriaCheck: function(uc) {

    var ucArrayofOne = [uc];
    return this._matchesUCList(ucArrayofOne, false);

},

/**
name: _matchesUCList
description: Makes call to OOB UserCriteriaLoader for evaluation of user/criteria and takes in to account empty user criteria.
param: {Array} [ucArray] - Array of relevent User Criteria sys_ids.
param: {boolean} [emptyListReturn] - what to return if User Criteria array is empty.

returns: {boolean} boolean if user is in User Criteria passed.
*/
_matchesUCList: function(ucArray, emptyListReturn) {

    var ret = false;
    if (this.isEmpty(ucArray))
        ret = emptyListReturn;
    else
        ret = sn_uc.UserCriteriaLoader.userMatches(this.userSysId, ucArray);
    return ret;

},

/**
name: isEmpty
description: Checks if the inpur array is empty or contains only inactive records.
param: {Array} [ucArray] - Array of relevent User Criteria sys_ids.
example:
this.isEmpty(ucArray)
returns: {boolean} True if array has no elements or if all associated records are inactive.
*/
isEmpty: function(ucArray) {
    if (ucArray.length == 0) {
        return true;
    }
    var ucGr = new GlideRecord("user_criteria");
    ucGr.addActiveQuery();
    ucGr.addQuery("sys_id", "IN", ucArray);
    ucGr.setLimit(1);
    ucGr.query();
    return !ucGr.hasNext();
},

/**
name: getAllUserCriteria
description: Given a user sys_id returns the list of User Criteria that user is part of.
example:
new UserCriteria(userSysID, grToCheck).getAllUserCriteria()
returns: {String} - List of User Criteria sys_id's that the user is part of.
*/
getAllUserCriteria: function() {

    return sn_uc.UserCriteriaLoader.getAllUserCriteria(this.userSysId);

},

/**
name: _glideQuerytoArray
description: An internal/hidden function used to look up the related User Criteria records and build them in to an array.
param: {String} [m2mTable] - Name of the m2m table connecting the record with User Criteria
param: {String} [grRefFieldName] - Name of the field on the m2m table that points to the GlideRecord.
param: {String} [ucRefFieldName] - Name of the field on the m2m table that points to the User Criteria.

returns: {Array} An array of User Criteria that are related to the record via the m2m table.
*/
_glideQuerytoArray: function(m2mTable, grRefFieldName, ucRefFieldName) {

    var ucArray = [];
    var grUC = new GlideRecord(m2mTable);
    grUC.addQuery(grRefFieldName, this.grToCheck.sys_id);
    grUC.query();
    while (grUC.next()) {
        ucArray.push(grUC.getValue(ucRefFieldName).toString());
    }

    return ucArray;
},

type: 'UserCriteria'

};

View original source

https://servicenowguru.com/scripting/leveraging-user-criteria-custom-applications/