Hi Everyone,
We have a custom Object i.e., Jira Case on Salesforce side and in this object we have field called "Jira Description" this is type of Rich Text and the use case is whenever the support users add any screen-capture or images in this field or Modify the content having font size, Underlined content etc.,. This has to be shown in the Jira "Description" field using REST API. Basically we have to show the images and the same content from Salesforce Description field to JIRA Description field
We tried to do this but it shows the URL for the image in Salesforce and content with HTML tags.
Is there any way we can decode the "Jira Description" field from Salesforce to JIRA to copy the same information from Salesforce to JIRA by using REST API. Please suggest if any solution.
My findings: In JIRA Description field we can do content formatting and add the screen-captures as same as Rich Text field.
Below is the API we are using to POST from Salesforce
https://domain.atlassian.net/rest/api/2/issue
Below is the Trigger on Salesforce
Public class SalesforceToJiraCallouts {
public static void getJiraDetails(list<Jira_Case__c> jiraCaseRecordsList){
SalesforceToJiraCalloutsBugParser jsonParserForBug = new SalesforceToJiraCalloutsBugParser();
SalesforceToJiraCalloutsIssueParser jsonParserForEnhancement = new SalesforceToJiraCalloutsIssueParser();
for(Jira_Case__c jiraCaseRecord: jiraCaseRecordsList ){
if(jiraCaseRecord.Link_to_Existing_Jira__c == false){
string jiraCaseDescription = jiraCaseRecord.Jira_Description__c;
jiraCaseDescription = jiraCaseDescription;
if(jiraCaseRecord.Jira_Issue_Type__c == 'Enhancement'){
if(jiraCaseRecord.Product_Sub_Type__c == '3D Sprint' && jiraCaseRecord.Jira_Project_Name__c == '3D Sprint'){
jsonParserForEnhancement.Fields.project.key = system.Label.X3D_Sprint;
list<string> jiraAffectVersionsList = jiraCaseRecord.Jira_Affect_Versions__c.split(';');
system.debug('jiraAffectVersionsList' + jiraAffectVersionsList);
list<SalesforceToJiraCalloutsIssueParser.versions> versionList = new list<SalesforceToJiraCalloutsIssueParser.versions>();
if(jiraAffectVersionsList.size()>0){
for(integer i=0; i<jiraAffectVersionsList.size();i++){
SalesforceToJiraCalloutsIssueParser.versions version = new SalesforceToJiraCalloutsIssueParser.versions();
version.name = jiraAffectVersionsList[i];
versionList.add(version);
system.debug('jiraAffectVersionsList' + jiraAffectVersionsList[i]);
}
}
jsonParserForEnhancement.fields.versions = versionList;
}
else if(jiraCaseRecord.Product_Sub_Type__c == '3D Sprint' && jiraCaseRecord.Jira_Project_Name__c == 'SBU Licensing System'){
jsonParserForEnhancement.Fields.project.key = system.Label.SBU_Licensing_System;
}
jsonParserForEnhancement.fields.issuetype.name = 'Improvement';
jsonParserForEnhancement.fields.summary = jiraCaseRecord.Jira_Summary__c;
jsonParserForEnhancement.fields.description = jiraCaseDescription;
jsonParserForEnhancement.fields.customfield_10408 = jiraCaseRecord.Jira_Customer_Info__c;
jsonParserForEnhancement.fields.customfield_13961 = jiraCaseRecord.Name;
}
else{
if(jiraCaseRecord.Product_Sub_Type__c == '3D Sprint' && jiraCaseRecord.Jira_Project_Name__c == '3D Sprint'){
jsonParserForBug.Fields.project.key = system.Label.X3D_Sprint;
list<string> jiraAffectVersionsList = jiraCaseRecord.Jira_Affect_Versions__c.split(';');
list<SalesforceToJiraCalloutsBugParser.versions> versionList = new list<SalesforceToJiraCalloutsBugParser.versions>();
if(jiraAffectVersionsList.size()>0){
for(integer i=0; i<jiraAffectVersionsList.size();i++){
SalesforceToJiraCalloutsBugParser.versions version = new SalesforceToJiraCalloutsBugParser.versions();
version.name = jiraAffectVersionsList[i];
versionList.add(version);
system.debug('jiraAffectVersionsList' + jiraAffectVersionsList[i]);
}
}
jsonParserForBug.fields.versions = versionList;
}
else if(jiraCaseRecord.Product_Sub_Type__c == '3D Sprint' && jiraCaseRecord.Jira_Project_Name__c == 'SBU Licensing System'){
jsonParserForBug.Fields.project.key = system.Label.SBU_Licensing_System;
}
jsonParserForBug.fields.issuetype.name = 'Bug';
jsonParserForBug.fields.Customfield_11500.value = jiraCaseRecord.Jira_Reproducibility__c;
jsonParserForBug.fields.summary = jiraCaseRecord.Jira_Summary__c;
jsonParserForBug.fields.description = jiraCaseDescription;
jsonParserForBug.fields.customfield_10408 = jiraCaseRecord.Jira_Customer_Info__c;
jsonParserForBug.fields.customfield_13961 = jiraCaseRecord.Name;
}
if(jiraCaseRecord.Jira_Issue_Type__c == 'Enhancement'){
createTicketInJIRA(string.valueof(JSON.Serialize(jsonParserForEnhancement)));
}
else{
createTicketInJIRA(string.valueof(JSON.Serialize(jsonParserForBug)));
}
}
}
}
@VKAPS Dev(callout=true)
public static void createTicketInJIRA(string requestBody){
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://domain.atlassian.net/rest/api/2/issue');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json;charset=UTF-8');
Blob headerValue = Blob.valueOf('USERNAME' + ':' + 'APITOKEN');
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
request.setHeader('Authorization', authorizationHeader);
System.debug('requestbody: ' + requestBody);
request.setBody(requestBody);
System.debug('request is: ' + string.valueOf(request));
HttpResponse response = http.send(request);
if (response.getStatusCode() != 200) {
System.debug('The status code returned was not expected: ' +
response.getStatusCode() + ' ' + response.getStatus() + ' Response body: ' + response.getBody());
} else {
System.debug('Respponse body is: ' + response.getBody());
}
}
}
@Znanatej Panga @Uma yes I found for the solution
We can use the richtext field in Salesforce but in the Target system i.e., JIRA the description field is not an Richtext field so it does not accept the attachment coming from the salesforce. Salesforce suggest the below option
A] Create a REST Resource Service. First get the Binary Image data into a Blob from RichTextArea field and pass it as Base64 encoded String as a Rest service response.
B] Now you can consume the Rest resource from any third party client e.g. Java to get the Base64 String and Decode the Base64 String from your third party app to get back the Image.
C] For testing we can use Base64 String in any online tool using which we can observe the end result. i.e. Source image
Sample Rest Resource Apex class which you can refer:
======================================================
@RestResource(urlMapping='/ImageService')
global with sharing class RESTImageController {
@HttpGet
global static void getImage(){
String strBase64 = 'Test';
Test_Custom_Object_1__c obj = [SELECT ImageField__c FROM Test_Custom_Object_1__c WHERE Id = 'a0M7F00000LL1D7UAL' LIMIT 1];
String bookimg = obj.ImageField__c.substringBetween('<img', 'img>');
String imgsrc=bookimg.substringBetween('src="', '"');
imgsrc=imgsrc.replace('amp;', '');
PageReference page = new PageReference(imgsrc);
Blob imgblob = page.getContent();
strBase64 = EncodingUtil.base64Encode(imgblob);
strBase64 = JSON.serialize(strBase64);
RestContext.response.addHeader('Content-Type','application/json');
RestContext.response.responseBody = Blob.valueOf('{ "Type" : "strBase64", "Value" : '+ strBase64+'}');
}
}
Note: You can also refer above apex logic in your Future method in order to convert a value stored in RichTextArea Field to encoded base64 string and pass that to your third party system so that they can decode to get actual image.
As discussed you will explore more about how to decode a base64 encoded image string at JIRA in order to get an original image or else in which format JIRA is expecting an image to be in, so it will get displayed in JIRA layout as expected.
I have already provided you a steps which you can refer from salesforce end and explore that further as per your requirement in order to send an image which is stored in RichTextArea field using REST API call.
Since Target system do not have the Description field has a Richtext field so below is the solution
From Salesforce richtext field, the text entered will go into the Description without HTML tags and the attachment attached in the Richtext will go as an attachment in Jira i.e., we will be invoking the two API's 1. Create a record in JIRA and 2. Based on the response Status=201 then invoking the attachment API
Trigger:
trigger JiraCaseTrigger on Jira_Case__c (after insert) {
if(trigger.isAfter){
if(trigger.isInsert){
JiraCaseTriggerHelper.getJiraDetails(trigger.new);
}
}
}
---------------------------------------------------------------------------
Trigger Helper:
public class JiraCaseTriggerHelper {
public static void getJiraDetails(list<Jira_Case__c> jiraCaseRecordsList){
SalesforceToJiraCalloutsBugParser jsonParserForBug = new SalesforceToJiraCalloutsBugParser();
SalesforceToJiraCalloutsIssueParser jsonParserForEnhancement = new SalesforceToJiraCalloutsIssueParser();
Map<String, Product_Sub_Type__c> prodsubtypeSettings = Product_Sub_Type__c.getAll();
string jiraCaseDescription;
system.debug('jiraCaseDescription1:-'+jiraCaseDescription);
for(Jira_Case__c jiraCaseRecord: jiraCaseRecordsList ){
if(jiraCaseRecord.Link_to_Existing_Jira__c == false){
jiraCaseDescription = (jiraCaseRecord.Jira_Description__c).replaceAll('<[/a-zAZ0-9]*>','').replaceAll('<img(.+?)>','').replaceAll('\\<.*?\\>', '');
system.debug('jiraCaseDescription:-'+jiraCaseDescription);
if(jiraCaseRecord.Jira_Issue_Type__c == 'Enhancement'){
if(prodsubtypeSettings.containsKey(jiraCaseRecord.Product_Sub_Type__c)&&prodsubtypeSettings.containsKey(jiraCaseRecord.Jira_Project_Name__c)){
jsonParserForEnhancement.Fields.project.key = prodsubtypeSettings.get(jiraCaseRecord.Product_Sub_Type__c).Project_Key__c;
list<string> jiraAffectVersionsList = jiraCaseRecord.Jira_Affect_Versions__c.split(';');
list<SalesforceToJiraCalloutsIssueParser.versions> versionList = new list<SalesforceToJiraCalloutsIssueParser.versions>();
if(jiraAffectVersionsList.size()>0){
for(integer i=0; i<jiraAffectVersionsList.size();i++){
SalesforceToJiraCalloutsIssueParser.versions version = new SalesforceToJiraCalloutsIssueParser.versions();
version.name = jiraAffectVersionsList[i];
versionList.add(version);
}
}
jsonParserForEnhancement.fields.versions = versionList;
}
else{
jsonParserForEnhancement.Fields.project.key = system.Label.SBU_Licensing_System;
}
jsonParserForEnhancement.fields.issuetype.name = system.Label.Improvement;
jsonParserForEnhancement.fields.summary = jiraCaseRecord.Jira_Summary__c;
jsonParserForEnhancement.fields.description = jiraCaseDescription;
jsonParserForEnhancement.fields.customfield_10408 = jiraCaseRecord.Jira_Customer_Info__c;
jsonParserForEnhancement.fields.customfield_13961 = jiraCaseRecord.Name;
}
else {
if(prodsubtypeSettings.containsKey(jiraCaseRecord.Product_Sub_Type__c)&&prodsubtypeSettings.containsKey(jiraCaseRecord.Jira_Project_Name__c)){
jsonParserForBug.Fields.project.key = prodsubtypeSettings.get(jiraCaseRecord.Product_Sub_Type__c).Project_Key__c;
list<string> jiraAffectVersionsList = jiraCaseRecord.Jira_Affect_Versions__c.split(';');
list<SalesforceToJiraCalloutsBugParser.versions> versionList = new list<SalesforceToJiraCalloutsBugParser.versions>();
if(jiraAffectVersionsList.size()>0){
for(integer i=0; i<jiraAffectVersionsList.size();i++){
SalesforceToJiraCalloutsBugParser.versions version = new SalesforceToJiraCalloutsBugParser.versions();
version.name = jiraAffectVersionsList[i];
versionList.add(version);
}
}
jsonParserForBug.fields.versions = versionList;
}
else{
jsonParserForBug.Fields.project.key = system.Label.SBU_Licensing_System;
}
jsonParserForBug.fields.issuetype.name = system.Label.Bug;
jsonParserForBug.fields.Customfield_11500.value = jiraCaseRecord.Jira_Reproducibility__c;
jsonParserForBug.fields.summary = jiraCaseRecord.Jira_Summary__c;
jsonParserForBug.fields.description = jiraCaseDescription;
jsonParserForBug.fields.customfield_10408 = jiraCaseRecord.Jira_Customer_Info__c;
jsonParserForBug.fields.customfield_13961 = jiraCaseRecord.Name;
}
}
if(jiraCaseRecord.Jira_Issue_Type__c == 'Enhancement'){
createTicketInJIRA(string.valueof(JSON.Serialize(jsonParserForEnhancement)),jiraCaseRecord.Jira_Description__c);
}
else{
createTicketInJIRA(string.valueof(JSON.Serialize(jsonParserForBug)), jiraCaseRecord.Jira_Description__c);
}
}
}
@future(callout=true)
public static void createTicketInJIRA(string requestBody, string jiraCaseDescription){
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint(system.Label.IssueAPI);
request.setMethod(system.Label.Jira_Set_Method);
request.setHeader(system.Label.Jira_Set_Header1, system.Label.Jira_Set_Header2);
Blob headerValue = Blob.valueOf(system.Label.Username + ':' +system.Label.APIToken);
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
request.setHeader('Authorization', authorizationHeader);
request.setBody(requestBody);
HttpResponse response = http.send(request);
if (response.getStatusCode() == 201) {
if(jiraCaseDescription.contains('<img')){
Map<String,Object> results=(Map<String,Object>)JSON.deserializeUntyped(response.getBody());
string jiraKey = String.valueOf(results.get('key'));
List<string> jiraCaseDescriptionList = jiraCaseDescription.split('<img');
string imageSrc;
List<blob> attachmentblobList = new List<blob>();
string url;
string boundary;
for(string jiraAttachment : jiraCaseDescriptionList ){
imagesrc=jiraAttachment.substringBetween('src="', '"');
if(imageSrc != null){
string file_name = 'Salesforce to Jira Screen Capture '+ Math.round(Math.random()*1000) ;
string imageUrl = imageSrc.replace('amp;', '');
PageReference page = new PageReference(imageUrl);
blob imageblob;
if(test.isRunningTest()){
imageblob = blob.valueOf('Unit Testing');
}
else{
imageblob = page.getContent();
}
url = system.Label.AttachmentAPI + jiraKey + system.Label.Attachment;
boundary = '----------------------------741e90d31eff';
String header = '--' + boundary + '\n' +
'Content-Disposition: form-data; name="file"; filename="' + file_name + '";\n' +
'Content-Type: application/octet-stream';
String footer = '--' + boundary + '--';
String headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header + '\r\n\r\n'));
while (headerEncoded.endsWith('=')){
header += ' ';
headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'\r\n\r\n'));
}
string bodyEncoded = EncodingUtil.base64Encode(imageblob);
Blob bodyBlob = null;
String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
if (last4Bytes.endsWith('==')) {
last4Bytes = last4Bytes.substring(0, 2) + '0K';
bodyEncoded = bodyEncoded.substring(0, bodyEncoded.length() - 4) + last4Bytes;
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
bodyBlob = EncodingUtil.base64Decode(headerEncoded + bodyEncoded + footerEncoded);
} else if (last4Bytes.endsWith('=')) {
last4Bytes = last4Bytes.substring(0, 3) + 'N';
bodyEncoded = bodyEncoded.substring(0, bodyEncoded.length()-4) + last4Bytes;
footer = '\n' + footer;
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
bodyBlob = EncodingUtil.base64Decode(headerEncoded + bodyEncoded + footerEncoded);
} else {
footer = '\r\n' + footer;
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
bodyBlob = EncodingUtil.base64Decode(headerEncoded + bodyEncoded + footerEncoded);
}
attachmentblobList.add(bodyBlob);
}
}
for(blob imageBlob :attachmentblobList ){
Blob headerVal = Blob.valueOf(system.Label.Username + ':' +system.Label.APIToken);
String auth_header = 'Basic ' + EncodingUtil.base64Encode(headerVal);
HttpRequest req = new HttpRequest();
req.setHeader(system.Label.Jira_Set_Header1, system.Label.Jira_Set_Header3 + boundary);
req.setHeader('Authorization', auth_header);
req.setHeader('X-Atlassian-Token', 'nocheck');
req.setMethod(system.Label.Jira_Set_Method);
req.setEndpoint(url);
req.setBodyAsBlob(imageBlob);
req.setTimeout(120000);
Http https = new Http();
HTTPResponse res = https.send(req);
}
}
}
else {
System.debug('Respponse body is: ' + response.getBody());
}
}
}
Based on our requirement I did created the fields and mapped.
Hope this solution works for you!
Thanks,
Santosh
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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.