floodmeadows / Jira paste shutter ticket description

// ==UserScript==
// @name         Jira paste shutter ticket description
// @namespace    https://openuserjs.org/users/floodmeadows
// @description  Adds button to replace the description of a ticket with one copied from the shutter ticket helper spreadsheet.
// @copyright    2023, floodmeadows (https://openuserjs.org/users/floodmeadows)
// @license      MIT
// @version      0.2
// @include      https://jira.*.uk/browse/*
// @updateURL    https://openuserjs.org/meta/floodmeadows/Jira_paste_shutter_ticket_description.meta.js
// @downloadURL  https://openuserjs.org/install/floodmeadows/Jira_paste_shutter_ticket_description.user.js
// @grant        none
// ==/UserScript==

/* jshint esversion: 6 */

const debug = false;
const targetElementForButton = document.getElementById('descriptionmodule-label');

(function () {
    'use strict';

    if (debug) addButton("Clear description", targetElementForButton, clearDescription);
    addButton("Paste shutter ticket description", targetElementForButton, pasteIntoDescription);
})();

function addButton(buttonText, targetElement, functionName) {
    const button = document.createElement("button");
    button.setAttribute("class", "aui-button");
    button.addEventListener("click", functionName);
    const text = document.createTextNode(buttonText);
    button.appendChild(text);
    targetElement.after(button);
}

function pasteIntoDescription() {
    //--- Get standard info ---//
    const currentUrl = new URL(document.URL);
    const jiraBaseUrl = currentUrl.protocol + '//' + currentUrl.host;
    const currentIssueKey = document.getElementById("key-val").childNodes[0].nodeValue;
    const apiUrl = `${jiraBaseUrl}/rest/api/latest/issue/${currentIssueKey}`;
    if(debug) console.log('URL: ' + apiUrl);

    var headers = new Headers();
    headers.append("Content-Type", "application/json");

    var requestOptions = {
        method: 'GET',
        headers: headers
    };

    fetch(apiUrl, requestOptions)
        .then(function() {
            navigator.clipboard.readText()
                .then(clipboardText => {
                    console.log('Clipboard text: ', clipboardText);
                    const newDescription = removeLeadingAndTrailingDoubleQuotes(convertDoubleDoubleQuotesToSingleDoubleQuotes(clipboardText));
                    console.log("New description = '" + newDescription + ".'");
                    updateDescription(newDescription);
                })
                .catch(err => {
                    console.error('Failed to read clipboard contents: ', err);
                });
        })
        .catch(error => {
            console.log('error', error);
            return false;
        });
}

function clearDescription() {
    updateDescription("");
}

function updateDescription(newDescription) {
    //--- Get standard info ---//
    const currentUrl = new URL(document.URL);
    const jiraBaseUrl = currentUrl.protocol + '//' + currentUrl.host;
    const currentIssueKey = document.getElementById("key-val").childNodes[0].nodeValue;
    const updateIssueUrl = `${jiraBaseUrl}/rest/api/latest/issue/${currentIssueKey}`;

    var headers = new Headers();
    headers.append("Content-Type", "application/json");

    var jsonToUpdateIssue = JSON.stringify({
        "fields": {
            "description": newDescription
        }
    });

    if (debug) console.log(jsonToUpdateIssue);

    var requestOptions = {
        method: 'PUT',
        headers: headers,
        body: jsonToUpdateIssue
    };

    fetch(updateIssueUrl, requestOptions)
        .then(response => {
            console.log(response.text());
            if(!debug) window.location.assign(currentUrl);
        })
        .catch(error => console.log('error', error));
}


function convertDoubleDoubleQuotesToSingleDoubleQuotes(text) {
    return text.replace(/""/g, '"');
}

function removeLeadingAndTrailingDoubleQuotes(text) {
    return text.substring(1,text.length-1);
}