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:
I got this error:
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
I
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:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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..
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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).
Thanks,
Daniel Mor
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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:
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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]]
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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;
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you very much @Matthew Clark ...
Unfortunately this code still don't work and the dialog stacked..
Do you have any idea why?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
It showed in the bottom of the dialog:
I 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;
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.