Catalog client script not working for ess users

Brendan Hallida
Kilo Guru

Hi friends,

I have an onChange catalog client script which auto populates Login Name, Title, Location, Department when a user is chosen (from sys_user)

function onChange(control, oldValue, newValue, isLoading) {

userObject = g_form.getReference('mavis_access_employee_name',setUserInfo);

}

function setUserInfo(userObject){

g_form.setValue('mavis_access_employee_login_name', userObject.user_name);

g_form.setValue('mavis_access_users_title', userObject.title);

g_form.setValue('mavis_access_please_select_office_locati', userObject.location);

g_form.setValue('mavis_access_please_select_department', userObject.department);

}

Now this script runs fine when running as an admin or as an ITIL user, however nothing populates when an ess user attempts to run it.

Now I found the below thread when searching for an answer, and they suggest creating a read only ACL rule on the sys_user table for all users, and this does work, however this creates a problem for us.

https://community.servicenow.com/thread/234140?q=Client%20catalog%20script%20not%20working%20for%20e...

With the ACL read only rule enabled, when a user clicks on the i (as shown below) they now have access to see other users details, which is a no no for our company

find_real_file.png

I also found another thread which had the same solution, and goranlundqvist suggested that the script should be using a GlideAjax call, and I am not sure that I am?   I am still very new to JavaScript, and was able to work this code out from others that I found and I sort of understand it.

https://community.servicenow.com/thread/234179?q=Client%20catalog%20script%20not%20working%20for%20e...

I really curious how to are fetching that. How does your client scripts look like? If it is with a GlideAjax call, which I hope it is, then it shouldn't be a ACL problem.

//Göran

Does anyone have any suggestions?

Thanks in Advance,

Brendan

1 ACCEPTED SOLUTION

Geoffrey2
ServiceNow Employee
ServiceNow Employee

Yes, you should definitely learn how to use GlideAjax.


GlideAjax - ServiceNow Wiki


Client Script Best Practices - ServiceNow Wiki



The Client Script would look something like this:


var ga = new GlideAjax('UserUtils');


ga.addParam('sysparm_name', 'getUserDetails');


ga.addParam('sysparm_user_id', g_form.getValue('mavis_access_employee_name'));


ga.getXMLAnswer(function(answer) {


      console.log('answer: ' + answer);


      if (!answer)


              return;


      try {


              var userObject = JSON.parse(answer);


              g_form.setValue('mavis_access_employee_login_name', userObject.user_name);


            g_form.setValue('mavis_access_users_title', userObject.title);


              g_form.setValue('mavis_access_please_select_office_locati', userObject.location.sys_id, userObject.location.name);


              g_form.setValue('mavis_access_please_select_department', userObject.department.sys_id, userObject.department.name);


      } catch (err) {


              console.log(err);


      }


});



This is calling a Script Includes that would look something like this:


Assume the Script Include is named UserUtils and is Client Callable


var UserUtils = Class.create();


UserUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {



    getUserDetails:function() {


          var sys_id = this.getParameter('sysparm_user_id');



          var user = new GlideRecord('sys_user');


          if (user.get(sys_id)) {


                  var userObject = {


                          "user_name": String(user.user_name),


                          "title": String(user.title),


                          "location": {


                                  "sys_id": String(user.location),


                                  "name": String(user.location.getDisplayValue())


                            },


                            "department": {


                                    "sys_id": String(user.department),


                                    "name": String(user.department.getDisplayValue())


                            }


                  };


                  return JSON.stringify(userObject);


          }


          return false;


  },



  type: 'UserUtils'


});



I'm assuming that the location and department fields are Reference fields, so I'm returning the sys_id and display values. Then you use


g_form.setValue('reference_field_name', 'sys_id', 'display_value');


This prevents a synchronous AJAX call from looking up the display value if you only pass it the sys_id.



There are many ways to pass back data from a Script Includes. I personally prefer using JSON.   You can of course use any other method you choose.


You may need to learn about JavaScript Objects: JavaScript Objects, and JSON: JSON Tutorial



For the User record ACL, try copying the script from the default Write ACL into the Read ACL:


answer = gs.getUserID() == current.sys_id || gs.getUser().hasRoles();


View solution in original post

8 REPLIES 8

Abhinay Erra
Giga Sage

Brendan,



  You will have to use GlideAjax for this and fetch the user values, since the GlideRecord queries does not obey ACL's.


Your onChange client script on the employee name variable


function onChange(control, oldValue, newValue, isLoading) {


  var ga = new GlideAjax('UserDetailsAjax');


  ga.addParam('sysparm_name','getUserDetails');


  ga.addParam('sysparm_user_id',newValue);


  ga.getXML(CallBack);


  function CallBack(response) {


  var answer = response.responseXML.documentElement.getAttribute("answer");


  answer = answer.evalJSON();


  g_form.setValue('mavis_access_employee_login_name', answer.user_name);


  g_form.setValue('mavis_access_users_title', answer.title);


  g_form.setValue('mavis_access_please_select_office_locati', answer.location);


  g_form.setValue('mavis_access_please_select_department', answer.department);


  }


}




Script include:


Name:UserDetailsAjax


Client callable: true


Script:


var UserDetailsAjax = Class.create();


UserDetailsAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {


  getUserDetails: function(){


  var obj = {};


  var gr= new GlideRecord('sys_user');


  gr.get(this.getParameter('sysparm_user_id'));


  obj.user_name = gr.getValue('user_name');


  obj.title= gr.getValue('title');


  obj.department= gr.getValue('department');


  obj.location=gr.getValue('location');


  var json = new JSON();


  var data = json.encode(obj);//JSON formatted string


  return data;


  },


  type: 'UserDetailsAjax'


});


Geoffrey2
ServiceNow Employee
ServiceNow Employee

Yes, you should definitely learn how to use GlideAjax.


GlideAjax - ServiceNow Wiki


Client Script Best Practices - ServiceNow Wiki



The Client Script would look something like this:


var ga = new GlideAjax('UserUtils');


ga.addParam('sysparm_name', 'getUserDetails');


ga.addParam('sysparm_user_id', g_form.getValue('mavis_access_employee_name'));


ga.getXMLAnswer(function(answer) {


      console.log('answer: ' + answer);


      if (!answer)


              return;


      try {


              var userObject = JSON.parse(answer);


              g_form.setValue('mavis_access_employee_login_name', userObject.user_name);


            g_form.setValue('mavis_access_users_title', userObject.title);


              g_form.setValue('mavis_access_please_select_office_locati', userObject.location.sys_id, userObject.location.name);


              g_form.setValue('mavis_access_please_select_department', userObject.department.sys_id, userObject.department.name);


      } catch (err) {


              console.log(err);


      }


});



This is calling a Script Includes that would look something like this:


Assume the Script Include is named UserUtils and is Client Callable


var UserUtils = Class.create();


UserUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {



    getUserDetails:function() {


          var sys_id = this.getParameter('sysparm_user_id');



          var user = new GlideRecord('sys_user');


          if (user.get(sys_id)) {


                  var userObject = {


                          "user_name": String(user.user_name),


                          "title": String(user.title),


                          "location": {


                                  "sys_id": String(user.location),


                                  "name": String(user.location.getDisplayValue())


                            },


                            "department": {


                                    "sys_id": String(user.department),


                                    "name": String(user.department.getDisplayValue())


                            }


                  };


                  return JSON.stringify(userObject);


          }


          return false;


  },



  type: 'UserUtils'


});



I'm assuming that the location and department fields are Reference fields, so I'm returning the sys_id and display values. Then you use


g_form.setValue('reference_field_name', 'sys_id', 'display_value');


This prevents a synchronous AJAX call from looking up the display value if you only pass it the sys_id.



There are many ways to pass back data from a Script Includes. I personally prefer using JSON.   You can of course use any other method you choose.


You may need to learn about JavaScript Objects: JavaScript Objects, and JSON: JSON Tutorial



For the User record ACL, try copying the script from the default Write ACL into the Read ACL:


answer = gs.getUserID() == current.sys_id || gs.getUser().hasRoles();


Abhinay Erra
Giga Sage

Forgot to mention, my code was assuming all the variables and their corresponding fields on the user table are of same type


Brendan Hallida
Kilo Guru

wow guys, really good info in this thread.



I have tested Geoff's code, and it works a treat.   I didn't even know that script includes existed.



This works on both the ESS side, and the service portal side.