I'm trying to create a page when sprint is closed using Webhook and REST Endpoint. It fails with the following error:
http-nio-8080-exec-1 ERROR anonymous 571x10420x2 - <IP>,127.0.0.1 /rest/scriptrunner/latest/custom/sprintClosed/427 [c.o.s.r.rest.common.UserCustomScriptEndpoint] Script endpoint failed on method: POST sprintClosed
java.lang.Exception: {"statusCode":403,"data":{"authorized":false,"valid":true,"errors":[],"successful":false},"message":"Could not create content with type page"}
at Script512$1.handle(Script512.groovy:367)
at com.atlassian.plugins.rest.module.jersey.JerseyRequest$1.handle(JerseyRequest.java:115)
at com.atlassian.plugins.rest.module.jersey.JerseyRequest$1.handle(JerseyRequest.java:113)
at com.atlassian.plugins.rest.module.jersey.JerseyRequest$2.handle(JerseyRequest.java:134)
at com.atlassian.sal.core.net.HttpClientRequest.executeAndReturn(HttpClientRequest.java:104)
at com.atlassian.plugins.rest.module.jersey.JerseyRequest.executeAndReturn(JerseyRequest.java:131)
at com.atlassian.plugins.rest.module.jersey.JerseyRequest.execute(JerseyRequest.java:113)
at com.atlassian.applinks.core.auth.ApplicationLinkRequestAdaptor.execute(ApplicationLinkRequestAdaptor.java:47)
at com.atlassian.sal.api.net.Request$execute$1.call(Unknown Source)
at Script512$_run_closure1.doCall(Script512.groovy:363)
at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.doEndpoint(UserCustomScriptEndpoint.groovy:311)
at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.postUserEndpoint(UserCustomScriptEndpoint.groovy:210)Here is the respective part of the code:
import com.onresolve.scriptrunner.runner.customisers.PluginModuleCompilationCustomiser
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import javax.servlet.http.HttpServletRequest
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.applinks.api.ApplicationLink
import com.atlassian.applinks.api.ApplicationLinkService
import com.atlassian.applinks.api.application.confluence.ConfluenceApplicationType
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.sal.api.net.Request
import com.atlassian.sal.api.net.Response
import com.atlassian.sal.api.net.ResponseException
import com.atlassian.sal.api.net.ResponseHandler
import groovy.json.JsonBuilder
@WithPlugin("com.pyxis.greenhopper.jira")
@BaseScript CustomEndpointDelegate delegate
def ApplicationLink getPrimaryConfluenceLink() {
def applicationLinkService = ComponentLocator.getComponent(ApplicationLinkService.class)
final ApplicationLink conflLink = applicationLinkService.getPrimaryApplicationLink(ConfluenceApplicationType.class);
conflLink
}
sprintClosed(httpMethod: "POST") { MultivaluedMap queryParams, String body, HttpServletRequest request ->
//report generation
def parameters = [
type: "page",
title: "Page Title",
space: [
key: "SR"
],
ancestors: [
[
type: "page",
id: "655386"
]
],
body: [
storage: [
value: "Some Text",
representation: "storage"
]
]
]
def confluenceLink = getPrimaryConfluenceLink()
assert confluenceLink
def authenticatedRequestFactory = confluenceLink.createAuthenticatedRequestFactory()
authenticatedRequestFactory
.createRequest(Request.MethodType.POST, "rest/api/content")
.addHeader("Content-Type", "application/json")
.setRequestBody(new JsonBuilder(parameters).toString())
.execute(new ResponseHandler<Response>() {
@Override
void handle(Response response) throws ResponseException {
if(response.statusCode != HttpURLConnection.HTTP_OK) {
throw new Exception(response.getResponseBodyAsString())
}
}
})
}However, the following code works (executed via Script Console):
import com.onresolve.scriptrunner.runner.customisers.PluginModuleCompilationCustomiser
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import javax.servlet.http.HttpServletRequest
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.applinks.api.ApplicationLink
import com.atlassian.applinks.api.ApplicationLinkService
import com.atlassian.applinks.api.application.confluence.ConfluenceApplicationType
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.sal.api.net.Request
import com.atlassian.sal.api.net.Response
import com.atlassian.sal.api.net.ResponseException
import com.atlassian.sal.api.net.ResponseHandler
import groovy.json.JsonBuilder
@WithPlugin("com.pyxis.greenhopper.jira")
@BaseScript CustomEndpointDelegate delegate
def ApplicationLink getPrimaryConfluenceLink() {
def applicationLinkService = ComponentLocator.getComponent(ApplicationLinkService.class)
final ApplicationLink conflLink = applicationLinkService.getPrimaryApplicationLink(ConfluenceApplicationType.class);
conflLink
}
def parameters = [
type: "page",
title: "Page Title",
space: [
key: "SR"
],
ancestors: [
[
type: "page",
id: "655386"
]
],
body: [
storage: [
value: "Some Text",
representation: "storage"
]
]
]
def confluenceLink = getPrimaryConfluenceLink()
assert confluenceLink
def authenticatedRequestFactory = confluenceLink.createAuthenticatedRequestFactory()
authenticatedRequestFactory
.createRequest(Request.MethodType.POST, "rest/api/content")
.addHeader("Content-Type", "application/json")
.setRequestBody(new JsonBuilder(parameters).toString())
.execute(new ResponseHandler<Response>() {
@Override
void handle(Response response) throws ResponseException {
if(response.statusCode != HttpURLConnection.HTTP_OK) {
throw new Exception(response.getResponseBodyAsString())
}
}
})Environment:
Please advice.
Hi Denys,
Ok now I see what you mean, try something like
sprintClosed(
httpMethod: "POST"
) { MultivaluedMap queryParams, String body, HttpServletRequest request ->
def confluenceLink = getPrimaryConfluenceLink()
assert confluenceLink
def jiraAuthenticationContext = ComponentAccessor.getJiraAuthenticationContext()
def currentlyLoggedInUser = jiraAuthenticationContext.getLoggedInUser()
// get the user key who triggered the web hook
def userKey = queryParams.getFirst("user_key") as String
def user = ComponentAccessor.getUserManager().getUserByKey(userKey)
try {
jiraAuthenticationContext.setLoggedInUser(user)
def authenticatedRequestFactory = confluenceLink.createAuthenticatedRequestFactory()
// rest of the script
}
catch (any) {
log.error ("Could not perform action as user ${user}", any)
}
finally {
jiraAuthenticationContext.setLoggedInUser(currentlyLoggedInUser)
}
}Please let me know if this does the trick.
regards, Thanos
Hi Thanos,
Thank you for the prompt reply! I'm using OAuth (impersonation) and I assume everything is ok with the Application Link itself, as it works when I run script manually.
Here're some of my observations:
So I guess it is needed to associate the request with a certain user. Could you suggest how to do that?
Anyway, any suggestions are welcome.
Thank you.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Denys,
I do not see something wrong with your script. So I would suggest to check the way you configured the Application Link between the applications.
For example try to use OAuth (impersonation). For more information OAuth security for application links
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.