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.