Speaking at Dreamforce next week :)

Next week I will be in San¬†Fransisco for the Dreamforce conference – this will be the biggest conference I have attended, never mind spoken at and I am really excited to go ūüôā

If anyone is going to be around at the conference¬†or in the area – ping me on Twitter @MarkyRoden¬†– be good to meet up ūüôā

 

Unleashing the power with Salesforce and Microsoft Office 365 Add-ins

https://success.salesforce.com/MyAgenda?eventId=a1Q3000000qQOd9EAG#/session/a2q3A000000LBjBQAW

TIME & LOCATION

Moscone West, Developer Lightning Theater

Saving a word document directly from an Office Add-In into Salesforce.com

In this article I will demonstrate and discuss how to programmatically save a Word document directly into Salesforce.

Introduction

In previous articles we have looked at how to programmatically interact with a Word document from within an Office Add-In. In this case we will use the Office JavaScript API to access the file as a binary string and then convert it into a format compatible with Salesforce.com.

Turning your word document into a binary

This article in the Office dev center details how to Get the whole document from an add-in for PowerPoint or Word. We will use the bulk of that article up to the point where we send the slice. We are going to look at a modified sendSlice() function. The dev.office.com article details how you can access the binary contents of the word document, but falls short when it comes to getting the base64 encoded version of the file to be submitted to an external site. This is the complicated part !

Getting the right format for Salesforce

Unfortunately the salesforce documentation is¬†not based around using JavaScript to access the REST APIs.¬†It is based around using curl commands in UNIX.¬†The sample page for¬†Inserting or updating Blob Data¬†explains how to upload a multipart message which includes both the meta-data¬†values and the¬†binary data for the¬†file. For the record they also neglect to provide any guidance on how to get the binary of the file….!

Using the code posted on this stackoverflow post  we are able to turn a binary string into the necessary format to send the file to salesforce.

The final sendSlice() function is shown below. The significant thing to note is that the initial file must be sent to the ContentVersion sobject. Because this is a new document a parentId is not necessary and a ContentDocumentId is created. In a future article we will look at how to then associate this new file attachment is an existing object.

function sendSlice(slice, state) {
  updateStatus("In sendSlice");
  var data = slice.data;

  // If the slice contains data, create an HTTP request.
  if (data) {

    // Encode the slice data, a byte array, as a Base64 string.
    // NOTE: The implementation of myEncodeBase64(input) function isn't
    // included with this example. For information about Base64 encoding with
    // JavaScript, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding.

    var u8 = new Uint8Array(data);
    var b64encoded = btoa(String.fromCharCode.apply(null, u8));

    var objectData = {
      "Description": "Demo Upload Directly from Word",
      "Title": "sample.docx",
      "ReasonForChange": "Initial Upload",
      "PathOnClient": "sample.docx"
    }

    var boundary = 'boundary_string_' + Date.now().toString();
    var attachmentContentType = 'application/octet-stream';

    // Serialize the object, excluding the body, which will be placed in the second partition of the multipart/form-data request
    var serializedObject = JSON.stringify(objectData);

    var requestBodyBeginning = '--' + boundary
        + '\r\n'
        + 'Content-Disposition: form-data; name="entity_attachment";'
        + '\r\n'
        + 'Content-Type: application/json'
        + '\r\n\r\n'
        + serializedObject
        + '\r\n\r\n' +
        '--' + boundary
        + '\r\n'
        + 'Content-Type: ' + attachmentContentType
        + '\r\n'
        + 'Content-Disposition: form-data; name="VersionData"; filename="filler"'
        + '\r\n\r\n';

    var requestBodyEnd =
        '\r\n\r\n'
        + '--' + boundary + '--';

    // The atob function will decode a base64-encoded string into a new string with a character for each byte of the binary data.
    var byteCharacters = window.atob(b64encoded);

    // Each character's code point (charCode) will be the value of the byte.
    // We can create an array of byte values by applying .charCodeAt for each character in the string.
    var byteNumbers = new Array(byteCharacters.length);

    for (var i = 0; i < byteCharacters.length; i++) {
      byteNumbers[i] = byteCharacters.charCodeAt(i);
    }

    // Convert into a real typed byte array. (Represents an array of 8-bit unsigned integers)
    var byteArray = new Uint8Array(byteNumbers);

    var totalRequestSize = requestBodyBeginning.length + byteArray.byteLength + requestBodyEnd.length;

    var uint8array = new Uint8Array(totalRequestSize);
    var i;

    // Append the beginning of the request
    for (i = 0; i < requestBodyBeginning.length; i++) {
      uint8array[i] = requestBodyBeginning.charCodeAt(i) & 0xff;
    }

    // Append the binary attachment
    for (var j = 0; j < byteArray.byteLength; i++, j++) {
      uint8array[i] = byteArray[j];
    }

    // Append the end of the request
    for (var j = 0; j < requestBodyEnd.length; i++, j++) {
      uint8array[i] = requestBodyEnd.charCodeAt(j) & 0xff;
    }

    //Create the new file in Salesforce
    var url = "https://yourdomain.my.salesforce.com/services/data/v37.0/sobjects/ContentVersion/"

    return $.ajax({
      method: "POST",
      url: url,
      processData: false,
      data: uint8array.buffer,
      headers: {
        "Content-Type": 'multipart/form-data' + "; boundary=\"" + boundary + "\"",
        "Authorization": "Bearer " + app.getCookie(app.addinName)
      }
    }).error(function (data) {
      updateStatus("FAIL: " + JSON.stringify(data))
    }).success(function (data) {
      updateStatus("Success creating ContentVersion: " + data.id)
      closeFile(state)
    });

  }
}

 

Conclusion

In this article we have seen an example of how we can extend the functionality of an Office Add-In to access the binary data of a word document and then save it to a cloud provider (in this case Salesforce).

 

Adding an attachment to an opportunity using Salesforce REST APIs

In this article I will show the simple and straight forward method for adding an attachment to a Opportunity using the Salesforce REST APIs.

Introduction

This article is written as a summation of a frustrating couple of days trying to discern the Salesforce REST API documentation. I started with the Insert or update Blob page. With all the examples based on UNIX commands it made it very difficult to figure out how to do this using client side JavaScript.

Eventually I realized there was a link to the¬†SObject Basic Information help page¬†and¬†SObject Rows help page. Using a combination of all three¬†pages of information as a reference I was able to figure out how to do what I needed to. I needed to write it up as I will likely forget about it ūüėČ

Adding attachments

To add an attachment into Salesforce you have to get the base64 encoded string thereof and submit it as an Attachment Object, referencing the parentId of the Opportunity.

In my example I have an opportunity Id = 00658000004kGVRAA2. note that there are no attachments.

sa1

Using the combination of the three help documents I was able to figure out that sending the base64 encoded attachment to the opportunity is nothing more complicated that constructing the following

var root = "https://yourpath.my.salesforce.com/"

var url = root+"services/data/v37.0/sobjects/Attachment"

var data = {
  "Name" : "demoAttachment.pdf",
  "Body": "Base64Encoded Attachment",
  "parentId": "00658000004kGVRAA2" //the id of the opportunity
}

$.ajax({
  url: url,
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer "+OAuthToken
  },
  data: JSON.stringify(data)
})

When the POST is successful you will receive the new Id of the Attached file

sa2

The attachment appears on the opportunity

sa3

and we can download and open the file

sa4

Conclusion

The important part of this example is to understand that we are not creating an attachment from the opportunity. We are creating the attachment and associating itself with the opportunity. Trying to go at the opportunity and throw the attachment at it directly was a complete failure.

Speaking at SharePointFest Chicago 2016

I am very excited to announce that I have been accepted to speak at SharePointFest, December 8th 2016 in Chicago.

http://www.sharepointfest.com/~spfadmin/Chicago/index.php/sessions/38-sharepoint-development/118-dev103-office-365-add-ins-a-web-developer-s-playground

Title 
DEV 103 – Office 365 Add-Ins: A web developer’s playground

Abstract
Like most office workers, we all spend a significant amount of time in our “Microsoft Office” productivity tools. Even email is still a productivity tool. Productivity starts to diminish though if we have to move outside of our Office environment and hunt for information and/or complete business workflow processes.

With the creation of Office 365 Add-Ins, Microsoft has presented web developers with a new opportunity to create rich, engaging and integrated user experiences without having to leave the “experience” of our Office applications. Developers have the ability to create Add-Ins using HTML/JS/CSS and these run in the Windows Client, on the web, on our phones and even on the OS X desktop client.

In this presentation Mark will provide lots of demonstrations of how to get started with Office Add-Ins. These will include: creating your first Add-In in under 2 minutes, how to simplify workflow approval without having to leave your email client, how to pull report and analytics data into your Office product suite applications, integrating SharePoint as a Service, integration with Salesforce and how to integrate your content with cognitive analytics.

Come to the presentation and find out why Office 365 Add-Ins are a modern web developers playground.

Speaking at Dreamforce 2016 – Unleashing the power with Salesforce and Microsoft Office 365 Add-ins

I am so SO excited to annouce that I have been accepted to speak at the largest technology conference in the world, Salesforce’s Dreamforce conference in San Francisco.¬†I will be co-speaking with my very good friend¬†old¬†Winklebeard himself (Ren√© Winkelmeyer). This opportunity is all down to him and I will be forever grateful. Ren√© became a Salesforce Evangelist back in May¬†2016. While we were at Engage.ug back in March this year we hatched a far fetched plan to be able to speak together and who’d have thought our world would have come together outside of the IBM Bubble.

We are going to talk about using Office Add-Ins to integrate with Salesforce. We are going to go well beyond the out of the box Office Add-Ins which Salesforce make available and show developers how to create their own from¬†scratch. There will be lots of cool demonstrations,¬†and hopefully we will both make it off stage without killing each other ūüôā

I am really excited !!

https://success.salesforce.com/Sessions?eventId=a1Q3000000qQOd9#/session/a2q3A000000LBjBQAW

Title
Unleashing the power with Salesforce and Microsoft Office 365 Add-ins

Abstract
Salesforce has created great out-of-the box integrations for Office 365. But have you ever thought about creating your own integrations for maximising your Salesforce and Office investments? That‚Äôs where Office 365 Add-ins and Lightning come to the rescue. Based on real-world scenarios you‚Äôll learn in this session all about the ‚Äúhow‚ÄĚ and ‚Äúwhere‚ÄĚ of connecting Office and Salesforce. After starting with needed authentication setups between the systems we‚Äôll quickly dive deep into the programmatic aspects. Be it RESTful or Lightning Out, we‚Äôll get you covered! Come and see the session where Mark and Ren√© will demonstrate custom integration between Salesforce and Office applications on all platforms. Source code will be provided for all examples shown.