Last active
June 2, 2017 08:28
-
-
Save mark-stephenson-/e915c70b17882decba8d3a52aca430e5 to your computer and use it in GitHub Desktop.
Wit Promise Issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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 + '...'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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