Skip to content

Commit

Permalink
express 4 & nforce .10 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffdonthemic committed Feb 10, 2015
0 parents commit 5f830b5
Show file tree
Hide file tree
Showing 16 changed files with 354 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
node_modules
.env
.DS_Store
1 change: 1 addition & 0 deletions Procfile
@@ -0,0 +1 @@
web: node app.js
45 changes: 45 additions & 0 deletions README.md
@@ -0,0 +1,45 @@
# node-nforce-demo

Simple node.js application for CRUDing salesforce.com Accounts using nforce and async.

## Installation Instructions

From the command line type in:

```
npm install
```


### Node Module Dependencies

These will be automatically installed when you use any of the above *npm* installation methods above.

1. [express](http://expressjs.com/) - framework
2. [nforce](https://github.com/kevinohara80/nforce) - REST wrapper for force.com
3. [async](https://github.com/caolan/async/) - asynchronous utility module
4. [jade](http://jade-lang.com/) - the view engine

### Running the Application Locally

1. Open terminal and change directory to node-nforce-demo root
2. `node app.js`
3. Point your browser to: [http://localhost:3001](http://localhost:3001)

### Deploying to Heroku

```
heroku create
heroku config:add CLIENT_ID=YOUR-SALESFORCE-CLIENT-ID
heroku config:add CLIENT_SECRET=YOUR-SALESFORCE-SECRET
heroku config:add USERNAME=YOUR-SALESFORCE-USERNAME
heroku config:add PASSWORD=YOUR-SALESFORCE-PASSWORD-AND-TOKEN
heroku open
```

### Demo on Heroku

This application is running on heroku at: [http://node-nforce-demo.herokuapp.com/](http://node-nforce-demo.herokuapp.com/)

## Contributors
* Jeff Douglas -> [jeffdonthemic](https://github.com/jeffdonthemic)
157 changes: 157 additions & 0 deletions app.js
@@ -0,0 +1,157 @@
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var async = require('async');
var nforce = require('nforce');

var app = express();
app.set('port', process.env.PORT || 3000);

// use the nforce package to create a connection to salesforce.com
var org = nforce.createConnection({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
redirectUri: 'http://localhost:' + app.get('port') + '/oauth/_callback',
mode: 'single'
});

// authenticate using username-password oauth flow
org.authenticate({ username: process.env.USERNAME, password: process.env.PASSWORD }, function(err, resp){
if(err) {
console.log('Error: ' + err.message);
} else {
console.log('Successfully connected to salesforce');
console.log('Access Token: ' + resp.access_token);
oauth = resp;
}
});

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});

// display a list of 10 accounts
app.get('/accounts', function(req, res) {
var q = 'select id, name from account limit 10';
org.query({ query: q }, function(err, resp){
res.render("accounts", { title: 'Accounts', data: resp.records } );
});
});

// display form to create a new account
app.get('/accounts/new', function(req, res) {
// call describe to dynamically generate the form fields
org.getDescribe({type: 'Account'}, function(err, resp) {
res.render('new', { title: 'New Account', data: resp });
});
});

// create the account in salesforce
app.post('/accounts/create', function(req, res) {
var obj = nforce.createSObject('Account', req.body);
org.insert({sobject: obj}, function(err, resp){
if (err) {
console.log(err);
} else {
if (resp.success === true) {
res.redirect('/accounts/'+resp.id);
res.end();
}
}
});
});

// display the account
app.get('/accounts/:id', function(req, res) {
var async = require('async');
var obj = nforce.createSObject('Account', {id: req.params.id});

async.parallel([
function(callback){
var q = "select count() from contact where accountid = '" + req.params.id + "'";
org.query({query: q}, function(err, resp){
callback(null, resp);
});
},
function(callback){
org.getRecord({sobject: obj}, function(err, resp) {
callback(null, resp);
});
},
],
// optional callback
function(err, results){
// returns the responses in an array
res.render('show', { title: 'Account Details', data: results });
});

});

// display form to update an existing account
app.get('/accounts/:id/edit', function(req, res) {
var obj = nforce.createSObject('Account', {id: req.params.id});
org.getRecord({sobject: obj}, function(err, resp) {
res.render('edit', { title: 'Edit Account', data: resp });
});
});

// update the account in salesforce
app.post('/accounts/:id/update', function(req, res) {
var obj = nforce.createSObject('Account', req.body);
org.update({sobject: obj}, function(results) {
res.redirect('/accounts/'+req.params.id);
res.end();
});
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});

var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + server.address().port);
});

module.exports = app;
7 changes: 7 additions & 0 deletions app.json
@@ -0,0 +1,7 @@
{
"name": "NodeJS Demo for Saleforce with nforce and async",
"description": "Simple node.js application for CRUDing salesforce.com Accounts using nforce and async.",
"repository": "https://github.com/jeffdonthemic/node-nforce-demo",
"logo": "",
"keywords": ["node", "salesforce", "nforce"]
}
22 changes: 22 additions & 0 deletions package.json
@@ -0,0 +1,22 @@
{
"name": "node-nforce-demo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"engines": {
"node": "0.10.x"
},
"dependencies": {
"express": "~4.9.0",
"body-parser": "~1.8.1",
"cookie-parser": "~1.3.3",
"morgan": "~1.3.0",
"serve-favicon": "~2.1.3",
"debug": "~2.0.0",
"jade": "~1.6.0",
"nforce": "0.10.0",
"async": "*"
}
}
Binary file added public/images/salesforce-logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions public/stylesheets/style.css
@@ -0,0 +1,36 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}

a {
color: #00B7FF;
}

.info, .success, .warning, .error, .validation {
border: 1px solid;
margin: 10px 0px;
padding:15px 10px 15px 50px;
background-repeat: no-repeat;
background-position: 10px center;
}
.info {
color: #00529B;
background-color: #BDE5F8;
background-image: url('info.png');
}
.success {
color: #4F8A10;
background-color: #DFF2BF;
background-image:url('success.png');
}
.warning {
color: #9F6000;
background-color: #FEEFB3;
background-image: url('warning.png');
}
.error {
color: #D8000C;
background-color: #FFBABA;
background-image: url('error.png');
}
9 changes: 9 additions & 0 deletions routes/index.js
@@ -0,0 +1,9 @@
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});

module.exports = router;
10 changes: 10 additions & 0 deletions views/accounts.jade
@@ -0,0 +1,10 @@
extends layout

block content

h1= title
a(href='/accounts/new') Create a new Account
p Existing Accounts
ul
each item in data
li: a(href='/accounts/#{item.getId()}') #{item.get('Name')}
16 changes: 16 additions & 0 deletions views/edit.jade
@@ -0,0 +1,16 @@
extends layout

block content

// form fields to be displayed
- var formFields = ['name','billingcity'];
h1= title
form(method='post', action='/accounts/#{data.getId()}/update')
input(name='id', value='#{data.getId()}', type='hidden')
each val, key in data._fields
- if (formFields.indexOf(key) != -1)
div
label #{key}:
input(name='#{key}', value=val || '', type='text')
div
input(type='submit', value='Save')
6 changes: 6 additions & 0 deletions views/error.jade
@@ -0,0 +1,6 @@
extends layout

block content
h1= message
h2= error.status
pre #{error.stack}
7 changes: 7 additions & 0 deletions views/index.jade
@@ -0,0 +1,7 @@
extends layout

block content
h1= title
p This is a simple node.js application for CRUDing salesforce.com Accounts using the nforce package and async.
ul
li: a(href='/accounts') Get a list of 10 Accounts
7 changes: 7 additions & 0 deletions views/layout.jade
@@ -0,0 +1,7 @@
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
15 changes: 15 additions & 0 deletions views/new.jade
@@ -0,0 +1,15 @@
extends layout

block content

// generate a form based upon metadata & display the following field
- var formFields = ['Name','BillingCity'];
h1= title
form(method='post', action='/accounts/create')
each field in data.fields
- if (formFields.indexOf(field.name) != -1)
div
label #{field.label}:
input(name='#{field.name}', value='', type='text')
div
input(type='submit', value='Save')
13 changes: 13 additions & 0 deletions views/show.jade
@@ -0,0 +1,13 @@
extends layout

block content

// fields NOT to be displayed
- var skipFields = ['attributes','isdeleted','setexternalid'];
h1= title
p Number of contacts: #{data[0].totalSize}
a(href='/accounts/#{data[1].getId()}/edit') Edit this record
ul
each val, key in data[1]._fields
- if (skipFields.indexOf(key) == -1)
li #{key}: #{val}

0 comments on commit 5f830b5

Please sign in to comment.