• Piyali Chowdhury 15
  • NEWBIE
  • 2 Points
  • Member since 2018

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 0
    Questions
  • 1
    Replies
If you do a SOQL query for a single UserRecordAccess record, you get the correct values. But if you query for multiple UserRecordAccess records in a single query, the values returned are often incorrect (for instance the HasAllAccess value may be true when it should be false).

This problem makes it impossible for us to reliably communicate object permissions to our users.

This is nearly identical to the following issues that was marked as fixed back in the Winter 15 release: https://success.salesforce.com/issues_view?id=a1p30000000T4iiAAC

Below is a test class I wrote that reproduces the issue.  In this test class I use the Macro sobject, but the problem applies to other objects as well.  I first noticed it on a custom object.
@isTest
public without sharing class UserRecordAccessTest {

	private static testMethod void test(){

		//Create the users that will own the records
		final User[] users = createStandardUsers(2);
		final User u1 = users[0];
		final User u2 = users[1];

		//Create the records, each owned by a different user
		final SObject o1 = createRecord(u1.Id);
		final SObject o2 = createRecord(u2.Id);
		insert new SObject[]{o1, o2};

		system.runAs(u1){

			//Query for each UserRecordAccess entry individually
			final UserRecordAccess access1 = queryForSingleUserRecordAccess(u1.Id, o1.Id);
			final UserRecordAccess access2 = queryForSingleUserRecordAccess(u1.Id, o2.Id);

			//Query for both UserRecordAccess entries at the same time
			final UserRecordAccess[] accessList = queryForUserRecordAccesses(u1.Id, new Set<Id>{o1.Id, o2.Id});

			//The UserRecordAccess entries should have the same values, regardless of how they were queried
			compareUserRecordAccesses(access1, accessList[0]);//This fails because the HasAllAccess value is false for the entry queried individually, but is true for the entry queried in a list
			compareUserRecordAccesses(access2, accessList[1]);

		}


	}

	private static UserRecordAccess queryForSingleUserRecordAccess(final Id userId, final Id recordId){
		return [
			SELECT RecordId, HasReadAccess, HasEditAccess, HasDeleteAccess, HasTransferAccess, HasAllAccess
			FROM UserRecordAccess
			WHERE UserId = :userId AND RecordId = :recordId
		];
	}

	private static UserRecordAccess[] queryForUserRecordAccesses(final Id userId, final Set<Id> recordIds){
		return [
			SELECT RecordId, HasReadAccess, HasEditAccess, HasDeleteAccess, HasTransferAccess, HasAllAccess
			FROM UserRecordAccess
			WHERE UserId = :userId AND RecordId IN :recordIds
			ORDER BY RecordId
		];
	}

	private static void compareUserRecordAccesses(final UserRecordAccess expected, final UserRecordAccess actual){

		system.assertEquals(expected.RecordId, 			actual.RecordId);
		system.assertEquals(expected.HasReadAccess, 	actual.HasReadAccess);
		system.assertEquals(expected.HasEditAccess, 	actual.HasEditAccess);
		system.assertEquals(expected.HasDeleteAccess, 	actual.HasDeleteAccess);
		system.assertEquals(expected.HasTransferAccess,	actual.HasTransferAccess);
		system.assertEquals(expected.HasAllAccess, 		actual.HasAllAccess);

	}

	private static User[] createStandardUsers(final Integer count){

		final Profile standardUser = [SELECT Id FROM Profile WHERE Name = 'Standard User'];

		final User[] users = new User[]{};
		for(Integer i = 0; i < count; i++){
			users.add(new User(
				UserName = 'test' + i + '@userrecordaccesstest.com',
				LastName = 'Smith',
				Email = 'test@user.com',
				Alias = 'test',
				CommunityNickname = 'test' + i,
				TimeZoneSidKey = 'America/Indiana/Indianapolis',
				LocaleSidKey = 'en_US',
				EmailEncodingKey = 'UTF-8',
				LanguageLocaleKey = 'en_US',
				ProfileId = standardUser.Id
			));
		}

		insert users;

		return users;
	}

	private static SObject createRecord(final Id ownerId){
		return new Macro(Name = 'Macro' + ownerId, OwnerId = ownerId);
	}

}