Synchronise Confluence Links

ConfluenceLinks.groovy
import com.atlassian.jira.bc.issue.link.RemoteIssueLinkService
import com.atlassian.jira.component.ComponentAccessor
import com.exalate.api.domain.connection.IConnection
import com.exalate.api.exception.IssueTrackerException
import com.exalate.api.node.INodeService
import com.exalate.basic.domain.hubobject.v1.BasicHubIssue
import com.exalate.processor.jira.JiraChangeIssueProcessor
import com.exalate.processor.jira.JiraCreateIssueProcessor
import com.exalate.processor.jira.JiraCreateReplicaProcessor
import org.slf4j.LoggerFactory






class ConfluenceLinks {
    static LOG = LoggerFactory.getLogger("com.exalate.script.ConfluenceLinks")
    
    
    
    static BasicHubIssue send() {
        def context
        if (JiraCreateReplicaProcessor.dataFilterContext != null
                && JiraCreateReplicaProcessor.dataFilterContext.get()) {
            context = JiraCreateReplicaProcessor.threadLocalContext.get()
        } else {
            throw new IssueTrackerException(""" No context for executing external script ConfluenceLinks.groovy. Please contact Exalate Support.""".toString())
        }
        
        final BasicHubIssue replica = context.replica as BasicHubIssue
        final BasicHubIssue issue = context.issue as BasicHubIssue
        final IConnection connection = context.connection
        send(replica, issue, connection)
    }
    
    
    static BasicHubIssue send(BasicHubIssue replica, BasicHubIssue issue, IConnection connection) {
        def nserv = ComponentAccessor.getOSGiComponentInstanceOfType(INodeService.class)
        def rilserv = ComponentAccessor.getComponent(RemoteIssueLinkService.class)
        def im = ComponentAccessor.getIssueManager()
    
        def proxyUser = nserv.getProxyUser()
        def jIssue = im.getIssueObject(issue.id as Long)
        def urlLinksForIssue = rilserv.getRemoteIssueLinksForIssue(proxyUser, jIssue)?.remoteIssueLinks ?: []
        
        if (urlLinksForIssue.size() > 0) LOG.info("Url links = ${urlLinksForIssue?.first().properties}")
        
        List<Clink> confluenceLinks = []
     
        urlLinksForIssue.each {
            link ->
                if (Clink.isConfluenceLink(link)) confluenceLinks.add new Clink(link)
                
        }
        
        replica.customKeys."confluencelinks" = confluenceLinks
        replica
    }
    
    static void receive() {
        def context
    
        if (JiraCreateIssueProcessor.createProcessorContext.get() == true) {
            context = JiraCreateIssueProcessor.threadLocalContext.get()
        
        } else if (JiraChangeIssueProcessor.changeProcessorContext.get() == true) {
            context = JiraChangeIssueProcessor.threadLocalContext.get()
        } else {
            throw new IssueTrackerException(""" No context for executing external script ConfluenceLinks.groovy. Please contact Exalate Support.""".toString())
        }
    
        final BasicHubIssue replica = context.replica as BasicHubIssue
        final BasicHubIssue issue = context.issue as BasicHubIssue
        final IConnection connection = context.connection
        receive(replica, issue, connection)
    
    }
    
    
    static void receive(BasicHubIssue replica, BasicHubIssue issue, IConnection connection) {
        
        // Check  if we have the right argument
        
        if (!replica.customKeys."confluencelinks" ) {
            LOG.warn("replica.customKeys.\"confluencelinks\" is not provided ")
            return
        }
        
        List confluenceLinks = replica.customKeys."confluencelinks"
        if (confluenceLinks.isEmpty()) {
            return
        }
    
        LOG.info("Confluence links - ${confluenceLinks}")
    
        def nserv = ComponentAccessor.getOSGiComponentInstanceOfType(INodeService.class)
        def im = ComponentAccessor.getIssueManager()
    
        def proxyUser = nserv.getProxyUser()
        def jIssue = im.getIssueObject(issue.id as Long)
        
        confluenceLinks.each {
            clinkData ->
                LOG.debug("CLINK --- ${clinkData}")
                def aClink = new Clink(clinkData)
                aClink.createConfluenceLink(proxyUser, jIssue)
        }
    }
    
}




Clink.groovy
import com.atlassian.jira.bc.issue.link.RemoteIssueLinkService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.link.RemoteIssueLink
import com.atlassian.jira.issue.link.RemoteIssueLinkBuilder
import com.atlassian.jira.user.ApplicationUser
import com.exalate.api.node.INodeService
import org.slf4j.LoggerFactory

class Clink {
    static LOG = LoggerFactory.getLogger("com.exalate.script.CLink")
    
    static String CONFLUENCEAPP = "com.atlassian.confluence"
    String title
    String url
    String globalId
    String relationship
    String applicationName
    
    Clink(RemoteIssueLink remoteIssueLink) {
        if (remoteIssueLink.applicationType != CONFLUENCEAPP)
            throw new IllegalArgumentException("The link is not a confluence link")
        
        this.title = remoteIssueLink.title
        this.url = remoteIssueLink.url
        this.globalId = remoteIssueLink.globalId
        this.relationship = remoteIssueLink.relationship
        this.applicationName = remoteIssueLink.applicationName
    }
    
    Clink(Map<String, String> clinkData) {
        this.title = clinkData.title
        this.url = clinkData.url
        this.globalId = clinkData.globalId
        this.relationship = clinkData.relationship
        this.applicationName = clinkData.applicationName
        
    }
    
    static Boolean isConfluenceLink(RemoteIssueLink remoteIssueLink) {
        return (remoteIssueLink.applicationType == CONFLUENCEAPP)
    }
    
    void createConfluenceLink(ApplicationUser proxyUser, Issue localIssue) {
        if (isDuplicate(localIssue)) return

        RemoteIssueLinkService remoteIssueLinkService = ComponentAccessor.getComponent(RemoteIssueLinkService.class)

        RemoteIssueLink remoteIssueLink = new RemoteIssueLinkBuilder()
                .issueId(localIssue.id)
                .relationship(this.relationship)
                .title(this.title)
                .url(this.url)
                .globalId(this.globalId)
                .id()
                .summary()
                .applicationType(CONFLUENCEAPP)
                .applicationName(this.applicationName)
                .build()

        RemoteIssueLinkService.CreateValidationResult validationResult = remoteIssueLinkService.validateCreate(proxyUser, remoteIssueLink)

        if (validationResult.isValid()) {
            RemoteIssueLinkService.RemoteIssueLinkResult result = remoteIssueLinkService.create(proxyUser, validationResult)

            if (!result.isValid()) {
                LOG.error("Failed to create the issue link due to ${result.errorCollection.toString()}")
            }
        } else {
            LOG.error("Failed to create the issue link due to ${validationResult.errorCollection.toString()}")
        }
    }
    
    boolean isDuplicate(Issue jIssue) {
        def nserv = ComponentAccessor.getOSGiComponentInstanceOfType(INodeService.class)
        def rilserv = ComponentAccessor.getComponent(RemoteIssueLinkService.class)
        def im = ComponentAccessor.getIssueManager()
    
        def proxyUser = nserv.getProxyUser()
        def urlLinksForIssue = rilserv.getRemoteIssueLinksForIssue(proxyUser, jIssue)?.remoteIssueLinks ?: []
        return urlLinksForIssue.find {it.globalId == this.globalId}
    }
}