[SalesForce] How to display a image in case feed

I have a custom object named 'comments' with which i made a 'action'.it is having a trigger handler class

 public void onAfterInsert(Comments__c[] newComments){

        if(newComments.size()>0){
            for(Comments__c comRec:newComments){
                FeedItem post = new FeedItem();
                post.ParentId = comRec.case__c; 
                post.IsRichText = true;
                post.body =  comRec.Case_Comments__c;  
                feedItemInsertList.add(post);
                try{
                    if(feedItemInsertList.size()>0){
                        insert post;
                    }
                }
                catch(Exception e){
                    system.debug(e.getMessage());
                } 
            } 

the 'case comments' field is a rich text but when i add a image to it in case feed it is creating a comment but I was not able to view the image in feed but in detail page the image is available.
It was throwing an error

System.DmlException: Insert failed. First exception on row 0; first
error: INVALID_CROSS_REFERENCE_KEY, Referenced file id is invalid, not
accessible, or does not exist: [RawBody]

Best Answer

In case if image has been added to Rich Text Area field, its body will be stored as ContentReference record. If you look at rich field, format will be like:

<img alt="User-added image" src="https://......."></img>

Where src attribute contains link to image.

We can define PageReference and get its content by:

string richTxt = '<img alt="User-added image" src="https://c.naxx.content.force.com/servlet/rtaImage?..."></img>';
String imgRef = richTxt.substringBetween('src="', '"');
PageReference pageRef = new PageReference(imgRef);

Then insert ContentVersion record:

ContentVersion cVersion = new ContentVersion (title = 'title', VersionData = pageRef.getContent(), PathOnClient = 'my.png');
insert cVersion;

As you can see there is constant name, reason of that - ContentReference doesn't have name, I think using attachment will be better option

And create Feed:

FeedItem fItem = new FeedItem(RelatedRecordId = cVersion.id, type = 'ContentPost', parentId = '50036000000rxec');
insert fItem;

One more thing I want to mention here is - it's not allowed to insert ContentReference and Feed in single context, queueable can be used here.

Assuming everything above, we can implement following triggerHandler method:

@future(callout=true)
public static void ProceedWithComments(set<id> caseIds) {

    list<Case> cases = [select id, Case_Comments__c from Case where id in :caseIds];

    map<id, ContentVersion> caseIdToContentMap = new map<id, ContentVersion> ();

    for (Case cs :cases){
        String imgRef = cs.Case_Comments__c.substringBetween('src="', '"').replace('amp;','');

        if (String.isNotBlank(imgRef)){
            PageReference pageRef = new PageReference(imgRef);
            ContentVersion cVersion = new ContentVersion (title = 'From Case', VersionData = pageRef.getContent(), PathOnClient = 'my.png');
            caseIdToContentMap.put(cs.id, cVersion);
        }
    }

    insert caseIdToContentMap.values();

    System.enqueueJob(new QueueableFeedInsert(caseIdToContentMap));

} 

Queueable class:

public with sharing class QueueableFeedInsert implements Queueable {

    private map <id, ContentVersion> caseIdToContentMap;

    public QueueableFeedInsert(map<id, ContentVersion> caseIdToContentMap) {
        this.caseIdToContentMap = caseIdToContentMap;
    }

    public void execute(QueueableContext context) {

        list<FeedItem> feedToInsert = new list<FeedItem>();

        for (Id csId :caseIdToContentMap.keySet()){
            feedToInsert.add(new FeedItem(RelatedRecordId = caseIdToContentMap.get(csid).id, type = 'ContentPost', parentId = csid));
        }

        insert feedToInsert;

    }
}
Related Topic