Sunday 7 September 2014

Salesforce1 Notifications from Apex

As documented in the Salesforce Summer 14 Release Notes, there are a number of activities that send a Salesforce1 notification to a user (assuming they haven’t disabled any), but all of these require manual actions to be taken via chatter.  While playing around with some code to notify the owner of a Salesforce system that a new user had been created in their system, I wanted to be able to send a notification programmatically.

The least intrusive mechanism looked to be a post to my profile, with a mention to the user in question - “Keir Chatter” in my case.  My first attempt at this was to simply create a FeedPost instance and set the body of the post to ‘@[Keir Chatter] a new user has been created’. Unfortunately, this simply placed the raw text ‘@[Keir Chatter]’ into the feed and didn’t get picked up as a mention at all.  

After a little research, I realised that I needed to use the Chatter Connect API, specifically the version of the postFeedItem method that takes a ConnectApi.FeedItemInput as a parameter, as the documentation makes clear (the bold is mine): 


postFeedItem(String, ConnectApi.FeedType, String, ConnectApi.FeedItemInput, ConnectApi.BinaryInput)

Adds a feed item to the specified feed from the context user Use this method to post rich text, including @mentions and hashtags, and to attach a file to a feed item. You can also use this method to share a feed item and add a comment. 


Generating a FeedItemInput is a little more complex than simply adding a body property to a post - the mention and the message have to be constructed separately as segments and then attached.  As I wanted this to be reusable, I created a utility method that would take a user id and message and take care of all the heavy lifting (the utility method also excludes attempts to notify yourself - i.e. to post an @mention to yourself on your own chatter feed):

ConnectApi.MessageBodyInput messageInput = 
new ConnectApi.MessageBodyInput();
messageInput.messageSegments = 
new List<ConnectApi.MessageSegmentInput>(); // create and add the mention segment ConnectApi.MentionSegmentInput mentionSegment =
new ConnectApi.MentionSegmentInput(); mentionSegment.id = userId; messageInput.messageSegments.add(mentionSegment); // create and add the message body segment ConnectApi.TextSegmentInput textSegment; textSegment = new ConnectApi.TextSegmentInput(); textSegment.text = message; messageInput.messageSegments.add(textSegment); // create the FeedItemInput and add the messageInput to it ConnectApi.FeedItemInput input =
new ConnectApi.FeedItemInput();
input.body = messageInput;

// finally, post to the current user's feed
ConnectApi.ChatterFeeds.postFeedItem(null, 
ConnectApi.FeedType.News, 'me', input, null);

I then created a simple trigger to notify the user whose name begins with ‘keir.chatter’ when a new user is added to the system - note that this is a chatter free user - the user doesn’t need a full Salesforce license as the post isn’t associated with a Salesforce record:

trigger user_ai on User (after insert)
{
  User notifyUser=[select id from User where
                    username like 'keir.chatter%'];
  MentionUtils.NotifyUser(notifyUser.Id,
            ' a new user has been created - ' +
            trigger.new[0].username);
}

Note that the trigger is set up to handle a single record at a time, purely for the purposes of this post.  This does show up one weakness of this technique though, as there is no way to bulk post a number of messages at the time of writing (September 2014).  If I needed to handle multiple records in this case I’d just post a large message containing information about all of the users that had been added.  If I needed to notify a different user per record, I’d have to use some asynchronous processing (either @future or batch Apex) to avoid breaching governor limits.

Adding a new user to the system:

 

Screen Shot 2014 09 07 at 16 04 51

 

sends a notification to my chatter user:

 

Screen Shot 2014 09 07 at 16 54 16

 

accessing Salesforce1 shows the red bell indicating I’ve received a notification:

 

Screen Shot 2014 09 07 at 16 55 37

 

tapping the bell shows a summary of the post:

 

Screen Shot 2014 09 07 at 16 55 53

 

and finally, click on the notification takes me to the full post:

 

Screen Shot 2014 09 07 at 16 56 08

 

I’ve added this utility class and unit test to my SF1Utils github repository and unmanaged package that I created for an earlier post

2 comments:

  1. Interesting approach, going to try it soon. Though I believe this should be a native Apex api (with usual limits), how about posting it as a new idea ?

    ReplyDelete
  2. Just an update to this post, it appears that bulk has become much easier with the addition of ConnectApi.BatchInput: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/connectapi_examples_post_feed_element_batch.htm

    ReplyDelete