Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to POST attachment to JIRA using REST API?

Tags:

rest

c#

jira

How to POST attachment to JIRA using JIRA REST API and HttpWebRequest in C#?

From the documentation under /rest/api/2/issue/{issueIdOrKey}/attachments:

POST

Add one or more attachments to an issue.

This resource expects a multipart post. The media-type multipart/form-data is defined in RFC 1867. Most client libraries have classes that make dealing with multipart posts simple. For instance, in Java the Apache HTTP Components library provides a MultiPartEntity that makes it simple to submit a multipart POST.

In order to protect against XSRF attacks, because this method accepts multipart/form-data, it has XSRF protection on it. This means you must submit a header of X-Atlassian-Token: nocheck with the request, otherwise it will be blocked.

The name of the multipart/form-data parameter that contains attachments must be "file"

A simple example to upload a file called "myfile.txt" to issue REST-123:

curl -D- -u admin:admin -X POST -H "X-Atlassian-Token: nocheck" -F "[email protected]" http://myhost.test/rest/api/2/issue/TEST-123/attachments


I have

foreach (JIRAAttachments attachm in attachments.attachments)
{
    request = HttpWebRequest.Create(
                  logInformation.GetUri() + "/rest/api/2/issue/" + key + "/attachments"
              ) as HttpWebRequest;
    request.Headers.Add("Authorization: Basic " + logInformation.GetEncodeAuthentication());
    request.Method = "POST";
    request.ContentType = "multipart/form-data";
    request.Headers.Add("X-Atlassian-Token: nocheck file=@" + Path.GetFullPath(@"..\Attachments\" + attachm.filename));
    request.KeepAlive = true;
    request.Proxy = wp;
    response = (HttpWebResponse)request.GetResponse();
    Stream s = response.GetResponseStream();
    FileStream fs = new FileStream(Path.GetFullPath(@"..\Attachments\" + attachm.filename), FileMode.Open);
    byte[] write = new byte[256];
    int count = fs.Read(write, 0, write.Length);
    while (count > 0)
    {
        s.Write(write, 0, count);
        count = fs.Read(write, 0, write.Length);
    }
    fs.Close();
    s.Close();
    response.Close();
}

but it returns a 404 error...

like image 992
Jiří Hejduk Avatar asked Aug 09 '12 15:08

Jiří Hejduk


3 Answers

solved your problem:

var boundary = string.Format("----------{0:N}", Guid.NewGuid());
System.IO.MemoryStream content = new MemoryStream();
var writer = new StreamWriter(content);
foreach (var att in attachments)
{

    writer.WriteLine("--{0}", boundary);
    writer.WriteLine("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", "file", Path.GetFileName(att["filename"]));
    writer.WriteLine("Content-Type: {0}", att.ContentType);
    writer.WriteLine();
    writer.Flush();
    att.Stream.CopyTo(content);
    writer.WriteLine();
}
writer.WriteLine("--" + boundary + "--");
writer.Flush();
content.Seek(0, SeekOrigin.Begin);


HttpWebRequest oRequest = null;
oRequest = (HttpWebRequest)HttpWebRequest.Create(string.Format(RestBaseURI + "issue/{0}/attachments", item.Key));
oRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
oRequest.Method = "POST";
oRequest.Headers.Add("Authorization", AuthData);
oRequest.Headers.Add("X-Atlassian-Token", "nocheck");
oRequest.UseDefaultCredentials = true;
oRequest.KeepAlive = true;
oRequest.ContentLength = content.Length;

using (var oStream = oRequest.GetRequestStream())
{
    content.CopyTo(oStream);
}

using (var oResponse = (HttpWebResponse)oRequest.GetResponse())
{
    using (var reader = new StreamReader(oResponse.GetResponseStream()))
    {
        var responseData = reader.ReadToEnd();
        var data = JObject.Parse(responseData);
    }
}

PS: thanks2mod to delete my previous post! nice ...

like image 87
mabunixda Avatar answered Jan 03 '23 13:01

mabunixda


There was a couple of mistakes in the OP's code.

With the snippet provided by @mabu and the code I found on http://www.briangrinstead.com/blog/multipart-form-post-in-c, here's a *functional** Code Block to Upload attachment to Jira.

public bool AddAttachments(string issueKey, IEnumerable<string> filePaths)
{
    string restUrl = Jira.FormatRestUrl(m_JiraId, true);
    string issueLinkUrl = String.Format("{0}/issue/{1}/attachments", restUrl, issueKey);

    var filesToUpload = new List<FileInfo>();
    foreach (var filePath in filePaths)
    {
        if (!File.Exists(filePath))
        {
            Jira.LogError("File '{0}' doesn't exist", filePath);
            return false;
        }

        var file = new FileInfo(filePath);
        if (file.Length > 10485760) // TODO Get Actual Limit
        {
            Jira.LogError("Attachment too large");
            return false;

        }

        filesToUpload.Add(file);
    }

    if (filesToUpload.Count <= 0)
    {
        Jira.LogWarning("No file to Upload");
        return false;
    }

    return PostMultiPart(issueLinkUrl, filesToUpload);
}

private Boolean PostMultiPart(string restUrl, IEnumerable<FileInfo> filePaths)
{
    HttpWebResponse response = null;
    HttpWebRequest request = null;

    try
    {
        var boundary = string.Format("----------{0:N}", Guid.NewGuid());
        var content = new MemoryStream();
        var writer = new StreamWriter(content);

        foreach (var filePath in filePaths)
        {
            var fs = new FileStream(filePath.FullName, FileMode.Open, FileAccess.Read);
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            fs.Close();

            writer.WriteLine("--{0}", boundary);
            writer.WriteLine("Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"", filePath.Name);
            writer.WriteLine("Content-Type: application/octet-stream");
            writer.WriteLine();
            writer.Flush();

            content.Write(data, 0, data.Length);

            writer.WriteLine();
        }

        writer.WriteLine("--" + boundary + "--");
        writer.Flush();
        content.Seek(0, SeekOrigin.Begin);

        request = WebRequest.Create(restUrl) as HttpWebRequest;
        if (request == null)
        {
            Jira.LogError("Unable to create REST query: {0}", restUrl);
            return false;
        }

        request.Method = "POST";
        request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
        request.Accept = "application/json";
        request.Headers.Add("Authorization", "Basic " + m_EncodedCredential);
        request.Headers.Add("X-Atlassian-Token", "nocheck");
        request.ContentLength = content.Length;

        using (Stream requestStream = request.GetRequestStream())
        {
            content.WriteTo(requestStream);
            requestStream.Close();
        }

        using (response = request.GetResponse() as HttpWebResponse)
        {
            if (response.StatusCode != HttpStatusCode.OK)
            {
                var reader = new StreamReader(response.GetResponseStream());
                Jira.LogError("The server returned '{0}'\n{1}", response.StatusCode, reader.ReadToEnd());
                return false;
            }

            return true;
        }
    }
    catch (WebException wex)
    {
        if (wex.Response != null)
        {
            using (var errorResponse = (HttpWebResponse)wex.Response)
            {
                var reader = new StreamReader(errorResponse.GetResponseStream());
                Jira.LogError("The server returned '{0}'\n{1}).", errorResponse.StatusCode, reader.ReadToEnd());
            }
        }

        if (request != null)
        {
            request.Abort();
        }

        return false;
    }
    finally
    {
        if (response != null)
        {
            response.Close();
        }
    }
}
like image 30
Jeff Caron Avatar answered Jan 03 '23 13:01

Jeff Caron


I really didn't want to deal with all that boundary stuff, so here's my shot at it. This works against Confluence whose API looks identical to Jira.

Thanks to Michael Teper at ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient and Jeff Caron (above).

var contents = "some long HTML that I wanted to upload";
var fileName = "Some fancy file name.html";

using (var client = new HttpClient())
{
    var uri = new Uri(URL);

    client.BaseAddress = new Uri(URL);
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    client.DefaultRequestHeaders.Authorization = authorization;
    client.DefaultRequestHeaders.Add("X-Atlassian-Token", "nocheck");

    var uriPath = String.Format(AttachmentPath, pageId);

    var content = new MultipartFormDataContent();
    var fileContent = new StringContent(contents);
    // also tested to work: 
    // var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes(contents));
    content.Add(fileContent, "file", fileName);

    var response = await client.PostAsync(uriPath, content);
    if (response.IsSuccessStatusCode)
    {
        return TaskResult.Success(null, response.ReasonPhrase);
    }
    else
    {
        return TaskResult.Failure("Service responded with Status Code: " + response.StatusCode + Environment.NewLine + "Reason Phrase: " + response.ReasonPhrase);
    }
}
like image 38
Colin Avatar answered Jan 03 '23 13:01

Colin