Finally there: Show and hide fields based on the users role!

Hi all,

I've been posting around showing and hiding fields more often. I won't be talking about that now, instead I'll be discussing the ability to perform JavaScript coding based on the users role.

This solution is very neat and very clean, though unsupported!!! Now... Let's get started and dig into this.

MS CRM has a lot of Javascript codes delivered with the product. One of these codes is located here: "/_controls/RemoteCommands/RemoteCommand.js". This file is being included into every page. One of the functions in this file is RemoteCommand(sObject, sCommand, sUrlBase). You can use this function to connect to CRM webservices.

Via Javascript you can get the userid of the currently logged in user via this RemoteCommand. This is done using this code:


var command = new RemoteCommand("SystemUser", "WhoAmI", "/MSCRMServices/");
var oResult = command.Execute();


Another webservice which is interesting is the UserManager webservice. By using this function, you can get all roles of the system. The roles to which the user is assigned are marked with "checked='true'". Here's the code to get this list


var command = new RemoteCommand("UserManager", "GetUserRoles");
command.SetParameter("userIds", "<guid>" + userId + "</guid>");
var oResult = command.Execute();


Now if we add this functionality to functions and add some try catches, then you'll end up with this code:


function getUserId()
{
try
{
var command = new RemoteCommand("SystemUser", "WhoAmI", "/MSCRMServices/");
var oResult = command.Execute();

if (oResult.Success)
{
return oResult.ReturnValue.UserId;
}
}
catch(e)
{
alert("Error while retrieving userid.");
}
return null;
}

function getUserRoles(userId)
{
try
{
var command = new RemoteCommand("UserManager", "GetUserRoles");
command.SetParameter("userIds", "<guid>" + userId + "</guid>");

var oResult = command.Execute();

if (oResult.Success)
{
return oResult.ReturnValue;
}
}
catch(e)
{
alert("Error while retrieving roles.");
}
return null;
}


Now we only have to add functions which checks if the user has a specific role. The final code is:


function getUserId()
{
try
{
var command = new RemoteCommand("SystemUser", "WhoAmI", "/MSCRMServices/");
var oResult = command.Execute();

if (oResult.Success)
{
return oResult.ReturnValue.UserId;
}
}
catch(e)
{
alert("Error while retrieving userid.");
}
return null;
}

function getUserRoles(userId)
{
try
{
var command = new RemoteCommand("UserManager", "GetUserRoles");
command.SetParameter("userIds", "<guid>" + userId + "</guid>");

var oResult = command.Execute();

if (oResult.Success)
{
return oResult.ReturnValue;
}
}
catch(e)
{
alert("Error while retrieving roles.");
}
return null;
}

function userHasRole(userId, roleName)
{
result = getUserRoles(userId);
if (result != null)
{
var oXml = new ActiveXObject("Microsoft.XMLDOM");
oXml.resolveExternals = false;
oXml.async = false;
oXml.loadXML(result);

roleNode = oXml.selectSingleNode("/roles/role[name='" + roleName + "']");
if (roleNode != null)
{
if (roleNode.selectSingleNode("roleid[@checked='true']") != null)
return true;
}
}

return false;
}

function currentUserHasRole(roleName)
{
userId = getUserId();
return userHasRole(userId, roleName);
}


Now you can check for roles by using the code listed down here:

if(currentUserHasRole('Salesperson')){
alert('true');
}else{
alert('false');
}


You can copy and paste the functions as well as the last code in the form onload event. This is not really user friendly / readable though. If you copy and paste the functions to the global.js script instead, then you can use the last code snippet in the form onload.

Now. To get back to the subject "show and hide fields based on the users role"... If you modify the last code snippet to contain the showing and hiding fields as discussed in this article, instead of alert('true') and alert('false'), then you've got a very good customized system.

Thanks go out to Steven Brom (Qurius Advanced Solutions - NL) for supplying the codes!

Update 1: Thanks to Josh Painter who pointed me to the fact that I forgot to replace the < sign with <> in the codes.

Update 2: I mentioned that this solution was supported, but since we're using webservices from MS CRM other then the regular webservice, this is unsupported anyway... But still it's cool ;)

Update 3: This code doens't work on the outlook client. I'm still thinking about a solution to that.

Update 4: The code above is created for CRM 3.0. For CRM 4.0 look at the following blogs:
http://www.crowehorwath.com/cs/blogs/crm/archive/2008/05/08/hide-show-fields-in-crm-4-0-based-on-security-role.aspx
http://jianwang.blogspot.com/2008/01/crm-40-check-current-users-security.html