March 21, 2014

Dynamics CRM 2013: Disable specific fields based on a user’s role

Filed under: Tips — Tags: , — Webopius @ 10:24 am

Out of the box, Microsoft Dynamics CRM 2011 and 2013 don’t appear to support field level security for out of the box fields. Often, there are situations where a specific user’s role needs overall read/write access to an entity but one or more fields on the form needs to be disabled for that user.

Using the excellent solution for determining if a user belongs to a specific role from Mitch Malam’s article here, and adding in a small amount of additional script, it is possible to support field level security for out of the box fields within CRM 2013.

Using the example JScript below, add the cust_check_role() call to the entity form’s OnLoad event

You can of course modify this approach to suit your specific form requirements.

// Disable specific fields based on the user's role
function cust_check_role()
{
   // As an Example. If this is a helpdesk user, disable the telephone field
   // Add more roles and fields if you like
   var is_helpdesk = cust_user_has_role("Helpdesk");  
   if (is_helpdesk) {
     cust_disable_field("telephone"); 
   }
}

// Disable field 'Fieldname' and give it a pink background.
function cust_disable_field(fieldname)
{
       document.getElementById(fieldname + "_c").style.backgroundColor = "#FCBABA";
       document.getElementById(fieldname + "_d").style.backgroundColor = "#FCBABA";
       Xrm.Page.getControl(fieldname).setDisabled(true);
}

// Code below returns True if the user belongs to a specific named role.
// Slightly modified from the original at 
// https://community.dynamics.com/crm/b/crmmitchmilam/archive/2010/11/16/retreiving-user-roles-in-crm-2011.aspx
function cust_user_has_role(roleName)
{
    var serverUrl = Xrm.Page.context.getServerUrl();

    var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";
    oDataEndpointUrl += "RoleSet?$top=1&$filter=Name eq '" + roleName + "'";
    var service = cust_GetRequestObject();

    if (service != null)
    {
        service.open("GET", oDataEndpointUrl, false);
        service.setRequestHeader("X-Requested-Width", "XMLHttpRequest");
        service.setRequestHeader("Accept", "application/json, text/javascript, */*");
        service.send(null);

       var requestResults = JSON.parse(service.responseText).d;

        if (requestResults != null)
        {
            var role = requestResults.results[0]; 

            var id = role.RoleId;
            var currentUserRoles = Xrm.Page.context.getUserRoles();

            for (var i = 0; i < currentUserRoles.length; i++)
            {
                var userRole = currentUserRoles[i];

                if (cust_GuidsAreEqual(userRole, id))
                {
                    return true;
                }
            }
        }
    }
    return false;
}

function cust_GetRequestObject()
{
    if (window.XMLHttpRequest)
    {
        return new window.XMLHttpRequest;
    }
    else
    {
        try
        {
            return new ActiveXObject("MSXML2.XMLHTTP.3.0");
        }
        catch (ex)
        {
            return null;
        }
    }
}

function cust_GuidsAreEqual(guid1, guid2)
{
    var isEqual = false;
    if (guid1 == null || guid2 == null)
    {
        isEqual = false;
    }
    else
    {
        isEqual = guid1.replace(/[{}]/g, "").toLowerCase() == guid2.replace(/[{}]/g, "").toLowerCase();
    }
    return isEqual;
}

This does beg the question though that if Microsoft can provide a Xrm.Page.context.getUserRoles() function to get a list of roles for this user, why can’t they provide a similar function to get all available system roles matching a specific name instead of having to call the CRM Web Service.

If you need any Dynamics CRM 2013 project work or custom development, contact Webopius for a no-obligation quote.

  • Tags