Confluence Scriptrunner Macro API: Upload an attachment (JQuery) Example.
Asked by IT Support:

Confluence Scriptrunner Macro API: Upload an attachment (JQuery) Example.

Please can someone advise me if it is possible to upload an attachment via an API using JQuery within a Confluence SR Macro?

I have successfully created a new page using the following example:

var jsondata = {"type":"page",  
"title":"My Test Page1",  
"space":{"key":"TST"},  
"body":{"storage":{"value":"\<p\>This is a TEST new page\</p\>","representation":"storage"}}};  

AJS.$.ajax({  
url: "https://confluence_server:8100/confluence/rest/api/content/",  
type: "POST",  
data:JSON.stringify(jsondata),  
dataType: "json",  
contentType: "application/json; charset=utf-8",  
success: function(msg){  
console.log("Success !");  
}  
});

The Atlassian Documentation:

[Confluence REST API examples (atlassian.com)](https://developer.atlassian.com/server/confluence/confluence-rest-api-examples/)

Gives a curl example:

curl -v -S -u admin:admin -X POST -H "X-Atlassian-Token: no-check" -F "file=@myfile.txt" -F "comment=this is my file" "http://localhost:8080/confluence/rest/api/content/3604482/child/attachment" \| python -mjson.tool

Please can you also advise what upload file paths are allowed for Windows Edge Chromium Browser i.e:

1) file : "//confluenec_server/temp/test.txt"

2) file : "file://localserver/temp/test.txt"


Answers:
author: Jonny Carter
body: So, this is an interesting question, and the answer may vary a little bit, depending on your use case. I'd like to hear a bit more about the *why* and *what* of what you're trying to accomplish.

Still, I can give you at least a couple of pointers on the "how".

I've created a very simple scripted macro for this example. It adds a form to the page that lets the end user upload an attachment to the page that they are on. Obviously, that's not very useful by itself, but it at least should give some idea how to interact with Confluence's REST API for attachments from JavaScript.

The macro's Groovy code is:

```
import groovy.xml.MarkupBuilder

def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
builder.form(class: "avatar-uploader") {
input(type: "file", class: "avatar-image", name: "file", accept: "image/png, image/jpeg")
button(class: "avatar-submit", type: 'button', "Upload attachment")
}

return writer.toString()
```

The JavaScript code is. I've left some rough console.log statements in there, just to help you follow the execution if you want to try it out.

```
AJS.toInit(($) => {
    console.log("Running intialization function");
    $('.avatar-uploader').each((index, $rootForm) => {
        console.log("Found avatar form", $rootForm);
        const submitButton = $rootForm.querySelector('button');
        console.log("Found submit button", submitButton);
        submitButton.addEventListener("click", clickEvent => {
            console.log("Clicked the button!");
            clickEvent.preventDefault();
            const pageId = Confluence.getContentId();
            console.log("Page id:", pageId);
            const formData = new FormData($rootForm);
            fetch(`${AJS.contextPath()}/rest/api/content/${pageId}/child/attachment`, {
                method: "POST",
                credentials: 'same-origin',
                headers: {
                    'X-Atlassian-token': 'no-check',
                },
                body  : formData
            }).then(response => console.log("Response", response));
        });
    });
});
```

The result should look something like this:

![example script macro to upload attachments.png](https://community.atlassian.com/t5/image/serverpage/image-id/124735iB522B6F2A05DF20E/image-dimensions/546x223?v=v2 "example script macro to upload attachments.png")

I assume that for your use case, you'll want to do things like target a different page for the attachments, or something along those lines. That could be accomplished by adjusting the pageId variable in the above JavaScript.

Best of luck!

comments: author: IT Support
body: Hi Jonny

Many thanks for you example. This works really well!

My Confluence page has a 'Select2' Dropdown Picker('select2-multiple') created by a Confluence Scriptrunner Macro. This Gets the JSON Metadata from a Confluence Scriptrunner Rest Endpoint(External MS SQL Stored Procedure).

I have the selected file URL( "localserver/temp/test.txt") to automatically add as an attachment to the Context PageID. This is also obtained from another Confluence Scriptrunner Rest Endpoint(External MS SQL Stored Procedure).

Please can you advise how I can change the script below:

```
const formData = new FormData($rootForm);
            fetch(`${AJS.contextPath()}/rest/api/content/${pageId}/child/attachment`, {
                method: "POST",
                credentials: 'same-origin',
                headers: {
                    'X-Atlassian-token': 'no-check',
                },
                body  : formData
            }).then(response => console.log("Response", response));
```

Can I automatically add the attachment details (File URL) to the formData object without the need for the input control?

Or Instead of passing formData object, is it possible to construct the required attachment File:value?

Below is a quick crude test example, I used to see if I could add a custom property value to a Confluence Page:

Example: Select2 Data = {key: "", value: "\[{"text":"File Name"}\]"}

AJS.$('#select2-multiple').change(function() {  
var dropdownData = {};  
dropdownData.key = '';  
const myObjStr = JSON.stringify($(this).select2('data'));  
dropdownData.value = myObjStr;  
console.log(dropdownData);  
AJS.$.ajax({  
url: "https://srvxxxxxx:8xxx/confluence/rest/api/content/26804233/property/my-property",  
type: "POST",  
data:JSON.stringify(dropdownData),  
dataType: "json",  
contentType: "application/json; charset=utf-8",  
success: function(msg){  
console.log("Success !");  
}  
});  
});

Please can you advise the best way forward?

Best Regards

Jonathan.


author: IT Support
body: Updated:

For Security Reasons I have completely changed my approach for this requirement.

Many Thanks.


Tags: confluence-server

server