kenor kenor - 4 days ago 5
Java Question

Single file upload in JIRA

I am trying to upload a single file on JIRA for my plugin. Default JIRA upload behaviour is uploading the files via Ajax and converting them to checkboxes, thus enabling multiple file to be "uploaded" via one form

type="file"
element (see the picture).

attached files

To disable inline attaching, class
ignore-inline-attach
can be specified:

<form action="TestBrowse.jspa" id="upload-form" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="10000"/>
<input type="file" name="uploadFile" class="ignore-inline-attach"/>
<input type="submit"/>
</form>


But then, when I try to get the
MultipartRequestWrapper
in the servlet / action, I get nothing (this should be the way to go according to various sources, like here):

@Override
public String doExecute() throws Exception {
MultiPartRequestWrapper requestWrapper = ServletActionContext.getMultiPartRequest();
if (requestWrapper == null)
log.error("Why am I not getting a multipart wrapper?")
else {
...do something...
}
return returnCompleteWithInlineRedirect("/browse/" + getIssueObject().getKey());
}


Also, the enctype of the request seems to be
application/x-www-form-urlencoded; charset=UTF-8
, although
multipart/form-data
is clearly specified in the form template. Any ideas where I am making a mistake or some workaround?

Answer

This is a late answer but here's what I find out after 1 day investigating...

If your <input type="file"> is in a JIRA dialog, then the form is submitted using ajax. That's why the content type of the request is "application/x-www-form-urlencoded;". Try opening the link in a new browser tab and this problem disappears. You will receive a MultiPartRequestWrapper in the server because the form is submitted normally(without ajax).

1) Extend JIRA.FormDialog

My first approach was to extend the JIRA.FormDialog component to send a FormData object with the file and other form inputs. This worked and the server recieved a multipart/form-data request.

(edit) The problem was returning the response to the dialog. I couldn't find a way to do this. The response always returned a complete JIRA page with the header and footer because somehow the server did not know that I was in the context of a Dialog.

I find out what was the problem. The parameters inline and decorator where not being reed by the server (appended to the FormData object). I tried adding these parameters to the action url and it worked:

   <form ... action="MyUploadAction.jspa#if($action.isInlineDialogMode())?inline=true&decorator=dialog#end"> 

Here is the code:

var TEST = window.TEST || {};
TEST.FormDialog = JIRA.FormDialog.extend({
    _getFormDataAsObject: function() {
        var data = new FormData(this.$form[0]);
        data.append('inline', true);
        data.append('decorator', 'dialog');
        return data;
    }
});

JIRA.Dialogs.uploadFile = new TEST.FormDialog({
    id: "dialog-id",
    trigger: "a.dialog-trigger",
    ajaxOptions: JIRA.Dialogs.getDefaultAjaxOptions,        
    onSuccessfulSubmit : JIRA.Dialogs.storeCurrentIssueIdOnSucessfulSubmit,
    submitAjaxOptions: {
        type: "post",
        data: {
            inline: true,
            decorator: "dialog"
        },
        processData: false,
        contentType: false,
        mimeType: 'multipart/form-data',
        dataType: "html"
    }
});

2) FileReader API

Next I tried the FileReader API. When the user changed the file input, I read the file and store its contents in the DOM. When the form is submitted via ajax, the file content is treated like a normal var. I did not like this approach very much because, if the file is big, then the webpage will take this unnecessary memory storing the contents.

3) JIRA temporary files API

Finally, I tried to use the JIRA approach (removing ignore-inline-attach) for sending files as you enter them in the input. JIRA stores them as temporary files in the server. Then you must access them in the webwork action via the JIRA Attachment API. The downside with this approach is that it is possible to send multiple files but I just wanted to send a single file (like you).

Note that the last 2 approaches require two ways of handling the files in the server: 1) the normal MultiPartRequestWrapper because the user can still open the dialog in a new page and the form is not submitted via ajax. 2) specific of the approach.

I ended up using the 1) approach after solving the response problem (mentioned above). HTH

Comments