I'm attempting to aggregate all ObjectPermissions at the user level for a user access review (audit) application. This application's central function is to show an end-user (a reviewer) their reviewee's access to in-scope objects. It should account for both Profile and PermissionSet driven permissions.
To accomplish the actual aggregation of ObjectPermissions I'm doing the following:
- Get all PermissionSetAssignments.
- Get all Object Permissions.
- Since both have a PermissionSetId, use PermissionSetAssignment.PermissionSetId to find the ObjectPermissions associated with each assignment.
- Do this for each user, for each of their PermissionSetAssignments.
- The end-result should be a comprehensive picture of their Object-level access.
I'm hitting CPU timeout limit on step 3 - probably because I'm looping through all of my ObjectPermissions for every single one of my PermissionSetIds.
// ObjectPermissions query
List<ObjectPermissions> allObjectPermissions = [SELECT Id, ParentId, PermissionsRead, PermissionsDelete, PermissionsEdit, PermissionsViewAllRecords, PermissionsModifyAllRecords, SObjectType
FROM ObjectPermissions
WHERE (ParentId IN (SELECT PermissionSetId
FROM PermissionSetAssignment
WHERE Assignee.Id IN: revieweeIds))
AND
PermissionsRead = true
AND
SobjectType IN
(: Constants.OPPORTUNITY_OBJ,
: Constants.ACCOUNT_OBJ,
: Constants.INSERTION_ORDER_OBJ,
: Constants.PLACEMENT_OBJ,
: Constants.APTTUS_AGREEMENT_OBJ,
: Constants.UPFRONT_OBJ,
: Constants.SNAPCHATSALESTEAM_OBJ,
: Constants.ORGANIZATION_OBJ,
: Constants.ADACCT_OBJ,
: Constants.CASE_OBJ,
: Constants.BRAND_OBJ,
: Constants.UPFRONT_ENTITY_OBJ)];
Here's the problematic looping:
// loop thru list of PermissionSetAssignments
String loopVar;
for(PermissionSetAssignment pSa : permSetAssignments){
// isolate PermissionSetId
loopVar = pSa.PermissionSetId;
// Loop thru all object permissions
for(ObjectPermissions objPermission : allObjectPermissions){
// find ObjectPermissions where ParentId == PermissionSetAssignment.PermissionSetId
if(loopVar == objPermission.ParentId){
/*
* do work to aggregate this ObjectPermission at Assignee level
*/
My question: how can I reduce the amount of ObjectPermissions i'm looping through? I initially thought to GROUP BY on my ObjectPermissions query and somehow access only the ObjectPermissions under a particular PermissionSetId grouping within the PermissionSetAssignment loop, but that doesn't seem to be possible. I'm currently trying to batch this operation to remediate, but I feel the loop can be improved.