Skip to content

Instantly share code, notes, and snippets.

@mark-stephenson-
Last active June 2, 2017 08:28
Show Gist options
  • Save mark-stephenson-/e915c70b17882decba8d3a52aca430e5 to your computer and use it in GitHub Desktop.
Save mark-stephenson-/e915c70b17882decba8d3a52aca430e5 to your computer and use it in GitHub Desktop.
Wit Promise Issue
'use strict';
let Wit = null;
let log = null;
try {
// if running from repo
Wit = require('./lib/wit');
log = require('./lib/log');
} catch (e) {
console.log('2');
Wit = require('node-wit').Wit;
log = require('node-wit').log;
}
const bodyParser = require('body-parser');
const crypto = require('crypto');
const express = require('express');
const fetch = require('node-fetch');
const request = require('request');
const config = require('./config');
const Shopify = require('./lib/shopify').Shopify;
// Webserver parameter
const PORT = process.env.PORT || 8445;
// Wit.ai parameters
const WIT_TOKEN = process.env.WIT_TOKEN;
// Messenger API parameters
const FB_PAGE_TOKEN = process.env.FB_PAGE_TOKEN;
if (!FB_PAGE_TOKEN) { throw new Error('missing FB_PAGE_TOKEN');}
const FB_APP_SECRET = process.env.FB_APP_SECRET;
if (!FB_APP_SECRET) { throw new Error('missing FB_APP_SECRET');}
let FB_VERIFY_TOKEN = null;
crypto.randomBytes(8, (err, buff) => {
if (err) throw err;
FB_VERIFY_TOKEN = buff.toString('hex');
console.log(`/webhook will accept the Verify Token "${FB_VERIFY_TOKEN}"`);
});
// ----------------------------------------------------------------------------
// Messenger API specific code
const fbMessage = (id, text) => {
const body = JSON.stringify({
recipient: { id },
message: { text },
});
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body,
})
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
return json;
});
};
const fbCollections = (id) => {
return new Promise(function(resolve, reject){
Shopify.collections(id)
.then(body => {
console.log('making call to fb');
let sbody = JSON.stringify(body);
const qs = 'access_token=' + encodeURIComponent(FB_PAGE_TOKEN);
return fetch('https://graph.facebook.com/me/messages?' + qs, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
sbody,
})
.then(rsp => console.log(JSON.stringify(rsp)))
.then(rsp => rsp.json())
.then(json => {
if (json.error && json.error.message) {
throw new Error(json.error.message);
}
resolve(json);
});
});
});
};
// ----------------------------------------------------------------------------
// Wit.ai bot specific code
// This will contain all user sessions.
// Each session has an entry:
// sessionId -> {fbid: facebookUserId, context: sessionState}
const sessions = {};
const findOrCreateSession = (fbid) => {
let sessionId;
// Let's see if we already have a session for the user fbid
Object.keys(sessions).forEach(k => {
if (sessions[k].fbid === fbid) {
// Yep, got it!
sessionId = k;
}
});
if (!sessionId) {
// No session found for user fbid, let's create a new one
sessionId = new Date().toISOString();
sessions[sessionId] = {fbid: fbid, context: {}};
}
return sessionId;
};
// Our bot actions
const actions = {
send({sessionId}, {text}) {
const recipientId = sessions[sessionId].fbid;
if (recipientId) {
// Yay, we found our recipient!
return fbMessage(recipientId, text)
.then(() => null)
.catch((err) => {
console.error(
'Oops! An error occurred while forwarding the response to',
recipientId,
':',
err.stack || err
);
});
} else {
console.error('Oops! Couldn\'t find user for session:', sessionId);
// Giving the wheel back to our bot
return Promise.resolve();
}
},
rand_reply({context, entities}) {
context.rand_reply = true;
return context;
},
show_prod_categories({context, entities, text, sessionId}){
return new Promise(function(resolve, reject){
const recipientId = sessions[sessionId].fbid;
if (recipientId) {
// Yay, we found our recipient!
fbCollections(recipientId)
.then(json => {
console.log('return context');
return context;
})
.catch((err) => {
console.error(
'Oops! An error occurred while forwarding the response to',
recipientId,
':',
err.stack || err
);
});
} else {
console.error('Oops! Couldn\'t find user for session:', sessionId);
// Giving the wheel back to our bot
return Promise.resolve();
}
return resolve(context);
});
},
send_rand_reply({context, entities, text, sessionId}) {
const recipientId = sessions[sessionId].fbid;
if (recipientId) {
delete context.rand_reply;
console.log(text);
wit._rand_msg = [];
// return context;
// Yay, we found our recipient!
return fbMessage(recipientId, text)
.then(() => {
return context;
})
.catch((err) => {
console.error(
'Oops! An error occurred while forwarding the response to',
recipientId,
':',
err.stack || err
);
});
} else {
console.error('Oops! Couldn\'t find user for session:', sessionId);
// Giving the wheel back to our bot
return Promise.resolve();
}
}
};
// Setting up our bot
const wit = new Wit({
accessToken: WIT_TOKEN,
actions,
logger: new log.Logger(log.INFO)
});
// Starting our webserver and putting it all together
const app = express();
app.use(({method, url}, rsp, next) => {
rsp.on('finish', () => {
console.log(`${rsp.statusCode} ${method} ${url}`);
});
next();
});
app.use(bodyParser.json({ verify: verifyRequestSignature }));
// Webhook setup
app.get('/webhook', (req, res) => {
if (req.query['hub.mode'] === 'subscribe' &&
req.query['hub.verify_token'] === FB_VERIFY_TOKEN) {
res.send(req.query['hub.challenge']);
} else {
res.sendStatus(400);
}
});
// Message handler
app.post('/webhook', (req, res) => {
// Parse the Messenger payload
// See the Webhook reference
// https://developers.facebook.com/docs/messenger-platform/webhook-reference
const data = req.body;
if (data.object === 'page') {
data.entry.forEach(entry => {
entry.messaging.forEach(event => {
if (event.message && !event.message.is_echo) {
// Yay! We got a new message!
// We retrieve the Facebook user ID of the sender
const sender = event.sender.id;
// We retrieve the user's current session, or create one if it doesn't exist
// This is needed for our bot to figure out the conversation history
const sessionId = findOrCreateSession(sender);
// We retrieve the message content
const {text, attachments} = event.message;
if (attachments) {
// We received an attachment
// Let's reply with an automatic message
fbMessage(sender, 'Sorry I can only process text messages for now.')
.catch(console.error);
} else if (text) {
// We received a text message
// Let's forward the message to the Wit.ai Bot Engine
// This will run all actions until our bot has nothing left to do
wit.runActions(
sessionId, // the user's current session
text, // the user's message
sessions[sessionId].context // the user's current session state
).then((context) => {
// Our bot did everything it has to do.
// Now it's waiting for further messages to proceed.
console.log('Waiting for next user messages');
// Based on the session state, you might want to reset the session.
// This depends heavily on the business logic of your bot.
// Example:
// if (context['done']) {
// delete sessions[sessionId];
// }
// Updating the user's current session state
sessions[sessionId].context = context;
})
.catch((err) => {
console.error('Oops! Got an error from Wit: ', err.stack || err);
});
}
} else {
console.log('received event', JSON.stringify(event));
}
});
});
}
res.sendStatus(200);
});
/*
* Verify that the callback came from Facebook. Using the App Secret from
* the App Dashboard, we can verify the signature that is sent with each
* callback in the x-hub-signature field, located in the header.
*
* https://developers.facebook.com/docs/graph-api/webhooks#setup
*
*/
function verifyRequestSignature(req, res, buf) {
var signature = req.headers["x-hub-signature"];
if (!signature) {
// For testing, let's log an error. In production, you should throw an
// error.
console.error("Couldn't validate the signature.");
} else {
var elements = signature.split('=');
var method = elements[0];
var signatureHash = elements[1];
var expectedHash = crypto.createHmac('sha1', FB_APP_SECRET)
.update(buf)
.digest('hex');
if (signatureHash != expectedHash) {
throw new Error("Couldn't validate the request signature.");
}
}
}
app.listen(PORT);
console.log('Listening on :' + PORT + '...');
'use strict';
// var fetch = require('node-fetch');
var config = require('../config');
var shopifyAPI = require('shopify-node-api');
var Shopify = function(){};
const shop = new shopifyAPI({
shop: 'ms12n-shopibot.myshopify.com', // MYSHOP.myshopify.com
shopify_api_key: config.SHOPIFY_API_KEY, // Your API key
access_token: config.SHOPIFY_API_SECRET, // Your API password
verbose: false
});
const fbCarousel = (fbid, collections) => {
console.log('fbCarousel');
var json =
{
"recipient": {
"id" : fbid
},
"message": {
"attachment":{
"type":"template",
"payload":{
"template_type":"generic",
"elements":[
]
}
}
}
};
for (var c in collections){
json.message.attachment.payload.elements.push({
"title":"Welcome to Peter\'s Hats",
"image_url":"https://petersfancybrownhats.com/company_image.png",
"subtitle":"We\'ve got the right hat for everyone.",
"buttons":[
{
"type":"postback",
"title":"View Website",
"payload":JSON.stringify({
"type":"test",
"id":"button1"
})
},{
"type":"postback",
"title":"Start Chatting",
"payload":JSON.stringify({
"type":"test",
"id":"button2"
})
}
]
});
}
return json;
};
Shopify.prototype.collections = function(fbid){
console.log('shopify.collections');
return new Promise(function(resolve, reject){
shop.get('/admin/custom_collections.json', function(err, data, headers){
let fbc = fbCarousel(fbid, data);
console.log(JSON.stringify(fbc));
resolve(fbc);
});
});
// .then(data => resolve(data));
// .then(collections => fbCarousel(fbid, collections))
// .then(function(carouseldata) {
// return fbCarousel(carouseldata);
// } )
};
exports.Shopify = new Shopify();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment