Skip to content

Instantly share code, notes, and snippets.

@bnookala
Last active January 20, 2017 00:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bnookala/a8c8c352e4c6180e822655fa311aa204 to your computer and use it in GitHub Desktop.
Save bnookala/a8c8c352e4c6180e822655fa311aa204 to your computer and use it in GitHub Desktop.
// The root dialog of our bot simply just jumps straight into the
// business logic of paying a fine.
bot.dialog('/', function (session, args) {
session.beginDialog('listFines');
});
// Simple three step dialog to list 'fines' that a user has received, and allow
// a user to 'pay' them.
bot.dialog('listFines', [
function (session, args) {
console.log('List Fines Dialog');
session.send('You have 1 outstanding fine:');
session.send('Parking Fine Violation');
builder.Prompts.choice(session, "What would you like to do?", ["Pay fine", "Cancel"]);
},
function (session, results, next) {
let choice = results.response;
if (choice.entity === 'Cancel') {
return;
}
// TODO: Create a payment, and ask the user to act on it.
},
function (session, results) {
session.send('Thanks for your payment!')
},
]);
const restify = require('restify');
const builder = require('botbuilder');
// A connector connects a bot on bot framework to various messaging services that a bot
// can talk to.
let connector = new builder.ChatConnector({
appId: undefined,
appPassword: undefined
});
// A bot listens and reacts to messages that the connector picks up on.
let bot = new builder.UniversalBot(connector);
// We're using restify here to set up an HTTP server, and then adding the queryParser middleware,
// which will parse the query string into on object on any requests.
let server = restify.createServer();
server.use(restify.queryParser());
// The server will start listening on this port defined in the environment.
server.listen(process.env.PORT, function () {
console.log('%s listening to %s', server.name, server.url);
});
// Messages are posted to this endpoint. We ask the connector to listen at this endpoint for new messages.
server.post('/api/messages', connector.listen());
server.get('approvalComplete', function (req, res, next) {
console.log('User approved transaction');
executePayment(req.params);
res.send(200);
});
function executePaymentJson (payerId) {
return {
"payer_id": payerId,
"transactions": [{
"amount": {
"currency": "USD",
"total": "1.00"
}
}]
};
}
function executePayment(params) {
console.log('Executing an Approved Payment');
// Appended to the URL by PayPal during the approval step.
let paymentId = parameters.paymentId;
let payerId = parameters.PayerID;
// Generate the sample payment execution JSON that paypal requires:
let paymentJson = executePaymentJson(payerId)
// Finally, execute the payment, and tell the user that we got their payment.
paypal.payment.execute(paymentId, paymentJson, function (error, payment) {
if (error) {
console.log(error.response);
throw error;
} else {
console.log('Payment Executed Successfully');
// TODO: Inform the user on their bot channel.
}
});
};
/**
* This function creates and returns an object that is passed through to the PayPal Node SDK
* to create a payment that a user must manually approve.
*
* See https://developer.paypal.com/docs/api/payments/#payment_create_request for a description of the fields.
*/
function createPaymentJson (returnUrl, cancelUrl) {
return {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": returnUrl,
"cancel_url": cancelUrl
},
"transactions": [{
"item_list": {
"items": [{
"name": "Fine",
"sku": "ParkingFine",
"price": "1.00",
"currency": "USD",
"quantity": 1
}]
},
"amount": {
"currency": "USD",
"total": "1.00"
},
"description": "This is your fine. Please pay it :3"
}]
};
}
/**
* Creates a payment on paypal that a user must approve.
*/
function createAndSendPayment (session) {
console.log('Creating Payment');
let paymentJson = createPaymentJson('http://localhost', 'http://localhost');
paypal.payment.create(paymentJson, function (error, payment) {
if (error) {
throw error;
} else {
// The SDK returns a payment object when the payment is successfully created.
// This object has a few properties, described at length here:
// https://developer.paypal.com/docs/api/payments/#payment_create_response
// We're looking for the 'approval_url' property, which the user must go to
// to approve the transaction before we can actively execute the transaction.
for (var index = 0; index < payment.links.length; index++) {
if (payment.links[index].rel === 'approval_url') {
session.send("Please pay your fine: " + payment.links[index].href);
}
}
}
});
};
const paypal = require('paypal-rest-sdk');
paypal.configure({
'mode': process.env.PAYPAL_CLIENT_MODE,
'client_id': process.env.PAYPAL_CLIENT_ID,
'client_secret': process.env.PAYPAL_CLIENT_SECRET
});
function createReturnUrl (address) {
console.log('Creating Return Url');
// The address passed in is an Object that defines the context
// of the conversation - the user, the channel, the http endpoint the bot
// exists on, and so on. We encode this information into the return URL
// to be parsed out by our approval completion endpoint.
let addressEncoded = encodeURIComponent(JSON.stringify(address));
// This object encodes the endpoint that PayPal redirects to when.
// a user approves the transaction.
let urlObject = {
protocol: 'http',
hostname: 'localhost',
port: configuration.PORT,
pathname: 'approvalComplete',
query: addressEncoded
}
return url.format(urlObject);
}
function executePayment (parameters) {
console.log('Executing an Approved Payment');
// Appended to the URL by PayPal during the approval step.
let paymentId = parameters.paymentId;
let payerId = parameters.PayerID;
// Generate the sample payment execution JSON that paypal requires:
let paymentJson = executePaymentJson(payerId)
// Grab the encoded address object, URL decode it, and parse it back into a JSON object.
let addressEncoded = decodeURIComponent(parameters.addressEncoded);
let address = JSON.parse(addressEncoded);
// Finally, execute the payment, and tell the user that we got their payment.
paypal.payment.execute(paymentId, paymentJson, function (error, payment) {
if (error) {
console.log(error.response);
throw error;
} else {
console.log('Payment Executed Successfully');
respondToUser(payment, address);
}
});
}
function respondToUser (payment, address) {
let message = new builder.Message().address(address).text('Thanks for your payment!');
// Asks the bot to send the message we built up above to the user.
bot.send(message.toMessage());
}
bot.dialog('listFines', [
function (session, args) {
console.log('List Fines Dialog');
session.send('You have 1 outstanding fine:');
session.send('Parking Fine Violation');
builder.Prompts.choice(session, "What would you like to do?", ["Pay fine", "Cancel"]);
},
function (session, results, next) {
let choice = results.response;
if (choice.entity === 'Cancel') {
return;
}
// Starts the payment flow.
createAndSendPayment(session);
},
]);
// This endpoint describes the approval redirect endpoint that you can provide in the JSON blob passed to PayPal.
// When a user approves a payment, PayPal will redirect you the user to this.
server.get('approvalComplete', function (req, res, next) {
console.log('User approved payment!');
res.send(200);
});
function createReturnUrl () {
let url = require('url');
// This object encodes the endpoint that PayPal redirects to when.
// a user approves the payment
let urlObject = {
protocol: 'http',
hostname: 'localhost',
port: configuration.PORT,
pathname: 'approvalComplete',
}
return url.format(urlObject);
};
function createAndSendPayment (session) {
let returnUrl = createReturnUrl();
let paymentJson = createPaymentJson(returnUrl);
// create payment, etc…
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment