dvp
Mega Sage
Mega Sage

User criteria is one of the wonderful features SN provided, but it is opened to only a set of tables.  It is a handy configuration to grant access to the record against user information like companies, roles, groups.

Recently there was a requirement where we need to grant read access to records dynamically. After a little research, I found out that there are similar needs by many developers. Below are some of scenarios that I came across

  • Catalogs
  • News
  • Announcements(Fixed in London)

Here is what I had implemented

1. Create a m2m relation between User Criteria and desired table (u_news). Navigate to sys_m2m.LIST and submit the details as shown in the screenshot

2. Add the user criteria related list to News form by Configure > Related Lists

3. Create a script include

Name: UserCriteria

Client callable: False

Script

var UserCriteria = Class.create();
UserCriteria.prototype = {
	initialize: function() {
	},
	
	
	canAccess: function(table, record, id){
		
		//Get all the user criteria's for the seleted record
		var usr_crit = new GlideRecord(table);
		usr_crit.addQuery(record, id);
		usr_crit.query();
		
		// Grant access to record If there are no user criteria's for the record
		if(usr_crit.getRowCount() == 0)
			return true;
		
		while (usr_crit.next()) {
			
			var crit = new GlideRecord('user_criteria');
			crit.addQuery('sys_id', usr_crit.u_user_criteria);
			crit.addActiveQuery();
			crit.query();
			
			while(crit.next()){
				
				//Get company, location and department information of the current user. 
				var gr = new GlideRecord('sys_user');
				gr.addQuery('sys_id', gs.getUserID());
				gr.query();
				
				var company, location, department = '';
				
				if(gr.next()){
					
					company = gr.company;
					location = gr.location;
					department = gr.department;
				}
				
				var groups = [];
				groups = crit.group.toString();
				
				var evaluator = new GlideScopedEvaluator();
				
				var match_arr = [];
				
				// Check if the current user is one of the users in user criteria
				if(crit.user != ''){
					
					if(crit.user.indexOf(gs.getUserID()) > -1)
						match_arr.push(true);
					else
						match_arr.push(false);
				}
				
				// Check if the Groups of a user belong to is one of groups in user criteria
				if(crit.group!= ''){
					match_arr.push(this._isMyGroup(groups));
				}
				
				
				// Check if logged in user roles is one of roles in user criteria
				if(crit.role != ''){
					match_arr.push(gs.hasRole(crit.role.getDisplayValue()));
				}
				
				// Check if the logged in user company is one of companies in user criteria
				if(crit.company != '' && company != ''){
					
					if(crit.company.indexOf(company) > -1)
						match_arr.push(true);
					else
						match_arr.push(false);
				}
				
				// Check if the logged in user location is one of locations in user criteria
				if(crit.location != '' && location != ''){
					if(crit.location.indexOf(location) > -1)
						match_arr.push(true);
					else
						match_arr.push(false);
				}
				
				// Check if the logged in user department is one of departments in user criteria
				if(crit.department != '' && department != ''){
					if(crit.department.indexOf(department) > -1)
						match_arr.push(true);
					else
						match_arr.push(false);
				}
				
				//execute the script in user criteria
				if(crit.advanced == true){
					match_arr.push(evaluator.evaluateScript(crit, 'script', ''));
				}
				
				
				var matched;
				
				//If Match all, in user criteria is marked false, then any one of fields match is enough
				if(crit.match_all == false){
					
					if(match_arr.indexOf(true) > -1)
						matched = true;
					else
						matched = false;
				}
				
				// If Match all is marked true then all of the values should be true
				else{
					if(match_arr.every(this._isValueTrue) == true)
						matched = true;
					else
						matched = false;
				}

				// Matching one of the user criteria should return the value. No need to execute the rest of the user criteria
				if(matched == true){
					return true;
				}
				
			}
		}
		// If none of the user criteria matches then return false
		return false;
		
	},
	
	_isMyGroup: function(groupIDs){
		
		var groups_arr = groupIDs.split(',');
		
		for(i=0; i<groups_arr.length; i++){
			if(gs.getUser().isMemberOf(groups_arr[i]))
				return true;
		}
		return false;
	},
	
	// Function to verify if all the values in an array are true
	_isValueTrue: function (currentValue) {
		return currentValue == true;
	},
	
	type: 'UserCriteria'
};

4. Create a read acl to restrict read access to the record and use the below script

answer = new UserCriteria().canAccess('u_m2m_news_user_criteria', 'u_news', current.sys_id);

/* canAccess menthod accepts the following input paramenters
table: M2M table name
record: Field name of News reference field on M2M table
id: sys_id of news record
*/

5. Use GlideRecordSecure for reference qualifers and glide queries, as GlideRecordSecure enforce read ACL rules.

 

Hope this helps!!

7 Comments