Introduction
Directive Sets are a way of providing a simple and secure way to drive issue changes from links in generated email notifications to achieve anything from simple custom field value changes, to more complex workflow. The links generated only have a security token, no arguments are supported, meaning that the links can only be used for exactly the purpose intended, one link per action. An Email can have many such links covering a variety of field values or actions. Here is a high level overview of the flow, showing the following flow:
An Webhook Issue Event occurs, rendering a TemplateSet (selected in Email Notification Mapping). As part of that, unique links are generated for each required DirectiveSet to run. The email is then sent to the Recipient.
The Recipient clicks on a link, that contains no data other than a token. The link points to a public REST API on the JEMHCloud server.
The JEMH REST service validates the token is still valid (not yet used), and executes the process.
JEMH Cloud renders a processing result, that the user can customize (in a DirectiveSet Render Result TemplateSet) and which is selected in each directiveSet it is needed. The HTML is returned to the user.
How it works
Directive Sets work in a very similar way to the manual approach (a Test Case), in a nutshell, the DirectiveSet is the 'body' of a text email, JEMH Cloud will 'supply' a minimal set of headers with specific values in order to drive the JEMH Cloud processing logic (issue selection by subject, sender lookup by address). The key pieces of information are shown below:
The From: contains the email address of the sender JIRA user
The To: matches the JEMH Cloud Profile catchemail (mailbox) address
The Subject: contains the issue-key
The content contains Directives (more on this later)
Using $jemhDirectiveSetLinkManager to create Directive Set Links
The DirectiveSetManager can be interacted with as shown below, to call createDirectiveSetLink. This is used to create the Directive Set Link that will trigger the Directive Set to update the issue. Directive Set Links can be created in the custom Templates, but the easiest way is to inject them in the notifications via a macro extension in Notification > Custom Macros.
JIRA - GENERIC - Directive Links Macros
For JIRA and Generic themes, add the following method in Custom Macros
#macro (jemhIncludeDirectiveSetLinks) #set ($groupId = $jemhDirectiveSetLinkManager.generateGroupIdForEvent($context)) #set ($profileId=13) #set ($directiveSetId=3) #set ($issueKey=$context.issue.key.textValue()) #set ($catchEmailAddress="user.2.hydra@gmail.com") #set ($recipient=$jemhUtils.getRecipient()) #set ($directSetLinkUrl = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetId, $profileId, $issueKey, $catchEmailAddress, $recipient)) #if($directSetLinkUrl) <tr> <td class="email-content-main mobile-expand wrapper-special-margin"> <a href="$directSetLinkUrl" target="_blank">$jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetId)</a> </td> </tr> #end #end
SERVICE DESK - Directive Links Macros
For Service Desk theme, add the following method in Custom Macros
#macro (renderDirectiveSetLinks) #set ($groupId = $jemhDirectiveSetLinkManager.generateGroupIdForEvent($context)) #set ($profileId=13) #set ($directiveSetId=3) #set ($issueKey=$context.issue.key.textValue()) #set ($catchEmailAddress="user.2.hydra@gmail.com") #set ($recipient=$jemhUtils.getRecipient()) #set ($directSetLinkUrl = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetId, $profileId, $issueKey, $catchEmailAddress, $recipient)) #if($directSetLinkUrl && !$context.webhookEvent.textValue().equals('jira:issue_deleted')) <tr> <td class="label" style="padding: 5px 0; color: #707070; width: 120px; padding-right: 10px; font-size: 14px"> Some Label For The Link </td> <td class="value" style="padding: 5px 0"> <table style="width: 100%; font-family: sans-serif"> <tbody> <tr class="sd-email-user-tagged"> <td> <a href="$directSetLinkUrl" target="_blank" style="text-decoration: none; color: black; cursor:pointer;"> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetId) </a> </td> </tr> </tbody> </table> </td> </tr> #end #end
The $jemhDirectiveSetLinkManager.createDirectiveSetLink parameters to this are as follows:
Example Variable | Example Value | Description |
---|---|---|
$groupId | 8f5f485b-7496-4f4b-a0fc-3e37269704bc | This is an id that is used to relate a set of links, such that when one link is used, the others are inherently expired/voided. An email may have several groups of links. |
$directiveSetId | 10 | This integer value must refer a known ID value shown in the DirectiveSet section of the JEMH Cloud Notification page. It refers to the set of Directives that will be applied. |
$profileId | 20 | This integer value must refer a known profile ID value shown in the JEMH Cloud Profiles page. It will be the profile that will be used for processing the DirectiveSet defined in $directiveSetId, as the $recipient on the $issue. |
$issueKey | ABC-123 | The issue key of the issue where the action will be performed. Value is generally $context.issue.key.textValue(). |
$catchEmailAddress | myprofile@company.com | An email address that matches one of the profile's catch email address. |
$recipient | myuser@mail.com | The email address of user that will perform the action, generally the current recipient $jemhUtils.getRecipient(). |
Terminology
Directive Sets
Allow users to perform defined Issue Directives by just clicking a link (called a Directive Set Link) generated in an email notification. Directive Set can be enabled or disabled - links will only be generated and consumed if the parent Directive Set is enabled.
Directive Set Links
These are the hyperlinks that are associated with a Directive Set and are validated using single-use tokens, meaning that only recipients of the notification will be able to use the Directive Set.
Each link in a single outbound notification is put in a Link Group which is unique to that recipient. Once a link has been processed by JEMH Cloud, it (and others in that link group) will expire. If 30 days pass without a link from an individual notification being processed, then this will also cause all related links to expire.
Directive Sets use Directives, so make sure you understand how they work before attempting to use this feature. If changes aren't applied:
Check the JEMH Cloud Auditing > Inbound Messages does not show any problems
Validate the Profile referred actually has Directives enabled, and the appropriate Field Processor for the body format used, e.g. At Prefix (the example used on this page)
Example Scenarios
As a Directive Set can be configured with any valid Directive there are many ways that this feature can be used, here are just a few example scenarios:
Changing an issue Assignee
Lets say that you want a nice link in a notification that assigns the issue to the user Ryan Clifton.
Create the Directive Set in Notifications > Directive Set > Create
Remember the id of the Directive Set (first column on table)
Go to Notifications > Custom Macros and Edit. Add the macro below (replace parameters $directiveSetId, $profileId, $catchEmailAddress) and save.
Create an Issue and inspect the generated email. The email should have the Assign to Ryan link
If you click the link, the directive will be executed and the issue's assignee changed. The response is generated based on the Directive Set's template.
JIRA - GENERIC - Assign to Ryan Custom Macro
#macro (jemhIncludeDirectiveSetLinks) #set ($groupId = $jemhDirectiveSetLinkManager.generateGroupIdForEvent($context)) #set ($profileId=13) #set ($directiveSetId=6) #set ($catchEmailAddress="user.2.hydra@gmail.com") #set ($recipient=$jemhUtils.getRecipient()) #set ($directSetLinkUrl = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetId, $profileId, $context.issue.key.textValue(), $catchEmailAddress, $recipient)) #if($directSetLinkUrl) <tr> <td class="email-content-main mobile-expand wrapper-special-margin"> <a href="$directSetLinkUrl" target="_blank"> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetId)</a> </td> </tr> #end #end
Implementing a Customer Satisfaction feature
In this scenario, we just show how to set a select custom field value, which will be done 'as' the user who is receiving the notification, whilst only one directive is shown, more could be added if needed.
Using a Select custom field, with values UNHAPPY, OK and HAPPY, we can create 3 DirectiveSets, here using the AtPrefix Directive format:
Create Select List (single choice) custom field in Cog > Issue > Custom Fields > Create
Add field to project's screen
Create 3 Directive Sets in JEMH Cloud >Notifications > Directive Sets
Directive Sets page should looks like this:
For JIRA and GENERIC themes, insert #jemhIncludeDirectiveSetLinks macro below in Notifications > Custom Macros. For Service Desk theme, insert #renderDirectiveSetLinks macro below in Notification >Custom Macros. Update $profileId, $directiveSetIdHAPPY, $directiveSetIdOK, $directiveSetIdUNHAPPY and $catchEmailAddress to match your values. Custom Macros in Notification should looks like this:
Then, an email sent to your customer will include the 3 icons + links.
When the user clicks in one of them, the Directive Set will be executed invalidating the other links.
JIRA - GENERIC - Custom Satisfaction Custom Macros
#macro (jemhIncludeDirectiveSetLinks) #set ($groupId = $jemhDirectiveSetLinkManager.generateGroupIdForEvent($context)) #set ($profileId=13) #set ($directiveSetIdHAPPY=3) #set ($directiveSetIdOK=5) #set ($directiveSetIdUNHAPPY=4) #set ($issueKey=$context.issue.key.textValue()) #set ($catchEmailAddress="user.2.hydra@gmail.com") #set ($recipient=$jemhUtils.getRecipient()) #set ($directSetLinkUrlHAPPY = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetIdHAPPY, $profileId, $issueKey, $catchEmailAddress, $recipient)) #set ($directSetLinkUrlOK = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetIdOK, $profileId, $issueKey,$catchEmailAddress, $recipient)) #set ($directSetLinkUrlUNHAPPY = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetIdUNHAPPY, $profileId, $issueKey, $catchEmailAddress, $recipient)) #if($directSetLinkUrlHAPPY || $directSetLinkUrlOK || $directSetLinkUrlUNHAPPY) <tr> <td class="email-content-main mobile-expand wrapper-special-margin"> #if($directSetLinkUrlHAPPY) <a href="$directSetLinkUrlHAPPY" target="_blank"> <img style="vertical-align:middle" src="$jemhUtils.getImageUrl('font-awesome_smile-o')"/> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetIdHAPPY)</a> #end #if($directSetLinkUrlOK) <a href="$directSetLinkUrlOK" target="_blank"> <img style="vertical-align:middle" src="$jemhUtils.getImageUrl('font-awesome_meh-o')"/> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetIdOK)</a> #end #if($directSetLinkUrlUNHAPPY) <a href="$directSetLinkUrlUNHAPPY" target="_blank"> <img style="vertical-align:middle" src="$jemhUtils.getImageUrl('font-awesome_frown-o')"/> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetIdUNHAPPY)</a> #end </td> </tr> #end #end
SERVICE DESK - Customer Satisfaction Macro
#macro (renderDirectiveSetLinks) #set ($groupId = $jemhDirectiveSetLinkManager.generateGroupIdForEvent($context)) #set ($profileId=13) #set ($directiveSetIdHAPPY=3) #set ($directiveSetIdOK=5) #set ($directiveSetIdUNHAPPY=4) #set ($catchEmailAddress="user.2.hydra@gmail.com") #set ($recipient=$jemhUtils.getRecipient()) #set ($directSetLinkUrlHAPPY = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetIdHAPPY, $profileId, $context.issue.key.textValue(), $catchEmailAddress, $recipient)) #set ($directSetLinkUrlOK = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetIdOK, $profileId, $context.issue.key.textValue(), $catchEmailAddress, $recipient)) #set ($directSetLinkUrlUNHAPPY = $jemhDirectiveSetLinkManager.createDirectiveSetLink($groupId, $directiveSetIdUNHAPPY, $profileId, $context.issue.key.textValue(), $catchEmailAddress, $recipient)) #if(($directSetLinkUrlHAPPY || $directSetLinkUrlOK || $directSetLinkUrlUNHAPPY) && !$context.webhookEvent.textValue().equals( 'jira:issue_deleted')) <tr> <td class="label" style="padding: 5px 0; color: #707070; width: 120px; padding-right: 10px; font-size: 14px"> Customer Satisfaction </td> <td class="value" style="padding: 5px 0"> <table style="width: 100%; font-family: sans-serif"> <tbody> <tr class="sd-email-user-tagged"> <td> #if($directSetLinkUrlHAPPY) <a href="$directSetLinkUrlHAPPY" target="_blank" style="text-decoration: none; color: black; cursor:pointer;"> <img style="vertical-align:middle" src="$jemhUtils.getImageUrl('font-awesome_smile-o')"/> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetIdHAPPY)</a> #end #if($directSetLinkUrlOK) <a href="$directSetLinkUrlOK" target="_blank" style="text-decoration: none; color: black; cursor:pointer;"> <img style="vertical-align:middle" src="$jemhUtils.getImageUrl('font-awesome_meh-o')"/> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetIdOK)</a> #end #if($directSetLinkUrlUNHAPPY) <a href="$directSetLinkUrlUNHAPPY" target="_blank" style="text-decoration: none; color: black; cursor:pointer;"> <img style="vertical-align:middle" src="$jemhUtils.getImageUrl('font-awesome_frown-o')"/> $jemhDirectiveSetLinkManager.getDirectiveSetName($directiveSetIdUNHAPPY)</a> #end </td> </tr> </tbody> </table> </td> </tr> #end #end