Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

REST Endpoint coding problem

Dan27
Contributor
March 13, 2019

1. I made a button using 'Script Fragments' that will call a 'REST Endpoints' script. The button made for the user a mail with all of the issue details.
When I clicked the button in the issue view, It worked perfectly.
When I tried to click the button from the Board:

publishmail-process.jpg

I got this error:

publishmail-error.JPG
Attached the script fragments script and the script REST Endpoints script.

This is the full link of the script fragments: 
/rest/scriptrunner/latest/custom/PublishMailDialog?issueId=$issueId&issueKey=$issue.getKey()

 

Atlassian and Adaptavist support told me this is a coding problem inside the REST, In the HTML part.. Can you help me to understand what is the problem?

This is my code (I removed all of the definition of values , So ignore it)

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import javax.servlet.http.HttpServletRequest;
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import org.apache.commons.lang.StringUtils
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpMethod
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.lang.StringUtils
import groovy.json.*
import com.atlassian.crowd.embedded.impl.ImmutableGroup
import com.atlassian.jira.issue.customfields.impl.MultiGroupCFType
import com.atlassian.jira.issue.fields.NavigableField
import com.atlassian.jira.issue.fields.FieldManager;
import com.atlassian.jira.issue.RendererManager;

@BaseScript CustomEndpointDelegate delegate

PublishMailDialog() { MultivaluedMap queryParams ->


def issueId = queryParams.getFirst("issueId") as String

String issueKey // use the issueId to retrieve this issue
String parentId

for (String theKey: queryParams.keySet()) {
String value = queryParams.get(theKey);
if (theKey.equals("issueKey")) {
issueKey = value
issueKey = issueKey.substring(1); // trimming the leading'['
issueKey = issueKey.substring(0, issueKey.length() - 1); // trimming the ending'['
}
}

//Test preview

issueId = queryParams.getFirst("issueId") as String
//test
IssueManager issueManager = ComponentAccessor.getIssueManager();
Issue issue = issueManager.getIssueObject(Long.parseLong(issueId));
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();

def groupManager = ComponentAccessor.groupManager;
def groups = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("E-mail Recipients")) as List;
if(groups==null)
{

def dialog =
"""

<html>
<head>
<script>
function goBack() {
window.history.back()
}
</script>
<style>
body {
font-family: 'Open Sans', sans-serif;
font-size: 14px;
text-align: center;
}
h1 {
font-size: 15px;
color: #333;
line-height: 22px;
font-weight: bold;
}
.reportheader {
border-bottom: #F86E00 1px solid;
margin-bottom: 7px;
text-align: center;

}

div {
text-align: center;
}
#1 {
text-align: center;
}
.logo {
width: 65px;
float: right;
margin: 6px 0px 0px 0px;
}
.st1 {
fill: #FE5000;
}
.st0 {
fill: #414042;
}
</style>
</head>
<body>
<div id="1">
<br><br><br><br>

<div class="reportheader"><h1>For publish mail, You need to fill "E-mail Recipients" field</h1></div>
<br><br>

<div class="aui-dialog2-footer-actions" style="color:#333; font-size: 15px; text-align:center; font-family:'Open Sans', sans-serif; font-weight: bold;">

<button onclick="goBack()">Close</button>
</div>
</div>

</body>
</html>
"""
Response.ok().type(MediaType.TEXT_HTML).entity(dialog.toString()).build()
}
else
{
groups= groups.getAt(0) as ImmutableGroup;
log.warn groups;
log.warn fixVersion;
def baseUrl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl");
log.warn baseUrl
def baseurlIssue = baseUrl+'/browse/'+issue;
log.warn baseurlIssue

def fieldManager = ComponentAccessor.getFieldManager()

def fieldLayoutItem = ComponentAccessor.getFieldLayoutManager().getFieldLayout(issue).getFieldLayoutItem("description")
def field = fieldManager.getField("description")
NavigableField navigableField = (NavigableField)field
def descriptionHTML = navigableField.getColumnViewHtml(fieldLayoutItem, new HashMap(), issue)

def dialog =
"""

<html>
<head>
<script>
function goBack() {
window.history.back()
}
</script>
<style>
body {
font-family: 'Open Sans', sans-serif;
max-width: 800px;
font-size: 14px;
display: block;
margin: 8px;
}
a {
font-family: 'Open Sans', sans-serif;
color: #00A79D;
opacity: 0.8;
}
h1 {
font-size: 15px;
display: inline-block;
color: #333;
line-height: 22px;
font-weight: bold;
}
.reportheader {
border-bottom: #F86E00 1px solid;
margin-bottom: 10px;
}

div {
display: block;
}
h2 {
display: block;
color: #F86E00;
font-size: 14px;
margin: 0px 0px 10px 0px;
}
.reportpropertywrapper {
margin-left: 10px;
}
h3 {
color: #333333;
font-size: 14px;
margin: 0px 0px 0px 0px !important;
}
p {
color: #666;
margin-top: 5px;
margin-left: 10px;
margin-bottom: 10px;
}
h4 {
margin: 0px !important;
font-size: 12px;
color: #333333;
}
* {
transform-origin: 0px 0px 0px;
}
.logo {
width: 65px;
float: right;
margin: 6px 0px 0px 0px;
}
.st1 {
fill: #FE5000;
}
.st0 {
fill: #414042;
}
</style>
</head>
<body>
<div class="reportheader">

<h1>This mail will send to group: '${groups.getName()}'</h1><br>
<h1>Issue Report for Bug Customer Key <a href='${baseurlIssue}'>${issue}</a></h1></div>

<div class="reportsection"><h2></h2>
<div class="reportpropertywrapper"><h3>Description</h3>
<h4></h4>
<p>${issue.getSummary()}</p>
</div>
<div class="reportpropertywrapper"><h3>Product Name</h3>
<h4></h4>
<p>${ProductName}</p>
</div>
<div class="reportpropertywrapper"><h3>Version</h3>
<h4>The version on which the bug was found</h4>
<p>${Inversion}</p>
</div>
<div class="reportpropertywrapper"><h3>Steps to reproduce</h3>
<h4></h4>
<p>${descriptionHTML}</p>
</div>
<div class="reportpropertywrapper"><h3>Root cause & Suggested solution (in code)</h3>
<h4></h4>
<p>${RootCause}</p>
</div>
</div>

<div class="reportsection"><h2>Priority & Severity</h2>
<div class="reportpropertywrapper"><h3>Regression?</h3>
<h4></h4>
<p>${Regression}</p>
</div>
<div class="reportpropertywrapper"><h3>Regression to version</h3>
<h4></h4>
<p>${RegressionInVersion}</p>
</div>
<div class="reportpropertywrapper"><h3>Impact on customer experience</h3>
<h4>Low/Medium/high</h4>
<p>${issue.getPriority().name}</p>
</div>
<div class="reportpropertywrapper"><h3>Workaround</h3>
<h4></h4>
<p>${Workaround}</p>
</div>
</div>

<div class="reportsection"><h2>Fix For</h2>
<div class="reportpropertywrapper"><h3>Effort estimation</h3>
<h4>In story points</h4>
<p>${StoryPoints}</p>
</div>
<div class="reportpropertywrapper"><h3>Risk estimation</h3>
<h4>Areas or functionality that may be affected by the fix</h4>
<p>${RiskEstimation}</p>
</div>
<div class="reportpropertywrapper"><h3>Target fix pack</h3>
<h4></h4>
<p>${if(issue.getStatus().name!='Done'){fixVersion} else{return 'NA'}}</p>
</div>
</div>

<div class="reportsection"><h2>Solution</h2>
<div class="reportpropertywrapper"><h3>Commit ID</h3>
<h4></h4>
<p>Filled automatically from GIT</p>
</div>
<div class="reportpropertywrapper"><h3>Fixed in version</h3>
<h4></h4>
<p>${if(issue.getStatus().name=='Done'){fixVersion} else{return 'NA'}}</p>
</div>
<div class="reportpropertywrapper"><h3>Testing guidelines</h3>
<h4></h4>
<p>See steps to reproduce (no field is required, should be in the text written in the description field)</p>
</div>
<div class="reportpropertywrapper"><h3>Manager approved</h3>
<h4></h4>
<p>${ManagerName}</p>
</div>
</div>
</body>

<footer>
<div>
<form method="get" id ="fConvert">
<input type="hidden" name="issueId" value="${issueId}">
<br><br>
<h1>Please confirm that you wish to Publish this mail</h1>
<br>

<button type="submit" onClick="this.form.submit(); this.disabled=true;">Publish</button>

</form>
<button onclick="goBack()" id="dialog-close-button" class="aui-button aui-button-link">Cancel</button>

<script>
document.getElementById("fConvert").action = "/rest/scriptrunner/latest/custom/PublishMail";
</script>
</div>



</footer>

</html>
"""

Response.ok().type(MediaType.TEXT_HTML).entity(dialog.toString()).build()
}
}

 

 

Thanks,

Daniel

2 answers

0 votes
Matthew Clark
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.
March 23, 2019

I

0 votes
Matthew Clark
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.
March 17, 2019

Hi Daniel

I think the issue is being caused by the way you are building the html for the aui-dialog2 box.


When your Rest endpoint is called it returns an entirely new page outside of the dialog section, rather than within it.


The failure is happening when looking for expected properties of the aui-dialog2 element and I suspect because you are returning an entirely new page instead of adding content within the dialog section, it is throwing an error when trying to run functions on elements it expects to exist in the current context.

I am not a JavaScript expert so it would take me longer to find the exact technical reason for this error, however, I have used your code (without the inline styles and scripts) on a test instance and it works correctly if contained within the dialog section correctly.

If you redefine your code within the correct dialog section I think this will work. You might want to define your styles and JavaScript functions in separate web Resource files instead of trying to place them inline.

e.g:

        def dialog =
"""
<section role="dialog" id="sr-dialog" class="aui-layer aui-dialog2 aui-dialog2-medium" aria-hidden="true" data-aui-remove-on-hide="true">
<header class="aui-dialog2-header">
<h2 class="aui-dialog2-header-main">Some dialog</h2>
<a class="aui-dialog2-header-close">
<span class="aui-icon aui-icon-small aui-iconfont-close-dialog">Close</span>
</a>
</header>
<div class="aui-dialog2-content">
<!-- Put your content in here -->
<div class="reportheader"><h1>For publish mail, You need to fill "E-mail Recipients" field</h1></div>
<br><br>
</div>
<div class="aui-dialog2-footer-actions" style="color:#333; font-size: 15px; text-align:center; font-family:'Open Sans', sans-serif; font-weight: bold;">
<button id="dialog-close-button" class="aui-button aui-button-link">Close</button>
</div>
<div class="aui-dialog2-footer-hint">Some hint here if you like</div>
</footer>
</section>
"""

 

This guide from Jira provides more information on how to use the dialog2 Modal Dialog provided by Jira:

dialog2 guide

Dan27
Contributor
March 18, 2019

In the view screen this dialog didn't work..

Matthew Clark
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.
March 19, 2019

Can you show me what you did and in what way it did not work?

i.e. Do you see errors or anything in the console logs?

I have tried this already without your inline CSS and JavaScript and it did work on both the view and board screens so we are probably just missing something that I will only be able to pick out if I see the code.

Dan27
Contributor
March 20, 2019

Hi @Matthew Clark  ,

My code is the same as I put here in the ticket..

When I click the button in the view screen- It opened a new tab.

When I click the button in the Board- It opened a dialog..

Matthew Clark
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.
March 23, 2019

Can you tell me exactly what this part of your code does?

<footer>
<div>
<form method="get" id ="fConvert">
<input type="hidden" name="issueId" value="${issueId}">
<br><br>
<h1>Please confirm that you wish to Publish this mail</h1>
<br>
<button type="submit" onClick="this.form.submit(); this.disabled=true;">Publish</button>
</form>
<button onclick="goBack()" id="dialog-close-button" class="aui-button aui-button-link">Cancel</button>
<script>
document.getElementById("fConvert").action = "/rest/scriptrunner/latest/custom/PublishMail";
</script>
</div>
</footer>

I can see you submit a form to a rest endpoint but I do not know what that endpoint does without seeing it.


You appear to be submitting the issueId, but can you explain what your "/rest/scriptrunner/latest/custom/PublishMail" endpoint does with the issueId?

Matthew Clark
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.
March 23, 2019

Hi Daniel

On second thought, I do not really need to know what the form is doing, I was just trying to work out the best ajax replacement for the form submission. I just replaced it with an ajax get request that submits the issueKey to another rest endpoint, as that looks like what you were doing anyway with the form submission.
I basically re-wrote your rest endpoint and have made a snippet on my bitbucket repo for you to try. It is quite long so I think it is easier to read on bit bucket. Here is the link:

Rest Endpoint Advanced Dialog Example

Note that I have tested this on both the View and Board Pages and it works.
I have made assumptions that your version fields are Collections and I have put a lot of groovy null safe code around the custom fields to make the code shorter and easier to read, as well as help it handle when fields are missing or values are empty.

You may need to add your own styling back in but I would advise against using the same CSS identifiers that Jira uses otherwise you could end up changing how other areas of Jira look outside of the Dialog box as well.

Can you give it a try and let us know?

Dan27
Contributor
March 24, 2019

Hi @Matthew Clark  ,

Thank you for your time ! There is a problem, In my view issue screens, the button opens the page in a new page (not a dialog).

It has to be the same in both scenarios (view and board).111.JPG

 

Thanks,

Daniel Mor

Matthew Clark
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.
March 24, 2019

If the button opens in a new page the problem is more likely to do with the web item that creates the button you click on.

Make sure there is no space in the key by adding an underscore like below:

Screenshot 2019-03-24 at 11.50.57.png


Also, just so you know, there is a scriptrunner bug that makes rest endpoints run twice on the Agile Boards page, so you might see 2 dialogs. Here is the bug SRJIRA-3152.

It means you may need to click close twice when opening the dialog on the agile board's pages until we fix it, but it should still work.

Like Kaveh M Mehr likes this
Dan27
Contributor
March 24, 2019

Perfect! Now in the view & board screen It opened a dialog!

Thanks

 

But now, the Publish dialog Stuck in the dialog after I press the Publish button.

 

Matthew Clark
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.
March 24, 2019

Great !

You will have to show me the PublishMail RestEndpoint. I tested it with a basic Rest Endpoint that just logs the parameter parsed to it and returns the string "Success" so I could make sure the second rest endpoint was working with the ajax call.

My PublishMail looks like this if you want to try the same test (it does not do anything but log to atlassian-jira.log):

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonBuilder
import groovy.transform.BaseScript
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import org.apache.log4j.Logger
import org.apache.log4j.Level
def log = Logger.getLogger(getClass())
log.setLevel(Level.DEBUG)

@BaseScript CustomEndpointDelegate delegate

PublishMail(httpMethod: "GET", groups: ["jira-administrators"]) { MultivaluedMap queryParams, String body ->
log.debug("queryParams = " + queryParams)
return Response.ok(new JsonBuilder([result: "Success"]).toString()).build();
}

//Example response for queryParams log:
//[issueId:[SSPA-9], _:[1553382484189]]
Dan27
Contributor
March 24, 2019

I tried your code, It still stuck in the dialog...

This is my code of the second rest (I deleted some not important data):

 

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import com.atlassian.jira.issue.issuetype.IssueType
import javax.ws.rs.core.Response
import javax.ws.rs.core.MultivaluedMap
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.config.IssueTypeManager;
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.mail.Email
import com.atlassian.mail.server.MailServerManager
import com.atlassian.mail.server.SMTPMailServer
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpMethod
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.lang.StringUtils
import groovy.json.*
import com.atlassian.jira.issue.customfields.impl.MultiGroupCFType
import com.atlassian.crowd.embedded.impl.ImmutableGroup
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.config.properties.APKeys
import com.atlassian.jira.issue.fields.NavigableField
import com.atlassian.jira.issue.fields.FieldManager;
import com.atlassian.jira.issue.RendererManager;

@BaseScript CustomEndpointDelegate delegate
PublishMail(httpMethod: "GET") {
MultivaluedMap queryParams,String body, HttpServletRequest request ->
log.warn 1;
String theUrltoReturn = ""
String issueId;
String clonedMessage;
try {
log.warn 2
issueId = queryParams.getFirst("issueId") as String
//test
log.warn issueId

IssueManager issueManager = ComponentAccessor.getIssueManager();
Issue issue = issueManager.getIssueObject(issueId);
log.warn issue
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
def bcc="";
//Get group details
def groupManager = ComponentAccessor.groupManager;
def groups = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("E-mail Recipients")) as List;
log.warn groups
def sizeGroup=groups.size();
groups= groups.getAt(0) as ImmutableGroup
log.warn sizeGroup
log.warn groups
//return groups[0].getName();
//def temp =issue.getCustomFieldValue(com.atlassian.jira.component.ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Group Mails"))*.name as List


sendEmail(bcc,'Issue: '+issue.toString(),createMessage(issue.toString()));
log.warn 5
def baseURL = ComponentAccessor.getApplicationProperties()getString(APKeys.JIRA_BASEURL)

//theUrltoReturn = request.getHeader("reffer");
theUrltoReturn = baseURL+'/browse/'+issue

catch (e) {
return Response.ok(new JsonBuilder([result: "Success"]).toString()).build();
//return Response.serverError().entity([error: e.message]).build();
}

Response.temporaryRedirect(URI.create(theUrltoReturn)).build()
}

 

// Create an email
def sendEmail(String emailAddr, String subject, String body) {
log.warn 8
//MailServerManager mailServerManager = ComponentAccessor.getMailServerManager();
def mailServer = ComponentAccessor.getMailServerManager().getDefaultSMTPMailServer();

//if (mailServer) {
try{
Email email = new Email(emailAddr)
email.setMimeType("text/html")
email.setSubject(subject)
email.setBody(body)
mailServer.send(email)
log.debug("Mail sent")
}

catch(Exception e) {
log.warn("Please make sure that a valid mailServer is configured")
log.warn e;
}
}

//Create message
def createMessage(String curIissue) {
log.warn 9
IssueManager issueManager = ComponentAccessor.getIssueManager();
Issue issue = issueManager.getIssueObject(curIissue.toString());
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
def baseUrl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl");
def baseurlIssue = baseUrl+'/browse/'+issue;


def fieldManager = ComponentAccessor.getFieldManager()

def fieldLayoutItem = ComponentAccessor.getFieldLayoutManager().getFieldLayout(issue).getFieldLayoutItem("description")
def field = fieldManager.getField("description")
NavigableField navigableField = (NavigableField)field
def descriptionHTML = navigableField.getColumnViewHtml(fieldLayoutItem, new HashMap(), issue)

def message="""

<html>
<head>
<style>
body {
font-family: 'Open Sans', sans-serif;
max-width: 800px;
font-size: 14px;
display: block;
margin: 8px;
}
a {
font-family: 'Open Sans', sans-serif;
color: #00A79D;
opacity: 0.8;
}
h1 {
font-size: 15px;
display: inline-block;
text-align:left;
color: #333;
line-height: 22px;
font-weight: bold;
}
.reportheader {
border-bottom: #F86E00 1px solid;
margin-bottom: 10px;
}

div {
display: block;
}
h2 {
display: block;
color: #F86E00;
font-size: 14px;
margin: 0px 0px 10px 0px;
}
.reportpropertywrapper {
margin-left: 10px;
}
h3 {
color: #333333;
font-size: 14px;
margin: 0px 0px 0px 0px !important;
line-height: 5px;
}
p {
color: #666;
margin-top: 5px;
margin-left: 10px;
margin-bottom: 10px;
line-height: 10px;
}
h4 {
margin: 0px !important;
font-size: 12px;
color: #333333;
}
* {
transform-origin: 0px 0px 0px;
}
.logo {
width: 65px;
float: right;
text-align: right;
padding-right: 0px;
}
th {
vertical-align: top
vertical-align: right
}
</style>
</head>
<body>
<table style="max-width:800px">
<div class="reportheader">
<table style="width:100%">
<tr>
<th>
<h1>Issue Report for Bug Customer Key <a href='${baseurlIssue}'>${issue}</a></h1>
</th>
<th></th>

</tr>
</table>
</div>
</table>
<table style="max-width:800px">

</table>

</body>

</html>
"""
return message;
}

Matthew Clark
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.
March 24, 2019

I never wired up the close event to the Publish button. You would have to add something like this within the code call for the publishButton:

<script>
\$(".publishButton").click(function (e) {
\$.ajax({
url : AJS.params.baseURL + "/rest/scriptrunner/latest/custom/PublishMail?issueId=$issueKey",
type : "get",
dataType: "json",
async : false,
success : function (data) {
console.log(data)
if(data.result == "Success"){
console.log("result variable from PublishMail endpoint = " + data.result)
AJS.dialog2("#sr-dialog").hide();
}

}
});
});

</script>


I was not sure what your PublishMail endpoint did so I did not want to assume you just wanted to close after clicking Publish. I will update the bitbucket code so it closes the dialog window.

It might take me longer to understand what your PublishMail endpoint does.
Did it ever work in the past?

Dan27
Contributor
March 25, 2019

Thank you very much @Matthew Clark  ...

Unfortunately this code still don't work and the dialog stacked..

Do you have any idea why?

Dan27
Contributor
March 25, 2019

And now I got the same error after I press the Publish Button from the board screen:

111.JPG

Matthew Clark
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.
March 25, 2019

If the dialog only stacks on the agile board's view then it is the bug I mentioned before SRJIRA-3152

And the error is not the same. It is complaining that it cannot access the property 'result' of null. Which is probably referring to the ajax call I put in at the bottom of the PublishMailDialog which sends data to the PublishMail endpoint
i.e. this part:

if(data.result == "Success"){
AJS.dialog2("#sr-dialog").hide()
}

If you take a look at the bitbucket repo again I updated it to include an error check.

But you will still get the "cannot access the property 'result' of null" if the PublishMail endpoint does not return the expected JSON data on a successful response


Your PublishMail endpoint needs to be redesigned as it has some un-required code. Take a look at this example I drew up from what you sent me: PublishMail endpoint

Dan27
Contributor
March 25, 2019

Hi, 

It showed in the bottom of the dialog:

111.JPGI will send you the full script (PublishMail) cause it still not working and I don't understand why...

 

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import com.atlassian.jira.issue.issuetype.IssueType
import javax.ws.rs.core.Response
import javax.ws.rs.core.MultivaluedMap
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.config.IssueTypeManager;
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.mail.Email
import com.atlassian.mail.server.MailServerManager
import com.atlassian.mail.server.SMTPMailServer
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.HttpMethod
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.lang.StringUtils
import groovy.json.*
import com.atlassian.jira.issue.customfields.impl.MultiGroupCFType
import com.atlassian.crowd.embedded.impl.ImmutableGroup
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.config.properties.APKeys
import com.atlassian.jira.issue.fields.NavigableField
import com.atlassian.jira.issue.fields.FieldManager;
import com.atlassian.jira.issue.RendererManager;

@BaseScript CustomEndpointDelegate delegate

PublishMail(httpMethod: "GET") {
MultivaluedMap queryParams,String body, HttpServletRequest request ->

String theUrltoReturn = ""
String issueId;
String clonedMessage;
try {

issueId = queryParams.getFirst("issueId") as String
//test
IssueManager issueManager = ComponentAccessor.getIssueManager();
Issue issue = issueManager.getIssueObject(Long.parseLong(issueId));

CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
def bcc="";
//Get group details
def groupManager = ComponentAccessor.groupManager;
def groups = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("E-mail Recipients")) as List;
def sizeGroup=groups.size();
groups= groups.getAt(0) as ImmutableGroup

//return groups[0].getName();
//def temp =issue.getCustomFieldValue(com.atlassian.jira.component.ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Group Mails"))*.name as List


def i = 0;
while ( i < sizeGroup) {

def members = groupManager.getUsersInGroup(groups.getName())
//return members
def j = 0;
while ( j < members.size()) {

bcc = bcc + "," + members[j].getEmailAddress();
j++
}
i++
}

log.warn bcc;
sendEmail(bcc,'Issue: '+issue.toString(),createMessage(issue.toString()));
def baseURL = ComponentAccessor.getApplicationProperties()getString(APKeys.JIRA_BASEURL)

//theUrltoReturn = request.getHeader("reffer");
theUrltoReturn = baseURL+'/browse/'+issue
log.warn theUrltoReturn
}
catch (e) {
return Response.serverError().entity([error: e.message]).build();
}

Response.temporaryRedirect(URI.create(theUrltoReturn)).build()

// UserMessageUtil.success(clonedMessage)
//go(baseurlIssue2)
}

 

// Create an email
def sendEmail(String emailAddr, String subject, String body) {
//MailServerManager mailServerManager = ComponentAccessor.getMailServerManager();
def mailServer = ComponentAccessor.getMailServerManager().getDefaultSMTPMailServer();

//if (mailServer) {
try{
Email email = new Email(emailAddr)
email.setMimeType("text/html")
email.setSubject(subject)
email.setBody(body)
mailServer.send(email)
log.debug("Mail sent")
}

catch(Exception e) {
log.warn("Please make sure that a valid mailServer is configured")
log.warn e;
}
}

//Create message
def createMessage(String curIissue) {
IssueManager issueManager = ComponentAccessor.getIssueManager();
Issue issue = issueManager.getIssueObject(curIissue.toString());
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
//def RemedyId = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Remedy Id"));
def ProductName = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Product Name"));
if(ProductName==null)
{
ProductName='NA'
}
def Inversion = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("In Version"));
if(Inversion==null)
{
Inversion='NA'
}
else
{
Inversion=Inversion.toString();
def size= Inversion.toString().length();
Inversion=Inversion.substring(1,size-1);
}
/*def EpicLink = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Epic Link"));
if(EpicLink==null)
{
EpicLink='NA'
}*/
def RootCause = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Root cause"));
if(RootCause==null)
{
RootCause='NA'
}
def Regression = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Regression"));
if(Regression==null)
{
Regression='NA'
}
def RegressionInVersion = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Regression in version"));
if(RegressionInVersion==null)
{
RegressionInVersion='NA'
}
else
{
RegressionInVersion=RegressionInVersion.toString();
def size= RegressionInVersion.toString().length();
RegressionInVersion=RegressionInVersion.substring(1,size-1);
}
def StoryPoints = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Story Points"));
if(StoryPoints==null)
{
StoryPoints='NA'
}
def Workaround = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Workaround"));
if(Workaround==null)
{
Workaround='NA'
}
def RiskEstimation = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Risk estimation"));
if(RiskEstimation==null)
{
RiskEstimation='NA'
}
def ManagerName = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Manager Name"));
if(ManagerName==null)
{
ManagerName='NA'
}
def fixVersion = issue.getFixVersions();
if(fixVersion==[])
{
fixVersion='None'
}
else
{
def size= fixVersion.toString().length();
fixVersion=fixVersion.toString().substring(1,size-1);
}

log.warn fixVersion;
//get the base url of Jira
def baseUrl = ComponentAccessor.getApplicationProperties().getString("jira.baseurl");
def baseurlIssue = baseUrl+'/browse/'+issue;

//rest api request
/*
HttpClient client = new HttpClient();

GetMethod method = new GetMethod(baseUrl + "/rest/api/latest/issue/" + issue + "?expand=renderedFields");
Credentials credentials = new UsernamePasswordCredentials("Jira26WLA@2016","sysadmin");
client.getParams().setAuthenticationPreemptive(true);
client.getState().setCredentials(AuthScope.ANY, credentials);
client.executeMethod(method);
def response = method.getResponseBodyAsString();
method.releaseConnection();
//return response;
def parsed = new JsonSlurper().parseText(response);
//return parsed;
def descriptionHTML = parsed.renderedFields.description;
*/
def fieldManager = ComponentAccessor.getFieldManager()

def fieldLayoutItem = ComponentAccessor.getFieldLayoutManager().getFieldLayout(issue).getFieldLayoutItem("description")
def field = fieldManager.getField("description")
NavigableField navigableField = (NavigableField)field
def descriptionHTML = navigableField.getColumnViewHtml(fieldLayoutItem, new HashMap(), issue)

def message="""

<html>
<head>
<style>
body {
font-family: 'Open Sans', sans-serif;
max-width: 800px;
font-size: 14px;
display: block;
margin: 8px;
}
a {
font-family: 'Open Sans', sans-serif;
color: #00A79D;
opacity: 0.8;
}
h1 {
font-size: 15px;
display: inline-block;
text-align:left;
color: #333;
line-height: 22px;
font-weight: bold;
}
.reportheader {
border-bottom: #F86E00 1px solid;
margin-bottom: 10px;
}

div {
display: block;
}
h2 {
display: block;
color: #F86E00;
font-size: 14px;
margin: 0px 0px 10px 0px;
}
.reportpropertywrapper {
margin-left: 10px;
}
h3 {
color: #333333;
font-size: 14px;
margin: 0px 0px 0px 0px !important;
line-height: 5px;
}
p {
color: #666;
margin-top: 5px;
margin-left: 10px;
margin-bottom: 10px;
line-height: 10px;
}
h4 {
margin: 0px !important;
font-size: 12px;
color: #333333;
}
* {
transform-origin: 0px 0px 0px;
}
.logo {
width: 65px;
float: right;
text-align: right;
padding-right: 0px;
}
th {
vertical-align: top
vertical-align: right
}
</style>
</head>
<body>
<table style="max-width:800px">
<div class="reportheader">
<table style="width:100%">
<tr>
<th>
<h1>Issue Report for Bug Customer Key <a href='${baseurlIssue}'>${issue}</a></h1>
</th>
<th></th>
<th><img src="${baseUrl}/images/icons/bmc_logo_header.png" class="logo" alt="logo" width="65" height="32" align="right"></th>
</tr>
</table>
</div>
</table>
<table style="max-width:800px">
<div class="reportsection"><h2></h2>
<div class="reportpropertywrapper"><h3>Description</h3>
<h4></h4>
<p>${issue.getSummary()}</p>
</div>
<div class="reportpropertywrapper"><h3>Product Name</h3>
<h4></h4>
<p>${ProductName}</p>
</div>
<div class="reportpropertywrapper"><h3>Version</h3>
<h4>The version on which the bug was found</h4>
<p>${Inversion}</p>
</div>
<div class="reportpropertywrapper"><h3>Steps to reproduce</h3>
<h4></h4>
<p>${descriptionHTML}</p>
</div>
<div class="reportpropertywrapper"><h3>Root cause & Suggested solution (in code)</h3>
<h4></h4>
<p>${RootCause}</p>
</div>
</div>

<div class="reportsection"><h2>Priority & Severity</h2>
<div class="reportpropertywrapper"><h3>Regression</h3>
<h4></h4>
<p>${Regression}</p>
</div>
<div class="reportpropertywrapper"><h3>Regression to version</h3>
<h4></h4>
<p>${RegressionInVersion}</p>
</div>
<div class="reportpropertywrapper"><h3>Impact on customer experience</h3>
<h4>Low/Medium/high</h4>
<p>${issue.getPriority().name}</p>
</div>
<div class="reportpropertywrapper"><h3>Workaround</h3>
<h4></h4>
<p>${Workaround}</p>
</div>
</div>

<div class="reportsection"><h2>Fix For</h2>
<div class="reportpropertywrapper"><h3>Effort estimation</h3>
<h4>In story points</h4>
<p>${StoryPoints}</p>
</div>
<div class="reportpropertywrapper"><h3>Risk estimation</h3>
<h4>Areas or functionality that may be affected by the fix</h4>
<p>${RiskEstimation}</p>
</div>
<div class="reportpropertywrapper"><h3>Target fix pack</h3>
<h4></h4>
<p>${if(issue.getStatus().name!='Done'){fixVersion} else{return 'NA'}}</p>
</div>
</div>

<div class="reportsection"><h2>Solution</h2>
<div class="reportpropertywrapper"><h3>Commit ID</h3>
<h4></h4>
<p>Filled automatically from GIT</p>
</div>
<div class="reportpropertywrapper"><h3>Fixed in version</h3>
<h4></h4>
<p>${if(issue.getStatus().name=='Done'){fixVersion} else{return 'NA'}}</p>
</div>
<div class="reportpropertywrapper"><h3>Testing guidelines</h3>
<h4></h4>
<p>See steps to reproduce (no field is required, should be in the text written in the description field)</p>
</div>
<div class="reportpropertywrapper"><h3>Manager approved</h3>
<h4></h4>
<p>${ManagerName}</p>
</div>
</div>
</table>

</body>

</html>
"""
return message;
}

Matthew Clark
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.
March 25, 2019

I actually programmed that red error text into the ajax call myself for just this sort of problem.

It should dump the stack trace to the browser console log or you can check the atlassian-jira.log

It means the PublishMail endpoint is throwing a HTTP 500 Internal Server error when called. The stack trace will give us a clue if you can post that here.

Suggest an answer

Log in or Sign up to answer