1

I'm changing the ownerId of a record though Apex to another User. This flow is not through Visualforce or Triggers. The code is running in system context and isn't initiated by a user. Hence even if the user does not have access to the record type, the assignment works.

How do I ensure that the user has update access on this record Type before assigning her as the owner?

1
  • "does not have access to the record type" - Do you mean that the user does not have CRUD access to the Object (i.e. you are assigning them as the owner of a record of an object type they will never be able to see) or do you mean that the user has not been granted access a RecordType on an Object and you are trying to determine if a RecordType is available to the user before assigning ownership?
    – Mark Pond
    Mar 21, 2017 at 5:23

4 Answers 4

3

A bit unclear on if you are talking about object or record, but if you want to check access on the specific record for a different user

You can query the UserRecordAccess object directly as so to see if user edit has access to the record:

SELECT RecordId
     FROM UserRecordAccess
     WHERE UserId = [single ID]
     AND RecordId = [single ID]      //or Record IN [list of IDs]
     AND HasEditAccess = true

UserRecordAccess

Keep this Known issue in mind

5
  • Thanks for your reply. I want to check the access on the object type and not for an individual record. Can I use UserRecordAccess for the same? Is there a way to check object.isUpdateable() by providing a user id?
    – Oliver
    Mar 20, 2017 at 18:31
  • @Oliver - That is exactly what it is doing. It will return results for a given user and record Id if they have Edit access (updatable)
    – Eric
    Mar 20, 2017 at 18:47
  • Can this be used for checking using objectType and not have to provide record IDs. Basically I just want to check if user has permissions on an object. Eg. If they have permission to update a Lead object. I presume I can just use this on one record to suffice this condition
    – Oliver
    Mar 20, 2017 at 19:04
  • I don't believe so no.
    – Eric
    Mar 20, 2017 at 19:28
  • 1
    @Oliver - You may be in a bit of an X-Y problem here. Maybe describe what you are tying to achieve in a business sense vs trying to see if your solution will work. Maybe someone will have a better way to do what you are trying to achieve
    – Eric
    Mar 20, 2017 at 21:32
2
if (Schema.sObjectType.Contact.isUpdateable()) {
   // Update contact 
}

Reference links:

1
  • Thanks for your reply. I am not running in the context of the user on which I want to check the permission. So this would not work for me.
    – Oliver
    Mar 20, 2017 at 18:32
1

Unfortunately, there is not a fast/easy way to do this (as far as I know).
You will have the use the following classes:
ObjectPermissions
PermissionSet
User

First retrieve the Id of the user you want to assign the Record.

User userTarget = [SELECT Id FROM User WHERE ...];

After that, retrieve all the PermissionSetAssigment for that User (in this class, all types of permission counts: from profile, permission set, custom permission, and so on). Also, store the ids in a set to use them to query.

Set<Id> permissionSets = new Set<Id>(); for(PermissionSetAssignment up : [SELECT PermissionSetId FROM PermissionSetAssignment WHERE AssigneeId = :userTarget.Id]){ permissionSets.add(up.PermissionSetId); }

Finally, get the ObjectPermission of the sObject type you are trying to assign

for(ObjectPermissions objPerm : [SELECT PermissionsCreate FROM ObjectPermissions WHERE ParentId IN :permissionSets ANd sObjectType = 'Account']){ if(objPerm.PermissionsCreate){ System.debug('Account Create access!'); break; } }

2
  • If you have the Id of the record there is no need to go through all of this. Simply do what is in my answer. If you are trying to check the permissions of a user to the object and not the record and it is not the running user then yes you will have to do all of this.
    – Eric
    Mar 20, 2017 at 21:29
  • I agree with that, if you need to know if you have access to the record the best way is to use UserRecordAccess, but the OP was asking for Object access (or at least that was what I thought when I posted)
    – Diana Man
    Mar 21, 2017 at 12:23
0

Its always better to move code in utility so as to increase the code re-usability. Following is the method which you can use in your apex code to check CRUD permissions and can customize as per your need, I am just giving you an example as there can be multiple instances where you would need to apply CRUD checks in that case it will be helpful.

// Variable Declaration
private static final String ID_STRING = 'Id';

/**
 * @description: Checks if user has save access on the records.
 * @param: 1. sObjectList - List of records to perform update / insert on
 *         2. userId - User for which the record access is checked.
 * @return: Void
 **/
public static void checkSaveAccessForSObject(List<sObject> sObjectList, Id userId ){

    Map<Id, sObject> currentSObjectMap = new Map<Id, sObject>();
    List<sObject> finalSObjectList = new List<sObject>();
    List<UserRecordAccess> listUserRecordAccess = new List<UserRecordAccess>();

    // Iterate over Sobject List
    for(sObject obj : sObjectList) {

        if(obj.get(ID_STRING) != NULL) {
            currentSObjectMap.put( (Id) obj.get(ID_STRING), obj);

        } else {
            finalSObjectList.add(obj);
        }
    } // for

    if(currentSObjectMap != NULL && currentSObjectMap.isEmpty() == false){

        listUserRecordAccess = checkUserAccessForSobject(currentSObjectMap.keySet(), userId);

        for(UserRecordAccess objUserAccess : listUserRecordAccess){
            if(objUserAccess.HasReadAccess && objUserAccess.HasEditAccess )
                finalSObjectList.add(currentSObjectMap.get(objUserAccess.RecordId));
        } // for
    } // if

    //Now you have this Sobject List You can do further manipulation on that
    system.debug('****finalSObjectList****'+finalSObjectList);
} // 

/**
 * @description: Checks if user has access to the set of record ids provided
 * @param: 1. recordIdsSet - Set of record ids to check access of
 *         2. userId - User for which the record access is checked.
 * @return: List<UserRecordAccess> having access values for each record provided
 **/
public static List<UserRecordAccess> checkUserAccessForSobject(Set<Id> recordIdsSet, Id userId ) {

    List<UserRecordAccess> listUserRecordAccess = new List<UserRecordAccess>();

    if(recordIdsSet == NULL
    || recordIdsSet.isEmpty()
    || userId == NULL) {
        return listUserRecordAccess;
    }

    recordIdsSet.remove(NULL);

    if( !recordIdsSet.isEmpty() ) {
        listUserRecordAccess = [SELECT RecordId,
                                       HasReadAccess,
                                       HasEditAccess,
                                       HasDeleteAccess
                                  FROM UserRecordAccess
                                 WHERE UserId =: userId AND
                                       RecordId IN : recordIdsSet];
    }
    return listUserRecordAccess;
} // End checkUserAccessSobject
5
  • 2
    your util method is returning strings/null - this is not really good practice for the use case; better would be isDeleteable(SobjectType sobjType) and isDeleteable(ID objId); and corresponding versions for isInsertable, isUpdateable. Let caller decide what to do if answer comes back false
    – cropredy
    Mar 20, 2017 at 6:21
  • The reason I am returning String because, I thought if I have to show message to user then I can use this String as a message! and if these Strings are blank then there is no error. Mar 21, 2017 at 2:29
  • 1
    yes, i surmised that. but still not good practice; caller should decide what message to send, if at all
    – cropredy
    Mar 21, 2017 at 2:46
  • Okay Than You ! Mar 21, 2017 at 2:50
  • @cropredy I have updated my answer ! Mar 21, 2017 at 2:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .