Validating Attachments/Links In Transitions

Writing a validator that needs to check for newly-added linked issues or attachments in the current transition is a special case. Unfortunately due to deficiencies in the Jira API you need to jump through some additional hoops. This code only applies where you have the Attachments or Issue Links field on the screen. If you can avoid this, you should try to do so. That is, require that the attachments or links are created through the standard operations before the transition is done. It will make your code simpler.

Typically you will get attachments and linked issues from AttachmentManager or IssueLinkManager…​ however these will only give you newly-added attachments/links once the current transaction has been committed. In a validator it has not as yet.

This in itself makes sense, the API deficiency is that there’s no way to get these things from the issue that is available to validators.

Validating Attachments Added this Transition

This code will only work in Jira 6.4 and above.

The following example details how to find properties of attachments added this transition, for example the file name. The Attachments field must be on the transition screen to get attachments like this.

import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.IssueFieldConstants import com.atlassian.jira.issue.attachment.TemporaryWebAttachment import com.atlassian.jira.issue.attachment.TemporaryWebAttachmentManager import webwork.action.ActionContext def temporaryAttachmentUtil = ComponentAccessor.getComponent(TemporaryWebAttachmentManager) def formToken = ActionContext.getRequest()?.getParameter(IssueFieldConstants.FORM_TOKEN) if (formToken) { def tempWebAttachments = temporaryAttachmentUtil.getTemporaryWebAttachmentsByFormToken(formToken) tempWebAttachments.each { TemporaryWebAttachment it -> log.debug "Uploaded attachment name: ${it.filename}" } }

Via the REST API, it’s not currently possible to create an issue with attachments, or add attachments on a transition. The form token above is not available in REST contexts, but because of this limitation it doesn’t matter.

Reading Attachments Added this Transition

If you need to read the contents of newly-added attachments, for in-depth validation, you can get the data like this:

import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.IssueFieldConstants import com.atlassian.jira.issue.attachment.FileSystemAttachmentDirectoryAccessor def attachmentDirectoryAccessor = ComponentAccessor.getComponent(FileSystemAttachmentDirectoryAccessor) def temporaryAttachmentDirectory = attachmentDirectoryAccessor.getTemporaryAttachmentDirectory() def newAttachmentNames = issue.modifiedFields.get(IssueFieldConstants.ATTACHMENT)?.newValue newAttachmentNames.each { String filename -> log.debug "File text:" + new File(temporaryAttachmentDirectory, filename).text }

Validating Links Added this Transition

The following example shows how to read links that have been added on the screen during the transition, and in this case, stops the action unless at least one blocks link has been added.

import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.IssueFieldConstants import com.atlassian.jira.issue.fields.IssueLinksSystemField import com.opensymphony.workflow.InvalidInputException import webwork.action.ActionContext def fieldManager = ComponentAccessor.getFieldManager() def linksSystemField = fieldManager.getField("issuelinks") as IssueLinksSystemField def request = ActionContext.getRequest() if (request) { def params = request.getParameterMap() def issueLinkingValue = linksSystemField.getRelevantParams(params) as IssueLinksSystemField.IssueLinkingValue if (!(issueLinkingValue.linkDescription == "blocks" && issueLinkingValue.linkedIssues.size() > 0)) { throw new InvalidInputException(IssueFieldConstants.ISSUE_LINKS, "You must link a blocker issue at this transition") } }

You should also allow for that the correct link may have been added previous to the transition, using the examples described here.

On this page