SALESFORCE - Sundog

kokomomammothΛογισμικό & κατασκευή λογ/κού

17 Φεβ 2014 (πριν από 3 χρόνια και 8 μήνες)

177 εμφανίσεις

Salesforce — Where to Save my Files?
|
Terry Luschen
1
701.235.5525

|
888.sundog
|
fax: 701.235.8941
2000 44th St. S
|
Floor 6
|
Fargo, ND 58103
www.sundoginteractive.com
S AL E S F ORCE
July 2013
T E RRY L US CHE N
SYSTEMS ARCHITECT / SENIOR SOFTWARE ENGINEER
WHE RE T O S AVE MY F I L E S?
Salesforce — Where to Save my Files?
|
Terry Luschen
2
With almost every application built on the Force.com
platform, the question will be raised about where the
files should be stored. To define files I mean Word
Documents, PDF Files and Image Files. Should the files
be stored within Salesforce itself or should the files be
stored in some other location? In this whitepaper I would
first like to first share with you what Salesforce offers for
files saved within itself. Second I would like to review the
pros and cons of saving the files to a couple of other
cloud providers like Amazon Web Services (AWS) S3 and
Box. Finally I would like to take a deeper dive into the
APIs of AWS S3 and Box to help jump-start any custom
integrations projects.
DEFINING THE PROBLEM
Saving the files in Salesforce seems like the obvious
choice in most regards. The licenses for Salesforce have
been paid for and there are some great features that
already exist for saving files. These internal files integrate
with all of the out-of-the-box features of Salesforce
like Visualforce, the built-in APIs, customer/partner
communities and security. There are three main reasons
why companies go down the path of saving the files
outside of Salesforce.
1. Cost
a.
By default with the Enterprise and Ultimate
versions of Salesforce 612MB of storage space is
allocated for each license and more storage space
can be purchased[1].

b.
This may seem like a lot of storage space, but
what if part of your application is collecting tens of
thousands of contracts where each PDF is 4MB in
size? That can add up to a lot of space pretty quickly.
c.
The pricing for that extra file storage may make
storing the files in Salesforce cost prohibitive.
d. Salesforce does a great job at many features,
but there are some things we must realize that
Salesforce is not at this point. It is a not a data mart,
although it can store a lot of data. It is not a mass
email application, although there are a ton of email
options and integrations. And as we are discussing,
Salesforce is not a place where tons of files that will
take up a large amount of space are usually stored,
but it does have great features to store lots of files.
2. Document Management System (DMS[2]) Vision
does not fit with Salesforce.
a.
Having the documents that are important to a
business in Salesforce may not be the best place for
them.
b.
These files are important assets to the business
and it may be too expensive to buy enough licenses
for Salesforce in order to allow the appropriate
number of employees to access these files. Using
Chatter licenses at times can overcome this limitation.
c.
There may be another system where the files can
be kept so that they can be accessed outside of
Salesforce, but yet can be linked to within Salesforce.
Maybe a company’s standard is to keep all files in a
certain file share or a product like SharePoint.
3. The File Management Features in Salesforce are
not Adequate
a.
One example would be if files greater that 5MB
consistently needed to be attached to standard or
custom objects in Salesforce, but Chatter was not
enabled. Chatter allows attachments called feed items
to be larger than 5MB, but regular attachments have
to be smaller than 5MB.[3][4]
Salesforce — Where to Save my Files?
|
Terry Luschen
3
SALESFORCE – WHAT OPTIONS
DOES IT PROVIDE?
Salesforce provides four main options for dealing with
files out of the box.
1. Documents Tab
The documents tab is a global place where files can
be stored with a folder structure. New folders can be
created and files can be placed in those folders so
that they are organized. There is also a ‘My Personal
Documents’ folder where documents that only you
should have access to can be stored. These files cannot
be tied to individual standard or custom objects. The
folders created within the Documents Tab are all at the
same level so there is not nesting of folders.
2. Notes & Attachments
The ‘Notes & Attachments’ related list can be added
to the page layout each standard and custom object.
This is an easy way of adding files that do not need any
associated metadata, as attachments do not support
custom fields. An example requirement would be adding
PDFs to a Contract object. This option would be an easy
way to do that, as the ‘Notes & Attachments’ related list
simply needs to be added to the Page Layout for the
Contract object. One limit to keep in mind with ‘Notes &
Attachments’ is that the files cannot be larger than 5MB.
3. Salesforce Content
Salesforce Content helps to organize files into libraries.
This is very similar to the folder structure that can be
created within the Document Tab as listed in #1 above,
but, some added benefits of the Salesforce Content
structure are:
A.
The files placed in the library are full-text
searchable. So if you place a PDF in the library that
has the words ‘Model X456Z’ in it, then that text
can be found by searching Salesforce or by doing a
Salesforce Object Search Language (SOSL) search.
B.
Custom fields can be added to the files so more
metadata about the file can be saved. These fields get
added to the ContentVersion standard object, which
is where every revision to a document is kept.
C.
Salesforce Content has made dealing with
revisions very easy. Once a file is saved to Salesforce
Content, adding a new revision to a file and accessing
the old revisions is all handled by the Salesforce
user interface. Revisions could not be done with
the ‘Documents Tab’ or the ‘Notes & Attachments’
related list. There will be one row saved to the
ContentDocument standard object for each file and
one row for each revision of that document will be
saved to the ContentVersion standard object.
D.
In Salesforce Content the maximum file size is
2GB, so there basically isn’t a limit. The time where file
size limits will come into play is if you are loading the
files through the API or a Visualforce page. Here are
those limits.[4]
4. Chatter Files
Chatter Files are a recent addition to the Salesforce
offerings. Chatter must be enabled for this feature
to be available. You can think of Chatter Files as
combining the features of the ‘Notes & Attachments’
with ‘Salesforce Content’. Chatter Files are like ‘Notes
& Attachments’ because the files are tied directly to the
standard or custom object. The Chatter Files will show
up in the chatter feed since that is where they were
originally added, but they also show up in the ‘Notes
& Attachments’ section as a ‘Chatter Feed’ row. The
Chatter Files are stored in some libraries within the
Salesforce — Where to Save my Files?
|
Terry Luschen
4
Salesforce Content so you get most of the great features
of Salesforce Content, like full text searching and easy
revision creation. These libraries where the Chatter Files
are stored are hidden though so you cannot see them on
the library tab. The one feature that is not available with
Chatter Files is the addition of custom fields. This can be
worked around if the files are first added to Salesforce
Content and then linked to a Chatter feed. That, however,
would make some processes more complicated than
necessary. If needed, metadata can be moved up to the
standard or custom object as needed, but then you will
have to make sure that there is only one chatter file per
custom object if the metadata is file specific. The last
point about Chatter Files is that they are in Chatter so
users can post comments about these files specifically.
Cool!
WHY WOULD A COMPANY
DECIDE TO SAVE THE FILES
OUTSIDE OF SALESFORCE?
There can be a variety of reasons, but as mentioned
earlier it comes down to potentially three reasons.
1. Cost
2. Document Management System (DMS[2]) Vision
does not fit with Salesforce.
3. The File Management Features in Salesforce are
not adequate.
We now have some reasons why files might need to be
stored outside of Salesforce. There are a number of solid
providers of this type of file service. The features to look
for in such a provider are:
1. Cost
2. Folder Structure
3. API Access
4. Search Abilities
5. Tagging Options
6. Ease of Integration
Next I would like to write about two of the leading
providers in this external file storage space and some
detailed levels about working with each one of them.
AMAZON WEB SERVICES - S3
S3 provides a simple way to store files as one of the
Amazon Web Services (AWS). There are other AWS
services for storing files like CloudFront, Glacier and
Storage Gateway, but S3 is typical what is used in
this type of scenario. A free developer edition of AWS
is available for a year and sign-up is available here[5].
I would like to first review the features we should be
reviewing with each storage provider.
1. Cost
You pay only for what you use. When the price is about
10 cents per Gigabyte it is very reasonable. Here is the
pricing[6] sheet.
2. Folder Structure
A bucket is created and then files can be placed in
that bucket. A bucket is a unique name across all S3
instances. So if I create a bucket with a certain name,
then nobody else in the world can create a bucket with
that same name. Within that bucket folders can be
created so the concept of nested folders is available
within S3.
Salesforce — Where to Save my Files?
|
Terry Luschen
5
3. API Access
AWS is all about integration. Product after product can
be found that have been built on top of AWS. Even
Amazon’s base web site runs on top of the same AWS
infrastructure. Here[7] is the link to the S3 document to
the available REST and SOAP APIs. I will give an example
later about how to save a file to S3 using a simple POST
on an HTML form.
4. Search Abilities
a.
Search S3 itself – This searching is limited to the
metadata around the files, the file names and the
keys. Here[8] is a link for those search options.
b.
Search S3 using CloudSearch[9][10]. Although it
says CloudSearch is in Beta it seems like a powerful
option that Amazon uses itself for its own search
engine.
5. Tagging Options
If you look at the properties of each file in a bucket or
folder, there is a Metadata section that can be used to
add tags for each file.
6. Ease of Integration
AWS is all about making it easy to use their services to
get you to build your solution on top of their services.
S-Drive is an off-the-shelf solution specifically for
Salesforce integration that I will write about next.
A custom integration example will follow after that.
S-DRIVE FOR AMAZON S3 –
AN OFF-THE-SHELF SOLUTION
With Amazon Web Services S3 you can hire a company
to do a custom integration matching to exactly fit your
needs as S3 has open REST and SOAP APIs that are
easy to use. Or you can turn to an AppExchange product
like S-Drive[11], which has already done the integration
work and will allow you to tie files stored in S3 with
standard or custom objects.
AMAZON S3 CUSTOM
INTEGRATION EXAMPLE
Amazon Web Service’s S3 product can be accessed
through the SOAP or REST based web services. When
using S3 with Salesforce the upload process could be
driven from APEX with the http object, but there are certain
limits in Salesforce on the request and heap size that seem
to make it better to do a Post from the page itself.
Here is an example of uploading an image file to a bucket
on S3. I tried to make this example as simple as possible
with as little code and mark-up as possible. I really want
to show the simplest implementation so you can see how
Salesforce and AWS S3 can work together.
Work to do in AWS S3:
1. Sign up for an AWS account and log into AWS S3
2. Create a bucket and a folder
a.
When you are on the ‘All Buckets’ view there is a
‘Create Bucket’ button
b.
When you are in a bucket there is a ‘Create Folder’
button
Salesforce — Where to Save my Files?
|
Terry Luschen
6
3. Create/Find your Security Credentials
a.
Click on your name in the upper right-hand corner
and click on ‘Security Credentials’.
b.
This will take you to the ‘Security Credentials’ page.
c.
Go to the ‘Access Credentials’ section in the
middle of the page
d.
If there is not already an ‘Access Key’ listed then
click on the ‘Create a new Access Key’.
e.
Keep the ‘Access Key ID’ and the ‘Secret Access
Key’ in a safe place. We will paste these values into
our APEX Class and Visualforce Page later. Instead
of pasting these values in the code, they could be
saved in encrypted fields on a custom object and then
retrieved as needed.
Work to do in Salesforce…
1. Log into Salesforce
2. Create a Controller called AWS_SimpleUpload.
See Appendix 1 for the APEX code for that
Controller…
3. Create a Visualforce Page called AWS_Upload.
See Appendix 2 for the markup for the Visualforce
Page…
Here
[12] is a page that can help in generating the
Visualforce markup and the parameters that can be
retrieved from the APEX class.
Here
[13] is a page that really defines clearly the different
pieces of the markup. This article really helped me
understand that the Policy document that is encoded
within the controller must exactly match the Policy
settings that are set in the Visualforce page.
Here
[14] is the detailed documentation from Amazon
about HTML Forms for S3.
4. Here is a picture of my S3 bucket and folder
before I uploaded my image file.
5. Here is a picture of the Visualforce Page before I
hit the Upload button. I had developed this page in
my Salesforce development org. Notice that I just
need to add apex/ and the name of the Visualforce
Page to the URL to test the aws_upload Visualforce
Page.
6. Here is a picture of AWS S3 after I did the upload.
There is another way to jump-start any custom
integration projects between AWS and Salesforce with
the Force.com toolkit for Amazon Web Services[15].
This toolkit will provide some example on connecting to
S3 and even EC/2 from Salesforce.
Salesforce — Where to Save my Files?
|
Terry Luschen
7
1. Cost
Pricing can be found here[17]. As with most on-line
services and just like S3 there is a free personal use level
that is adequate for most consumers. There are also
Business and Enterprise plans available.
2. Folder Structure
The folder structure in Box is very easy to understand.
A hierarchical folder structure can be created through a
simple user interface.
3. API Access
Box is making efforts on its API to allow integration with
Salesforce and other Cloud offerings. This blog post[18]
talks about version 2 of Box’s API.
4. Search Abilities
Version 2 of the API has search capabilities built-in.
The same blog post above touches on the search API
options.
5. Tagging Options
Tagging is simple within Box and each file/folder can be
tagged separately.
6. Ease of Integration
Box, just like AWS, is all about making it easy to use
their services to get you to build your solution on top of
their services. Their version 2 API mentioned earlier is
the integration starting point. Box has delivered its own
off-the-shelf solution specifically for Salesforce integration
that I will write about next. A custom integration example
will follow after that.
APPEXCHANGE OPTION WITH
BOX – AN OFF-THE-SHELF
SOLUTION
Box provides an app-exchange[19] product to
integrate with Salesforce. It is a free product to install
on Salesforce and seems to require at minimum the
$15/month business Box account. With this type of
integration with Salesforce certain users within a business
would not need Salesforce licenses to view the files
because they could view them in Box directly. Using
Chatter users in Salesforce for certain use cases can also
reduce the need to have so many Salesforce licenses if
you are just trying to get more users access to Chatter
Feed files.
BOX CUSTOM INTEGRATION
EXAMPLE
Here are the steps for connecting to Box’s REST API. In
my reading I learned that there was a direct connection
option with a username and password with version 1
of the API, but with version 2 of the API you must use
OAuth 2 to authenticate.
Salesforce — Where to Save my Files?
|
Terry Luschen
8
1. Sign-up for a free personal Box account by
going to this page[20] and clicking on the ‘Sign Up’
button.
2. During the sign-up process an email will be sent
to you and you will have to click on it to confirm the
email account.
3. Log into your new Box account.
4. Go to this page[21] and click on ‘Get Started
Now’.
5. Go to this page[22] and click on the ‘register for
an API key’ link.
a.
Enter a new name for the application like
‘TestAPISundog’
b.
You will now receive your new API Key. Copy that
to a safe place.
6. We need to allow Salesforce to make outbound
web service calls to Box.
a.
Log into Salesforce
b.
Click on Your Name, Setup
c.
Go to Administration Setup, Security Controls,
Remote Site Settings
i.
Click on New Remote Site
ii.
Enter a name and the URL should be
https://www.Box.com
iii.
Create another Remote site for https://api.Box.com.
7. This page[23] walks through how to connect to
Box and get the OAuth code.
a.
Note that the only supported production
authentication method with version 2 of the Box API
seems to be OAuth2.
b.
If you do not want to use OAuth 2 then this
page[24] gives some other options with using version
one of the API.
c.
This page[25] walks through how to verify the
OAuth credentials using Postman.
d.
This page[26] walks through all the steps with
OAuth 2 for Box from authentication, to getting the
access token, to making your first API call.
8. Now we are ready to try to connect to our Box
account via the Version 2 of the API using OAuth 2.
9. Log into Salesforce
10. Create a Controller called BoxConnect.
See Appendix 3 for the APEX code for that
Controller…
Again I tried to use as little code as possible
to make the important pieces obvious. A lot
more needs to be done to this code before it is
production ready such as responding to errors from
Box. This code tries to do three things:
a.
Redirect to Box so that the user can enter his/
her credentials. This is done in the boxConnect()
method where a PageReference does this. This code
is hit when the CommandButton is clicked on the
Visualforce Page
Salesforce — Where to Save my Files?
|
Terry Luschen
9
b.
Call Box to request an Access Token
This is done in getBoxToken()
c.
Use the Access Token to make any API calls
The example API call here is in getBoxFolder() and it
lists all of the files in the specified folder.
11. Create a Visualforce page called BoxConnect
See Appendix 4 for the markup for the Visualforce
Page…
12. To run this code add apex/BoxConnect to the
end of your Salesforce URL

13. Click on the ‘Connect to Box’ CommandButton
on the Visualforce Page
a.
This will redirect to Box. Enter the Box credentials

This is done in the boxConnect() method where a
PageReference does this.
14. Fill in you username and password at Box
a.
Box will automatically send the page back to your
Visualforce page because of redirect_uri parameter in
the call to authorize via OAth 2.
b.
Note that the redirect_uri parameter is optional as it
can be setup in the app within Box too. If you do send
it and it is not blank at Box, then it must match.
c.
You may have to change your URL from c.na9.
visual.force.com to whatever your URL is.
15. Now Box will have redirected back to your page.
Now all of the action takes place in the Controller.
a.
In the constructor we check if the ‘code’ query
string parameter is there. If it is then we grab it and
then try to ask for the access token.
b.
The access token code is in getBoxToken(). A
HTTP POST call is made with all the needed items in
the body. Make sure you put them in the body and
not as headers or query string parameters. The values
must be urlEndcoded and the ‘Content-Type’ and
‘charset’ values are also required.
c.
We now get back a JSON response that we can
parse to get our access and refresh tokens.
d.
Now that we have our access token we can make
any calls that we want to the API.
e.
The call in the code within getBoxFolder() is
to https://api.box.com/2.0/folders/FOLDER_ID/
items[27], which will return all of the items, files and
folders in this folder. The only tricky part to this one is
to get the Authorization header set correctly.
f.
We again get a JSON value back which can be
parsed using the built-in JSON parser in APEX.
Salesforce — Where to Save my Files?
|
Terry Luschen
10
g.
We now have the files that were in that specific
folder.
16. Now that we have the code to
a.
Authenticate
b.
Get the Access Token and
c.
Make our first API call, we are now able to make
any API calls that we need.
17. More code will have to be written to get a new
access code using the refresh token as the access
token is only good for 1 hour. The refresh token
also has a certain lifetime so if that is up, then the
user will have to authenticate at Box again from the
beginning of the OAuth 2.0 process.
SUMMARY
I hope this paper has given some good points to ponder
when a decision has to be made when choosing
between storing files in Salesforce or in some other cloud
provider like Amazon S3 or Box. Also, please do not limit
yourself to just S3 and Box when doing your research on
this important decision either. With just a quick search
I found a product by integrate.DesertBloom[28] that
integrates Google Drive with Salesforce in the exact same
manner as how S-Drive and Box are working. I was also
able to find great links for doing custom integrations with
Google Drive here: [29][30][31]. Where to store your files
is an important decision and there are a lot of options
to decide from. The great part is that there are a lot of
quality options to decide from.
I wish you the best in solving your Salesforce environment
challenges. If you extend any of the ideas in this paper
please let me know. We are all trying to make our daily
development and integration lives easier to manage while
solving critical challenges for our clients. Happy Coding
and Decision Making!
Salesforce — Where to Save my Files?
|
Terry Luschen
11
Appendix 1 – Code for APEX Controller for AWS

public with sharing class AWS_SimpleUpload {
public string getEncodedPolicy()
{
// Replace www.cnn.com with where you want to redirect to
String policy_string = this.getJson(‘sundogfolder’,’http://www.cnn.com’,’image/’);
Blob policy_blob = Blob.valueOf(policy_string);
String encoded_policy = EncodingUtil.base64Encode(policy_blob);
return encoded_policy;
}

private string getJson(String folder, String redirect, String content_type)
{
String j = ‘’;
j += ‘{“expiration”: “’ + Datetime.now().addDays(1).format(‘yyyy-MM-dd\’T\’HH:mm:ss\’.000Z\’’) + ‘”,’;
j += ‘”conditions”: [‘;
j += ‘{“bucket”: “’ + ‘terryfilessundog’ + ‘”},’;
j += ‘[“starts-with”, “$key”, “’ + folder + ‘/”],’;
j += ‘{“acl”: “private”},’;
j += ‘{“success_action_redirect”: “’ + redirect + ‘”},’;
j += ‘[“starts-with”, “$Content-Type”, “’ + content_type + ‘”]’;
j += ‘]}’;
return j;
}

public string getSignature()
{
String algorithmName = ‘hmacSHA1’;
Blob input = Blob.valueOf(getEncodedPolicy());
//aws_secret_key
Blob privateKey = Blob.valueOf(‘MySecretKey’);
Blob macSignature = Crypto.generateMac(algorithmName,input,privateKey);
String encodedSignature = EncodingUtil.base64Encode(macSignature);
return encodedSignature;
Salesforce — Where to Save my Files?
|
Terry Luschen
12
Appendix 2 – Code for Visualforce Page for AWS S3
<apex:page showHeader=”false” sidebar=”false” cache=”false” contentType=”text/html” controller=”AWS_
SimpleUpload”>
<head>
<title>S3 POST Form</title>
<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8” />
</head>
<form action=”http://terryfilessundog.s3.amazonaws.com/” data-folder=”sundogfolder” id=”upload_form”
method=”post” enctype=”multipart/form-data”>
<div>
<input type=”hidden” name=”key” value=”sundogfolder/${filename}” />
<input type=”hidden” name=”acl” value=”private” />
<input type=”hidden” name=”success_action_redirect” value=”http://www.cnn.com” />
<input type=”hidden” name=”Content-Type” value=”image/png” />
<input type=”hidden” name=”AWSAccessKeyId” value=”My AWSAccessKeyId” />
<input type=”hidden” name=”Policy” value=”{!EncodedPolicy}” />
<input type=”hidden” name=”Signature” value=”{!Signature}” />
<label id=”upload_label”>Upload the image to be saved at AWS S3</label>
<div class=”divide_n”>
<input type=”file” id=”upload_file” name=”file” />
</div>
<div class=”divide_n”>
<input type=”submit” name=”upload” id=”upload_submit_button” class=”form_button button_link” value=”Upload” />
<a href=”#” id=”cancel_upload” class=”button_link button_gray button_inline”>Cancel</a>
</div>
</div>
</form>
</apex:page>
Salesforce — Where to Save my Files?
|
Terry Luschen
13
Appendix 3 – Code for APEX Controller for Box
public with sharing class BoxConnect {
public string valueToShow{get;set;}
private final string boxClientID = ‘BOX_CLIENT_ID’;
private final string boxSecretCode = ‘BOX_SECRET_CODE’;
private final string redirectURI =’https://c.na9.visual.force.com/apex/boxconnect’;
private string codeFromBox;
private string accessToken;
private string refreshToken;

public BoxConnect(){
valueToShow = ‘Start’;
//Check if we received the authorization code from Box because the redirectUI
// URI points to this page. It will look like this...
//https://c.na9.visual.force.com/apex/boxconnect?state=&code=RETURNED_AUTH_CODE
codeFromBox = System.currentPageReference().getParameters().get(‘code’);
if(codeFromBox == null || codeFromBox == ‘’){

}else{
//Try to get a token and then make an API call to Box
getBoxToken();
}
}

public pageReference boxConnect(){
//Redirect to the OAuth page at Box so the login credentials can be entered.
PageReference pr = new PageReference(‘https://www.box.com/api/oauth2/authorize?’ +
‘response_type=code’ +
‘&client_id=’ + boxClientID +
‘&redirect_uri=’ + redirectURI);
return pr;
}

private void getBoxToken(){
Http h = new Http();
HttpRequest req = new HttpRequest();
string endPointValue = ‘https://www.box.com/api/oauth2/token’;
req.setEndpoint(endPointValue);
Salesforce — Where to Save my Files?
|
Terry Luschen
14
Appendix 3 – Code for APEX Controller for Box (continued)
private void getBoxToken(){
Http h = new Http();
HttpRequest req = new HttpRequest();
string endPointValue = ‘https://www.box.com/api/oauth2/token’;
req.setEndpoint(endPointValue);
req.setBody(‘Content-Type=’ +
EncodingUtil.urlEncode(‘application/x-www-form-urlencoded’, ‘UTF-8’) +
‘&charset=’ + EncodingUtil.urlEncode(‘UTF-8’, ‘UTF-8’) +
‘&grant_type=’ + EncodingUtil.urlEncode(‘authorization_code’, ‘UTF-8’) +
‘&code=’ + EncodingUtil.urlEncode(codeFromBox, ‘UTF-8’) +
‘&client_id=’ + EncodingUtil.urlEncode(boxClientID, ‘UTF-8’) +
‘&client_secret=’ + EncodingUtil.urlEncode(boxSecretCode, ‘UTF-8’) +
‘&redirect_uri=’ + EncodingUtil.urlEncode(redirectURI, ‘UTF-8’));
req.setMethod(‘POST’);
HttpResponse res = h.send(req);
//Get back this... {“access_token”:”RETURNED_ACCESS_TOKEN”,
// “expires_in”:3600,
// “refresh_token”:”RETURNED_REFRESH_TOKEN”,
// “token_type”:”bearer”}
parseAuthJSON(res.getBody());
if(accessToken <> null & accessToken <> ‘’){
//Try to get items from a folder in Box
getBoxFolder();
}else{
//Just some debug lines to see the request and response
valuetoShow = ‘Get Authorization Code Return: ‘ + res.getBody() +
‘request: ‘ + req.toString();
}
}

private void getBoxFolder(){
Http h = new Http();
HttpRequest req = new HttpRequest();
string endPointValue = ‘https://api.box.com/2.0/folders/904543862/items’;
//?limit=5&offset=0
//Returns this: {“total_count”:2,”entries”:[
// {“type”:”file”,”id”:”8308841816”,”sequence_id”:”0”,
// “etag”:”0”,”sha1”:”6dce26ad1a3578a00a40722ec4472abc143313cf”,
Salesforce — Where to Save my Files?
|
Terry Luschen
15
Appendix 3 – Code for APEX Controller for Box (continued)
req.setBody(‘Content-Type=’ +
EncodingUtil.urlEncode(‘application/x-www-form-urlencoded’, ‘UTF-8’) +
‘&charset=’ + EncodingUtil.urlEncode(‘UTF-8’, ‘UTF-8’) +
‘&grant_type=’ + EncodingUtil.urlEncode(‘authorization_code’, ‘UTF-8’) +
‘&code=’ + EncodingUtil.urlEncode(codeFromBox, ‘UTF-8’) +
‘&client_id=’ + EncodingUtil.urlEncode(boxClientID, ‘UTF-8’) +
‘&client_secret=’ + EncodingUtil.urlEncode(boxSecretCode, ‘UTF-8’) +
‘&redirect_uri=’ + EncodingUtil.urlEncode(redirectURI, ‘UTF-8’));
req.setMethod(‘POST’);
HttpResponse res = h.send(req);
//Get back this... {“access_token”:”RETURNED_ACCESS_TOKEN”,
// “expires_in”:3600,
// “refresh_token”:”RETURNED_REFRESH_TOKEN”,
// “token_type”:”bearer”}
parseAuthJSON(res.getBody());
if(accessToken <> null & accessToken <> ‘’){
//Try to get items from a folder in Box
getBoxFolder();
}else{
//Just some debug lines to see the request and response
valuetoShow = ‘Get Authorization Code Return: ‘ + res.getBody() +
‘request: ‘ + req.toString();
}
}

private void getBoxFolder(){
Http h = new Http();
HttpRequest req = new HttpRequest();
string endPointValue = ‘https://api.box.com/2.0/folders/904543862/items’;
//?limit=5&offset=0
//Returns this: {“total_count”:2,”entries”:[
// {“type”:”file”,”id”:”8308841816”,”sequence_id”:”0”,
// “etag”:”0”,”sha1”:”6dce26ad1a3578a00a40722ec4472abc143313cf”,
// “name”:”Luschen Quote for West Fargo Property.pdf”},
// {“type”:”file”,”id”:”8308878690”,”sequence_id”:”1”,
// “etag”:”1”,”sha1”:”5b595457a86396ddf45318d1ab9ddd6aa3b7bc1e”,
// “name”:”New Google Doc 1.gdoc”}
// ],”offset”:0,”limit”:100,”order”:[
// {“by”:”type”,”direction”:”ASC”},{“by”:”name”,”direction”:”ASC”}]}
Salesforce — Where to Save my Files?
|
Terry Luschen
16
Appendix 3 – Code for APEX Controller for Box (continued)

//This one works to get the properties for a specific file
//endPointValue = ‘https://api.box.com/2.0/files/8308878690?
// fields=modified_at,path_collection,name’;
//Returns this {“type”:”file”,”id”:”8308878690”,
// “etag”:”1”,”modified_at”:”2013-05-25T16:08:52-07:00”,
// “path_collection”:{“total_count”:2,”entries”:[
// {“type”:”folder”,”id”:”0”,”sequence_id”:null,”etag”:null,”name”:”All Files”},
// {“type”:”folder”,”id”:”904543862”,”sequence_id”:”1”,
// “etag”:”1”,”name”:”Buy Fargo Home”}
// ]},”name”:”New Google Doc 1.gdoc”}
req.setEndpoint(endPointValue);
req.setHeader(‘Authorization’, ‘Bearer ‘ + accessToken);
req.setMethod(‘GET’);
HttpResponse res = h.send(req);
//Now we could parse through the JSON again and get the values that we want
valuetoShow = ‘Get Folder: ‘ + res.getBody();
}

private void parseAuthJSON(string JSONValue){
JSONParser parser = JSON.createParser(JSONValue);
accessToken = ‘’;
refreshToken = ‘’;
while (parser.nextToken() != null) {
if(parser.getCurrentToken() == JSONToken.FIELD_NAME){
if(parser.getText() == ‘access_token’){
parser.nextToken();
accessToken = parser.getText();
}
if(parser.getText() == ‘refresh_token’){
parser.nextToken();
refreshToken = parser.getText();
}
}
if(accessToken <> ‘’ && refreshToken <> ‘’){
break;
}
}
}
}
Salesforce — Where to Save my Files?
|
Terry Luschen
17
Appendix 4 – Code for Visualforce Page for Box

<apex:page showHeader=”false” sidebar=”false” cache=”false” contentType=”text/html” controller=”BoxConnect” >
<apex:form >
<apex:commandbutton id=”connectToBox” value=”Connect to Box” action=”{!boxConnect}”>
</apex:commandbutton>
<apex:outputText id=”outputText” value=”{!valueToShow}”>
</apex:outputText>
</apex:form>
</apex:page>
Salesforce — Where to Save my Files?
|
Terry Luschen
18
References:
Selecting the right Sales Cloud Edition. Retrieved May 26, 2013 from
http://www.sfdcstatic.com/assets/pdf/datasheets/DS_SalesCloud_EdCompare.pdf
Document Management System. Retrieved May 26, 2013 from
http://en.wikipedia.org/wiki/Document_management_system
Salesforce CRM Content File Size Limits. Retrieved May 26, 2013 from
http://login.salesforce.com/help/doc/en/content_file_size_limits.htm
File Size Limits in Salesforce. Retrieved May 26, 2013 from
http://login.salesforce.com/help/doc/en/collab_files_size_limits.htm
Amazon Web Services Home Page. Sign Up Button. Retrieved June 1, 2013 from
http://aws.amazon.com/
Amazon S3 Pricing. Retrieved June 1, 2013 from
http://aws.amazon.com/s3/pricing/
Amazon S3 API Documentation Home Page. Retrieved June 1, 2013 from
http://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html
How do you search an Amazon S3 bucket. Retrieved June 1, 2013 from
http://stackoverflow.com/questions/4979218/how-do-you-search-an-amazon-s3-bucket
Amazon CloudSearch. Retrieved June 1, 2013 from
http://aws.amazon.com/cloudsearch/
Amazon CloudSearch – Start Searching in One Hour for less than $100 / Month. Retrieved June 1, 2013 from
http://aws.typepad.com/aws/2012/04/amazon-cloudsearch-start-searching-in-one-hour.html
S-Drive AppExchange Home Page. Retrieved June 1, 2013 from
https://appexchange.salesforce.com/listingDetail?listingId=a0N30000001SWUTEA4
Amazon S3 Browser-Based Uploads. Retrieved June 1, 2013 from
http://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html
Browser Uploads to S3 using HTML POST forms. Retrieved June 1, 2013 from
http://aws.amazon.com/articles/1434?_encoding=UTF8&jiveRedirect=1
Salesforce — Where to Save my Files?
|
Terry Luschen
19
References:
Policy Construction. Retrieved June 1, 2013 from
http://docs.aws.amazon.com/AmazonS3/2006-03-01/dev/HTTPPOSTForms.html#HTTPPOSTConstructPolicy
Force.com Toolkit for Amazon Web Services. Retrieved June 1, 2013 from
http://aws.amazon.com/solutions/global-solution-providers/salesforce/
Box.com – Simple, Secure Sharing from Anywhere. Retrieved June 1, 2013 from
https://www.box.com/
Pricing for Box. Retrieved June 1, 2013 from
https://www.box.com/pricing/
Box V2API Overview and FAQs. Retrieved June 1, 2013 from
https://support.box.com/entries/22628786
App-Exchange product for Box. Box for Salesforce. Retrieved June 1, 2013 from
https://appexchange.salesforce.com/listingDetail?listingId=a0N30000001qNeKEAU
Personal Plan for Box. Retrieved June 1, 2013 from
https://www.box.com/personal/
Box Platform Developer Documentation. Retrieved June 1, 2013 from
https://developers.box.com/
API Basics. Retrieved June 1, 2013 from
https://developers.box.com/docs/#api-basics
OAuth 2.0 for Box. Retrieved June 1, 2013 from
http://developers.box.com/oauth/
Authentication from desktop app for Box.com. Retrieved June 1, 2013 from
http://stackoverflow.com/questions/10484671/authentication-from-desktop-app/10486729#10486729
Get Box Access Tokens in 2 Quick Steps. Retrieved June 2, 2013 from
https://developers.blog.box.com/2013/05/17/get-box-access-tokens-in-2-quick-steps/
Oauth 2.0 for Box. Retrieved June 2, 2013 from
http://developers.box.com/oauth/
Salesforce — Where to Save my Files?
|
Terry Luschen
20
References:
Retrieve a folder’s items from the Box 2.0 API. Retrieved June 2, 2013 from
http://developers.box.com/docs/#folders-retrieve-a-folders-items
Integrate.DesertBloom – Integrate Google Drive and Salesforce. Retrieved June 1, 2013 from
http://integrate.desertbloom.com/
How to upload a file from Salesforce to Google Drive? Retrieved June 1, 2013 from
http://stackoverflow.com/questions/10764740/how-to-upload-a-file-from-salesforce-to-google-drive
What can you do with the Drive SDK? Retrieved June 1, 2013 from
https://developers.google.com/drive/about-sdk
Integration of Google Drive into Force.com. Retrieved June 1, 2013 from
http://theforcetimes.wordpress.com/2012/12/15/integration-of-google-drive-into-force-com/