24 February 2014

If I were cloned which would I be, I, myself, yours truly, or me?


While talking with salesforce administrators, I often get the request to be able to clone a user. It's a common user provisioning flow in IT. As an administrator, it's easier to ask who a new user is most like rather than figure out all the settings and apps they need to get up and running in the organization as quickly as possible. There are even a couple of ideas on the ideaexchange and answers forum about it.

Cloning a user has three simple requirements:
  1. I should be able to provision a new user by creating a copy of an existing one.
  2. I should only have to provide the minimal information necessary for the clone to take place. 
  3. The new user should include the right level of access (public groups and permission sets) and apps necessary to get them up and running as soon as possible.
Almost everything I need to clone a user can be done with the app building tools on the salesforce platform.

The first requirement is pretty easy. I just need to easily search for an existing user to set as my source user.

It turns out I only need three user fields to create a unique clone or target user for the second requirement: first name, last name, and email address. Everything else can either be assumed based on that information or copied directly from the source user.

The third requirement is the tough one. Cloning a parent object is pretty easy. There are lots of articles and hacks like Salesforce: Clone Records Using a Custom Button or Link or Clone a User In Salesforce.com Without Apex. However the user object is unique and there are a number of additional hurdles to overcome when cloning.

Last summer I pitched the idea to bring a summer intern on board to build a sample Apex app that could simplify some of the clone user flow. Ian Dalton came on board and built out the majority of Apex we needed to demonstrate that it was possible. I built out the rest to surface it as a force.com app with a simple interface.

The flow is pretty simple:
  1. search for a source user.
  2. enter the minimal information for the target user.
  3. click the clone button.
  4. click the newly created target user's link and view their record. You'll find the permission sets and public groups came over as well.


To try this out, download the sample code from my github repository.

The easiest way to install this project into your org is to make use of the workbench tool (http://workbench.developerforce.com).
  1. Download a ZIP of the repository.
  2. Open Workbench.
  3. Login to the desired organization with a user that has Modify All Data permission.
  4. Select Deploy from the migration menu and when prompted, choose your zip file and select 'Allow Missing Files' checkbox before deploying it.
  5. If you get an error that the deployment failed because package.xml cannot be found: unzip the cloneUser.zip file you downloaded and use the terminal to re-zip it (e.g. zip -r cloneUser.zip cloneUser) before retrying step 4.
To start using, just assign the CloneUser permission set to any administrator who should be able to clone users using this app.

Once the permission set is assigned, you should be able to select the app from the app picker and begin cloning. All that is required is a source user, a first name, last name, and an email address.

Building administrative apps like the ability to clone users easily is a great way to learn more about the salesforce platform and build value within your organization at the same time.



Additional Credits:
Title is from a poem 'On Cloning' by M M Marshall
Picture is from Deviantart by dandroid

10 February 2014

You can retrieve if you want to, you can leave your friends behind

I had the following question come up twice recently, once on the salesforce stackexchange: Are profile and permission set metadata files getting all objectPermissions?

You can get a better sense of what's supported and how profiles/permission sets behave with the Metadata API (MdAPI) through the SalesforceHacker blog posting: Dude, Where's My Permission?

The short answer here is that, as a general rule, we try to retrieve only enabled permissions through the MdAPI. This helps reduce the size of the .profile or .permissionset file and also keeps the focus on what the user has rather than what they don't. Since we are firm believers in positive permissions, this helps us keep track of what we are rather than what we are not.

Keep in mind that retrieve is very different from deploy where permissions are concerned in the MdAPI.

Retrieve has very specific behaviors, many of which require a junction object in the payload/package.xml to retrieve 'custom' permission settings (e.g. Foo__c CRUD will be retrieved *only* if the Foo__c custom object is also in the payload).

As a result, custom permissions in particular will only be retrieved *if* there is both an enabled permission *and* the junction object is specified in the manifest. For instance the following will only retrieve CRUD on Foo__c if at least Read permission is enabled:

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Standard User</members>
        <name>Profile</name>
    </types>
    <types>
        <members>Foo__c</members>
        <name>CustomObject</name>
    </types>
    <version>30.0</version>
</Package>

However, deployment doesn't require the concept of junction. I can declare whatever permission I want (e.g. Foo__c CRUD = false across all object permissions). As a result, If I create a prototypical profile or permission set with *all* permissions enabled and retrieve it, I will know the syntax of every permission that is allowed within my deployment.

For instance, I can now define something like Foo__c CRUD = false across all CRUD permissions for that object and when I deploy it, I will revoke Foo_c CRUD in my target org for that profile or permission set:

<?xml version="1.0" encoding="UTF-8"?>
<Profile xmlns="http://soap.sforce.com/2006/04/metadata">
    <custom>true</custom>
    <objectPermissions>
        <allowCreate>false</allowCreate>
        <allowDelete>false</allowDelete>
        <allowEdit>false</allowEdit>
        <allowRead>false</allowRead>
        <modifyAllRecords>false</modifyAllRecords>
        <object>Foo__c</object>
        <viewAllRecords>false</viewAllRecords>
    </objectPermissions>
    ...
</Profile>

As a result, I have a lot more control over deployment of permissions including revoking them if I modify the .profile or .permission set files before deploying my permissions.