Scriptrunner: How can I determine whether an attachment is internal or public?

Tom Hudgins May 25, 2021

In Scriptrunner I'm using ComponentAccessor.attachmentManager.getAttachments(issue) to get a list of attachments on my issue. Some of these attachments are internal and some are visible to customers in our Service Desk portal. How can I tell which is which? In the Attachment objects I get back from the call, I see no way to discern which attachments can be seen by external users and which can't.

Thanks

1 answer

0 votes
Payne
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 26, 2021

I don't have a full answer, but hopefully this will get you headed down the right path ...

An attachment itself is not internal or external, but rather the comment containing it is one or the other. Note that when you add a new attachment to a service desk issue, it creates a comment, whether you type anything or not. So it's the comment that is either internal or external. That, though, I don't know how to tell, but you may be able to dig around and figure it out. You can drop the following in Script Console for experimenting:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.issue.comments.Comment
import org.apache.log4j.Level
import com.atlassian.jira.issue.Issue
log.setLevel(Level.DEBUG)
Issue issue = ComponentAccessor.issueManager.getIssueByCurrentKey("SD-7181")
CommentManager commMgr = ComponentAccessor.getCommentManager()
List<Comment> comments = commMgr.getComments(issue)
comments.each{
log.debug(it.getBody())
}

Here is the Comment class documentation to see available methods: https://docs.atlassian.com/software/jira/docs/api/7.1.4/com/atlassian/jira/issue/comments/Comment.html 

Hope this helps!

Payne
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 26, 2021

This may be of some use to you, though I know you're working within ScriptRunner. The REST API will return comments for an issue and includes a "public" attribute for each.

https://docs.atlassian.com/jira-servicedesk/REST/3.6.2/#servicedeskapi/request/{issueIdOrKey}/comment-getRequestComments

Sample call: https://YOURDOMAIN/rest/servicedeskapi/request/SD-7181/comment

Tom Hudgins May 27, 2021

Thanks Payne,

It helped to understand that the visibility of attachments are dictated by the "comment" they are in so thanks for that. From some other examples, I was able to work this out and ended up creating a class to make things easier to work with. 

import com.atlassian.jira.bc.issue.comment.property.CommentPropertyService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.comments.Comment

import groovy.json.JsonSlurper
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.Issue;
import groovy.util.logging.Log4j

@Log4j

class MFComments {

List<Comment> comments
CommentPropertyService commentPropertyService
final String SD_PUBLIC_COMMENT = 'sd.public.comment'

def MFComments(Issue issue) {
commentPropertyService = ComponentAccessor.getComponent(CommentPropertyService)
def commentManager = ComponentAccessor.getCommentManager()
comments = commentManager.getComments(issue)
}

public List<Comment> getPublicComments() {
return getComments(true, false)
}

public List<Comment> getInternalComments() {
return getComments(false, true)
}

public List<String> getPublicAttachments() {
return findAttachments(getPublicComments())
}

public List<String> getInternalAttachments() {
return findAttachments(getInternalComments())
}

public List<String> getAllAttachments() {
return findAttachments(comments)
}

private List<String> findAttachments(List<Comment> comments) {
List<String> filenames = []
comments.each {
def matcher = it.body =~ /\[\^(.*)\]/
matcher.each {
filenames << it[1]
}
}
return filenames
}

public List<Comment> getComments(Boolean publicComment, Boolean internalComment) {

def isInternal = { Comment comment ->
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def commentProperty = commentPropertyService.getProperty(user, comment.id, SD_PUBLIC_COMMENT).getEntityProperty().getOrNull()
if (commentProperty) {
def props = new JsonSlurper().parseText(commentProperty.getValue())
props['internal']
}
else {
null
}
}
if (publicComment && internalComment) return comments
if (internalComment) return comments.findAll { isInternal(it)}
if (publicComment) return comments.findAll { ! isInternal(it)}
}
}

IssueManager issueMgr = ComponentAccessor.getIssueManager()
Issue issue = issueMgr.getIssueObject("MEETING-363")

MFComments mfComments = new MFComments(issue)

log.warn("All Comments: ${mfComments.getAllAttachments()}")
log.warn("Public Comments: ${mfComments.getPublicAttachments()}")
log.warn("Internal Comments: ${mfComments.getInternalAttachments()}")

 
Tom Hudgins May 27, 2021

Ugh. What's the trick to keep the formatting (indents) of the code block???

Anyway, hope this helps someone. 

I think there is another wrench in this puzzle in that if you delete a comment that has an attachment, the attachment still stays in the ticket but it will disappear from this method. Also, if you delete an attachment in the ticket but the comment still references it, I think you could get tripped up. I may need to use another call to get all the attachments in the ticket and correlate it against the list of attachments from the comments to get the definitive list. 

Seems like a right pain (see what I did there?) to do.

Thanks for your help

Like Payne likes this
Payne
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 28, 2021

Hey, good job, Tom! Good use of the CommentPropertyService. Thank you for sharing your solution.

Seems like a right pain (see what I did there?) to do. I do see what you did there :-) and agree that it ought not be this involved. Seems there ought to be an isInternal() method or something similar in the Comment class for this purpose.

Regarding indents, I don't know of a way to keep them when I paste code, which is indeed aggravating. If the block isn't too large I key them in by hand after pasting - either with spaces or alt+09 (on the number pad) for tabs.

Cheers!
Payne

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
SERVER
VERSION
8.16
TAGS
AUG Leaders

Atlassian Community Events