Code

Code

Sunday, March 8, 2015

Custom Contact Roles - Part 2

So if you remember from Part 1, we created a hierarchical custom setting to allow us to control who can create/edit/delete certain contact roles.  We made it flexible enough to allow for an admin to make changes on the fly without a developer needing to adjust code.

There is however, a use case that we did not account for that would require a coding change.  In the code in part 1, if there was a requirement to allow a new profile access to one or more of the existing roles, all you would need to do is add a new value to our hierarchy custom setting for the new profile.  Quick and easy, but no coding required.

What about though if the business decided there was a new role that needed to be added?  Now we not only have a Buyer, Technical, and Executive role, but now there is a 'Influencer' role that needed to be available?

Since we have our roles hard-coded into our trigger, and they rely on a field on the custom setting, the only way to accomplish this wold be to add a new custom field to the custom setting and to update ur code.

if(
    (r.Role__c == 'Buyer' && !perm.Buyer__c) ||
    (r.Role__c == 'Technical' && !perm.Technical__c) ||
    (r.Role__c == 'Executive' && !perm.Executive__c)
)

....not as flexible as we had hoped.  BUMMER.


So how can we adjust our custom setting and code to account for this flexibility?  What if instead of a custom setting field for each role, we just have a single text field that contains the text name of the role that a profile has permission to.  This way, you never have to hardcode a role into your code, you can just check that the text field in the custom setting contains the role name.


So here would be our new custom setting.  Its still a hierarchy custom setting, but now there is only a single field.  This field will hold all the roles the profile has permission to.


The custom setting we created last time.  You see there is a field for each custom role



Now you can see our new custom setting just has a single field that contains all the roles that the profile or user has permission to


So now we have to adjust our code to use this new custom setting.  As you can see our code gets much simpler as we don't have to check each custom setting field against the role.  Its just a single check now.

public with sharing class CustomContactRoleTriggerHelper {

    public void CustomRoleBeforeInsert(List<Custom_Contact_Role__c> newRoles){
        checkPermissions(newRoles, null, 'create');
    }

    public void CustomRoleBeforeUpdate(List<Custom_Contact_Role__c> newRoles, List<Custom_Contact_Role__c> oldRoles, map<Id,Custom_Contact_Role__c> newMap, map<Id,Custom_Contact_Role__c> oldMap){
        checkPermissions(newRoles, oldMap, 'update');
    }

    public void CustomRoleBeforeDelete(List<Custom_Contact_Role__c> newRoles, List<Custom_Contact_Role__c> oldRoles, map<Id,Custom_Contact_Role__c> newMap, map<Id,Custom_Contact_Role__c> oldMap){
        checkPermissions(oldRoles, oldMap, 'delete');
    }

    private void checkPermissions(List<Custom_Contact_Role__c> rolesToCheck, map<Id,Custom_Contact_Role__c> oldMap, string actionDone){

        Contact_Role_Permissions_2__c perm = Contact_Role_Permissions_2__c.getInstance(UserInfo.getUserId());
        string roleString = (perm.Permission_to_Roles__c == null) ? '' : perm.Permission_to_Roles__c;
        set<String> roleSet = new set<String>(roleString.split(','));
        
        for(Custom_Contact_Role__c r : rolesToCheck){
            
            if(actionDone == 'create'){

                if(!roleSet.contains(r.Role__c)){
                    r.Role__c.addError('You do not have permission to ' + actionDone + ' contact roles with the role of  \'' + r.Role__c + '\'');
                }
            
            }else If(actionDone == 'update'){

                if(!roleSet.contains(oldMap.get(r.Id).Role__c)){
                    r.Role__c.addError('You do not have permission to ' + actionDone + ' contact roles with the role of  \'' + oldMap.get(r.Id).Role__c + '\'');
                }else if(!roleSet.contains(r.Role__c)){
                    r.Role__c.addError('You do not have permission to ' + actionDone + ' contact roles to the role of  \'' + r.Role__c + '\'');
                }

            }else If(actionDone == 'delete'){

                if(!roleSet.contains(oldMap.get(r.Id).Role__c)){
                    r.Role__c.addError('You do not have permission to ' + actionDone + ' contact roles with the role of  \'' + oldMap.get(r.Id).Role__c + '\'');
                }
            }
        }
    }
}

So let's try to break down how I use the custom setting now.  

Contact_Role_Permissions_2__c perm = Contact_Role_Permissions_2__c.getInstance(UserInfo.getUserId());
string roleString = (perm.Permission_to_Roles__c == null) ? '' : perm.Permission_to_Roles__c;
set<String> roleList = new set<String>(roleString.split(','));


Line 1 - I first get the text field from the custom setting as you see in line
Line 2 - Here we are accounting for the edge case that the field is null.  We don't want the code to throw an exception, so we set it to a blank string or ''.
Line 3 - Here we are using the string split method.  The split method returns a list, and we want to leverage the contains method, which is a set method so we add the list returned from the set method to a set.

Now that we have a set of strings that contains the roles the current user has permission to, we just need to check that the set contains the role they are trying to use.

if(!roleSet.contains(r.Role__c)){
     r.Role__c.addError('You do not have permission to ' + actionDone + ' contact roles with the role of  \'' + r.Role__c + '\'');
}

And that's it.  We now have made our code even more flexible and scalable.  We now can add any new role to the custom contact role picklist and it does not require any recoding of our trigger.

That's all I have this time.  Next time I will go through writing the test code for this helper class.