+ Start a Discussion
Ian Robertson.ax927Ian Robertson.ax927 

How to determine Record Level access of the current user?

 

I am struggling with determining whether the current user has Edit or Read Only rights on a record. In this case its an opportunity.
I check if the User has a sharing record. As the Owner or someone who has been manually/APEX shared with, they will have a sharing record.
I check if they have elevated rights using our own custom permission model.
I want to know if the user is also in the hierarchy above the owner, but don't seem to be able to code against the role hierarchy. The only option I have found is to try an edit on the opportunity, and revert it back. Its the last step if they don't have edit rights by other means. It means 2 updates which I believe are unnecessary  and ineloquent. I check if the update fails for the reason they only have READ ONLY rights. It could fail for other reasons such as validation rules, but that doesnt mean they dont have edit rights, it means they didnt complete the form properly.
The function below determines how a VF component on the Opportunity page layout behaves. If they have edit rights on the opportunity they see one thing, if they dont they see something else. This logic should work as the page loads and not when a user clicks a button on the opportunity.
Below is my function.
private boolean bCanBeEdited()
    {
     boolean edit = false;
    
     try
     {
       
     //Get a list of Users/Groups that the Opportunity is shared with, limited by opp id and the users ID.
       
     List<OpportunityShare> SharedWith = [Select o.id, o.UserOrGroupId, o.RowCause, o.OpportunityAccessLevel From OpportunityShare o where o.UserOrGroupId = :UserInfo.getUserId() AND o.OpportunityId = :oppId];
     edit = (!opp.Revenue_From_Order__c && SharedWith.Size() > 0);  //Allow edit if the check box is not checked (as before) and the user has a share on the Opportunity.
   
    edit = (edit || SecurityFunctions.hasPrivilege(SecurityFunctions.CanEditOpportunityRevenue)); // Allow Edit if they are an owner or SysAdmin
   
    system.debug('##########1 Edit: ' + edit);
   
    if(!edit)
    {
    string temp = opp.Name;
    system.debug('################1 Opp Name: ' + opp.name);
    opp.name = opp.Name + 'Edit';
    system.debug('################2 Opp Name: ' + opp.name);
    update opp;
    system.debug('################3 Opp Name: ' + opp.name);
    opp.name = temp;
    system.debug('################4 Opp Name: ' + opp.name);
    update opp;
    system.debug('################5 Opp Name: ' + opp.name);
    edit = true;
    }
     }
     catch (System.DmlException  DMLEx)
     {
     if(StatusCode.INSUFFICIENT_ACCESS_OR_READONLY == DMLEx.getDmlType(0))
     {
     system.debug('##########Exception - Edit Rights: None');
     edit = false;
     }
     else
     {
     system.debug('##########Exception - Another Exception');
     edit = true;
     }
    
     system.debug('##########2 Edit: ' + edit);
    return (edit || SecurityFunctions.hasPrivilege(SecurityFunctions.CanEditOpportunityRevenue)); // Allow Edit if they are an owner or SysAdmin
     }
        
     system.debug('##########2 Edit: ' + edit);
     return (edit || SecurityFunctions.hasPrivilege(SecurityFunctions.CanEditOpportunityRevenue)); // Allow Edit if they are an owner or SysAdmin
    }

 

md1md1

Have you tried using the 'isAccessible' and 'isCreatable'' methods of Schema.DescribeFieldResult?

Ian Robertson.ax927Ian Robertson.ax927

 

Hi md1
I have just tried your suggestion as follows:
******************************
Schema.DescribeFieldResult f = Schema.sObjectType.Opportunity.fields.Name;
system.debug(Schema.sObjectType.Opportunity.fields.Name);
system.debug('###########1 Field Description: '+ f.isUpdateable());
edit = (f.isUpdateable() || SecurityFunctions.hasPrivilege(SecurityFunctions.CanEditOpportunityRevenue)); // Allow Edit if they have the override or Name field is updatedable.
*******************************
f.isUpdateable/isAccessible/isCreatable is always true, even when I log in as a user who cannot edit a particular Opportunity.
Is Schema.sObjectType.Opportunity.fields.Name referring to my instance of the Opportunity (the record), is it saying that the user in general has rights to Opportunites?
I need to know at record level if the current user has edit rights on the current record.
I am just getting started in SFDC so forgive me if I am making amaturish mistakes.
Thanks
Ian

 

mtbclimbermtbclimber

 


Ian Robertson wrote:

 

Is Schema.sObjectType.Opportunity.fields.Name referring to my instance of the Opportunity (the record), is it saying that the user in general has rights to Opportunites?

 

Yes, it is saying the user has general access to update records in the opportunity table. It doesn't mean he/she can update all of them or any given one in particular.

 

About the best you can do today is check describe like this then see if the user is the owner, then see if there is a share record for this user and the access. There is no efficient way to evaluate the user's role hierarchy access or if he/she is the member of a group share via an implicit association, i.e. member of a group that is part of another group, etc.  There is another factor that can determine editability and that's if the record has been locked by an approval process which you also can't determine programmatically unfortunately.  Locking supersedes ownership and sharing access but administrators can still edit even if the record is locked. 

 

For now the only way to truly know if the user can edit a record is to try and catch the exception. I would do something benign that doesn't need a compensating reset like setting a field to be the same as it was before or incrementing a number field that is reserved for this purpose.  The thing you can't fix is lastmodifieddate/by and of course this requires burning a dml request.

 

Sorry there isn't a better answer today. I spent some time looking on the ideaexchange to see if anyone had submitted these but didn't see them.  I recommend creating an idea for what you are looking for, describe the use case a bit and add a pointer to that idea in a comment on this thread.

 

 Regards