7

Background: I want to add all users who are assigned a specific permission set to a specific chatter group. I have a simple version of this working, but would like to abstract this to use a list custom setting to store ChatterGroupName and PermissionSetName so I can run this on N pairings, and then make it scheduleable and perhaps batchable tho I dont think the data volume will need to go batchable.

Question: I cant wrap my head around a pattern to use in moving from my little proof of concept that has one method to handle one permission set / chatter group, to one that works w N number of records from a custom setting.

Where I'm at: I created a simple class and called it via execute anonymous and amazingly enough users were added to the chatter group as desired. I have created a custom setting and added 2 records in it, and i added a line to my controller to populate a list with the rows from it. And...now I dont really know what to do next, besides for coming up with a more concise name for the custom setting.

I feel like I could wrap the whole thing in a giant for loop, but that just seems wrong. My sense is that I need to use maps, but I dont really have the experience w/ maps needed to think through how to proceed, so requesting some top-level help on how best to do so. Also would appreciate any tips / flags for things to look out for that might blow up now or when I try to go scheduleable.

Controller Code:

public class UserAddToChatterGroupFromPermSet {
    list <Permission_Set_Chatter_Group_Map__c> pscg = new list <Permission_Set_Chatter_Group_Map__c> ([SELECT Permission_Set_Name__c, Chatter_Group_Name__c FROM Permission_Set_Chatter_Group_Map__c WHERE Active__c = TRUE]);
    list <user> psusers = new list<user>();
    list <permissionsetassignment> psa = new list <permissionsetassignment>();
    permissionset permset = new permissionset();
    collaborationgroup cg = new collaborationgroup();
    set <Id> permSetUserIds = new set<Id>();
    set <Id> cgUserIds = new set<Id>();


    public UserAddToChatterGroupFromPermSet(){
        addUsersToEchosignGroup();
    }

    public void addUsersToEchosignGroup() {

        //get all active users currently assigned permission set
        permset = [SELECT Id from PermissionSet WHERE Label = 'App: Echosign' LIMIT 1];
        system.debug('permset id = ' + permset);
        psusers = [SELECT Name, ID from USER WHERE ID IN (SELECT AssigneeID from PermissionSetAssignment WHERE PermissionSetId =: permset.Id) AND IsActive = TRUE];
        system.debug('users = ' + psusers);

        //get all group members currently in chatter group
        cg = [SELECT ID from CollaborationGroup WHERE Name = 'E-Signature Users (Adobe Echosign)'];
        list <CollaborationGroupMember> cgusers = new list <CollaborationGroupMember>([SELECT MemberId from CollaborationGroupMember WHERE CollaborationGroupId =: cg.Id ]);
        system.debug('cgusers = ' + cgusers);

        //compare existing perm set users ID to collaboration group members ID and prepare list of cgmembers to insert
        FOR(CollaborationGroupMember cguser : cgusers){
            cguserIds.add(cguser.MemberId);
        }
        list <CollaborationGroupMember> cgUsersToInsert = new list <CollaborationGroupMember>();
        FOR(User psuser : psusers){
            CollaborationGroupMember cgmember = new CollaborationGroupMember();
            IF(cguserIds.contains(psuser.Id)){
                }
            ELSE{
                cgmember.MemberId = psuser.Id;
                cgmember.CollaborationGroupId = cg.Id;
                cgusersToInsert.add(cgmember);
            }
        }
        system.debug('cgUsersToInsertsize = ' + cgusersToInsert.size());
        IF(cgUsersToInsert.size() >= 1){
        insert(cgUsersToInsert);
        }
        ELSE{
            system.debug('no cg members to insert');
        }
    }
}

1 Answer 1

4

Common Misconceptions

You do not need to check if a collection of records is empty before performing DML on it. Check the following in Execute Anonymous:

insert new List<Lead>();
system.assertEquals(0, Limits.getDMLStatements());

So there is no need to check if cgUsersToInsert.isEmpty() before calling insert.

Also, you do not need to do new List<SObject>([query]). Just replace any instance of that with [query]. In addition to being less verbose, it probably consumes less CPU Time.

Answer

You should make your query by a unique field. In this case, I would use PermissionSet.Name instead of PermissionSet.Label. CollaborationGroup.Name is fine, since it is unique. You can use a List Custom Setting with fields for these two values. I would just name them PermissionSet__c and CollaborationGroup__c.

Step 1: Get Filter Data

You need to get a Set<String> for each WHERE filter:

Set<String> permissionSetNames = new Set<String>();
Set<String> chatterGroupNames = new Set<String>();
for (PermissionSet_ChatterGroup__c mapping : PermissionSet_ChatterGroup__c)
{
    permissionSetNames.add(mapping.PermissionSet__c);
    chatterGroupNames.add(mapping.CollaborationGroup__c);
}

Step 2: Query SObject Data

List<PermissionSet> permissionSets = new List<PermissionSet>();
for (PermissionSet permissionSet : [
    SELECT Name, (SELECT AssigneeId FROM Assignments)
    FROM PermissionSet WHERE Name IN :permissionSetNames
]) permissionSets.add(permissionSet);

Map<String, CollaborationGroup> chatterGroups = new Map<String, CollaborationGroup>();
for (CollaborationGroup chatterGroup : [
    SELECT Name FROM CollaborationGroup
    WHERE Name IN :chatterGroupNames
]) chatterGroups.put(chatterGroup.Name, chatterGroup);

Step 3: Tie Into Existing Code

I think you should be able to figure most of the remaining steps out. Change your User query sub-filter from PermissionSetId =: permset.Id to PermissionSet.Name IN :permissionSets.keySet(). Your CollaborationGroupMember filter will need a similar modification.

You can loop through the child PermissionSetAssignment records as follows:

for (PermissionSet permissionSet : permissionSets)
{
    for (PermissionSetAssignment assignment : permissionSet.Assignments)
    {
        // do stuff
    }
}

Slick, eh? If you're curious how I got the name of this child relationship:

DescribeSObjectResult describe = SObjectType.PermissionSet;
for (ChildRelationship relationship : describe.getChildRelationships())
{
    if (relationship.getChildSObject() == PermissionSetAssignment.SObjectType)
        system.debug(relationship.getRelationshipName());
}
7
  • it never crossed my mind that it would be possible to store the child Assignee Ids 'inside' a PermissionSet sObject from a single query. This is very cool. I am trying to figure out how to access these child IDs when I retrieve a permissionSet 'ps' from the map. i've tried dot notation ps.Assignments.AssigneeId and a for loop (which seems wierd since its a single perm set) but neither is compiling - can you clue me in to how to get at these? Trying to add them to a set of IDs. Thanks
    – gorav
    Feb 18, 2016 at 22:47
  • finally got it...ps.Assignments gets me the list of child permssionSetAssignment sObjects...
    – gorav
    Feb 18, 2016 at 22:56
  • @gorav See my updated answer. :)
    – Adrian Larson
    Feb 18, 2016 at 22:57
  • thanks @adrian I just used the same technique to pull in collaboration group members in the collaboration group query. I am slowly slashing and burning my way towards a solution, turning back when i get into nested for loops and i think w a few more attempts i will finally get a sense of proper use of maps!
    – gorav
    Feb 18, 2016 at 23:05
  • @gorav good luck man, you got this!
    – Adrian Larson
    Feb 18, 2016 at 23:06

You must log in to answer this question.

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