Recipes by Category

App Distribution (2) Bundle logic, interface and services for distribution. App Logic (37) The Apex programming language, workflow and formulas for logic. Collaboration (6) The Salesforce Chatter collaboration platform. Database (29) Data persistence, reporting and analytics. Integration (33) Web Service APIs and toolkits for integration. Security (9) Platform, application and data security. Tools (4) Force.com tooling User Interface (36) Visualforce MVC and metadata-drive user interfaces. Web Sites (12) Public web sites and apps with optional user registration and login.
Beta Feedback
Cookbook Home » Last Chatter Date

Last Chatter Date

Post by Chef Tim__m  (2012-01-23)

Status: Unverified
Level: intermediate

Problem

The last Chatter date is not easy to get to when writing reports, formulas, or custom UIs. If only there was a field on the sObject that had the last Chatter date that automatically updates when users post on a feed or comment on a post.

Solution

Build a trigger that saves the last Chatter date on the parent sObject if it has a last chatter date field. Architecture: The ChatterDate class is a small class with one static method called updateChatterTimestamp. The static method is called by a Feed Item and Feed Comment trigger with one parameter, the trigger.newMap. The ChatterDate class is generic so all you need to do is add the LastChatterDate__c field to an sObject that is Chatter enabled.

public class ChatterDate {

    private static final String LAST_CHAT_DATE_FIELD_NAME = 'LastChatterDate__c';
    
    public static void updateChatterTimestamp(map<Id, Sobject> sobjectMap) {
        try {
            // Get the global schema
            map<String, Schema.Sobjecttype> globalDescribe = Schema.getGlobalDescribe();
            
            // A list to put our sObjects in so we can bulk update them
            List<SObject> sobjList = new List<SObject>();
            
            // Iterate through the sObjectMap param
            for(Sobject obj : sobjectMap.values()) {
                String parentId = String.valueOf(obj.get('ParentId'));
                
                // Iterate through the sObject types and find our parent sObject type by keyPrefix
                for(schema.Sobjecttype objToken : globalDescribe.values()) {
                    DescribeSObjectResult objDef = objToken.getDescribe();
                    
                    if(null != objDef.keyPrefix && parentId.startsWith(objDef.keyPrefix)) {
                        // We found our sObject type now check if it has the magic field
                        if(objDef.fields.getMap().containsKey(LAST_CHAT_DATE_FIELD_NAME)) {
                            // This sObject type has the magic field so create a new sObject with the 
                            // parentId and set the last chatter date to the crated date of the
                            // the FeedItem or FeedComment)
                            Sobject targetObj = objToken.newSObject(parentId);
                            targetObj.put(LAST_CHAT_DATE_FIELD_NAME, (Datetime) obj.get('CreatedDate'));
                            sobjList.add(targetObj);
                        }
                        
                        // We found our sObject so break out
                        break;
                    }
                }
            }
            
            if(!sobjList.isEmpty()) {
                // Call the update DML method, try to save what we can and deal with the exceptions
                List<Database.SaveResult> saveResultList = database.update(sobjList, false);
                // Iterate through the Save Results
                for(Database.SaveResult sr:saveResultList) {
                    if(!sr.isSuccess()) {
                        // Validation rules and other unknown things can
                        // cause exceptions so deal with it as you see fit
                    }
                }
            }
        } catch(system.Exception ex) {
            // an unknown exception
        }
    }
}

The Triggers

trigger FeedItemLastChatterDate on FeedItem (after insert) {
    ChatterDate.updateChatterTimestamp(trigger.newMap);
}
trigger FeedCommentLastChatterDate on FeedComment (after insert) {
    ChatterDate.updateChatterTimestamp(trigger.newMap);
}

And no sample is complete without a nice unit test.

@isTest
private class ChatterDateTest {

    static testMethod void singleUnitTest() {
        Account testAccount = new Account(Name='TestAccount');
        insert testAccount;
        
        FeedItem post = new FeedItem();
        post.parentId = testAccount.Id;
        post.body = 'Test chatter post';
        
        FeedComment comment = new FeedComment();
        comment.CommentBody = 'Test chatter comment on test post';
        
        test.startTest();
            insert post;
            comment.FeedItemId = post.Id;
            insert comment;
        test.stopTest();
        
        Account resultAccount = [SELECT LastChatterDate__c FROM Account WHERE Id = :testAccount.Id];
        AccountFeed resultFeed = [Select (Select Id, FeedItemId, ParentId, CreatedDate From FeedComments Where Id = :comment.Id) From AccountFeed Where Id = :post.Id];
                                  
        system.assertEquals(resultAccount.LastChatterDate__c, resultFeed.FeedComments[0].CreatedDate);
    }
    
    static testMethod void multiUnitTest() {
        Account testAccount = new Account(Name='TestAccount');
        insert testAccount;
        
        Contact testContact = new Contact(LastName='TestContact');
        insert testContact;
        
        List<FeedItem> feedItemList = new List<FeedItem>();
        
        FeedItem accountPost = new FeedItem();
        accountPost.parentId = testAccount.Id;
        accountPost.body = 'Test chatter post';
        feedItemList.add(accountPost);
        
        FeedItem contactPost = new FeedItem();
        contactPost.ParentId = testContact.Id;
        contactPost.body = 'Test chatter post';
        feedItemList.add(contactPost);
        
        test.startTest();
            insert feedItemList;
        test.stopTest();
        
        Account resultAccount = [SELECT LastChatterDate__c FROM Account WHERE Id = :testAccount.Id];
        AccountFeed resultAccountFeed = [SELECT CreatedDate FROM AccountFeed WHERE Id = :accountPost.Id];
        system.assertEquals(resultAccountFeed.CreatedDate, resultAccount.LastChatterDate__c);
        
        Contact resultContact = [SELECT LastChatterDate__c FROM Contact WHERE Id = :testContact.Id];
        ContactFeed resultContactFeed = [SELECT CreatedDate FROM ContactFeed WHERE Id = :contactPost.Id];
        system.assertEquals(resultContactFeed.CreatedDate, resultContact.LastChatterDate__c);
    }
}

Here is the Last Chatter Date field definition:

    <fields>
        <fullName>LastChatterDate__c</fullName>
        <description>Used to record the date and time of the last chatter post or comment.</description>
        <externalId>false</externalId>
        <inlineHelpText>The date and time of the last Chatter post or comment.</inlineHelpText>
        <label>Last Chatter Date</label>
        <required>false</required>
        <trackFeedHistory>false</trackFeedHistory>
        <type>DateTime</type>
    </fields>

Discussion

You will need the LastChatterDate__c field on the Account and Contact sObject for the unit test to work.

Share

Recipe Activity - Please Log in to write a comment

Be the first to comment.

X

Vote to Verify a Recipe

Verifying a recipe is a way to give feedback to others and broaden your own understanding of the capabilities on Force.com. When you verify a recipe, please make sure the code runs, and the functionality solves the articulated problem as expected.

Please make sure:
  • All the necessary pieces are mentioned
  • You have tested the recipe in practice
  • Have sent any suggestions for improvements to the author

Please Log in to verify a recipe

You have voted to verify this recipe.