IBM Connections API - How to attach files to wiki pages? - ibm-connections

In the IBM Connections user interface, it's possible to attach files directly to wiki pages.
I want to attach files to wiki pages programatically, but can't find a documented way to do so.
I've been looking at the Connections 4.5 API documentation here:
http://www-10.lotus.com/ldd/appdevwiki.nsf/xpDocViewer.xsp?lookupName=IBM+Connections+4.5+API+Documentation#action=openDocument&content=catcontent&ct=prodDoc
Looking specifically at the APIs for Files and Wikis, there seems to be nothing about wiki-page attachments. While I'm mainly looking to upload attachments, I can't even see a documented API to retrieve attachments, despite the user-interface having a link to a feed (on each wiki page) that does that.
Is there any (possibly undocumented) API to attach files to a wiki page?

Here is some sample code to show how to do it in a supported way.
First, you need two URLs.
private static String apiUrlWikiNonce = "https://sdkdev.swg.usma.ibm.com:444/wikis/basic/api/nonce";
private static String apiUrlWikiAttachment = "https://sdkdev.swg.usma.ibm.com:444/wikis/form/api/wiki/{WIKI_LABEL_OR_WIKI_UUID}/page/{PAGE_LABEL_OR_PAGE_UUID}/feed";
Get the Nonce
/**
* gets the nonce value only valid return type is text, anything else throws
* an error
*
* #param httpClient
* #param user
* #param password
* #return
*/
public static String getNonce(CloseableHttpClient httpClient, String user,
String password) {
String result = "";
HttpGet httpGet = new HttpGet(apiUrlWikiNonce);
String combo = user + ":" + password;
String hash = org.apache.commons.codec.binary.Base64
.encodeBase64String(combo.getBytes());
System.out.println(user + " is logging in with " + hash);
String auth = "Basic " + hash;
httpGet.setHeader("Authorization", auth.replace("=", ""));
HttpClientContext context = HttpClientContext.create();
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httpGet, context);
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
StringWriter writer = new StringWriter();
IOUtils.copy(is, writer);
String responseString = writer.toString();
// System.out.println(responseString);
result = responseString;
EntityUtils.consume(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
Now that you have the nonce such as... b1911872-36f1-4767-956d-214759886406
Then upload a file with X-Update-Nonce
/**
* uploads a file to a given wiki page.
*
* #param httpClient
* #param user
* #param password
* #param wikiLabel
* #param wikiPage
* #param file
* #param nonce
* #return uuid <empty or uuid of file>
*/
public static String uploadFileToWiki(CloseableHttpClient httpClient, String user,
String password, String wikiLabel, String wikiPage, File file, String nonce){
String uuid = "";
String apiUrl = apiUrlWikiAttachment.replace("{WIKI_LABEL_OR_WIKI_UUID}", wikiLabel);
apiUrl = apiUrl.replace("{PAGE_LABEL_OR_PAGE_UUID}", wikiPage);
//Mandatory Parameter
apiUrl += "?category=attachment";
System.out.println("API Url : " + apiUrl);
HttpPost post = new HttpPost(apiUrl);
post.addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0");
post.addHeader("Content-Type", "image/png");
String combo = user + ":" + password;
String hash = org.apache.commons.codec.binary.Base64
.encodeBase64String(combo.getBytes());
System.out.println(user + " is logging in with " + hash);
String auth = "Basic " + hash;
post.setHeader("Authorization", auth.replace("=", ""));
HttpClientContext context = HttpClientContext.create();
CloseableHttpResponse response = null;
try {
EntityBuilder builder = EntityBuilder.create();
builder.setFile(file);
HttpEntity postentity = builder.build();
post.setHeader("Slug","NominalWorkItem-v1.png");
post.setHeader("title","Test Title");
post.setHeader("label","Test Test");
post.setEntity(postentity);
response = httpClient.execute(post, context);
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
StringWriter writer = new StringWriter();
IOUtils.copy(is, writer);
String responseString = writer.toString();
System.out.println(responseString);
uuid = responseString;
EntityUtils.consume(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return uuid;
}
The file is updated, and you get the response code 201 when created, and the XML
> <?xml version="1.0" encoding="UTF-8"?><entry
> xmlns:thr="http://purl.org/syndication/thread/1.0"
> xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"
> xmlns:snx="http://www.ibm.com/xmlns/prod/sn" xmlns:td="urn:ibm.com/td"
> xmlns="http://www.w3.org/2005/Atom"><id>urn:lsid:ibm.com:td:7780e11c-7240-41b3-8f0c-00a10ea69c93</id><td:uuid>7780e11c-7240-41b3-8f0c-00a10ea69c93</td:uuid><td:label>NominalWorkItem-v1.png</td:label><link
> href="https://sdkdev.swg.usma.ibm.com:444/wikis/form/api/wiki/744ccaeb-e9af-434c-9fa6-78831fb94846/page/3b017473-2dbe-4920-85a2-bf908a8e1475/attachment/7780e11c-7240-41b3-8f0c-00a10ea69c93/entry"
> rel="self"></link><link
> href="https://sdkdev.swg.usma.ibm.com:444/wikis/form/anonymous/api/wiki/744ccaeb-e9af-434c-9fa6-78831fb94846/page/3b017473-2dbe-4920-85a2-bf908a8e1475/attachment/7780e11c-7240-41b3-8f0c-00a10ea69c93/media/NominalWorkItem-v1.png"
> rel="alternate"></link><link
> href="https://sdkdev.swg.usma.ibm.com:444/wikis/form/api/wiki/744ccaeb-e9af-434c-9fa6-78831fb94846/page/3b017473-2dbe-4920-85a2-bf908a8e1475/attachment/7780e11c-7240-41b3-8f0c-00a10ea69c93/entry"
> rel="edit"></link><link
> href="https://sdkdev.swg.usma.ibm.com:444/wikis/form/api/wiki/744ccaeb-e9af-434c-9fa6-78831fb94846/page/3b017473-2dbe-4920-85a2-bf908a8e1475/attachment/7780e11c-7240-41b3-8f0c-00a10ea69c93/media"
> rel="edit-media"></link><link
> href="https://sdkdev.swg.usma.ibm.com:444/wikis/form/anonymous/api/wiki/744ccaeb-e9af-434c-9fa6-78831fb94846/page/3b017473-2dbe-4920-85a2-bf908a8e1475/attachment/7780e11c-7240-41b3-8f0c-00a10ea69c93/media/NominalWorkItem-v1.png"
> rel="enclosure" type="image/png" title="NominalWorkItem-v1.png"
> length="107763"></link><category term="attachment"
> scheme="tag:ibm.com,2006:td/type"
> label="attachment"></category><summary
> type="text"></summary><td:documentUuid>3b017473-2dbe-4920-85a2-bf908a8e1475</td:documentUuid><td:libraryId>744ccaeb-e9af-434c-9fa6-78831fb94846</td:libraryId><author><name>Frank
> Adams</name><snx:userid>6B54D23A-0A70-C7A4-8525-7CA50082A393</snx:userid><email>fadams#renovations.com</email><snx:userState>active</snx:userState></author><td:modifier><name>Frank
> Adams</name><snx:userid>6B54D23A-0A70-C7A4-8525-7CA50082A393</snx:userid><email>fadams#renovations.com</email><snx:userState>active</snx:userState></td:modifier><title
> type="text">NominalWorkItem-v1.png</title><published>2014-09-29T20:29:16.210Z</published><updated>2014-09-29T20:29:16.210Z</updated><td:created>2014-09-29T20:29:16.210Z</td:created><td:modified>2014-09-29T20:29:16.210Z</td:modified><td:lastAccessed></td:lastAccessed><content
> type="image/png"
> src="https://sdkdev.swg.usma.ibm.com:444/wikis/form/api/wiki/744ccaeb-e9af-434c-9fa6-78831fb94846/page/3b017473-2dbe-4920-85a2-bf908a8e1475/attachment/7780e11c-7240-41b3-8f0c-00a10ea69c93/media"></content></entry>

I think it is possible to do this with a multi-part post, but in my own code I'm doing it in steps:
POST the XML-Atom entry:
Url:
https://<Server>/<Wikis-Context-Root>/basic/api/wiki/<wikiUuid>/page/<pageUuid>/feed
Content:
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:td="urn:ibm.com/td">
<category label="attachment" scheme="tag:ibm.com,2006:td/type" term="attachment"/>
<td:label>file_name.extension</td:label>
</entry>
Headers:
Content-Type: <file mime-type, e.g. IMAGE/JPG>
Slug: <file_name.extension>
Response: 201; Location: URL to attachment entry
PUT the attachment content
Url: Location Response-Header of previous response, only exchange the last "/entry" for "/media"
Content: File-content stream
Headers:
Content-Type: <Mime-Type>
Response: 200 or 201
Optional: PUT a description for the file
Url: Location Response-Header of request from 1.)
Content:
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:td="urn:ibm.com/td">
<category label="attachment" scheme="tag:ibm.com,2006:td/type" term="attachment"/>
<summary type="text">MY ATTACHMENT DESCRIPTION TEXT</summary>
<td:label>file_name.extension</td:label>
</entry>
Headers:
Content-Type: application/atom+xml
Response: 200 or 201

Related

Azure blob storage java generate SAS token always throw sr is mandatory. Cannot be empty error

I want to use Java to generate a SAS token, this is what I do:
public static String GetSASToken(String resourceUri, String keyName, String key) {
long epoch = System.currentTimeMillis() / 1000L;
int week = 60 * 30 * 1000;
String expiry = Long.toString(epoch + week);
String sasToken = null;
try {
String stringToSign = URLEncoder.encode(resourceUri, "UTF-8") + "\n" + expiry;
String signature = getHMAC256(key, stringToSign);
sasToken =
"SharedAccessSignature sr=" + URLEncoder.encode(resourceUri, "UTF-8") + "&sig="
+
URLEncoder.encode(signature, "UTF-8") + "&se=" + expiry + "&skn="
+ keyName;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return sasToken;
}
public static String getHMAC256(String key, String input) {
Mac sha256_HMAC = null;
String hash = null;
try {
sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
Encoder encoder = Base64.getEncoder();
hash = new String(encoder.encode(sha256_HMAC.doFinal(input.getBytes("UTF-8"))));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return hash;
}
This code is nothing but copied from microsoft website,
Then in main class:
String key = "xxxxxHh9jP1ZOTYZI/z1OCVeThsjK00sSc3TYUuiHJQ==";
String kn = "frankbucket";
String url = "https://frankbucket.blob.core.windows.net/mycontainer";
System.out.print(AzureSASTokenGenerator.GetSASToken(url, kn, key));
when I run this, I got below SAS:
SharedAccessSignature sr=https%3A%2F%2Ffrankbucket.blob.core.windows.net%2Fmycontainer&sig=xxxj7Fgbkz5OSag%2BzFQAzBkIdd3I1J9AmFwxjcQg%3D&se=1588299503&skn=frankbucket
In Javascript:
var blobUri = 'https://frankbucket.blob.core.windows.net';
var token =
"SharedAccessSignature sr=https%3A%2F%2Ffrankbucket.blob.core.windows.net%2Fmycontainer&sig=ZA5fgKKny5%2BzdffvdEmy6WdsqqpoMsssssYYM9ruXgAdo0%3D&se=1588299257&skn=frankbucket";
var blobService = AzureStorage.Blob.createBlobServiceWithSas(blobUri, token);
blobService.listBlobsSegmented('mycontainer', null, function(error, results) {
When I run it, I got below error:
<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:ea315aac-001e-00a0-0700-0f2e4d000000
Time:2020-04-10T06:22:18.2383162Zsr is mandatory. Cannot be empty
I have no clue where is the issue, I got code form microsoft website, but it does not work.
Can anyone show me working example for this?
Hope to hear your advice.
Thanks
If you want to know how to create account sas token with java, please refer to the following code
public void callblobRestAPIWithSas() throws NoSuchAlgorithmException, InvalidKeyException, IOException {
// 1. create account sas token
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DATE, -2);
String start = fmt.format(cal.getTime());
cal.add(Calendar.DATE, 4);
String expiry = fmt.format(cal.getTime());
String StorageAccountName = "blobstorage0516";
String StorageAccountKey = "";
String apiVersion="2019-07-07";
String resource ="sco";
String permissions ="rwdlac";
String service = "b";
String stringToSign = StorageAccountName + "\n" +
permissions +"\n" + // signed permissions
service+"\n" + // signed service
resource+"\n" + // signed resource type
start + "\n" + // signed start
expiry + "\n" + // signed expiry
"\n" + // signed IP
"https\n" + // signed Protocol
apiVersion+"\n"; // signed version
SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(StorageAccountKey), "HmacSHA256");
Mac sha256HMAC = Mac.getInstance("HmacSHA256");
sha256HMAC.init(secretKey);
String signature=Base64.getEncoder().encodeToString(sha256HMAC.doFinal(stringToSign.getBytes("UTF-8")));
String sasToken = "sv=" + apiVersion +
"&ss=" + service+
"&srt=" + resource+
"&sp=" +permissions+
"&se=" + URLEncoder.encode(expiry, "UTF-8") +
"&st=" + URLEncoder.encode(start, "UTF-8") +
"&spr=https" +
"&sig=" + URLEncoder.encode(signature,"UTF-8");
//2. test the sas token
String resourceUrl="https://blobstorage0516.blob.core.windows.net/test/help.txt"; // your blob url
URL url = new URL(resourceUrl+"?"+sasToken);
OkHttpClient httpClient = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder()
.url(url)
.method("GET", null)
.build();
okhttp3.Response response = httpClient.newCall(request).execute();
if(response.isSuccessful()){
System.out.println("The blob content : "+ response.body().string());
}
}

enrollment error in using microsoft azure api during speaker enrollment

I am trying to use MS Azure Speaker recognition API (java) as per https://westus.dev.cognitive.microsoft.com/docs/services/563309b6778daf02acc0a508/operations/5645c3271984551c84ec6797 . I am able to get a identificationProfileId. The error occues when I try to enroll. Here is how I am enrolling
- get a wav file of the enrollment audio
- convert to base64 (thru online service)
- attach the base64 it as content to the call for enrollment along with identificationProfileId. I am doubtful about the b64 part
I am getting "Invalid Audio Format: Not a WAVE file - no RIFF header"
I am aware that the service needs the audio in PCM encoding as per doc.
Can someone pls let me know how to convert a wav audio to the required format that can be passed to the enrollment REST endpoint.
public class azureApiTest
{
public static String getID()
{
HttpClient httpclient = HttpClients.createDefault();
String ret = null;
try
{
URIBuilder builder = new URIBuilder("https://westus.api.cognitive.microsoft.com/spid/v1.0/identificationProfiles");
URI uri = builder.build();
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "application/json");
request.setHeader("Ocp-Apim-Subscription-Key", "fad541725xxxxxxx3362125790411");
// Request body
JsonObject locale = new JsonObject();
locale.addProperty("locale", "en-us");
StringEntity reqEntity = new StringEntity(locale.toString());
request.setEntity(reqEntity);
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null)
{
JsonParser parser = new JsonParser();
JsonObject o = parser.parse(EntityUtils.toString(entity)).getAsJsonObject();
ret = o.get("identificationProfileId").getAsString();
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
finally
{
return ret;
}
}
public static void main(String[] args)
{
HttpClient httpclient = HttpClients.createDefault();
try
{
String id = azureApiTest.getID();
System.out.println("ID created = "+id);
String enrollURL = "https://westus.api.cognitive.microsoft.com/spid/v1.0/identificationProfiles/" +id + "/enroll";
System.out.println("enrollURL = "+enrollURL);
URIBuilder builder = new URIBuilder(enrollURL);
builder.setParameter("shortAudio", "true");
URI uri = builder.build();
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "multipart/form-data");
request.setHeader("Ocp-Apim-Subscription-Key", "fad5417xxxxxxx3362125790411");
// Request body
File voiceb64 = new File("/Users/premnair/Desktop/vp/voice1b64.txt");
String data = FileUtils.readFileToString(voiceb64, "utf-8");
StringEntity reqEntity = new StringEntity(data);
request.setEntity(reqEntity);
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null)
{
System.out.println(EntityUtils.toString(entity));
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}
If I pass the file like in the snippet below it works !
File file = new File("/Users/jdoe/Desktop/vp/v5.wav");
request.setEntity( new FileEntity(file, ContentType.APPLICATION_OCTET_STREAM) );
Don't use base 64, just raw byte array data will work.

Writing a binary response (stream) directly to MIME in a Notes document

As I'm playing around with the Watson API I am using the Text2Speech service to get an audio stream (file) from the service. I already get the file with the code but my MIME doesn't contain anything later. I save the document after I call this method below. Any best pratices for streaming a byte content directly to a MIME would be appreciated.
public void getSpeechFromText(AveedoContext aveedoContext, Document doc, String fieldName, String text, String voiceName) {
try {
Session session = aveedoContext.getXspHelper().getSession();
session.setConvertMIME(false);
TextToSpeech service = new TextToSpeech();
String username = watsonSettings.getTextToSpeechUsername();
String password = watsonSettings.getTextToSpeechPassword();
if (username.isEmpty() || password.isEmpty()) {
throw new AveedoException("No credentials provided for service");
}
service.setUsernameAndPassword(username, password);
MIMEEntity mime = doc.getMIMEEntity(fieldName);
if (mime == null) {
mime = doc.createMIMEEntity(fieldName);
}
// local proxy?
if (!Util.isEmpty(customEndpoint)) {
// service.setEndPoint(customEndpoint + "/speech/");
}
Voice voice = Voice.getByName(voiceName);
AudioFormat audio = AudioFormat.WAV;
System.out.println("Fieldname: " + fieldName + "SPEECH: " + text + ", Voice: " + voice.getName() + ", Format: "
+ audio.toString());
InputStream stream = service.synthesize(text, voice, audio).execute();
InputStream in = WaveUtils.reWriteWaveHeader(stream);
Stream out = session.createStream();
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer);
}
mime.setContentFromBytes(out, "audio/wav", MIMEEntity.ENC_IDENTITY_BINARY);
out.close();
session.setConvertMIME(true);
in.close();
stream.close();
} catch (Throwable e) {
aveedoLogger.error("Error calling Watson service (text to speech)", e);
e.printStackTrace();
}
}
I believe that you need to create a child MIME entity. I use the following code in one of my apps to attach an image:
boolean convertMime = JSFUtil.getSessionAsSigner().isConvertMime();
if (convertMime) {
JSFUtil.getSessionAsSigner().setConvertMime(false);
}
final MIMEEntity body = doc.createMIMEEntity(getAttachmentFieldName());
// Add binary attachment
final MIMEEntity attachmentChild = body.createChildEntity();
final MIMEHeader bodyHeader = attachmentChild.createHeader("Content-Disposition");
bodyHeader.setHeaderVal("attachment; filename=" + incident.getPhoto().getName());
Stream imgStream = getPhoto(doc, incident.getPhoto());
attachmentChild.setContentFromBytes(imgStream, incident.getPhoto().getType(), MIMEEntity.ENC_IDENTITY_BINARY);
imgStream.close();
imgStream.recycle();
imgStream = null;
if (convertMime) {
JSFUtil.getSessionAsSigner().setConvertMime(true);
}

DocuSign "UNSPECIFIED_ERROR" Index was outside the bounds of the array

I'm trying to create a new envelope using the DocuSign REST API version 2. This is the response I'm getting:
{
"errorCode" : "UNSPECIFIED_ERROR",
"message" : "Index was outside the bounds of the array."
}
Here's the (sanitized and word wrapped) data that's being sent. Note that we're using OAuth2.
POST https://na2.docusign.net/restapi/v2/accounts/{account_id}/envelopes
Content-Length: 72523
Content-Type: application/json
Accept: application/json
Authorization: bearer{oauth2_token}
{"status": "created",
"documents": [
{"documentBase64": "<DELETED_BASE64_DATA>", "name": "Sample Document",
"documentId": "1"}
],
"emailSubject": "Documents to Sign",
"recipients": {
"signers": [
{"recipientId": "1", "email": "user#example.com",
"routingOrder": "1", "name": "Example User"
}
]
}
}
Any thoughts as to which index is out of bounds?
Thanks
You have the document bytes in the wrong location, and you need to make a proper multipart/form-data request to create a new DocuSign envelope. Here is a full code sample in C#, copy a document to the same directory and fill in the variables at the top and it should work for you.
Note that this was copied from the DocuSign API Walkthroughs:
// DocuSign API Walkthrough 04 in C# - Request Signature on a Document
//
// To run this sample:
// 1) Create a new .NET project.
// 2) Add 4 assembly references to the project: System, System.Net, System.XML, and System.XML.Linq
// 3) Update the email, password, integrator key, recipient name, and document name in the code
// 4) Copy a sample PDF file into project directory with same name as the document name you set in the code
// 5) Compile and Run
//
// NOTE 1: The DocuSign REST API accepts both JSON and XML formatted http requests. These C# API walkthroughs
// demonstrate the use of XML format, whereas the other walkthroughs show examples in JSON format.
using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Xml.Linq;
namespace DocuSignAPIWalkthrough04
{
public class RequestSignatureOnDocument
{
public static void Main ()
{
//---------------------------------------------------------------------------------------------------
// ENTER VALUES FOR THE FOLLOWING 6 VARIABLES:
//---------------------------------------------------------------------------------------------------
string username = "***"; // your account email
string password = "***"; // your account password
string integratorKey = "***"; // your account Integrator Key (found on Preferences -> API page)
string recipientName = "***"; // recipient (signer) name
string recipientEmail = "***"; // recipient (signer) email
string documentName = "***"; // copy document with same name and extension into project directory (i.e. "test.pdf")
string contentType = "application/pdf"; // default content type is PDF
//---------------------------------------------------------------------------------------------------
// additional variable declarations
string baseURL = ""; // - we will retrieve this through the Login API call
try {
//============================================================================
// STEP 1 - Login API Call (used to retrieve your baseUrl)
//============================================================================
// Endpoint for Login api call (in demo environment):
string url = "https://demo.docusign.net/restapi/v2/login_information";
// set request url, method, and headers. No body needed for login api call
HttpWebRequest request = initializeRequest( url, "GET", null, username, password, integratorKey);
// read the http response
string response = getResponseBody(request);
// parse baseUrl from response body
baseURL = parseDataFromResponse(response, "baseUrl");
//--- display results
Console.WriteLine("\nAPI Call Result: \n\n" + prettyPrintXml(response));
//============================================================================
// STEP 2 - Send Signature Request from Template
//============================================================================
/*
This is the only DocuSign API call that requires a "multipart/form-data" content type. We will be
constructing a request body in the following format (each newline is a CRLF):
--AAA
Content-Type: application/xml
Content-Disposition: form-data
<XML BODY GOES HERE>
--AAA
Content-Type:application/pdf
Content-Disposition: file; filename="document.pdf"; documentid=1
<DOCUMENT BYTES GO HERE>
--AAA--
*/
// append "/envelopes" to baseURL and use for signature request api call
url = baseURL + "/envelopes";
// construct an outgoing XML formatted request body (JSON also accepted)
// .. following body adds one signer and places a signature tab 100 pixels to the right
// and 100 pixels down from the top left corner of the document you supply
string xmlBody =
"<envelopeDefinition xmlns=\"http://www.docusign.com/restapi\">" +
"<emailSubject>DocuSign API - Signature Request on Document</emailSubject>" +
"<status>sent</status>" + // "sent" to send immediately, "created" to save as draft in your account
// add document(s)
"<documents>" +
"<document>" +
"<documentId>1</documentId>" +
"<name>" + documentName + "</name>" +
"</document>" +
"</documents>" +
// add recipient(s)
"<recipients>" +
"<signers>" +
"<signer>" +
"<recipientId>1</recipientId>" +
"<email>" + recipientEmail + "</email>" +
"<name>" + recipientName + "</name>" +
"<tabs>" +
"<signHereTabs>" +
"<signHere>" +
"<xPosition>100</xPosition>" + // default unit is pixels
"<yPosition>100</yPosition>" + // default unit is pixels
"<documentId>1</documentId>" +
"<pageNumber>1</pageNumber>" +
"</signHere>" +
"</signHereTabs>" +
"</tabs>" +
"</signer>" +
"</signers>" +
"</recipients>" +
"</envelopeDefinition>";
// set request url, method, headers. Don't set the body yet, we'll set that separelty after
// we read the document bytes and configure the rest of the multipart/form-data request
request = initializeRequest( url, "POST", null, username, password, integratorKey);
// some extra config for this api call
configureMultiPartFormDataRequest(request, xmlBody, documentName, contentType);
// read the http response
response = getResponseBody(request);
//--- display results
Console.WriteLine("\nAPI Call Result: \n\n" + prettyPrintXml(response));
}
catch (WebException e) {
using (WebResponse response = e.Response) {
HttpWebResponse httpResponse = (HttpWebResponse)response;
Console.WriteLine("Error code: {0}", httpResponse.StatusCode);
using (Stream data = response.GetResponseStream())
{
string text = new StreamReader(data).ReadToEnd();
Console.WriteLine(prettyPrintXml(text));
}
}
}
} // end main()
//***********************************************************************************************
// --- HELPER FUNCTIONS ---
//***********************************************************************************************
public static HttpWebRequest initializeRequest(string url, string method, string body, string email, string password, string intKey)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create (url);
request.Method = method;
addRequestHeaders( request, email, password, intKey );
if( body != null )
addRequestBody(request, body);
return request;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
public static void addRequestHeaders(HttpWebRequest request, string email, string password, string intKey)
{
// authentication header can be in JSON or XML format. XML used for this walkthrough:
string authenticateStr =
"<DocuSignCredentials>" +
"<Username>" + email + "</Username>" +
"<Password>" + password + "</Password>" +
"<IntegratorKey>" + intKey + "</IntegratorKey>" +
"</DocuSignCredentials>";
request.Headers.Add ("X-DocuSign-Authentication", authenticateStr);
request.Accept = "application/xml";
request.ContentType = "application/xml";
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
public static void addRequestBody(HttpWebRequest request, string requestBody)
{
// create byte array out of request body and add to the request object
byte[] body = System.Text.Encoding.UTF8.GetBytes (requestBody);
Stream dataStream = request.GetRequestStream ();
dataStream.Write (body, 0, requestBody.Length);
dataStream.Close ();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
public static void configureMultiPartFormDataRequest(HttpWebRequest request, string xmlBody, string docName, string contentType)
{
// overwrite the default content-type header and set a boundary marker
request.ContentType = "multipart/form-data; boundary=BOUNDARY";
// start building the multipart request body
string requestBodyStart = "\r\n\r\n--BOUNDARY\r\n" +
"Content-Type: application/xml\r\n" +
"Content-Disposition: form-data\r\n" +
"\r\n" +
xmlBody + "\r\n\r\n--BOUNDARY\r\n" + // our xml formatted envelopeDefinition
"Content-Type: " + contentType + "\r\n" +
"Content-Disposition: file; filename=\"" + docName + "\"; documentId=1\r\n" +
"\r\n";
string requestBodyEnd = "\r\n--BOUNDARY--\r\n\r\n";
// read contents of provided document into the request stream
FileStream fileStream = File.OpenRead(docName);
// write the body of the request
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(requestBodyStart.ToString());
byte[] bodyEnd = System.Text.Encoding.UTF8.GetBytes(requestBodyEnd.ToString());
Stream dataStream = request.GetRequestStream();
dataStream.Write(bodyStart, 0, requestBodyStart.ToString().Length);
// Read the file contents and write them to the request stream. We read in blocks of 4096 bytes
byte[] buf = new byte[4096];
int len;
while ((len = fileStream.Read(buf, 0, 4096) ) > 0) {
dataStream.Write(buf, 0, len);
}
dataStream.Write(bodyEnd, 0, requestBodyEnd.ToString().Length);
dataStream.Close();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
public static string getResponseBody(HttpWebRequest request)
{
// read the response stream into a local string
HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse ();
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
string responseText = sr.ReadToEnd();
return responseText;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
public static string parseDataFromResponse(string response, string searchToken)
{
// look for "searchToken" in the response body and parse its value
using (XmlReader reader = XmlReader.Create(new StringReader(response))) {
while (reader.Read()) {
if((reader.NodeType == XmlNodeType.Element) && (reader.Name == searchToken))
return reader.ReadString();
}
}
return null;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
public static string prettyPrintXml(string xml)
{
// print nicely formatted xml
try {
XDocument doc = XDocument.Parse(xml);
return doc.ToString();
}
catch (Exception) {
return xml;
}
}
} // end class
} // end namespace

POI not sending xls file as attachment , sending as string

one of my junior code is not sending excel file as attachment . It is sending file like
------=_Part_0_2066339629.1374147892060
Content-Type: text/plain; name="Service_Change_Alert_Thu Jul 18 17:14:50 IST 2013.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="Service_Change_Alert_Thu Jul 18 17:14:50 IST 2013.xlsx"
UEsDBBQACAAIANqJ8kIAAAAAAAAAAAAAAAARAAAAZG9jUHJvcHMvY29yZS54bWytkV1LwzAUhu/7
K0Lu2yTr1BHaDlEGguLADsW7kB7bYvNBEu3892bdrCheennyPu/D4aRY79WA3sH53ugSs4xiBFqa
ptdtiXf1Jl3hdZUkhTQOts5YcKEHj2JL+xJ3IVhOiJcdKOGzGOuYvBinRIija4kV8lW0QBaUnhMF
QTQiCHKwpXbW4aOPS/vvykbOSvvmhknQSAIDKNDBE5Yx8s0GcMr/WZiSmdz7fqbGcczGfOLiRow8
3d0+TMunvfZBaAm4ShAqTnYuHYgADYoOHj4slPgrecyvrusNrhaU5Sm9SNmqZowvl/yMPhfkV//k
function is following
public void sendSeviceabilityMail(List<OctpinSaveBean> datalist)
throws MessagingException {
Session session = null;
Map<String, String> utilsMap = ApplicationBean.utilsProperties;
if (utilsMap == null || utilsMap.size() == 0)
utilsMap = ApplicationBean.getUtilsPropertyFileValues();
smtpHost = utilsMap.get("SMTPHost");
to = utilsMap.get("To");
try {
if (smtpHost != null && to != null) {
Date date = new Date();
XSSFWorkbook updateDataBook =
updatedServiceabilityExcel(datalist);
Properties props = System.getProperties();
props.put("mail.smtp.host", smtpHost);
props.put("To", to);
session = Session.getInstance(props, null);
String str = "strstr";
Multipart multipart = new MimeMultipart();
BodyPart messageBodyPart1 = new MimeBodyPart();
messageBodyPart1.setContent(str, "text/html");
BodyPart messageBodyPart = new MimeBodyPart();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
updateDataBook.write(baos);
byte[] bytes = baos.toByteArray();
DataSource ds = new ByteArrayDataSource(bytes,
"application/vnd.ms-excel");
DataHandler dh = new DataHandler(ds);
messageBodyPart.setDataHandler(dh);
String fileName = "Service_Change_Alert_" + date+".xlsx";
messageBodyPart.setFileName(fileName);
messageBodyPart.setHeader("Content-disposition", "attachment;
filename=\"" + fileName + "\"");
multipart.addBodyPart(messageBodyPart1);
multipart.addBodyPart(messageBodyPart);
if (to != null && to.length() > 0) {
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("tech_noida
<tech_noida#xyz.com>"));
String[] toArray = to.split(",");
InternetAddress[] address = new
InternetAddress[toArray.length];
for (int i = 0; i < toArray.length; i++) {
address[i] = new InternetAddress(toArray[i]);
}
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject("Updated Serviceability Alert!!!");
msg.setContent(multipart);
msg.setSentDate(date);
try {
Transport.send(msg);
logger.info("Mail has been sent about the updated serviceability alert to :" + to);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
The problem is not related to POI, but with JavaMail (plus the way different email clients handles the specs and malformed emails). Try this:
Multipart multipart = new MimeMultipart();
MimeBodyPart html = new MimeBodyPart();
// Use actual html not "strstr"
html.setContent("<html><body><h1>Hi</h1></body></html>", "text/html");
multipart.addBodyPart(html);
// ...
// Joop Eggen suggestion to avoid spaces in the file name
String fileName = "Service_Change_Alert_"
+ new SimpleDateFormat("yyyy-MM-dd_HH:mm").format(date) + ".xlsx";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
updateDataBook.write(baos);
byte[] poiBytes = baos.toByteArray();
// Can be followed by the DataSource / DataHandler stuff if you really need it
MimeBodyPart attachment = new MimeBodyPart();
attachment.setFileName(filename);
attachment.setContent(poiBytes, "application/vnd.ms-excel");
//attachment.setDataHandler(dh);
attachment.setDisposition(MimeBodyPart.ATTACHMENT);
multipart.addBodyPart(attachment);
Update:
Also don't forget to call saveChanges to update the headers before sending the message.
msg.saveChanges();
See this answer for further details.

Resources