3

When a field is populated on an Opportunity record I want to alert a team of users of that. I don't want to spam them with emails so I thought to make a chatter group and then post chatter feed items with the details that they can review whenever.

I wrote this method and it seems to work posting the link to the Opportunity:

public static void competitionAlert(Map<Id, Opportunity> newMap, Map<Id, Opportunity> oldMap)
{
    // Find the Chatter group Id
    CollaborationGroup chatterGroup = [ SELECT Id, Name 
                                        FROM CollaborationGroup 
                                        WHERE Name = 'Competitive Intelligence'];

    List<FeedItem> feedPost = new List<FeedItem>();

    // loop the Opportunities to see if the compeitition field changed.
    for (Opportunity  oppy : newMap.values())
    {
        if(
            oppy.Competition__c != oldMap.get(oppy.Id).Competition__c &&
            oppy.Competition__c != null
        )
        {
            // create a chatter feed post alerting the team
            FeedItem fpost = new FeedItem();
                fpost.ParentId = chatterGroup.Id;
                fpost.LinkURL = URL.getSalesforceBaseUrl().toExternalForm() + '/' +oppy.Id;
                fpost.Title = oppy.Name;
                fpost.Body = 'An Opportunity was flagged as "Closed Lost" to ' + oppy.Competition__c + ' please review.';
            feedPost.add(fpost);
        }
    }
insert feedPost;
}   

The challenge is that the chatter group needs to be private, so when I lock the group down I get errors when a user who does not have access triggers the method and tries to create the post.

Is there a way to post into groups without having access to the group or a way to post as a user who does?

FINAL Solution:

Handler Class:

public static List<Opportunity> competitionAlertFilter(Map<Id, Opportunity> newMap, Map<Id, Opportunity> oldMap)
{
    List<Opportunity> oppy = new List<Opportunity>();

    // loop the Opportunities to see if the compeitition field changed.
    for (Opportunity  o : newMap.values())
    {
        if(
            o.Competition__c != oldMap.get(o.Id).Competition__c &&
            o.Competition__c != null
        )
            {
                oppy.add(o);
            }
    }
    return oppy;
}

public static void competitionAlert(List<Opportunity> chatFilter)
{
    ChatterPosts.createCompetitiveIntelligencePost(chatFilter);
}
}

Extender Class

public without sharing class ChatterPosts {

public static void createCompetitiveIntelligencePost(List<Opportunity> chatFilter)
{       
    // Find the Chatter group Id
    CollaborationGroup chatterGroup = [ SELECT Id, Name 
                                        FROM CollaborationGroup 
                                        WHERE Name = 'Competitive Intelligence'];

    List<FeedItem> feedPost = new List<FeedItem>();

    // loop the Opportunities to see if the compeitition field changed.
    for (Opportunity  oppy : chatfilter)
    {
        // create a chatter feed post alerting the team
        FeedItem fpost = new FeedItem();
            fpost.ParentId = chatterGroup.Id;
            fpost.LinkURL = URL.getSalesforceBaseUrl().toExternalForm() + '/' +oppy.Id;
            fpost.Title = oppy.Name;
            fpost.Body = 'An Opportunity was flagged as "Closed Lost" to ' + oppy.Competition__c + ' please review.';
        feedPost.add(fpost);
    }
insert feedPost;
}    

}

I'm excited about this methodology because for future use cases I can pass whatever data to the ChatterPosts class and not run into this issue again.

1

It's a very common problem. I have already faced the same issue.the solution is to move the same functionality in the trigger. As the trigger run on system mode,then there will be no issue regarding access.Then error what you get will be resolve. I have tried and it is working fine for me.

|improve this answer|||||
  • what if the specific code runs without sharing class? – Santanu Boral Apr 13 '17 at 18:06
  • I think Dan is facing the issue because it was a sharing class..And without knowing functionality i can't suggest him to make it without sharing – Avijit Das Apr 13 '17 at 18:08
  • the class is a trigger handler so I can't make the whole thing without sharing as I don't want to break the other things going on. I think I can break this out into a separate class and make that without sharing. I'll give that a try. – Dan Wooding Apr 13 '17 at 18:50
1

Try using the process Builder, When a field is populated on an Opportunity record you can create a post on a specific chatter group based what you need.

I would recommend you check out the this Trailhead which seems to address your use case. Select object/field conditions enter image description here create configure your actions (post to a chatter group, something) enter image description here

You can also reference an apex class to execute upon your object/record update.

|improve this answer|||||
  • Process Builder does not work. I get "Error Occurred: You don't have permission to do this." when trying to post as a non member of the group. – Dan Wooding Apr 13 '17 at 18:48
  • As a sys admin, I recently created a Process that basically Posts on a Chatter private group without being part of it. I think you can even flush your apex class and simply reference the Custom Object fields you want + the message to the chatter group (As a sys admin, even if it is set to private, and you are not a member of it) – glls Apr 13 '17 at 19:16
  • Interesting, I must have been doing something wrong. I went with code as I can set a link to the record which didn't seem to be available in PB. – Dan Wooding Apr 13 '17 at 19:24
  • @glls I am wondering how your process builder is configured, because we have the same problem as Dan: if the user is not in the private group, the process errors out when the user makes the change that fires the process. – David Cheng Mar 11 at 16:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.