Skip to content

Instantly share code, notes, and snippets.

@hatton
Last active December 22, 2022 14:04
Show Gist options
  • Save hatton/49c802824faebdc44fb05e2b15d78ca2 to your computer and use it in GitHub Desktop.
Save hatton/49c802824faebdc44fb05e2b15d78ca2 to your computer and use it in GitHub Desktop.
Bloom YouTrack Help Desk Scripts as of Dec 2022
/*jshint esversion: 6 */
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var gatherReporter = require('./gather.reporter.info.from.description');
// when issues come in via api, the reporter is set to "auto report creator".
// The email listed in the description and is a little obfuscated, because when we were on the free plan,
// we could not control the visibility of fields. This grabs the email from the desription, de-obfuscates it,
// and puts it, along with the user's name, in the appropriate fields
exports.rule = entities.Issue.action({
title: 'Gather.autoreporter.emails',
command: 'gatherAutoReporterEmails',
guard: function(ctx) {
return ctx.issue.isReported;
},
action: function(ctx) {
gatherReporter.gather(ctx.issue);
console.log("Gathered "+JSON.stringify(ctx));
},
requirements: {
reporterEmail: {
name: 'Reporter Email',
type: entities.Field.stringType
},
reporterName: {
name: 'Reporter Name',
type: entities.Field.stringType
}
}
});
/*jshint esversion: 6 */
// When issues come in via api, the reporter is set to "auto report creator".
// The email listed in the description and is a little obfuscated, because when we were on the free plan,
// we could not control the visibility of fields. This grabs the email from the desription, de-obfuscates it,
// and puts it, along with the user's name, in the appropriate fields.
exports.gather = function(issue) {
//console.log(JSON.stringify(issue));
if (issue.reporter && issue.reporter.fullName == "auto report creator" && (!issue.fields.reporterEmail || issue.fields.reporterEmail.length === 0)) {
var matches = /Error Report from (.*)\s\((.+)\/(.+)\s(.+)\)/.exec(issue.description);
var name = "";
var email = "";
if (matches && matches.length == 5) {
email = matches[4].replace(/\//g, ".") + "@" + matches[2].replace(/\//g, ".") + "." + matches[3];
name = matches[1];
} else {
// some older issues have non-obfuscated emails
matches = /Error Report from (.*)\s\((.*@.*\..*)\)/.exec(issue.description);
if (matches && matches.length == 3) {
name = matches[1];
email = matches[2];
}
}
//console.log(JSON.stringify(matches));
if (matches) {
//console.log("Setting reporter of " + issue.id + " to " + name + " with email: " + email);
issue.fields.reporterEmail = email;
issue.fields.reporterName = name;
}
}
};
var gatherReporter = require('./gather.reporter.info.from.description');
var entities = require('@jetbrains/youtrack-scripting-api/entities');
exports.rule = entities.Issue.onChange({
title: 'Incoming.issue.via.api',
guard: function(ctx) {
return ctx.issue.becomesReported;
},
action: function(ctx) {
gatherReporter.gather(ctx.issue);
//ctx.issue.isUsingMarkdown = true;
},
requirements: {
reporterEmail: {
name: 'Reporter Email',
type: entities.Field.stringType
},
reporterName: {
name: 'Reporter Name',
type: entities.Field.stringType
}
}
});
/**
* This is a template for an on-change rule. This rule defines what
* happens when a change is applied to an issue.
*
* For details, read the Quick Start Guide:
* https://www.jetbrains.com/help/youtrack/incloud/2018.2/Quick-Start-Guide-Workflows-JS.html
*/
var entities = require('@jetbrains/youtrack-scripting-api/entities');
exports.rule = entities.Issue.onChange({
title: 'Reply.from.user.removes.waiting.for.user.tag',
guard: function(ctx) {
var issue = ctx.issue;
if (issue.comments.added.isEmpty() ||
issue.comments.added.first().author.login !== "Email_Submission" ||
!issue.hasTag("waiting on user")) {
return false;
}
return true;
},
action: function(ctx) {
var issue = ctx.issue;
//console.log('removing "waiting on user" tag');
issue.removeTag("waiting on user");
},
requirements: {
// TODO: add requirements
}
});
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
var notifications = require('@jetbrains/youtrack-scripting-api/notifications');
exports.rule = entities.Issue.onChange({
title: workflow.i18n('Send user an email on issue creation'),
guard: function(ctx) {
console.log("Checking " + JSON.stringify(ctx) + " " + (ctx.issue.fields.reporterEmail || "missing reporterEmail")) ;
return ctx.issue.becomesReported
// also we don't want to send this if it was reported via youtrack directly. Just via email or API
&& ctx.issue.fields.reporterEmail && ctx.issue.fields.reporterEmail.length > 0;
},
action: function(ctx) {
var issue = ctx.issue;
//console.log(issue.id + "reporter.email:"+ issue.reporter.email +" reporterEmail:"+issue.fields.reporterEmai);
var email = issue.fields.reporterEmail; // this should be available for email and API submissions, but not YouTrack UI ones.
var message = {
fromName: "Bloom Team",
toEmails: [email],
subject: 'Bloom Issue ' + issue.id,
body: "<br/><br/>Thanks for contacting the Bloom team bug reporting system.<br/><br/>We have received your message and will respond soon. If you learn anything more about the issue just reply to this email with the additional information.<br/><br/>If you just need some help or have a feature request, please head over to our community support site:<br/><br/>How To: https://community.software.sil.org/c/bloom/howto<br/>Questions: https://community.software.sil.org/c/bloom<br/>Feature requests: https://community.software.sil.org/c/bloom/featurerequests<br/><br/>Regards,<br/>The Bloom Team<br/></br/><br/></br/><hr/>Issue "+issue.id+": "+issue.summary
};
console.log("Sending to " + email + " for " + issue.id + " "+issue.summary);
notifications.sendEmail(message, issue);
},
requirements: {
reporterEmail: {
name: 'Reporter Email',
type: entities.Field.stringType
}
}
});
/**
* Detect when the author of a comment intends it to go to the user. Send the user an email, and mark the comment showing that this was done.
*/
/*jshint esversion: 6 */
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
var notifications = require('@jetbrains/youtrack-scripting-api/notifications');
exports.rule = entities.Issue.onChange({
// TODO: give the rule a human-readable title
title: 'Send.reporter.notification',
guard: function(ctx) {
if (ctx.issue.comments.added.isEmpty()) {
return false;
}
const text = ctx.issue.comments.added.first().text.toLowerCase();
const meantForReporter = (text.indexOf("@@") > -1 || text.indexOf("@reporter") > -1 || text.indexOf("@Email_Submission") > -1) ;
return meantForReporter;
},
action: function(ctx) {
console.log("send.reporter.notification ");
workflow.check(ctx.issue.fields.reporterEmail && ctx.issue.fields.reporterEmail.length > 0, "Cannot notify reporter because Reporter Email is empty.");
var message = {
fromName: "Bloom Team",
toEmails: [ctx.issue.fields.reporterEmail],
subject: createSubject(ctx.issue),
body: createMessage(ctx.issue)
};
console.log("Sending " + JSON.stringify(message.body));
notifications.sendEmail(message, ctx.issue);
const obfuscated = ctx.issue.fields.reporterEmail.replace("@"," ").replace(/\./g," ");
ctx.issue.comments.added.first().text = ctx.issue.comments.added.first().text + "\n\n[Youtrack sent this in an email to " + obfuscated + "].";
//ctx.issue.comments.added.first().text = ctx.issue.comments.added.first().text + message.body;
},
requirements: {
reporterEmail: {
name: 'Reporter Email',
type: entities.Field.stringType
},
}
});
function createMessage(issue) {
const comment = issue.comments.added.first();
var commentText = comment.text;
// replace the alias in the actual comment just to make it more readable
comment.text = commentText.replace("@@", "@Reporter"); // @@ is an alias for @Reporter
// but remove it enirely from what the user sees in the email
commentText = comment.text.replace("@reporter", ""); // remove the special sequence we use to indicate that it should go to a user
commentText = commentText.replace("@Reporter", "");
//commentText = inlineImages(commentText);
// var issueLink = "<a href='https://issues.bloomlibrary.org/youtrack/issue/"+issue.id+"'>"+issue.id+"</a>";
//var issueLink = "["+issue.id+"](https://issues.bloomlibrary.org/youtrack/issue/"+issue.id+")";
// putting this at the top because gmail trims it off of the bottom (hides under ellipsis)
var message = 'Regarding Bloom issue ' + issue.id + ":\n\n";
// the comment itself
message += commentText.trim() + "\n\n";
message = message + [
"Regards,", comment.author.fullName, "", ""
].join('\n');
//Can only give links, because actual attachments are waiting on https://youtrack.jetbrains.com/issue/JT-23972
//Technically, we could replace the garbage the user sees "![](image1526074447151.png)" with links to these images
//but it's Friday and I'm not up to a regex adventure right now.
if (issue.attachments.added.size > 0) {
message += "Links to attached files: ";
issue.attachments.added.forEach((attachment) => {
message += '[file:' + attachment.name + '] ';
});
message+="\n";
}
return issue.wikify(message);
}
function createSubject(issue) {
var reStr = workflow.i18n('Re:');
var summary = issue.summary;
return summary.indexOf(reStr) === 0 ? summary : reStr + ' ' + summary +" ("+issue.id+")";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment