SF chatter feed: Threaded replies not included in replica

Originally asked by Syed Majid Hassan on 18 September 2022 (original question)


When syncing chatter feed comments from SF to Jira, the threaded replies in SF are not included in the replica and hence, never sent to Jira. Can you please help with this?


Comments:

Serhiy Onyshchenko commented on 22 September 2022

Hey, Syed Majid Hassan
I’ve added this to the outgoing sync script:

def feedResponse = httpClient.getResponse("/services/data/v54.0/chatter/feed-elements/0D57Q00000Pf2DiSAJ")
def js = new groovy.json.JsonSlurper()
def feedJson = groovy.json.JsonOutput.toJson(feedResponse.body)
def feedSubComments = feedResponse.body.capabilities.comments.page.items.collect { it.body.text }
debug.error("feed=${feedSubComments}")

where 0D57Q00000Pf2DiSAJ is an id of a comment:

and here’s the error produced:

You may then inject through the list of comments on an entity, fetch sub-comments via httpClient and then
turn them into a

def c = new com.exalate.basic.domain.hubobject.v1.BasicHubComment()c.body = "..."

Happy Exalating!

add them to the injected result

Answer by Syed Majid Hassan on 03 November 2022

The final scripts are here in full:

Jira Outgoing Expand source

replica.key            = issue.key
replica.type           = issue.type
replica.assignee       = issue.assignee
replica.reporter       = issue.reporter
replica.summary        = issue.summary
replica.description    = issue.description
replica.labels         = issue.labels

replica.comments = issue.comments.collect {
    comment ->
    def matcher  = comment.body =~ /\[~accountid:([\w:-]+)\]/
    def newCommentBody = comment.body
    matcher.each {
        target = nodeHelper.getUser(it[1])?.email
        newCommentBody = newCommentBody.replace(it[0],target)
    }
    comment.body = newCommentBody
    comment
}

replica.resolution     = issue.resolution
replica.status         = issue.status
replica.parentId       = issue.parentId
replica.priority       = issue.priority
replica.attachments    = issue.attachments
replica.project        = issue.project

//Comment these lines out if you are interested in sending the full list of versions and components of the source project. 
replica.project.versions = []
replica.project.components = []


Salesforce Outgoing Expand source

if(entity.entityType == "Case") {
replica.key            = entity.Id
replica.summary        = entity.Subject
replica.description    = entity.Description
replica.attachments    = entity.attachments
replica.Status         = entity.Status

replica.comments = entity.comments.inject([]) { result, comment -> 
    def res = httpClient.get("/services/data/v54.0/query/?q=SELECT+Name+from+User+where+id=%27${comment.author.key}%27")
    comment.body = nodeHelper.stripHtml(res.records.Name[0] + " commented: " + comment.body)
    result += comment

    def feedResponse = httpClient.getResponse("/services/data/v54.0/chatter/feed-elements/${comment.idStr}")
    def js = new groovy.json.JsonSlurper()
    def feedJson = groovy.json.JsonOutput.toJson(feedResponse.body)
    feedResponse.body.capabilities.comments.page.items.collect { 
        res = httpClient.get("/services/data/v54.0/query/?q=SELECT+Name+from+User+where+id=%27${it.user.id}%27")
        def c = new com.exalate.basic.domain.hubobject.v1.BasicHubComment()
        c.body = res.records.Name[0] + " commented: " + it.body.text
        c.id = it.id
        result += c
        }
    result
    }

}  

Salesforce Incoming Expand source

if(firstSync){
        entity.entityType = "Case"
}
if(entity.entityType == "Case"){
   entity.Subject      = replica.summary
   entity.Description  = replica.description
   entity.Origin       = "Web"
   entity.Status       = "New"
   entity.attachments  = attachmentHelper.mergeAttachments(entity, replica)
   
def commentMap = [
   "mathieu.lepoutre@idalko.com" : "0058d000004df3DAAQ",
   "syed.majid.hassan@idalko.com" : "0057Q000006fOOOQA2"
   ]

def flag = 0
replica.addedComments.collect {
    comment ->
    def matcher  = comment.body =~ /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)/
    def newCommentBody = comment.body
    
    matcher.each {
        newCommentBody = newCommentBody.replace(it[0],"")
        def res = httpClient.post("/services/data/v54.0/chatter/feed-elements", \
        "{\"body\":{\"messageSegments\":[{\"type\":\"Text\", \"text\":\"${newCommentBody} \" },{\"type\":\"Mention\", \"id\":\"${commentMap[it[0]]}\"}]},\"feedElementType\":\"FeedItem\",\"subjectId\":\"${entity.Id}\"}")
        flag = 1
        
    }
}

if (flag == 0) 
    entity.comments     = commentHelper.mergeComments(entity, replica) 


}


Here is a SF Jira - Threads + User mentions.mp4 (old community) of the use cases covered above.

Thanks

Majid


Answer by Syed Majid Hassan on 29 September 2022

Thanks for the direction here Serhiy Onyshchenko !

The code that I have come up with is the following:

if(entity.entityType == "Case") {
    replica.key            = entity.Id
    replica.summary        = entity.Subject
    replica.description    = entity.Description
    replica.attachments    = entity.attachments
    replica.Status         = entity.Status
    
    //Pick up normal SF chatter comments and append the username of the commenter
    replica.comments       = entity.comments.findAll {
        comment ->
        def res = httpClient.get("/services/data/v54.0/query/?q=SELECT+Name+from+User+where+id=%27${comment.author.key}%27")
        comment.body = nodeHelper.stripHtml(res.records.Name[0] + ": " + comment.body)
    }
    
    //Get the feed-element-id of all chatter threads in this case
    def feedIds = httpClient.get("/services/data/v54.0/query/?q=SELECT+id+from+CaseFeed+where+ParentId=%27${entity.Id}%27")
    
    //For each chatter thread, read all the replies and append usernames to it
    for(int i=0; i<feedIds.records.size(); i++){
        def feedResponse = httpClient.getResponse("/services/data/v54.0/chatter/feed-elements/${feedIds.records[i].Id}")
        def js = new groovy.json.JsonSlurper()
        def feedJson = groovy.json.JsonOutput.toJson(feedResponse.body)
        feedResponse.body.capabilities.comments.page.items.collect { 
            def res = httpClient.get("/services/data/v54.0/query/?q=SELECT+Name+from+User+where+id=%27${it.user.id}%27")
            def c = new com.exalate.basic.domain.hubobject.v1.BasicHubComment()
            c.body = res.records.Name[0] + " commented: " + it.body.text
            c.id = it.id
            replica.comments += c
            }
        }
}

This is working perfectly for sending threaded replies as well as normal comments.

Please let me know your thoughts here.

Thanks

Majid


Comments:

Stéphane Thillay commented on 13 July 2023

Hi Majid,

This script works and is useful.

I’m wondering what is the purpose of the line “def js =``new groovy.json.JsonSlurper()”?

My groovy skill is poor so I may miss the point. It looks like a variable/instance of a class, but it is not used elsewhere in the script.

Regards,

Stéphane

Syed Majid Hassan commented on 06 September 2023

Good catch Stéphane Thillay ,
I believe it was there to parse the response as part of the debugging effort needed in developing the script.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.