30 September 2013

Build Your Own Custom Sharing Button

Judi Sohn gave me a great use case last Friday on twitter. While discussing the issue of whether to use only profiles or also use permission sets, the question of why a user has access to a record came up.

This is an interesting question because there is a sharing button on every record designed to provide this information. However, there are two shortcomings with using this button:

  1. The sharing button is disabled if org wide defaults are set to public read/write for an object
  2. It only tells you about sharing rows, not the object permissions contained in a user's profile or permission sets

As a result, it's possible to use this button to see which users have access to a record, only to find out that the user lacked the object permissions necessary to work with this record.

However, there is a workaround for these issues. You can create your own custom sharing button that will take both sharing and profile or permission set permissions into consideration, regardless of the sharing settings on the object.

For instance, we have a user, Doug Bitting. His profile grants him View Setup and Configuration permission and nothing else.

While on an account record, we can click on the sharing button to view which users have access to the record as long as accounts do not have their org wide default set to public read/write.

Viewing this sharing page tells us that our user, Doug Bitting, has access to the record even though he doesn't actually have the object permissions necessary to read the record.

By clicking on a custom button that I added called 'User Access', I can look up more information on what level of access a user like Doug actually has. This button launches a visualforce page with a custom apex controller in a new window.

In this case, when I look up Doug Bitting, I find out that he doesn't have access to the record.

I can add access to accounts through an accountRead permission set that has read on accounts.

Now when I use the custom 'User Access' button, I find that Doug actually has the read access I need him to have.

I built this solution with a custom button, visualforce page, and custom apex controller.

The button can be applied to any object where sharing and custom buttons are supported. Here's an example of the account button that I created. All that is required is to pass in the record Id in the URL when the page is called.

The apex code is pretty simple. The first part enables you to find a user using SOQL.

    // query user from the User's Name input Text
   public void queryUserName() {
    // prevent SOQL Injection - oh no Mr. Bill!
    String queryU = '%' + uName + '%'; 
    // create query passing in queryLabel from input text in page
    // this can easily be changed with other search parameters 
    // only return one user,may require narrowing search results
    queryUser = 
   [SELECT Id, Username, Name, Title, Profile.Name, UserRole.Name
    FROM User
    WHERE Name like :queryU
    OR Title like :queryU
    OR Profile.Name like :queryU 
    ORDER By Name
    LIMIT 1];

The second part enables you to use the user Id from the SOQL query and the record Id from the URL in the UserRecordAccess where clause to determine the user's actual access.

   // Determine User Access based on the queryUser  
  // and the Id passed in through page reference in the URL 
   public void queryAccess()
       // Store queryUser results in a new object
       User u = [SELECT Id 
                 FROM User 
                 WHERE Id = :queryUser];
       // Extract the Id from the user results
       String uId = u.Id;     
       // UserRecordAccess using the userId and recordId 
       ura = [SELECT MaxAccessLevel,RecordId
              FROM UserRecordAccess 
              WHERE RecordId =      :ApexPages.currentPage().getParameters().get('Id') 
                    AND UserId = :uId];

This solution works because the UserRecordAccess sObject which is available in the API. If you haven't seen this before, it's a great way to determine who has access to any record by combining profiles, permission sets, and sharing together.

The source code for the apex page and controller can be found on my github page: https://github.com/atorman/CustomSharingButton. Feel free to use it although there is some more work that I am planning to do so keep in mind that there is more to come.

While this doesn't address the original intent of the twitter conversation, it does address a couple of shortcomings with the Sharing button in particular.

1 comment:

  1. error:Method does not exist or incorrect signature: [String].isUpdateable()
    public updatecheckbox{get; set;}
    public String selecteduserId { get; set; }
    public void checkFields()
    list sobjectfields = new list();
    Map fieldMap = schemaMap.get(selectedObject).getDescribe().fields.getMap();
    for ( Schema.SObjectField sfield : fieldMap.values() )
    schema.describefieldresult fieldresult = sfield.getDescribe();

    searchresult = 'SELECT ' + fieldresult.getName() + 'FROM '+ selectedObject + where + id =: selecteduserid;
    // System.runAs(selecteduserId) // You can only use runAs in a test method.
    accesscheckbox = searchresult.isAccessible();----> again,i am getting an same error, if true means enable check
    box in visualforce whether user have access permission..
    updatecheckbox = searchresult.isUpdatable();
    please help me code.....


Note: Only a member of this blog may post a comment.