How to upload an attachment to a work item via REST API
Hi,
I'm currently working with python to interface with the RTC REST API, and have been having a lot of success so far. I've hit a bit of a problem however in uploading an attachment to a project and linking it to a work item.
I've done plenty of googling on this one and have found a couple of people using java as a solution however this doesn't really help me. The same article mentions REST but in the form of:
So, it should be doable with HTML (not sure about REST), but it is probably not trivial and undocumented.
I've also had a few people say that they have completed this with OSLC version 2.0 however without any details.
Currently I'm using the python requests library and the following is my code (assuming authentication has already taken place):
csrf = ""
for cookie in self.session.cookies:
if cookie.name == 'JSESSIONID':
csrf = cookie.value
self.session.headers.update({'Content-Type': 'multipart/form-data'})
post_params = { "projectId": "_At5S5zAUEeKjpdbNKmwlgA",
"multiple": "true",
"target": "_A_ziQDAUEeKjpdbNKmwlgA",
"category": "_BYNbMjAUEeKjpdbNKmwlgA"
}
upload_url = "https://hub.jazz.net/ccm/service/com.ibm.team.workitem.service.internal.rest.IAttachmentRestService/"
files = {'file': open(file_name, 'rb')}
post_response = self.session.post(upload_url, params=post_params, files=files)
print(post_response.json())
With the above I'm getting an error of "invalid post request", not sure what I'm doing wrong but I don't think that I'm that far off.
I've also tried looking at the source of the RQMUtility for uploading attachments without finding out any conclusive differences to what I'm trying to complete here.
Can anyone help?
Cheers,
Hugh
Accepted answer
I really don't like answering my own questions but here goes...
I did manage to get this working in the end up. It's a two step process, firstly uploading the attachment to the project area, and then linking that attachment to the work item.
def upload_attachment(self, file_location, work_item_number):
# First get the work item details
filters = {'oslc_cm.properties': 'oslc_cmx:project'}
attachment_work_item = self.get_work_item(work_item_number, filters=filters)
if attachment_work_item is None:
raise Exception("Error: Work item to add link to could not be found")
work_item_project_area = attachment_work_item['oslc_cmx:project']['rdf:resource'].rsplit('/', 1)[1]
file = open(file_location, 'rb')
file_short_name = os.path.basename(file.name)
files = {'attach': (file_short_name, file,
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')}
# This is really important for requests to work out what kind of content it is
if self.session.headers.__contains__('Content-Type'):
self.session.headers.__delitem__('Content-Type')
# Not a 100% sure what is the category here???? Seems to be constant for now through
post_params = {"projectId": work_item_project_area,
"multiple": "true",
"category": "_IlAckNAwEeOaT8v4QaB0Wg"}
url = self._base_url + "/ccm/service/com.ibm.team.workitem.service.internal.rest.IAttachmentRestService/"
upload_response = self.session.post(url, files=files, params=post_params)
if not upload_response.ok:
raise Exception("A problem occurred in retrieving the work item: "
+ upload_response.reason + " - " + upload_response.url)
return upload_response.json()
This code uses the python requests library. You can then link the attachment to the work item. The key part here is the attachment UUID which is returned from in the above response.
def add_attachment_link(self, work_item_number, attachment_uuid):
attachment_url = self._base_url + '/ccm/resource/itemOid/com.ibm.team.workitem.Attachment/' + attachment_uuid attachment_get_repsonse = self._session_get(attachment_url) attachment_get_repsonse_json = attachment_get_repsonse.json() attachment_identifier = attachment_get_repsonse_json['dcterms:identifier'] attachment_description = attachment_get_repsonse_json['dcterms:description']
# May need to add some checking in here to make sure that the work item is not closed or something
self.session.headers.update({'Content-Type': 'application/json'})
payload = {'rdf:resource': self._base_url + '/ccm/resource/itemOid/com.ibm.team.workitem.Attachment/' + attachment_uuid, 'dcterms:title': attachment_identifier.__str__() + ": " + attachment_description, } attachment_collection_url = self._base_url + "/ccm/oslc/workitems/" + work_item_number \ + "/rtc_cm:com.ibm.team.workitem.linktype.attachment.attachment" update_response = self._session_post(attachment_collection_url, payload)
return update_response.json()
You should then have a link to your workitem.
4 other answers
I am not aware that there is a public API to do this. This might be out of age knowledge. I know that others have used protocol tracking tools to determine how this is done and successfully coded up solutions. It is apparently a series of requests.
I only know how to do this with the Plain Java API. See https://rsjazz.wordpress.com/2012/08/01/uploading-attachments-to-work-items/
I only know how to do this with the Plain Java API. See https://rsjazz.wordpress.com/2012/08/01/uploading-attachments-to-work-items/
Comments
Hi,
I am using the follwing code to upload files using Lyo Client CM:
I am using the follwing code to upload files using Lyo Client CM:
Utils.java
private URI uploadAttachment(File file, ChangeRequest request,
JazzFormAuthClient client.String urlRTC, String projectAreaUUID) throws Exception {
URI attachmentUploadUrl = URI
.create(urlRTC
+ "/service/com.ibm.team.workitem.service.internal.rest.IAttachmentRestService/?projectId="+projectAreaUUID+"&multiple=true");
String fileName = file.getName();
byte[] bytes = FileUtils.readFileToByteArray(file);
OutPart outPart = new OutPart();
outPart.setContentType("application/octet-stream; name=" + fileName);
outPart.addHeader("Content-Transfer-Encoding", "binary");
outPart.addHeader("Content-Disposition", "form-data; name=\""
+ fileName + "\"; filename=\"" + fileName + "\"");
outPart.addHeader("Content-Length", String.valueOf(bytes.length));
outPart.addHeader("Accept", "application/text");
outPart.setBody(bytes);
String boundary = "---------------------------"
+ UUID.randomUUID().toString();
BufferedOutMultiPart requestEntity = new BufferedOutMultiPart();
requestEntity.addPart(outPart);
requestEntity.setBoundary(boundary);
ClientResponse response;
synchronized (client) {
response = client.createResource(attachmentUploadUrl.toString(),
requestEntity, "multipart/form-data; boundary=" + boundary);
}
if (response.getStatusCode() != HttpStatus.SC_OK) {
throw new Exception("Failed to upload attachment at "
+ attachmentUploadUrl.toString() + ". "
+ response.getStatusCode() + ": " + response.getMessage());
}
String uploadResponse = response.getEntity(String.class);
JSONObject obj = new JSONObject(uploadResponse.toString().substring(
uploadResponse.indexOf("[") + 1,
uploadResponse.lastIndexOf("]")));
String url = urlRTC
+ "/resource/itemOid/com.ibm.team.workitem.Attachment/"
+ obj.getString("uuid");
return URI.create(url);
}
Client.java
files=...
task=...
client=...
projectAreaUUID=...
urlRTC=...
ArrayList<URI> filesURL = new ArrayList<>();
for (File file : files) {
URI url = uploadAttachment(file, task, client,urlRTC, projectAreaUUID);
filesURL.add(url);
}
task.getExtendedProperties()
.put(new QName(RTC_NAMESPACE,
"com.ibm.team.workitem.linktype.attachment.attachment"),
filesURL);
Comments
Hi guys,
I am currently working on the same issue. I try to upload an attachment using Java (for RTC v6.0.1), without luck. No matter if I am posting the content directly or using Eclipse Lyo with Fernando's solution, I always see "Invalid POST request". It's not a matter of params as an error in the params section leads to an appropriate error message.
@fernd.fs: Does your solution work with v6 too? If yes it would be cool to know whether you modified your code in some way. It seems as I am missing something here but right now I don't get it.
@hmcmanus could you please post the JSON string you are sending in the body part of the request to the IAttachmentRestService?
Regards
Michael
I am currently working on the same issue. I try to upload an attachment using Java (for RTC v6.0.1), without luck. No matter if I am posting the content directly or using Eclipse Lyo with Fernando's solution, I always see "Invalid POST request". It's not a matter of params as an error in the params section leads to an appropriate error message.
@fernd.fs: Does your solution work with v6 too? If yes it would be cool to know whether you modified your code in some way. It seems as I am missing something here but right now I don't get it.
@hmcmanus could you please post the JSON string you are sending in the body part of the request to the IAttachmentRestService?
Regards
Michael
Comments
1 vote