Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.0.1 #18

Merged
merged 4 commits into from
Nov 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This library wraps the [Force.com REST API](https://www.salesforce.com/us/developer/docs/api_rest/). Force.com is a suite of point-and-click tools for creating custom employee-facing apps. The Electric Imp Salesforce library enables you to interact with your Force.com objects, allowing you to easily create products that can interact with a powerful CRM backend.

**To add this library to your project, add** `#require "Salesforce.agent.lib.nut:2.0.0"` **to the top of your agent code.**
**To add this library to your project, add** `#require "Salesforce.agent.lib.nut:2.0.1"` **to the top of your agent code.**

## Callbacks ##

Expand All @@ -19,7 +19,7 @@ If no callback is supplied (ie. a synchronous request was made), the method will
To create a new Salesforce object you will need the Consumer Key and Consumer Secret of a Connected App. Information about creating a Connected App can be found [here](https://help.salesforce.com/apex/HTViewHelpDoc?id=connected_app_create.htm). The constructor also allows you to pass in two additional parameters to override defaults: *loginService* (default value is `"login.salesforce.com"`) and *version* (default value is `"v33.0"`). If you are working in a Salesforce sandbox environment, you should pass `"test.salesforce.com"` as *loginService*.

```squirrel
#require "Salesforce.agent.lib.nut:2.0.0"
#require "Salesforce.agent.lib.nut:2.0.1"

force <- Salesforce("<-- CONSUMER_KEY -->", "<-- CONSUMER_SECRET -->");
```
Expand Down Expand Up @@ -54,6 +54,10 @@ force.login(USERNAME, PASSWORD, SECURITY_TOKEN, function(err, data) {

This method immediately returns a boolean value indicating whether or not the Salesforce object has completed a login request and stored the authentication token.

### setRefreshToken(*refreshToken*) ###

This method can be used to set or change the refresh token for the Firebase account, when necessary. Application is not required to call the method. But it might be useful if refresh token is persisted and restored on the application side and no login operation is required when device is rebooted.

### setVersion(*versionString*) ###

This method can be used to set or change the version of the Force.com REST API you are working with. For example:
Expand Down
14 changes: 9 additions & 5 deletions Salesforce.agent.lib.nut
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
class Salesforce {

// Library version
static VERSION = "2.0.0";
static VERSION = "2.0.1";

// service URLs
_loginServiceBase = "https://login.salesforce.com/";
Expand Down Expand Up @@ -71,6 +71,10 @@ class Salesforce {
_token = token;
}

function setRefreshToken(refreshToken) {
_refreshToken = refreshToken;
}

function login(username, password, securityToken = null, cb = null) {
// Add token if required
if (securityToken != null) password = password+securityToken;
Expand Down Expand Up @@ -114,10 +118,10 @@ class Salesforce {
return { err = err, data = null };
}
try {
this._userUrl = data.id;
this._instanceUrl = data.instance_url;
this._token = data.access_token;
if("refresh_token" in data) this._refreshToken = data.refresh_token;
this._userUrl = data.id;
this._instanceUrl = data.instance_url;
this._token = data.access_token;
if("refresh_token" in data) this._refreshToken = data.refresh_token;
} catch (ex) {
return { err = [{"errorCode": "NO_AUTH", "message": "Could not find auth token with supplied login information"}], data = null };
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#require "Salesforce.agent.lib.nut:2.0.0"
#require "Salesforce.agent.lib.nut:2.0.1"
#require "Rocky.class.nut:1.2.3"


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#require "Salesforce.agent.lib.nut:2.0.0"
#require "Salesforce.agent.lib.nut:2.0.1"
#require "Rocky.class.nut:1.2.3"


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#require "Salesforce.agent.lib.nut:2.0.0"
#require "Salesforce.agent.lib.nut:2.0.1"
#require "Rocky.class.nut:1.2.3"


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#require "Rocky.class.nut:1.2.3"

// Web Integration Library
#require "Salesforce.agent.lib.nut:2.0.0"
#require "Salesforce.agent.lib.nut:2.0.1"

// Extends Salesforce Library to handle authorization
class SalesforceOAuth2 extends Salesforce {
Expand Down Expand Up @@ -60,6 +60,9 @@ class SalesforceOAuth2 extends Salesforce {
// Set the credentials in the Salesforce object
setInstanceUrl(oAuth.instance_url);
setToken(oAuth.access_token);
if ("refresh_token" in oAuth) {
setRefreshToken(oAuth.refresh_token);
}

// Log a message
server.log("Loaded OAuth Credentials!");
Expand Down Expand Up @@ -90,13 +93,7 @@ class SalesforceOAuth2 extends Salesforce {
return;
}

// If it was successful, save the data locally
local persist = { "oAuth" : respData };
server.save(persist);

// Set/update the credentials in the Salesforce object
setInstanceUrl(persist.oAuth.instance_url);
setToken(persist.oAuth.access_token);
storeAuthData(respData);

// Finally - inform the user we're done!
context.send(200, "Authentication complete - you may now close this window");
Expand Down Expand Up @@ -142,7 +139,9 @@ class SalesforceOAuth2 extends Salesforce {
local err = null;

// If there was an error, set the error code
if (resp.statuscode != 200) err = data.message;
if (resp.statuscode != 200) {
err = "message" in respData ? respData.message : "generic error: " + resp.body;
}

// Invoke the callback
if (cb) {
Expand All @@ -152,6 +151,18 @@ class SalesforceOAuth2 extends Salesforce {
}
});
}

function storeAuthData(authData) {

// If it was successful, save the data locally
local persist = {"oAuth" : authData};
server.save(persist);

// Set/update the credentials in the Salesforce object
setInstanceUrl(persist.oAuth.instance_url);
setToken(persist.oAuth.access_token);
}

}

// Door status strings
Expand Down Expand Up @@ -194,36 +205,51 @@ class SmartFridgeApplication {
server.error("Not logged into Salesforce.")
return;
}

// Log the data being sent to the cloud
server.log(http.jsonencode(body));

// Send Salesforce platform event with device readings
_force.request("POST", _sendReadingUrl, http.jsonencode(body), function (err, respData) {
if (err) {
if (err[0].errorCode == "INVALID_SESSION_ID") {
_force.getStoredCredentials();
_force.refreshOAuthToken(_force.getRefreshToken(),
function(e, resp, respData) {
if (e) {
server.error(e);
return;
}
_force.storeAuthData(respData);
}.bindenv(this)
);
}
server.error(http.jsonencode(err));
}
else {
server.log("Readings sent successfully");
}
});
}.bindenv(this));
}

// Converts timestamp to "2017-12-03T00:54:51Z" format
function formatTimestamp(ts = null) {
local d = ts ? date(ts) : date();
return format("%04d-%02d-%02dT%02d:%02d:%02dZ", d.year, d.month + 1, d.day, d.hour, d.min, d.sec);
}

}

// RUNTIME
// ---------------------------------------------------------------------------------

// SALESFORCE CONSTANTS
// ----------------------------------------------------------
const CONSUMER_KEY = "<YOUR_CONSUMER_KEY_HERE>";
const CONSUMER_SECRET = "<YOUR_CONSUMER_SECRET_HERE>";
//
// NOTE: Please replace values of these constants with real user credentials
// ---------------------------------------------------------------------------------
const CONSUMER_KEY = "@{SALESFORCE_CONSUMER_KEY}";
ppetrosh marked this conversation as resolved.
Show resolved Hide resolved
const CONSUMER_SECRET = "@{SALESFORCE_CONSUMER_SECRET}";
const READING_EVENT_NAME = "Smart_Fridge_Reading__e";

// Start Application
SmartFridgeApplication(CONSUMER_KEY, CONSUMER_SECRET, READING_EVENT_NAME);
SmartFridgeApplication(CONSUMER_KEY, CONSUMER_SECRET, READING_EVENT_NAME);