From 78908a6ae019ab523bd15793a4154e67f00b3dc1 Mon Sep 17 00:00:00 2001 From: clint Date: Wed, 5 Oct 2016 12:10:24 -0500 Subject: [PATCH 01/68] added users.identify --- lib/Slack_web_api.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Slack_web_api.js b/lib/Slack_web_api.js index 8a986ac76..356cf6bc3 100755 --- a/lib/Slack_web_api.js +++ b/lib/Slack_web_api.js @@ -91,6 +91,7 @@ module.exports = function(bot, config) { 'team.info', 'users.getPresence', 'users.info', + 'users.identity', 'users.list', 'users.setActive' ]; From 2cad077ba8db49e084095648db18f5eb62ab7ddf Mon Sep 17 00:00:00 2001 From: Kristian Muniz Date: Fri, 24 Mar 2017 17:32:57 -0400 Subject: [PATCH 02/68] Add support for Twilio Programmable SMS --- lib/Botkit.js | 2 + lib/TwilioSMSBot.js | 204 ++++++++++++++++++++++++++++++++++++++++++++ twilio_sms_bot.js | 108 +++++++++++++++++++++++ 3 files changed, 314 insertions(+) create mode 100644 lib/TwilioSMSBot.js create mode 100644 twilio_sms_bot.js diff --git a/lib/Botkit.js b/lib/Botkit.js index 9cde8362e..2e62e0360 100755 --- a/lib/Botkit.js +++ b/lib/Botkit.js @@ -2,6 +2,7 @@ var CoreBot = require(__dirname + '/CoreBot.js'); var Slackbot = require(__dirname + '/SlackBot.js'); var Facebookbot = require(__dirname + '/Facebook.js'); var TwilioIPMbot = require(__dirname + '/TwilioIPMBot.js'); +var TwilioSMSbot = require(__dirname + '/TwilioSMSBot.js'); var BotFrameworkBot = require(__dirname + '/BotFramework.js'); var SparkBot = require(__dirname + '/CiscoSparkbot.js'); var ConsoleBot = require(__dirname + '/ConsoleBot.js'); @@ -12,6 +13,7 @@ module.exports = { sparkbot: SparkBot, facebookbot: Facebookbot, twilioipmbot: TwilioIPMbot, + twiliosmsbot: TwilioSMSbot, botframeworkbot: BotFrameworkBot, consolebot: ConsoleBot, }; diff --git a/lib/TwilioSMSBot.js b/lib/TwilioSMSBot.js new file mode 100644 index 000000000..83d72647b --- /dev/null +++ b/lib/TwilioSMSBot.js @@ -0,0 +1,204 @@ +'use strict'; +var path = require('path'); +var os = require('os'); +var Botkit = require('./CoreBot'); +var express = require('express'); +var bodyParser = require('body-parser'); +var twilio = require('twilio'); + +function TwilioSMS(configuration) { + + var twilioSMS = Botkit(configuration || {}); + + if (!configuration) { + throw Error('Specify your \'account_sid\', \'auth_token\', and ' + + '\'twilio_number\' as properties of the \'configuration\' object'); + } + + if (configuration && !configuration.account_sid) { + throw Error('Specify an \'account_sid\' in your configuration object'); + } + + if (configuration && !configuration.auth_token) { + throw Error('Specify an \'auth_token\''); + } + + if (configuration && !configuration.twilio_number) { + throw Error('Specify a \'twilio_number\''); + } + + twilioSMS.defineBot(function(botkit, config) { + + var bot = { + botkit: botkit, + config: config || {}, + utterances: botkit.utterances + }; + + bot.startConversation = function(message, cb) { + botkit.startConversation(this, message, cb); + }; + + bot.send = function(message, cb) { + + var client = new twilio.RestClient( + configuration.account_sid, + configuration.auth_token + ); + + var sms = { + body: message.text, + from: configuration.twilio_number, + to: message.channel + }; + + client.messages.create(sms, function(err, message) { + + if (err) { + cb(err); + } else { + cb(null, message); + } + + }); + + }; + + bot.reply = function(src, resp, cb) { + var msg = {}; + + if (typeof resp === 'string') { + msg.text = resp; + } else { + msg = resp; + } + + msg.channel = src.channel; + + if (typeof cb === 'function') { + bot.say(msg, cb); + } else { + bot.say(msg, function() {}); + } + + }; + + bot.findConversation = function(message, cb) { + + botkit.debug('CUSTOM FIND CONVO', message.user, message.channel); + + for (var t = 0; t < botkit.tasks.length; t++) { + for (var c = 0; c < botkit.tasks[t].convos.length; c++) { + + var convo = botkit.tasks[t].convos[c]; + var matchesConvo = ( + convo.source_message.channel === message.channel || + convo.source_message.user === message.user + ); + + if (convo.isActive() && matchesConvo) { + botkit.debug('FOUND EXISTING CONVO!'); + cb(botkit.tasks[t].convos[c]); + return; + } + + } + } + + cb(); + }; + + return bot; + }); + + twilioSMS.handleWebhookPayload = function(req, res, bot) { + + twilioSMS.log('=> Got a message hook'); + + var message = { + text: req.body.Body, + from: req.body.From, + to: req.body.To, + user: req.body.From, + channel: req.body.From, + timestamp: Date.now(), + sid: req.body.MessageSid, + NumMedia: req.body.NumMedia, + MediaUrl0: req.body.MediaUrl0, + MediaUrl1: req.body.MediaUrl1, + MediaUrl2: req.body.MediaUrl2, + MediaUrl3: req.body.MediaUrl3, + MediaUrl4: req.body.MediaUrl4, + MediaUrl5: req.body.MediaUrl5, + MediaUrl6: req.body.MediaUrl6, + MediaUrl7: req.body.MediaUrl7, + MediaUrl9: req.body.MediaUrl9, + MediaUrl10: req.body.MediaUrl10, + }; + + twilioSMS.receiveMessage(bot, message); + + }; + + // set up a web route for receiving outgoing webhooks + twilioSMS.createWebhookEndpoints = function(webserver, bot, cb) { + + twilioSMS.log('** Serving webhook endpoints for Twilio Programmable SMS' + + ' at: ' + os.hostname() + ':' + twilioSMS.config.port + '/sms/receive'); + + var endpoint = twilioSMS.config.endpoint || '/sms/receive'; + + webserver.post(endpoint, function(req, res) { + twilioSMS.handleWebhookPayload(req, res, bot); + + // Send empty TwiML response to Twilio + var twiml = new twilio.TwimlResponse(); + res.type('text/xml'); + res.send(twiml.toString()); + }); + + if (cb) cb(); + + return twilioSMS; + }; + + twilioSMS.setupWebserver = function(port, cb) { + + if (!port) { + throw new Error('Cannot start webserver without a \'port\' parameter'); + } + + if (isNaN(port)) { + throw new TypeError('Specified \'port\' parameter is not a valid number'); + } + + var static_dir = path.join(__dirname, '/public'); + + var config = twilioSMS.config; + + if (config && config.webserver && config.webserver.static_dir) { + static_dir = twilioSMS.config.webserver.static_dir; + } + + twilioSMS.config.port = port; + + twilioSMS.webserver = express(); + twilioSMS.webserver.use(bodyParser.json()); + twilioSMS.webserver.use(bodyParser.urlencoded({extended: true})); + twilioSMS.webserver.use(express.static(static_dir)); + + twilioSMS.webserver.listen(twilioSMS.config.port, function() { + + twilioSMS.log('*> Listening on port ' + twilioSMS.config.port); + twilioSMS.startTicking(); + if (cb) cb(null, twilioSMS.webserver); + + }); + + return twilioSMS; + }; + + return twilioSMS; +} + +module.exports = TwilioSMS; diff --git a/twilio_sms_bot.js b/twilio_sms_bot.js new file mode 100644 index 000000000..ade546dd4 --- /dev/null +++ b/twilio_sms_bot.js @@ -0,0 +1,108 @@ +var Botkit = require('./lib/Botkit.js'); +var os = require('os'); + +var controller = Botkit.twiliosmsbot({ + account_sid: process.env.TWILIO_ACCOUNT_SID, + auth_token: process.env.TWILIO_AUTH_TOKEN, + twilio_number: process.env.TWILIO_NUMBER, + debug: true +}); + +var bot = controller.spawn({}); + +controller.setupWebserver(5000, function(err, server) { + server.get('/', function(req, res) { + res.send(':)'); + }); + + controller.createWebhookEndpoints(server, bot); +}) + +controller.hears(['hello', 'hi'], 'message_received', function(bot, message) { + controller.storage.users.get(message.user, function(err, user) { + if (user && user.name) { + bot.reply(message, 'Hello ' + user.name + '!!'); + } else { + bot.reply(message, 'Hello.'); + } + }); +}); + +controller.hears(['call me (.*)'], 'message_received', function(bot, message) { + var matches = message.text.match(/call me (.*)/i); + var name = matches[1]; + controller.storage.users.get(message.user, function(err, user) { + if (!user) { + user = { + id: message.user, + }; + } + user.name = name; + controller.storage.users.save(user, function(err, id) { + bot.reply(message, 'Got it. I will call you ' + user.name + ' from now on.'); + }); + }); +}); + +controller.hears(['what is my name', 'who am i'], 'message_received', function(bot, message) { + controller.storage.users.get(message.user, function(err, user) { + if (user && user.name) { + bot.reply(message, 'Your name is ' + user.name); + } else { + bot.reply(message, 'I don\'t know yet!'); + } + }); +}); + + +controller.hears(['shutdown'], 'message_received', function(bot, message) { + bot.startConversation(message, function(err, convo) { + convo.ask('Are you sure you want me to shutdown?', [{ + pattern: bot.utterances.yes, + callback: function(response, convo) { + convo.say('Bye!'); + convo.next(); + setTimeout(function() { + process.exit(); + }, 3000); + } + }, + { + pattern: bot.utterances.no, + default: true, + callback: function(response, convo) { + convo.say('*Phew!*'); + convo.next(); + } + } + ]); + }); +}); + + +controller.hears(['uptime', 'identify yourself', 'who are you', 'what is your name'], 'message_received', function(bot, message) { + + var hostname = os.hostname(); + var uptime = formatUptime(process.uptime()); + + bot.reply(message, 'I am a bot! I have been running for ' + uptime + ' on ' + hostname + '.'); + +}); + +function formatUptime(uptime) { + var unit = 'second'; + if (uptime > 60) { + uptime = uptime / 60; + unit = 'minute'; + } + if (uptime > 60) { + uptime = uptime / 60; + unit = 'hour'; + } + if (uptime != 1) { + unit = unit + 's'; + } + + uptime = uptime + ' ' + unit; + return uptime; +} From a678481d8482e340a1e4ab8f50aa78656461b517 Mon Sep 17 00:00:00 2001 From: Kristian Muniz Date: Fri, 24 Mar 2017 18:34:49 -0400 Subject: [PATCH 03/68] Remove 'use strict' pragma --- lib/TwilioSMSBot.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/TwilioSMSBot.js b/lib/TwilioSMSBot.js index 83d72647b..dbad130a7 100644 --- a/lib/TwilioSMSBot.js +++ b/lib/TwilioSMSBot.js @@ -1,4 +1,3 @@ -'use strict'; var path = require('path'); var os = require('os'); var Botkit = require('./CoreBot'); From 33aa7ea884ba50b551290632f48804b6fc6306ff Mon Sep 17 00:00:00 2001 From: Kristian Muniz Date: Thu, 27 Apr 2017 02:21:50 -0400 Subject: [PATCH 04/68] Add documentation for Twilio SMS bot --- readme-twiliosms.md | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 readme-twiliosms.md diff --git a/readme-twiliosms.md b/readme-twiliosms.md new file mode 100644 index 000000000..88d65b584 --- /dev/null +++ b/readme-twiliosms.md @@ -0,0 +1,51 @@ +# Botkit and Twilio Programmable SMS + +Botkit is designed to ease the process of designing and running useful, creative bots that live inside [Slack](http://slack.com), [Facebook Messenger](http://facebook.com), [Twilio IP Messaging](https://www.twilio.com/docs/api/ip-messaging), and other messaging platforms like [Twilio's Programmable SMS](https://www.twilio.com/sms/). + +Botkit features a comprehensive set of tools to deal with [Twilio's Programmable SMS API](http://www.twilio.com/sms/), and allows developers to build interactive bots and applications that send and receive messages just like real humans. Twilio SMS bots receive and send messages through a regular phone number. + +This document covers the Twilio Programmable SMS API implementation details only. [Start here](readme.md) if you want to learn about how to develop with Botkit. + +# Getting Started + +1) Install Botkit [more info here](readme.md#installation) + +2) Register a developer account with Twilio. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. + +After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. + +**Twilio Account SID and Auth Token** + +These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) + +**Twilio Number** + +You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` + +4) Configure your Twilio Number. Head to the [Phone Numbers](https://www.twilio.com/console/phone-numbers) in your Twilio Console and select the phone number you will use for your SMS bot. + +Under the *Messaging* section, select "Webhooks/TwiML" as your *Configure with* preference. Two more fields will pop up: ***A message comes in***, and ***Primary handler fails***. + +The first one is the type of handler you will use to respond to Twilio webhooks. Select "Webhook" and input the URI of your endpoint (e.g. `https://mysmsbot.localtunnel.me/sms/receive`) and select `HTTP POST` as your handling method. + +Twilio will send `POST` request to this address every time a user sends an SMS to your Twilio Number. + +> By default Botkit will serve content from `https://YOURSERVER/sms/receive`. If you are not running your bot on a public, SSL-enabled internet address, you can use a tool like [ngrok.io](http://ngrok.io/) or [localtunnel.me](localtunnel.me) to expose your local development enviroment to the outside world for the purposes of testing your SMS bot. + +The second preference ("Primary handler fails") is your backup plan. The URI Twilio should `POST` to in case your primary handler is unavailable. You can leave this field in blank for now but keep in mind this is useful for error handling (e.g. to notify users that your bot is unavailable). + +5) Run the example Twilio SMS bot included in Botkit's repository ([`./twilio_sms_bot.js`](twilio_sms_bot.js)). Copy and paste the example bot's code into a new JavaScript file (e.g. `twilio_sms_bot.js`) in your current working directory and run the following command on your terminal: + +```bash +$ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_NUMBER= node twilio_sms_bot.js +``` + +> Note: Remember to run localtunnel or ngrok to expose your local development environment to the outside world. For example, in localtunnel run `lt --port 5000 --subdomain mysmsbot` (See note on step 4) + +6) Your bot should be online! Grab your phone and text `hi` to your Twilio Number and you will get a `Hello.` message back! + +Try the following messages: `Hi`, `Call me bob`, `what's my name?` + +### What now? + +Head over to [Botkit's core guide](https://github.com/howdyai/botkit/blob/master/docs/readme.md) to know how to build bots! From 41310b11b9bd65771a65c4548cae90518c17999b Mon Sep 17 00:00:00 2001 From: jonchurch Date: Sun, 30 Apr 2017 19:59:11 -0400 Subject: [PATCH 05/68] add bot.createConversation to ConsoleBot.js --- lib/ConsoleBot.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ConsoleBot.js b/lib/ConsoleBot.js index ff581489d..7928b62e5 100644 --- a/lib/ConsoleBot.js +++ b/lib/ConsoleBot.js @@ -23,6 +23,10 @@ function TextBot(configuration) { utterances: botkit.utterances, }; + bot.createConversation = function(message, cb) { + botkit.createConversation(this, message, cb) + }; + bot.startConversation = function(message, cb) { botkit.startConversation(this, message, cb); }; From 54368b9c12b25844782711a6c617e52c57d82c81 Mon Sep 17 00:00:00 2001 From: jonchurch Date: Tue, 2 May 2017 16:12:32 -0400 Subject: [PATCH 06/68] replace space characters in events string --- lib/CoreBot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CoreBot.js b/lib/CoreBot.js index 25b5dd428..3ed2dff09 100755 --- a/lib/CoreBot.js +++ b/lib/CoreBot.js @@ -1007,7 +1007,7 @@ function Botkit(configuration) { } if (typeof(events) == 'string') { - events = events.split(/\,/g); + events = events.replace(/ /g, '').split(/\,/g); } for (var e = 0; e < events.length; e++) { From 4540af4d4ef3014e7995943ee39a341ea8a12768 Mon Sep 17 00:00:00 2001 From: jonchurch Date: Thu, 4 May 2017 16:59:39 -0400 Subject: [PATCH 07/68] use map and trim to remove spaces --- lib/CoreBot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CoreBot.js b/lib/CoreBot.js index 3ed2dff09..b6b55100f 100755 --- a/lib/CoreBot.js +++ b/lib/CoreBot.js @@ -1007,7 +1007,7 @@ function Botkit(configuration) { } if (typeof(events) == 'string') { - events = events.replace(/ /g, '').split(/\,/g); + events = events.split(/\,/g).map(function(str) { return str.trim() }) } for (var e = 0; e < events.length; e++) { From 72ed847fa945f877846d75368b571ef3d5284aa1 Mon Sep 17 00:00:00 2001 From: Xavi Date: Thu, 4 May 2017 15:14:16 -0700 Subject: [PATCH 08/68] Explicit error message for rate limiting --- lib/Slack_web_api.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Slack_web_api.js b/lib/Slack_web_api.js index 86b6911f7..5765a2883 100755 --- a/lib/Slack_web_api.js +++ b/lib/Slack_web_api.js @@ -227,6 +227,9 @@ module.exports = function(bot, config) { request.post(params, function(error, response, body) { bot.debug('Got response', error, body); + if(response.statusCode == 429) { + return cb(new Error('You have been rate limited')); + } if (!error && response.statusCode == 200) { var json; try { From 400ac24073f0ed3a73fff9118d395fc619029903 Mon Sep 17 00:00:00 2001 From: Xavi Date: Mon, 8 May 2017 18:52:47 -0700 Subject: [PATCH 09/68] Re-worded error message --- lib/Slack_web_api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slack_web_api.js b/lib/Slack_web_api.js index 5765a2883..73a6a75e0 100755 --- a/lib/Slack_web_api.js +++ b/lib/Slack_web_api.js @@ -228,7 +228,7 @@ module.exports = function(bot, config) { request.post(params, function(error, response, body) { bot.debug('Got response', error, body); if(response.statusCode == 429) { - return cb(new Error('You have been rate limited')); + return cb(new Error('Rate limit exceeded')); } if (!error && response.statusCode == 200) { var json; From 51da6b398fa38601308cef5a07bf45149b0a24ce Mon Sep 17 00:00:00 2001 From: Marcello Federico Date: Sun, 14 May 2017 20:23:14 -0700 Subject: [PATCH 10/68] Respond with a 200 ok Respond to the Incoming Cisco Spark web hook with a 200 ok. --- lib/CiscoSparkbot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CiscoSparkbot.js b/lib/CiscoSparkbot.js index ca2a72671..f72911db4 100644 --- a/lib/CiscoSparkbot.js +++ b/lib/CiscoSparkbot.js @@ -76,7 +76,7 @@ function Sparkbot(configuration) { '** Serving webhook endpoints for Cisco Spark Platform at: ' + 'http://' + controller.config.hostname + ':' + controller.config.port + '/ciscospark/receive'); webserver.post('/ciscospark/receive', function(req, res) { - + res.sendStatus(200) controller.handleWebhookPayload(req, res, bot); }); From 78ac896e86d77228bc6681a91ef481b1e5f0a8bd Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Mon, 15 May 2017 15:13:36 -0400 Subject: [PATCH 11/68] moves examples under the example directory, slack detailed examples to /examples/details, updates references in docs --- changelog.md | 4 ++-- docs/examples.md | 22 +++++++++---------- docs/readme-botframework.md | 2 +- docs/readme-ciscospark.md | 2 +- docs/readme-facebook.md | 4 ++-- docs/readme-slack.md | 2 +- docs/readme-twilioipm.md | 2 +- .../botframework_bot.js | 2 +- console_bot.js => examples/console_bot.js | 2 +- facebook_bot.js => examples/facebook_bot.js | 2 +- examples/{ => slack}/convo_bot.js | 2 +- examples/{ => slack}/demo_bot.js | 2 +- examples/{ => slack}/incoming_webhooks.js | 0 examples/{ => slack}/middleware_example.js | 2 +- examples/{ => slack}/sentiment_analysis.js | 0 examples/{ => slack}/slack_app.js | 0 examples/{ => slack}/slackbutton_bot.js | 2 +- .../slackbutton_bot_interactivemsg.js | 2 +- .../slackbutton_incomingwebhooks.js | 2 +- .../{ => slack}/slackbutton_slashcommand.js | 2 +- examples/{ => slack}/team_outgoingwebhook.js | 2 +- examples/{ => slack}/team_slashcommand.js | 2 +- slack_bot.js => examples/slack_bot.js | 2 +- spark_bot.js => examples/spark_bot.js | 2 +- .../twilio_ipm_bot.js | 2 +- 25 files changed, 34 insertions(+), 34 deletions(-) rename botframework_bot.js => examples/botframework_bot.js (99%) rename console_bot.js => examples/console_bot.js (99%) rename facebook_bot.js => examples/facebook_bot.js (99%) rename examples/{ => slack}/convo_bot.js (98%) rename examples/{ => slack}/demo_bot.js (98%) rename examples/{ => slack}/incoming_webhooks.js (100%) rename examples/{ => slack}/middleware_example.js (99%) rename examples/{ => slack}/sentiment_analysis.js (100%) rename examples/{ => slack}/slack_app.js (100%) rename examples/{ => slack}/slackbutton_bot.js (99%) rename examples/{ => slack}/slackbutton_bot_interactivemsg.js (99%) rename examples/{ => slack}/slackbutton_incomingwebhooks.js (98%) rename examples/{ => slack}/slackbutton_slashcommand.js (98%) rename examples/{ => slack}/team_outgoingwebhook.js (87%) rename examples/{ => slack}/team_slashcommand.js (93%) rename slack_bot.js => examples/slack_bot.js (99%) rename spark_bot.js => examples/spark_bot.js (98%) rename twilio_ipm_bot.js => examples/twilio_ipm_bot.js (98%) diff --git a/changelog.md b/changelog.md index 1ffe1a53a..1838229e1 100644 --- a/changelog.md +++ b/changelog.md @@ -206,7 +206,7 @@ Adds [ConsoleBot](lib/ConsoleBot.js) for creating bots that work on the command Adds a new [Middleware Readme](readme-middlewares.md) for documenting the existing middleware modules -Adds an example for using quick replies in the [Facebook Example Bot](facebook_bot.js) +Adds an example for using quick replies in the [Facebook Example Bot](examples/facebook_bot.js) Adds additional fields to Facebook messages to specify if they are `facebook_postback`s or normal messages. @@ -290,7 +290,7 @@ Make the oauth identity available to the user of the OAuth endpoint via `req.ide Fix issue where single team apps had a hard time receiving slash command events without funky workaround. (closes [Issue #108](https://github.com/howdyai/botkit/issues/108)) -Add [team_slashcommand.js](/examples/team_slashcommand.js) and [team_outgoingwebhook.js](/examples/team_outgoingwebhook.js) to the examples folder. +Add [team_slashcommand.js](/examples/slack/team_slashcommand.js) and [team_outgoingwebhook.js](/examples/slack/team_outgoingwebhook.js) to the examples folder. diff --git a/docs/examples.md b/docs/examples.md index 6a2910b61..aadd245c2 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -3,24 +3,24 @@ These examples are included in the Botkit [Github repo](https://github.com/howdyai/botkit). -[slack_bot.js](https://github.com/howdyai/botkit/blob/master/slack_bot.js) An example bot that can be connected to your team. Useful as a basis for creating your first bot! +[slack_bot.js](https://github.com/howdyai/botkit/blob/master/examples/slack_bot.js) An example bot that can be connected to your team. Useful as a basis for creating your first bot! -[spark_bot.js](https://github.com/howdyai/botkit/blob/master/spark_bot.js) An example bot that can be connected to Cisco Spark. Useful as a basis for creating your first bot! +[spark_bot.js](https://github.com/howdyai/botkit/blob/master/examples/spark_bot.js) An example bot that can be connected to Cisco Spark. Useful as a basis for creating your first bot! -[facebook_bot.js](https://github.com/howdyai/botkit/blob/master/facebook_bot.js) An example bot that can be connected to your Facebook page. Useful as a basis for creating your first bot! +[facebook_bot.js](https://github.com/howdyai/botkit/blob/master/examples/facebook_bot.js) An example bot that can be connected to your Facebook page. Useful as a basis for creating your first bot! -[twilio_ipm_bot.js](https://github.com/howdyai/botkit/blob/master/twilio_ipm_bot.js) An example bot that can be connected to your Twilio IP Messaging client. Useful as a basis for creating your first bot! +[twilio_ipm_bot.js](https://github.com/howdyai/botkit/blob/master/examples/twilio_ipm_bot.js) An example bot that can be connected to your Twilio IP Messaging client. Useful as a basis for creating your first bot! -[botframework_bot.js](https://github.com/howdyai/botkit/blob/master/botframework_bot.js) An example bot that can be connected to the Microsoft Bot Framework network. Useful as a basis for creating your first bot! +[botframework_bot.js](https://github.com/howdyai/botkit/blob/master/examples/botframework_bot.js) An example bot that can be connected to the Microsoft Bot Framework network. Useful as a basis for creating your first bot! -[examples/demo_bot.js](https://github.com/howdyai/botkit/blob/master/examples/demo_bot.js) another example bot that uses different ways to send and receive messages. +[examples/demo_bot.js](https://github.com/howdyai/botkit/blob/master/examples/slack/demo_bot.js) another example bot that uses different ways to send and receive messages. -[examples/team_outgoingwebhook.js](https://github.com/howdyai/botkit/blob/master/examples/team_outgoingwebhook.js) an example of a Botkit app that receives and responds to outgoing webhooks from a single team. +[examples/team_outgoingwebhook.js](https://github.com/howdyai/botkit/blob/master/examples/slack/team_outgoingwebhook.js) an example of a Botkit app that receives and responds to outgoing webhooks from a single team. -[examples/team_slashcommand.js](https://github.com/howdyai/botkit/blob/master/examples/team_slashcommand.js) an example of a Botkit app that receives slash commands from a single team. +[examples/team_slashcommand.js](https://github.com/howdyai/botkit/blob/master/examples/slack/team_slashcommand.js) an example of a Botkit app that receives slash commands from a single team. -[examples/slackbutton_bot.js](https://github.com/howdyai/botkit/blob/master/examples/slackbutton_bot.js) an example of using the Slack Button to offer a bot integration. +[examples/slackbutton_bot.js](https://github.com/howdyai/botkit/blob/master/examples/slack/slackbutton_bot.js) an example of using the Slack Button to offer a bot integration. -[examples/slackbutton_incomingwebhooks.js](https://github.com/howdyai/botkit/blob/master/examples/slackbutton_incomingwebhooks.js) an example of using the Slack Button to offer an incoming webhook integration. This example also includes a simple form which allows you to broadcast a message to any team who adds the integration. +[examples/slackbutton_incomingwebhooks.js](https://github.com/howdyai/botkit/blob/master/examples/slack/slackbutton_incomingwebhooks.js) an example of using the Slack Button to offer an incoming webhook integration. This example also includes a simple form which allows you to broadcast a message to any team who adds the integration. -[example/sentiment_analysis.js](https://github.com/howdyai/botkit/blob/master/examples/sentiment_analysis.js) a simple example of a chatbot using sentiment analysis. Keeps a running score of each user based on positive and negative keywords. Messages and thresholds can be configured. +[example/sentiment_analysis.js](https://github.com/howdyai/botkit/blob/master/examples/slack/sentiment_analysis.js) a simple example of a chatbot using sentiment analysis. Keeps a running score of each user based on positive and negative keywords. Messages and thresholds can be configured. diff --git a/docs/readme-botframework.md b/docs/readme-botframework.md index 0aeeb6405..cf031adf3 100644 --- a/docs/readme-botframework.md +++ b/docs/readme-botframework.md @@ -34,7 +34,7 @@ Table of Contents 4) Run the example bot using the App ID & Password you were assigned. If you are _not_ running your bot at a public, SSL-enabled internet address, use the --lt option and update your bots endpoint in the developer portal to use the URL assigned to your bot. ``` -app_id= app_password= node botframework_bot.js [--lt [--ltsubdomain CUSTOM_SUBDOMAIN]] +app_id= app_password= node examples/botframework_bot.js [--lt [--ltsubdomain CUSTOM_SUBDOMAIN]] ``` 5) Your bot should be online! Within Skype, find the bot in your contacts list, and send it a message. diff --git a/docs/readme-ciscospark.md b/docs/readme-ciscospark.md index 4f1ca2a51..3436bb55a 100644 --- a/docs/readme-ciscospark.md +++ b/docs/readme-ciscospark.md @@ -35,7 +35,7 @@ ngrok http 3000 4) Run your bot application using the access token you received, the base url of your bot application, and a secret which is used to validate the origin of incoming webhooks: ``` -access_token= public_address= secret= node spark_bot.js +access_token= public_address= secret= node examples/spark_bot.js ``` 5) Your bot should now come online and respond to requests! Find it in Cisco Spark by searching for it's name. diff --git a/docs/readme-facebook.md b/docs/readme-facebook.md index 3c35cd0ae..3c335ad48 100644 --- a/docs/readme-facebook.md +++ b/docs/readme-facebook.md @@ -38,7 +38,7 @@ Copy this token, you'll need it! 5) Run the example bot app, using the two tokens you just created. If you are _not_ running your bot at a public, SSL-enabled internet address, use the --lt option and note the URL it gives you. ``` -page_token= verify_token= node facebook_bot.js [--lt [--ltsubdomain CUSTOM_SUBDOMAIN]] +page_token= verify_token= node examples/facebook_bot.js [--lt [--ltsubdomain CUSTOM_SUBDOMAIN]] ``` 6) [Set up a webhook endpoint for your app](https://developers.facebook.com/docs/messenger-platform/guides/setup#webhook_setup) that uses your public URL. Use the verify token you defined in step 4! @@ -65,7 +65,7 @@ Facebook sends an X-HUB signature header with requests to your webhook. You can The Facebook App secret is available on the Overview page of your Facebook App's admin page. Click show to reveal it. ``` -app_secret=abcdefg12345 page_token=123455abcd verify_token=VerIfY-tOkEn node facebook_bot.js +app_secret=abcdefg12345 page_token=123455abcd verify_token=VerIfY-tOkEn node examples/facebook_bot.js ``` ## Facebook-specific Events diff --git a/docs/readme-slack.md b/docs/readme-slack.md index a61517386..794b3ce3c 100644 --- a/docs/readme-slack.md +++ b/docs/readme-slack.md @@ -39,7 +39,7 @@ Copy the API token that Slack gives you. You'll need it. 4) Run the example bot app, using the token you just copied: ​ ``` -token=REPLACE_THIS_WITH_YOUR_TOKEN node slack_bot.js +token=REPLACE_THIS_WITH_YOUR_TOKEN node examples/slack_bot.js ``` ​ 5) Your bot should be online! Within Slack, send it a quick direct message to say hello. It should say hello back! diff --git a/docs/readme-twilioipm.md b/docs/readme-twilioipm.md index 350e60c52..31214cf06 100644 --- a/docs/readme-twilioipm.md +++ b/docs/readme-twilioipm.md @@ -45,7 +45,7 @@ Follow the instructions to get your IP Messaging Demo client up and running usin 5) Start up the sample Twilio IPM Bot. From inside your cloned Botkit repo, run: ``` -TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_IPM_SERVICE_SID= TWILIO_API_KEY= TWILIO_API_SECRET= node twilio_ipm_bot.js +TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_IPM_SERVICE_SID= TWILIO_API_KEY= TWILIO_API_SECRET= node examples/twilio_ipm_bot.js ``` 6) If you are _not_ running your bot at a public, SSL-enabled internet address, use [localtunnel.me](http://localtunnel.me) to make it available to Twilio. Note the URL it gives you. For example, it may say your url is `https://xyx.localtunnel.me/` In this case, the webhook URL for use in step 7 would be `https://xyx.localtunnel.me/twilio/receive` diff --git a/botframework_bot.js b/examples/botframework_bot.js similarity index 99% rename from botframework_bot.js rename to examples/botframework_bot.js index 904091830..ed76d4dcf 100644 --- a/botframework_bot.js +++ b/examples/botframework_bot.js @@ -64,7 +64,7 @@ This bot demonstrates many of the core features of Botkit: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -var Botkit = require('./lib/Botkit.js'); +var Botkit = require('../lib/Botkit.js'); var os = require('os'); var commandLineArgs = require('command-line-args'); var localtunnel = require('localtunnel'); diff --git a/console_bot.js b/examples/console_bot.js similarity index 99% rename from console_bot.js rename to examples/console_bot.js index 885ad2c53..d36d8d4dd 100644 --- a/console_bot.js +++ b/examples/console_bot.js @@ -56,7 +56,7 @@ This bot demonstrates many of the core features of Botkit: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -var Botkit = require('./lib/Botkit.js'); +var Botkit = require('../lib/Botkit.js'); var os = require('os'); var controller = Botkit.consolebot({ diff --git a/facebook_bot.js b/examples/facebook_bot.js similarity index 99% rename from facebook_bot.js rename to examples/facebook_bot.js index c4efd4b18..29e0ed41f 100755 --- a/facebook_bot.js +++ b/examples/facebook_bot.js @@ -81,7 +81,7 @@ if (!process.env.app_secret) { process.exit(1); } -var Botkit = require('./lib/Botkit.js'); +var Botkit = require('../lib/Botkit.js'); var os = require('os'); var commandLineArgs = require('command-line-args'); var localtunnel = require('localtunnel'); diff --git a/examples/convo_bot.js b/examples/slack/convo_bot.js similarity index 98% rename from examples/convo_bot.js rename to examples/slack/convo_bot.js index 68b13e224..cb10d1244 100644 --- a/examples/convo_bot.js +++ b/examples/slack/convo_bot.js @@ -52,7 +52,7 @@ This bot demonstrates a multi-stage conversation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); if (!process.env.token) { console.log('Error: Specify token in environment'); diff --git a/examples/demo_bot.js b/examples/slack/demo_bot.js similarity index 98% rename from examples/demo_bot.js rename to examples/slack/demo_bot.js index d5d18ba0a..e6a9a8315 100755 --- a/examples/demo_bot.js +++ b/examples/slack/demo_bot.js @@ -53,7 +53,7 @@ This bot demonstrates many of the core features of Botkit: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); if (!process.env.token) { diff --git a/examples/incoming_webhooks.js b/examples/slack/incoming_webhooks.js similarity index 100% rename from examples/incoming_webhooks.js rename to examples/slack/incoming_webhooks.js diff --git a/examples/middleware_example.js b/examples/slack/middleware_example.js similarity index 99% rename from examples/middleware_example.js rename to examples/slack/middleware_example.js index de4f8416e..2fdfdc62d 100644 --- a/examples/middleware_example.js +++ b/examples/slack/middleware_example.js @@ -69,7 +69,7 @@ if (!process.env.token) { process.exit(1); } -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); var os = require('os'); var controller = Botkit.slackbot({ diff --git a/examples/sentiment_analysis.js b/examples/slack/sentiment_analysis.js similarity index 100% rename from examples/sentiment_analysis.js rename to examples/slack/sentiment_analysis.js diff --git a/examples/slack_app.js b/examples/slack/slack_app.js similarity index 100% rename from examples/slack_app.js rename to examples/slack/slack_app.js diff --git a/examples/slackbutton_bot.js b/examples/slack/slackbutton_bot.js similarity index 99% rename from examples/slackbutton_bot.js rename to examples/slack/slackbutton_bot.js index 89c8ac92f..b86dff0fe 100755 --- a/examples/slackbutton_bot.js +++ b/examples/slack/slackbutton_bot.js @@ -25,7 +25,7 @@ This is a sample Slack Button application that adds a bot to one or many slack t ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Uses the slack button feature to offer a real time bot to multiple teams */ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); if (!process.env.clientId || !process.env.clientSecret || !process.env.port) { console.log('Error: Specify clientId clientSecret and port in environment'); diff --git a/examples/slackbutton_bot_interactivemsg.js b/examples/slack/slackbutton_bot_interactivemsg.js similarity index 99% rename from examples/slackbutton_bot_interactivemsg.js rename to examples/slack/slackbutton_bot_interactivemsg.js index 03f79f6fd..6dbc04404 100644 --- a/examples/slackbutton_bot_interactivemsg.js +++ b/examples/slack/slackbutton_bot_interactivemsg.js @@ -25,7 +25,7 @@ This is a sample Slack Button application that adds a bot to one or many slack t ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ /* Uses the slack button feature to offer a real time bot to multiple teams */ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); if (!process.env.clientId || !process.env.clientSecret || !process.env.port) { console.log('Error: Specify clientId clientSecret and port in environment'); diff --git a/examples/slackbutton_incomingwebhooks.js b/examples/slack/slackbutton_incomingwebhooks.js similarity index 98% rename from examples/slackbutton_incomingwebhooks.js rename to examples/slack/slackbutton_incomingwebhooks.js index 76441caf6..047f8f3ea 100644 --- a/examples/slackbutton_incomingwebhooks.js +++ b/examples/slack/slackbutton_incomingwebhooks.js @@ -49,7 +49,7 @@ This bot demonstrates many of the core features of Botkit: -> http://howdy.ai/botkit ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); if (!process.env.clientId || !process.env.clientSecret || !process.env.port) { console.log('Error: Specify clientId clientSecret and port in environment'); diff --git a/examples/slackbutton_slashcommand.js b/examples/slack/slackbutton_slashcommand.js similarity index 98% rename from examples/slackbutton_slashcommand.js rename to examples/slack/slackbutton_slashcommand.js index 546f94868..ef0368a54 100755 --- a/examples/slackbutton_slashcommand.js +++ b/examples/slack/slackbutton_slashcommand.js @@ -39,7 +39,7 @@ This bot demonstrates many of the core features of Botkit: -> http://howdy.ai/botkit ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); if (!process.env.clientId || !process.env.clientSecret || !process.env.port) { console.log('Error: Specify clientId clientSecret and port in environment'); diff --git a/examples/team_outgoingwebhook.js b/examples/slack/team_outgoingwebhook.js similarity index 87% rename from examples/team_outgoingwebhook.js rename to examples/slack/team_outgoingwebhook.js index 8d8490daa..7e4813625 100755 --- a/examples/team_outgoingwebhook.js +++ b/examples/slack/team_outgoingwebhook.js @@ -1,4 +1,4 @@ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); var controller = Botkit.slackbot({ debug: true diff --git a/examples/team_slashcommand.js b/examples/slack/team_slashcommand.js similarity index 93% rename from examples/team_slashcommand.js rename to examples/slack/team_slashcommand.js index f4ae87e2f..286ce7040 100755 --- a/examples/team_slashcommand.js +++ b/examples/slack/team_slashcommand.js @@ -1,4 +1,4 @@ -var Botkit = require('../lib/Botkit.js'); +var Botkit = require('../../lib/Botkit.js'); var controller = Botkit.slackbot({ debug: true diff --git a/slack_bot.js b/examples/slack_bot.js similarity index 99% rename from slack_bot.js rename to examples/slack_bot.js index 941ab4a1f..3bcaab063 100644 --- a/slack_bot.js +++ b/examples/slack_bot.js @@ -69,7 +69,7 @@ if (!process.env.token) { process.exit(1); } -var Botkit = require('./lib/Botkit.js'); +var Botkit = require('../lib/Botkit.js'); var os = require('os'); var controller = Botkit.slackbot({ diff --git a/spark_bot.js b/examples/spark_bot.js similarity index 98% rename from spark_bot.js rename to examples/spark_bot.js index a44b27199..e1d41e4c6 100644 --- a/spark_bot.js +++ b/examples/spark_bot.js @@ -27,7 +27,7 @@ This bot demonstrates many of the core features of Botkit: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -var Botkit = require('./lib/Botkit.js'); +var Botkit = require('../lib/Botkit.js'); var controller = Botkit.sparkbot({ debug: false, diff --git a/twilio_ipm_bot.js b/examples/twilio_ipm_bot.js similarity index 98% rename from twilio_ipm_bot.js rename to examples/twilio_ipm_bot.js index b8636f18a..2dcd4d935 100644 --- a/twilio_ipm_bot.js +++ b/examples/twilio_ipm_bot.js @@ -1,4 +1,4 @@ -var Botkit = require('./lib/Botkit.js'); +var Botkit = require('../lib/Botkit.js'); var os = require('os'); var controller = Botkit.twilioipmbot({ debug: false, From cd1fed9e83330263ea0cf0116ae0fd88d6663eff Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Mon, 15 May 2017 15:38:32 -0400 Subject: [PATCH 12/68] removes .vscode meta directory --- .vscode/launch.json | 46 --------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 21ff6bb99..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Launch", - "type": "node", - "request": "launch", - "program": "${workspaceRoot}/botframework_bot.js", - "stopOnEntry": false, - "args": [], - "cwd": "${workspaceRoot}", - "preLaunchTask": null, - "runtimeExecutable": null, - "runtimeArgs": [ - "--nolazy" - ], - "env": { - "NODE_ENV": "development" - }, - "console": "internalConsole", - "sourceMaps": false, - "outDir": null - }, - { - "name": "Attach", - "type": "node", - "request": "attach", - "port": 5858, - "address": "localhost", - "restart": false, - "sourceMaps": false, - "outDir": null, - "localRoot": "${workspaceRoot}", - "remoteRoot": null - }, - { - "name": "Attach to Process", - "type": "node", - "request": "attach", - "processId": "${command.PickProcess}", - "port": 5858, - "sourceMaps": false, - "outDir": null - } - ] -} \ No newline at end of file From 296886e7a3eb939008fe3d2b1276fd326fe0d9e1 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Mon, 15 May 2017 15:38:47 -0400 Subject: [PATCH 13/68] adds .vscode to gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 29a07e164..a75685f66 100755 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ examples/db_team_bot/ */.DS_Store .env .idea -.vscode/settings.json \ No newline at end of file +.vscode From 6d2c992eed475089c4361806936dcdba1f91050f Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Tue, 16 May 2017 21:31:37 -0400 Subject: [PATCH 14/68] adds jest, adds one unit test --- __test__/lib/Botkit.test.js | 23 +++++++++++++++++++++++ package.json | 12 +++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 __test__/lib/Botkit.test.js diff --git a/__test__/lib/Botkit.test.js b/__test__/lib/Botkit.test.js new file mode 100644 index 000000000..3d112b1aa --- /dev/null +++ b/__test__/lib/Botkit.test.js @@ -0,0 +1,23 @@ +let botkit; + +beforeEach(() => { + jest.mock('../../lib/CoreBot', () => 'corebot') + jest.mock('../../lib/SlackBot', () => 'slackbot') + jest.mock('../../lib/Facebook', () => 'facebook') + jest.mock('../../lib/TwilioIPMBot', () => 'twilio') + jest.mock('../../lib/BotFramework', () => 'botframework') + jest.mock('../../lib/CiscoSparkbot', () => 'spark') + jest.mock('../../lib/ConsoleBot', () => 'console') + + botkit = require('../../lib/Botkit'); +}) + +test('exports bot interfaces', () => { + expect(botkit.core).toBe('corebot'); + expect(botkit.slackbot).toBe('slackbot'); + expect(botkit.facebookbot).toBe('facebook'); + expect(botkit.twilioipmbot).toBe('twilio'); + expect(botkit.botframeworkbot).toBe('botframework'); + expect(botkit.sparkbot).toBe('spark'); + expect(botkit.consolebot).toBe('console'); +}); diff --git a/package.json b/package.json index 5008ee65a..10440a4a2 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "ws": "^2.2.2" }, "devDependencies": { + "jest-cli": "^20.0.1", "jscs": "^3.0.7", "mocha": "^3.2.0", "should": "^11.2.1", @@ -34,8 +35,10 @@ "winston": "^2.3.1" }, "scripts": { - "pretest": "jscs ./lib/", - "test": "mocha tests/*.js" + "pretest": "jscs ./lib/ ./__test__", + "test": "mocha tests/*.js", + "jest": "jest", + "jest-watch": "jest --watch" }, "repository": { "type": "git", @@ -55,5 +58,8 @@ "microsoft bot framework" ], "author": "ben@howdy.ai", - "license": "MIT" + "license": "MIT", + "jest": { + "testEnvironment": "node" + } } From 1396901d6f72cfb2be7fbaed24a47f4aa943065d Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Tue, 16 May 2017 21:32:01 -0400 Subject: [PATCH 15/68] fixes linting issue --- lib/Slackbot_worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slackbot_worker.js b/lib/Slackbot_worker.js index 86bd5d879..e3aeb4211 100755 --- a/lib/Slackbot_worker.js +++ b/lib/Slackbot_worker.js @@ -156,7 +156,7 @@ module.exports = function(botkit, config) { } bot.rtm = new Ws(res.url, null, { - agent: agent + agent: agent }); bot.msgcount = 1; From 00e237f300f60d12d5118983dff512e7644c45ae Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Wed, 17 May 2017 16:13:51 -0400 Subject: [PATCH 16/68] adds test-legacy command --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 10440a4a2..323fc7294 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,8 @@ }, "scripts": { "pretest": "jscs ./lib/ ./__test__", - "test": "mocha tests/*.js", - "jest": "jest", - "jest-watch": "jest --watch" + "test": "jest", + "test-legacy": "mocha ./tests/*.js" }, "repository": { "type": "git", From 770ae849e1be8d7d7efcd57ae513ddb55460f7ac Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Wed, 17 May 2017 16:14:33 -0400 Subject: [PATCH 17/68] simplifies botkit test, adds slack web app unit test file --- __test__/lib/Botkit.test.js | 16 ++++++------- __test__/lib/Slack_web_api.test.js | 36 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 __test__/lib/Slack_web_api.test.js diff --git a/__test__/lib/Botkit.test.js b/__test__/lib/Botkit.test.js index 3d112b1aa..dd4a891e3 100644 --- a/__test__/lib/Botkit.test.js +++ b/__test__/lib/Botkit.test.js @@ -1,16 +1,16 @@ let botkit; beforeEach(() => { - jest.mock('../../lib/CoreBot', () => 'corebot') - jest.mock('../../lib/SlackBot', () => 'slackbot') - jest.mock('../../lib/Facebook', () => 'facebook') - jest.mock('../../lib/TwilioIPMBot', () => 'twilio') - jest.mock('../../lib/BotFramework', () => 'botframework') - jest.mock('../../lib/CiscoSparkbot', () => 'spark') - jest.mock('../../lib/ConsoleBot', () => 'console') + jest.mock('../../lib/CoreBot', () => 'corebot'); + jest.mock('../../lib/SlackBot', () => 'slackbot'); + jest.mock('../../lib/Facebook', () => 'facebook'); + jest.mock('../../lib/TwilioIPMBot', () => 'twilio'); + jest.mock('../../lib/BotFramework', () => 'botframework'); + jest.mock('../../lib/CiscoSparkbot', () => 'spark'); + jest.mock('../../lib/ConsoleBot', () => 'console'); botkit = require('../../lib/Botkit'); -}) +}); test('exports bot interfaces', () => { expect(botkit.core).toBe('corebot'); diff --git a/__test__/lib/Slack_web_api.test.js b/__test__/lib/Slack_web_api.test.js new file mode 100644 index 000000000..40ba425f5 --- /dev/null +++ b/__test__/lib/Slack_web_api.test.js @@ -0,0 +1,36 @@ +let slackWebApi; +let mockRequest; +let mockBot; + +beforeEach(() => { + + mockRequest = { + post: jest.fn() + }; + jest.mock('request', () => mockRequest); + + mockBot = { + config: {}, + debug: jest.fn(), + log: jest.fn(), + userAgent: jest.fn() + }; + + mockBot.log.error = jest.fn(); + + slackWebApi = require('../../lib/Slack_web_api'); +}); + +describe('config', function() { + test('default api_root', () => { + const instance = slackWebApi(mockBot, {}); + expect(instance.api_url).toBe('https://slack.com/api/'); + }); + + test('setting api_root', () => { + mockBot.config.api_root = 'http://www.somethingelse.com'; + const instance = slackWebApi(mockBot, {}); + expect(instance.api_url).toBe('http://www.somethingelse.com/api/'); + }); +}); + From 7967cb1fe1b8405baa72ad7b3a52b9931963fe4e Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Wed, 17 May 2017 16:24:53 -0400 Subject: [PATCH 18/68] adds documentation on running tests --- CONTRIBUTING.md | 2 ++ readme.md | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4619447cc..269fef495 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,6 +24,8 @@ possible with your report. If you can, please include: * Create, or link to an existing issue identifying the need driving your PR request. The issue can contain more details of the need for the PR as well as host debate as to which course of action the PR will take that will most serve the common good. * Include screenshots and animated GIFs in your pull request whenever possible. * Follow the JavaScript coding style with details from `.jscsrc` and `.editorconfig` files and use necessary plugins for your text editor. +* Run `npm test` before submitting and fix any issues. +* Add tests to cover any new functionality. Add and/or update tests for any updates to the code. * Write documentation in [Markdown](https://daringfireball.net/projects/markdown). * Please follow, [JSDoc](http://usejsdoc.org/) for proper documentation. * Use short, present tense commit messages. See [Commit Message Styleguide](#git-commit-messages). diff --git a/readme.md b/readme.md index c7462a0e7..9f3fb8a58 100644 --- a/readme.md +++ b/readme.md @@ -140,6 +140,21 @@ Use the `--production` flag to skip the installation of devDependencies from Bot npm install --production ``` +## Running Tests + +To run tests, use the npm `test` command. Note: you will need dev dependencies installed using `npm install`. + +```bash +npm test +``` + +Tests are run with [Jest](https://facebook.github.io/jest/docs/getting-started.html). You can pass Jest command line options after a `--`. +For example to have Jest watch for file changes you can run + +```bash +npm test -- --watch +``` + ## Documentation * [Get Started](docs/readme.md) From 9d2f2c314b1d0aebbe00417fad0ad0f9b0f78178 Mon Sep 17 00:00:00 2001 From: Mehedi Hasan Masum Date: Sat, 20 May 2017 21:08:03 +0600 Subject: [PATCH 19/68] Delete functions parameter fixed fixed: 1st parameter of all 3 delete functions were mistaken --- lib/storage/simple_storage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/storage/simple_storage.js b/lib/storage/simple_storage.js index 795298443..fa6c6e01e 100755 --- a/lib/storage/simple_storage.js +++ b/lib/storage/simple_storage.js @@ -57,7 +57,7 @@ module.exports = function(config) { teams_db.save(team_data.id, team_data, cb); }, delete: function(team_id, cb) { - teams_db.delete(team_id.id, cb); + teams_db.delete(team_id, cb); }, all: function(cb) { teams_db.all(objectsToList(cb)); @@ -71,7 +71,7 @@ module.exports = function(config) { users_db.save(user.id, user, cb); }, delete: function(user_id, cb) { - users_db.delete(user_id.id, cb); + users_db.delete(user_id, cb); }, all: function(cb) { users_db.all(objectsToList(cb)); @@ -85,7 +85,7 @@ module.exports = function(config) { channels_db.save(channel.id, channel, cb); }, delete: function(channel_id, cb) { - channels_db.delete(channel_id.id, cb); + channels_db.delete(channel_id, cb); }, all: function(cb) { channels_db.all(objectsToList(cb)); From d9b7b61733bb66c58126ed8485d931708e72dcd0 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Sat, 20 May 2017 17:32:16 -0400 Subject: [PATCH 20/68] adds tests for callAPI and callAPIWithoutToken --- __test__/lib/Slack_web_api.test.js | 167 ++++++++++++++++++++++++++++- package.json | 2 +- 2 files changed, 163 insertions(+), 6 deletions(-) diff --git a/__test__/lib/Slack_web_api.test.js b/__test__/lib/Slack_web_api.test.js index 40ba425f5..2237fbef2 100644 --- a/__test__/lib/Slack_web_api.test.js +++ b/__test__/lib/Slack_web_api.test.js @@ -1,13 +1,24 @@ let slackWebApi; let mockRequest; +let mockResponse; +let responseError; let mockBot; +mockRequest = { + post: jest.fn() +}; + +jest.mock('request', () => mockRequest); + beforeEach(() => { + jest.clearAllMocks(); - mockRequest = { - post: jest.fn() - }; - jest.mock('request', () => mockRequest); + responseError = null; + + mockResponse = { + statusCode: 200, + body: '{}' + } mockBot = { config: {}, @@ -18,10 +29,14 @@ beforeEach(() => { mockBot.log.error = jest.fn(); + mockRequest.post.mockImplementation((params, cb) => { + cb(null, mockResponse, mockResponse.body); + }); + slackWebApi = require('../../lib/Slack_web_api'); }); -describe('config', function() { +describe('config', () => { test('default api_root', () => { const instance = slackWebApi(mockBot, {}); expect(instance.api_url).toBe('https://slack.com/api/'); @@ -34,3 +49,145 @@ describe('config', function() { }); }); +describe('callApi', () => { + let instance; + + test('uses data.token by default and post', () => { + const data = { + token: 'abc123' + }; + const cb = jest.fn(); + + instance = slackWebApi(mockBot, {}); + instance.callAPI('some.method', data, cb); + + expect(mockRequest.post.mock.calls.length).toBe(1); + const firstArg = mockRequest.post.mock.calls[0][0]; + expect(firstArg.form.token).toBe('abc123'); + }); + + test('uses config.token if data.token is missing', () => { + const data = {}; + const cb = jest.fn(); + + instance = slackWebApi(mockBot, { token: 'abc123' }); + instance.callAPI('some.method', data, cb); + + expect(mockRequest.post.mock.calls.length).toBe(1); + const firstArg = mockRequest.post.mock.calls[0][0]; + expect(firstArg.form.token).toBe('abc123'); + }); +}); + +describe('callApiWithoutToken', () => { + let instance; + + test('uses data values by default', () => { + const data = { + client_id: 'id', + client_secret: 'secret', + redirect_uri: 'redirectUri' + }; + const cb = jest.fn(); + + instance = slackWebApi(mockBot, {}); + instance.callAPIWithoutToken('some.method', data, cb); + + expect(mockRequest.post.mock.calls.length).toBe(1); + const firstArg = mockRequest.post.mock.calls[0][0]; + expect(firstArg.form.client_id).toBe('id'); + expect(firstArg.form.client_secret).toBe('secret'); + expect(firstArg.form.redirect_uri).toBe('redirectUri'); + }); + + test('uses config values if not set in data', () => { + const config = { + clientId: 'id', + clientSecret: 'secret', + redirectUri: 'redirectUri' + }; + const cb = jest.fn(); + + // this seems to be an API inconsistency: + // callAPIWithoutToken uses bot.config, but callAPI uses that passed config + mockBot.config = config; + + instance = slackWebApi(mockBot, {}); + instance.callAPIWithoutToken('some.method', {}, cb); + + expect(mockRequest.post.mock.calls.length).toBe(1); + const firstArg = mockRequest.post.mock.calls[0][0]; + expect(firstArg.form.client_id).toBe('id'); + expect(firstArg.form.client_secret).toBe('secret'); + expect(firstArg.form.redirect_uri).toBe('redirectUri'); + + }); +}); + +describe('postForm', () => { + + test('handles success', () => { + + }); + + test('handles multipart data', () => { + + }); + + test('handles request lib error', () => { + + }); + + test('handles non 200 response code', () => { + + }); + + test('handles error parsing body', () => { + + }); + + test('handles ok.false response', () => { + + }); +}); + + +describe('api methods', () => { + let instance; + + beforeEach(() => { + instance = slackWebApi(mockBot, {}); + }); + + test('spot check api methods ', () => { + // testing for all methods seems wasteful, but let's confirm the methods got built correctly and test the following scenarios + + // two levels + expect(instance.auth).toBeDefined(); + expect(instance.auth.test).toBeDefined(); + + // three levels + expect(instance.users).toBeDefined(); + expect(instance.users.profile).toBeDefined(); + expect(instance.users.profile.get).toBeDefined(); + }); + + describe('special cases', () => { + + beforeEach(() => { + + }); + + test('chat.postMessage ', () => { + + }); + + test('chat.update ', () => { + + }); + + test('files.upload ', () => { + + }); + }); +}); diff --git a/package.json b/package.json index 323fc7294..dfa4d7049 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "winston": "^2.3.1" }, "scripts": { - "pretest": "jscs ./lib/ ./__test__", + "pretest": "jscs ./lib/ ./__test__ --fix", "test": "jest", "test-legacy": "mocha ./tests/*.js" }, From f2d2f60a38423c46da2499a46182a88501a184f0 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Sat, 20 May 2017 22:27:48 -0400 Subject: [PATCH 21/68] adds test coverage and test-watch command --- .gitignore | 3 ++- package.json | 5 +++-- readme.md | 10 ++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 29a07e164..f8354de38 100755 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ examples/db_team_bot/ */.DS_Store .env .idea -.vscode/settings.json \ No newline at end of file +.vscode/settings.json +coverage diff --git a/package.json b/package.json index dfa4d7049..7df5c9897 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,9 @@ }, "scripts": { "pretest": "jscs ./lib/ ./__test__ --fix", - "test": "jest", - "test-legacy": "mocha ./tests/*.js" + "test": "jest --coverage", + "test-legacy": "mocha ./tests/*.js", + "test-watch": "jest --watch" }, "repository": { "type": "git", diff --git a/readme.md b/readme.md index 9f3fb8a58..1973432ba 100644 --- a/readme.md +++ b/readme.md @@ -148,11 +148,17 @@ To run tests, use the npm `test` command. Note: you will need dev dependencies i npm test ``` +To run tests in watch mode run: + +```bash +npm run test-watch +``` + Tests are run with [Jest](https://facebook.github.io/jest/docs/getting-started.html). You can pass Jest command line options after a `--`. -For example to have Jest watch for file changes you can run +For example to have Jest bail on the first error you can run ```bash -npm test -- --watch +npm test -- --bail ``` ## Documentation From e6098df29e0dd3cbfd61e3ac55794d3a675040f7 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Sat, 20 May 2017 23:03:08 -0400 Subject: [PATCH 22/68] adds tests for postForm --- __test__/lib/Slack_web_api.test.js | 97 +++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 15 deletions(-) diff --git a/__test__/lib/Slack_web_api.test.js b/__test__/lib/Slack_web_api.test.js index 2237fbef2..38e910e22 100644 --- a/__test__/lib/Slack_web_api.test.js +++ b/__test__/lib/Slack_web_api.test.js @@ -17,14 +17,14 @@ beforeEach(() => { mockResponse = { statusCode: 200, - body: '{}' - } + body: '{"ok": true}' + }; mockBot = { config: {}, debug: jest.fn(), log: jest.fn(), - userAgent: jest.fn() + userAgent: jest.fn().mockReturnValue('jesting') }; mockBot.log.error = jest.fn(); @@ -77,6 +77,20 @@ describe('callApi', () => { const firstArg = mockRequest.post.mock.calls[0][0]; expect(firstArg.form.token).toBe('abc123'); }); + + // this case is specific to callAPI, shared cases will be tested below + test(`handles multipart data`, () => { + const cb = jest.fn(); + instance = slackWebApi(mockBot, {}); + instance.callAPI('some.method', 'data', cb, true); + + expect(mockRequest.post).toHaveBeenCalledTimes(1); + const firstArg = mockRequest.post.mock.calls[0][0]; + + expect(firstArg.formData).toBe('data'); + expect(firstArg.form).toBeUndefined(); + expect(cb).toHaveBeenCalledWith(null, { ok: true }); + }); }); describe('callApiWithoutToken', () => { @@ -120,34 +134,87 @@ describe('callApiWithoutToken', () => { expect(firstArg.form.client_id).toBe('id'); expect(firstArg.form.client_secret).toBe('secret'); expect(firstArg.form.redirect_uri).toBe('redirectUri'); - }); }); describe('postForm', () => { - test('handles success', () => { + ['callAPI', 'callAPIWithoutToken'].forEach((methodName) => { + let method; + let cb; - }); + beforeEach(() => { + const instance = slackWebApi(mockBot, {}); + method = instance[methodName]; + cb = jest.fn(); + }); + + test(`${methodName}: handles success`, () => { + method('some.action', 'data', cb); + expect(mockRequest.post).toHaveBeenCalledTimes(1); + const firstArg = mockRequest.post.mock.calls[0][0]; + + // do some thorough assertions here for a baseline + expect(firstArg.url).toMatch(/some.action$/); + expect(firstArg.form).toBe('data'); + expect(firstArg.formData).toBeUndefined(); + expect(firstArg.headers).toEqual({ 'User-Agent': 'jesting' }); + expect(cb).toHaveBeenCalledWith(null, { ok: true }); + }); - test('handles multipart data', () => { + test(`${methodName}: defaults callback`, () => { + method('some.action', 'data', null); + expect(mockRequest.post).toHaveBeenCalledTimes(1); + }); - }); + test(`${methodName}: handles request lib error`, () => { + const error = new Error('WHOOPS!'); + mockRequest.post.mockImplementation((params, callback) => { + callback(error, null, null); + }); - test('handles request lib error', () => { + method('some.action', 'data', cb); - }); + expect(mockRequest.post).toHaveBeenCalledTimes(1); + expect(cb).toHaveBeenCalledWith(error); + }); - test('handles non 200 response code', () => { + test(`${methodName}: handles non 200 response code`, () => { + mockRequest.post.mockImplementation((params, callback) => { + callback(null, { statusCode: 400 }, null); + }); - }); + method('some.action', 'data', cb); - test('handles error parsing body', () => { + expect(mockRequest.post).toHaveBeenCalledTimes(1); + expect(cb).toHaveBeenCalledTimes(1); + const firstArg = cb.mock.calls[0][0]; + expect(firstArg.message).toBe('Invalid response'); + }); - }); + test(`${methodName}: handles error parsing body`, () => { + mockRequest.post.mockImplementation((params, callback) => { + callback(null, { statusCode: 200 }, '{'); + }); + + method('some.action', 'data', cb); + + expect(mockRequest.post).toHaveBeenCalledTimes(1); + expect(cb).toHaveBeenCalledTimes(1); + const firstArg = cb.mock.calls[0][0]; + expect(firstArg).toBeInstanceOf(Error); + }); + + test(`${methodName}: handles ok.false response`, () => { + mockRequest.post.mockImplementation((params, callback) => { + callback(null, { statusCode: 200 }, '{ "ok": false, "error": "not ok"}'); + }); - test('handles ok.false response', () => { + method('some.action', 'data', cb); + expect(mockRequest.post).toHaveBeenCalledTimes(1); + expect(cb).toHaveBeenCalledWith('not ok', { ok: false, error: 'not ok'}); + }); }); }); From e0aa23bd14b79bae76393c12504e8a149d02643a Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Sat, 20 May 2017 23:43:34 -0400 Subject: [PATCH 23/68] :100: --- __test__/lib/Slack_web_api.test.js | 66 +++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/__test__/lib/Slack_web_api.test.js b/__test__/lib/Slack_web_api.test.js index 38e910e22..31d4caca6 100644 --- a/__test__/lib/Slack_web_api.test.js +++ b/__test__/lib/Slack_web_api.test.js @@ -3,13 +3,13 @@ let mockRequest; let mockResponse; let responseError; let mockBot; + mockRequest = { post: jest.fn() }; jest.mock('request', () => mockRequest); - beforeEach(() => { jest.clearAllMocks(); @@ -218,12 +218,22 @@ describe('postForm', () => { }); }); - describe('api methods', () => { let instance; + let cb; beforeEach(() => { instance = slackWebApi(mockBot, {}); + cb = jest.fn(); + jest.spyOn(instance, 'callAPI'); + instance.callAPI.mockImplementation(() => {}); + }); + + afterEach(() => { + if (jest.isMockFunction(JSON.stringify)) { + JSON.stringify.mockRestore(); + } + instance.callAPI.mockRestore(); }); test('spot check api methods ', () => { @@ -233,28 +243,72 @@ describe('api methods', () => { expect(instance.auth).toBeDefined(); expect(instance.auth.test).toBeDefined(); + instance.auth.test('options', 'cb'); + const firstCallArgs = instance.callAPI.mock.calls[0]; + expect(firstCallArgs).toEqual(['auth.test', 'options', 'cb']); + // three levels expect(instance.users).toBeDefined(); expect(instance.users.profile).toBeDefined(); expect(instance.users.profile.get).toBeDefined(); + + instance.users.profile.get('options', 'cb'); + const secondCallArgs = instance.callAPI.mock.calls[1]; + expect(secondCallArgs).toEqual(['users.profile.get', 'options', 'cb']); }); describe('special cases', () => { - beforeEach(() => { + test('chat.postMessage stringifies attachments', () => { + instance.chat.postMessage({attachments: []}, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', {attachments: '[]'}, cb); + }); + test('chat.postMessage handles attachments as Strings', () => { + jest.spyOn(JSON, 'stringify'); + instance.chat.postMessage({attachments: 'string'}, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', {attachments: 'string'}, cb); + expect(JSON.stringify).not.toHaveBeenCalled(); }); - test('chat.postMessage ', () => { + test('chat.postMessage handles attachments stringification errors', () => { + const error = new Error('WHOOPSIE'); + jest.spyOn(JSON, 'stringify').mockImplementation(() => { throw error; }); + instance.chat.postMessage({attachments: []}, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', {}, cb); + expect(JSON.stringify).toHaveBeenCalled(); + }); + test('chat.update stringifies attachments', () => { + instance.chat.update({attachments: []}, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.update', {attachments: '[]'}, cb); }); - test('chat.update ', () => { + test('chat.update handles attachments as Strings', () => { + jest.spyOn(JSON, 'stringify'); + instance.chat.update({attachments: 'string'}, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.update', {attachments: 'string'}, cb); + expect(JSON.stringify).not.toHaveBeenCalled(); + }); + test('chat.postMessage handles attachments stringification errors', () => { + const error = new Error('WHOOPSIE'); + jest.spyOn(JSON, 'stringify').mockImplementation(() => { throw error; }); + instance.chat.update({attachments: []}, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.update', {}, cb); + expect(JSON.stringify).toHaveBeenCalled(); }); - test('files.upload ', () => { + test('files.upload should not use multipart if file is false', () => { + const options = { file: false, token: 'abc123' }; + instance.files.upload(options, cb); + expect(instance.callAPI).toHaveBeenCalledWith('files.upload', options, cb, false); + }); + test('files.upload should use multipart if file is true', () => { + const options = { file: true, token: 'abc123' }; + instance.files.upload(options, cb); + expect(instance.callAPI).toHaveBeenCalledWith('files.upload', options, cb, true); }); }); }); From 23ba3eddda25d71e7d6e20c71006115a5d0ea6db Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Sat, 20 May 2017 23:55:55 -0400 Subject: [PATCH 24/68] moves botkit module mocks and adds clearAllMocks call --- __test__/lib/Botkit.test.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/__test__/lib/Botkit.test.js b/__test__/lib/Botkit.test.js index dd4a891e3..cbf8e837c 100644 --- a/__test__/lib/Botkit.test.js +++ b/__test__/lib/Botkit.test.js @@ -1,14 +1,15 @@ let botkit; -beforeEach(() => { - jest.mock('../../lib/CoreBot', () => 'corebot'); - jest.mock('../../lib/SlackBot', () => 'slackbot'); - jest.mock('../../lib/Facebook', () => 'facebook'); - jest.mock('../../lib/TwilioIPMBot', () => 'twilio'); - jest.mock('../../lib/BotFramework', () => 'botframework'); - jest.mock('../../lib/CiscoSparkbot', () => 'spark'); - jest.mock('../../lib/ConsoleBot', () => 'console'); +jest.mock('../../lib/CoreBot', () => 'corebot'); +jest.mock('../../lib/SlackBot', () => 'slackbot'); +jest.mock('../../lib/Facebook', () => 'facebook'); +jest.mock('../../lib/TwilioIPMBot', () => 'twilio'); +jest.mock('../../lib/BotFramework', () => 'botframework'); +jest.mock('../../lib/CiscoSparkbot', () => 'spark'); +jest.mock('../../lib/ConsoleBot', () => 'console'); +beforeEach(() => { + jest.clearAllMocks(); botkit = require('../../lib/Botkit'); }); From aec1812ef8a89488c9b337608f22e3627053f579 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Sun, 21 May 2017 00:22:03 -0400 Subject: [PATCH 25/68] improves slack_web_api mocking --- __test__/lib/Slack_web_api.test.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/__test__/lib/Slack_web_api.test.js b/__test__/lib/Slack_web_api.test.js index 31d4caca6..523832250 100644 --- a/__test__/lib/Slack_web_api.test.js +++ b/__test__/lib/Slack_web_api.test.js @@ -1,20 +1,13 @@ let slackWebApi; let mockRequest; let mockResponse; -let responseError; let mockBot; -mockRequest = { - post: jest.fn() -}; +mockRequest = {}; jest.mock('request', () => mockRequest); beforeEach(() => { - jest.clearAllMocks(); - - responseError = null; - mockResponse = { statusCode: 200, body: '{"ok": true}' @@ -29,7 +22,7 @@ beforeEach(() => { mockBot.log.error = jest.fn(); - mockRequest.post.mockImplementation((params, cb) => { + mockRequest.post = jest.fn().mockImplementation((params, cb) => { cb(null, mockResponse, mockResponse.body); }); @@ -61,7 +54,7 @@ describe('callApi', () => { instance = slackWebApi(mockBot, {}); instance.callAPI('some.method', data, cb); - expect(mockRequest.post.mock.calls.length).toBe(1); + expect(mockRequest.post).toHaveBeenCalledTimes(1); const firstArg = mockRequest.post.mock.calls[0][0]; expect(firstArg.form.token).toBe('abc123'); }); @@ -73,7 +66,7 @@ describe('callApi', () => { instance = slackWebApi(mockBot, { token: 'abc123' }); instance.callAPI('some.method', data, cb); - expect(mockRequest.post.mock.calls.length).toBe(1); + expect(mockRequest.post).toHaveBeenCalledTimes(1); const firstArg = mockRequest.post.mock.calls[0][0]; expect(firstArg.form.token).toBe('abc123'); }); @@ -163,7 +156,7 @@ describe('postForm', () => { }); test(`${methodName}: defaults callback`, () => { - method('some.action', 'data', null); + method('some.action', 'data'); expect(mockRequest.post).toHaveBeenCalledTimes(1); }); From bb202e17d40208fd9fb4dd7a28f6f4e587fe4d3d Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Mon, 22 May 2017 11:58:13 -0500 Subject: [PATCH 26/68] Update slack-events-api.md --- docs/provisioning/slack-events-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/provisioning/slack-events-api.md b/docs/provisioning/slack-events-api.md index 2ea514d88..2a5c39088 100644 --- a/docs/provisioning/slack-events-api.md +++ b/docs/provisioning/slack-events-api.md @@ -1,6 +1,6 @@ # Configure Botkit and the Slack Events API -Building a bot with Botkit and the Slack Events API gives you access to all of the best tools and options available to createe a feature-rich bot for Slack. +Building a bot with Botkit and the Slack Events API gives you access to all of the best tools and options available to create a feature-rich bot for Slack. In order to get everything set up, you will need to configure a new Slack App inside the [Slack Developer Portal](http://api.slack.com/apps), and at the same time, configure a [Botkit-powered bot](http://botkit.ai). It only takes a few moments, but there are a bunch of steps, so follow these instructions carefully. From ec44c1675af2a2c842f8a69f11ba9bd621f62071 Mon Sep 17 00:00:00 2001 From: Emily Lam Date: Thu, 25 May 2017 17:17:57 -0700 Subject: [PATCH 27/68] Correct url for Cisco Spark Corrected url for Cisco Spark --- docs/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/readme.md b/docs/readme.md index c8d18371f..7995f878b 100755 --- a/docs/readme.md +++ b/docs/readme.md @@ -21,7 +21,7 @@ it is ready to be connected to a stream of incoming messages. Currently, Botkit * [Twilio IP Messaging](https://www.twilio.com/user/account/ip-messaging/getting-started) * [Microsoft Bot Framework](http://botframework.com/) -Read more about [connecting your bot to Slack](readme-slack.md#connecting-your-bot-to-slack), [connecting your bot to Cisco Spark](readme-slack.md#getting-started), [connecting your bot to Facebook](readme-facebook.md#getting-started), [connecting your bot to Twilio](readme-twilioipm.md#getting-started), +Read more about [connecting your bot to Slack](readme-slack.md#connecting-your-bot-to-slack), [connecting your bot to Cisco Spark](readme-ciscospark.md#getting-started), [connecting your bot to Facebook](readme-facebook.md#getting-started), [connecting your bot to Twilio](readme-twilioipm.md#getting-started), or [connecting your bot to Microsoft Bot Framework](readme-botframework.md#getting-started) ## Basic Usage From ec3c11d8cfee09fb4d861ff5f6ebf0bddcf8097c Mon Sep 17 00:00:00 2001 From: Alec Lazarescu Date: Sat, 17 Jun 2017 21:06:33 -0400 Subject: [PATCH 28/68] Add missing error callback from team not found --- lib/SlackBot.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/SlackBot.js b/lib/SlackBot.js index fff75229e..f2fa292f8 100755 --- a/lib/SlackBot.js +++ b/lib/SlackBot.js @@ -168,6 +168,8 @@ function Slackbot(configuration) { cb(null, found_team); } }); + } else { + cb(new Error(`could not find team ${team_id}`)); } } }); From 050937136cefaab6dc573f0d2ecbeb031641f029 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Mon, 19 Jun 2017 13:44:49 -0400 Subject: [PATCH 29/68] adds use strict directive to test files that use ES6 --- __test__/lib/Slack_web_api.test.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/__test__/lib/Slack_web_api.test.js b/__test__/lib/Slack_web_api.test.js index 523832250..c6b748928 100644 --- a/__test__/lib/Slack_web_api.test.js +++ b/__test__/lib/Slack_web_api.test.js @@ -1,3 +1,5 @@ +'use strict'; + let slackWebApi; let mockRequest; let mockResponse; @@ -206,7 +208,7 @@ describe('postForm', () => { method('some.action', 'data', cb); expect(mockRequest.post).toHaveBeenCalledTimes(1); - expect(cb).toHaveBeenCalledWith('not ok', { ok: false, error: 'not ok'}); + expect(cb).toHaveBeenCalledWith('not ok', { ok: false, error: 'not ok' }); }); }); }); @@ -219,7 +221,7 @@ describe('api methods', () => { instance = slackWebApi(mockBot, {}); cb = jest.fn(); jest.spyOn(instance, 'callAPI'); - instance.callAPI.mockImplementation(() => {}); + instance.callAPI.mockImplementation(() => { }); }); afterEach(() => { @@ -253,41 +255,41 @@ describe('api methods', () => { describe('special cases', () => { test('chat.postMessage stringifies attachments', () => { - instance.chat.postMessage({attachments: []}, cb); - expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', {attachments: '[]'}, cb); + instance.chat.postMessage({ attachments: [] }, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', { attachments: '[]' }, cb); }); test('chat.postMessage handles attachments as Strings', () => { jest.spyOn(JSON, 'stringify'); - instance.chat.postMessage({attachments: 'string'}, cb); - expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', {attachments: 'string'}, cb); + instance.chat.postMessage({ attachments: 'string' }, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', { attachments: 'string' }, cb); expect(JSON.stringify).not.toHaveBeenCalled(); }); test('chat.postMessage handles attachments stringification errors', () => { const error = new Error('WHOOPSIE'); jest.spyOn(JSON, 'stringify').mockImplementation(() => { throw error; }); - instance.chat.postMessage({attachments: []}, cb); + instance.chat.postMessage({ attachments: [] }, cb); expect(instance.callAPI).toHaveBeenCalledWith('chat.postMessage', {}, cb); expect(JSON.stringify).toHaveBeenCalled(); }); test('chat.update stringifies attachments', () => { - instance.chat.update({attachments: []}, cb); - expect(instance.callAPI).toHaveBeenCalledWith('chat.update', {attachments: '[]'}, cb); + instance.chat.update({ attachments: [] }, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.update', { attachments: '[]' }, cb); }); test('chat.update handles attachments as Strings', () => { jest.spyOn(JSON, 'stringify'); - instance.chat.update({attachments: 'string'}, cb); - expect(instance.callAPI).toHaveBeenCalledWith('chat.update', {attachments: 'string'}, cb); + instance.chat.update({ attachments: 'string' }, cb); + expect(instance.callAPI).toHaveBeenCalledWith('chat.update', { attachments: 'string' }, cb); expect(JSON.stringify).not.toHaveBeenCalled(); }); test('chat.postMessage handles attachments stringification errors', () => { const error = new Error('WHOOPSIE'); jest.spyOn(JSON, 'stringify').mockImplementation(() => { throw error; }); - instance.chat.update({attachments: []}, cb); + instance.chat.update({ attachments: [] }, cb); expect(instance.callAPI).toHaveBeenCalledWith('chat.update', {}, cb); expect(JSON.stringify).toHaveBeenCalled(); }); From c5d0fa1815d53b320c8c67f35d46dac845621d01 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Mon, 19 Jun 2017 14:27:09 -0400 Subject: [PATCH 30/68] adds use strict --- __test__/lib/Botkit.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/__test__/lib/Botkit.test.js b/__test__/lib/Botkit.test.js index cbf8e837c..06a3eb450 100644 --- a/__test__/lib/Botkit.test.js +++ b/__test__/lib/Botkit.test.js @@ -1,3 +1,5 @@ +'use strict'; + let botkit; jest.mock('../../lib/CoreBot', () => 'corebot'); From aeb1b025f1fd8f69879ebe33096ad3bd3eb63456 Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Mon, 19 Jun 2017 14:27:17 -0400 Subject: [PATCH 31/68] fixes linting errors --- lib/CoreBot.js | 2 +- lib/Slack_web_api.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CoreBot.js b/lib/CoreBot.js index 0183972cf..2541a985f 100755 --- a/lib/CoreBot.js +++ b/lib/CoreBot.js @@ -1007,7 +1007,7 @@ function Botkit(configuration) { } if (typeof(events) == 'string') { - events = events.split(/\,/g).map(function(str) { return str.trim() }) + events = events.split(/\,/g).map(function(str) { return str.trim(); }); } for (var e = 0; e < events.length; e++) { diff --git a/lib/Slack_web_api.js b/lib/Slack_web_api.js index 73a6a75e0..d17de8a3f 100755 --- a/lib/Slack_web_api.js +++ b/lib/Slack_web_api.js @@ -227,7 +227,7 @@ module.exports = function(bot, config) { request.post(params, function(error, response, body) { bot.debug('Got response', error, body); - if(response.statusCode == 429) { + if (response.statusCode == 429) { return cb(new Error('Rate limit exceeded')); } if (!error && response.statusCode == 200) { From c0769d36f205f5a7c92bba5714ce79e5dd60120d Mon Sep 17 00:00:00 2001 From: Cole Furfaro-Strode Date: Mon, 19 Jun 2017 14:35:14 -0400 Subject: [PATCH 32/68] adds test coverage for 429 rate limiting --- __test__/lib/Slack_web_api.test.js | 15 ++++++++++++++- lib/Slack_web_api.js | 16 ++++++++++------ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/__test__/lib/Slack_web_api.test.js b/__test__/lib/Slack_web_api.test.js index c6b748928..1067b0e21 100644 --- a/__test__/lib/Slack_web_api.test.js +++ b/__test__/lib/Slack_web_api.test.js @@ -174,7 +174,20 @@ describe('postForm', () => { expect(cb).toHaveBeenCalledWith(error); }); - test(`${methodName}: handles non 200 response code`, () => { + test(`${methodName}: handles 429 response code`, () => { + mockRequest.post.mockImplementation((params, callback) => { + callback(null, { statusCode: 429 }, null); + }); + + method('some.action', 'data', cb); + + expect(mockRequest.post).toHaveBeenCalledTimes(1); + expect(cb).toHaveBeenCalledTimes(1); + const firstArg = cb.mock.calls[0][0]; + expect(firstArg.message).toBe('Rate limit exceeded'); + }); + + test(`${methodName}: handles other response codes`, () => { mockRequest.post.mockImplementation((params, callback) => { callback(null, { statusCode: 400 }, null); }); diff --git a/lib/Slack_web_api.js b/lib/Slack_web_api.js index d17de8a3f..41d88a774 100755 --- a/lib/Slack_web_api.js +++ b/lib/Slack_web_api.js @@ -3,7 +3,7 @@ var request = require('request'); /** * Does nothing. Takes no params, returns nothing. It's a no-op! */ -function noop() {} +function noop() { } /** * Returns an interface to the Slack API in the context of the given bot @@ -187,7 +187,7 @@ module.exports = function(bot, config) { }; function sanitizeOptions(options) { - if (options.attachments && typeof(options.attachments) != 'string') { + if (options.attachments && typeof (options.attachments) != 'string') { try { options.attachments = JSON.stringify(options.attachments); } catch (err) { @@ -227,10 +227,11 @@ module.exports = function(bot, config) { request.post(params, function(error, response, body) { bot.debug('Got response', error, body); - if (response.statusCode == 429) { - return cb(new Error('Rate limit exceeded')); + if (error) { + return cb(error); } - if (!error && response.statusCode == 200) { + + if (response.statusCode == 200) { var json; try { json = JSON.parse(body); @@ -239,8 +240,11 @@ module.exports = function(bot, config) { } return cb((json.ok ? null : json.error), json); + } else if (response.statusCode == 429) { + return cb(new Error('Rate limit exceeded')); + } else { + return cb(new Error('Invalid response')); } - return cb(error || new Error('Invalid response')); }); } }; From 7e03e63c15fcd0c17f472c967cf27ecbf7f4fe1a Mon Sep 17 00:00:00 2001 From: Peter Swimm Date: Mon, 19 Jun 2017 15:52:04 -0500 Subject: [PATCH 33/68] Update cisco-spark.md --- docs/provisioning/cisco-spark.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/provisioning/cisco-spark.md b/docs/provisioning/cisco-spark.md index 9814a15c2..3ac4f398b 100644 --- a/docs/provisioning/cisco-spark.md +++ b/docs/provisioning/cisco-spark.md @@ -18,7 +18,9 @@ Take note of the bot username, you'll need it later. **Note about your icon**: Cisco requires you host an avatar for your bot before you can create it in their portal. This bot needs to be a 512x512px image icon hosted anywhere on the web. This can be changed later. -You can copy and paste this URL for a Botkit icon you can use right away: `https://raw.githubusercontent.com/howdyai/botkit-starter-ciscospark/master/public/default_icon.png` +You can copy and paste this URL for a Botkit icon you can use right away: + +https://raw.githubusercontent.com/howdyai/botkit-starter-ciscospark/master/public/default_icon.png ### 3. Copy your access token From c1afb76b6c9edd2d4918bb5de67b560da01016bc Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Mon, 19 Jun 2017 17:12:10 -0500 Subject: [PATCH 34/68] Fixes to console bot --- examples/console_bot.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/console_bot.js b/examples/console_bot.js index d36d8d4dd..6f6b38e7a 100644 --- a/examples/console_bot.js +++ b/examples/console_bot.js @@ -189,14 +189,13 @@ controller.hears(['shutdown'], 'message_received', function(bot, message) { controller.hears(['uptime', 'identify yourself', 'who are you', 'what is your name'], - 'direct_message,direct_mention,mention', function(bot, message) { + 'message_received', function(bot, message) { var hostname = os.hostname(); var uptime = formatUptime(process.uptime()); bot.reply(message, - ':robot_face: I am a bot named <@' + bot.identity.name + - '>. I have been running for ' + uptime + ' on ' + hostname + '.'); + ':robot_face: I am ConsoleBot. I have been running for ' + uptime + ' on ' + hostname + '.'); }); From 5212ce18838136b92b312992ae05d12e74563647 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Mon, 19 Jun 2017 17:28:18 -0500 Subject: [PATCH 35/68] Fix issue with consolebot --- lib/ConsoleBot.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ConsoleBot.js b/lib/ConsoleBot.js index ff581489d..f2aa99bc1 100644 --- a/lib/ConsoleBot.js +++ b/lib/ConsoleBot.js @@ -29,6 +29,9 @@ function TextBot(configuration) { bot.send = function(message, cb) { console.log('BOT:', message.text); + if (cb) { + cb(); + } }; bot.reply = function(src, resp, cb) { From 7e16b49b1bb097fe8fb1aaca6663096bdb822380 Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Sat, 24 Jun 2017 05:50:17 +0200 Subject: [PATCH 36/68] add attachment_upload to facebook_botkit.api --- lib/Facebook.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Facebook.js b/lib/Facebook.js index 78cf8f208..3d0a83bcb 100644 --- a/lib/Facebook.js +++ b/lib/Facebook.js @@ -610,9 +610,12 @@ function Facebookbot(configuration) { } }; + var attachment_upload_api = {}; + facebook_botkit.api = { 'messenger_profile': messenger_profile_api, - 'thread_settings': messenger_profile_api + 'thread_settings': messenger_profile_api, + 'attachment_upload': attachment_upload_api }; // Verifies the SHA1 signature of the raw request payload before bodyParser parses it From a4a4c2ac0be70167ef16fec2e42f5c14637fcb2f Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Sat, 24 Jun 2017 05:54:55 +0200 Subject: [PATCH 37/68] Add upload and postApi methods --- lib/Facebook.js | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/Facebook.js b/lib/Facebook.js index 3d0a83bcb..0275d2d50 100644 --- a/lib/Facebook.js +++ b/lib/Facebook.js @@ -610,7 +610,40 @@ function Facebookbot(configuration) { } }; - var attachment_upload_api = {}; + var attachment_upload_api = { + upload: function(attachment) { + var message = { + attachment: attachment + }; + facebook_botkit.api.attachment_upload.postAPI(message); + }, + postAPI: function(message) { + request.post('https://' + api_host + '/v2.6/me/message_attachments?access_token=' + configuration.access_token, + {form: message}, + function(err, res, body) { + if (err) { + facebook_botkit.log('Could not configure messenger profile'); + } else { + + var results = null; + try { + results = JSON.parse(body); + } catch (err) { + facebook_botkit.log('ERROR in messenger profile API call: Could not parse JSON', err, body); + } + + if (results) { + if (results.error) { + facebook_botkit.log('ERROR in messenger profile API call: ', results.error.message); + } else { + facebook_botkit.debug('Successfully configured messenger profile', body); + } + } + } + }); + } + + }; facebook_botkit.api = { 'messenger_profile': messenger_profile_api, From 0aadb15f4f65892a11b7335e24b4a83423dfcbb4 Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Sat, 24 Jun 2017 06:01:39 +0200 Subject: [PATCH 38/68] Add upload method --- lib/Facebook.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/Facebook.js b/lib/Facebook.js index 0275d2d50..2d2abcc3f 100644 --- a/lib/Facebook.js +++ b/lib/Facebook.js @@ -611,32 +611,35 @@ function Facebookbot(configuration) { }; var attachment_upload_api = { - upload: function(attachment) { + upload: function(attachment, cb) { var message = { attachment: attachment }; - facebook_botkit.api.attachment_upload.postAPI(message); - }, - postAPI: function(message) { + request.post('https://' + api_host + '/v2.6/me/message_attachments?access_token=' + configuration.access_token, - {form: message}, + { form: message }, function(err, res, body) { if (err) { - facebook_botkit.log('Could not configure messenger profile'); + facebook_botkit.log('Could not upload attachment'); + cb(err); } else { var results = null; try { results = JSON.parse(body); } catch (err) { - facebook_botkit.log('ERROR in messenger profile API call: Could not parse JSON', err, body); + facebook_botkit.log('ERROR in attachment upload API call: Could not parse JSON', err, body); + cb(err); } if (results) { if (results.error) { - facebook_botkit.log('ERROR in messenger profile API call: ', results.error.message); + facebook_botkit.log('ERROR in attachment upload API call: ', results.error.message); + cb(results.error); } else { - facebook_botkit.debug('Successfully configured messenger profile', body); + var attachment_id = results.attachment_id; + facebook_botkit.log('Successfully got attachment id ', attachment_id); + cb(null, attachment_id); } } } From 8af4916bb78af13858070f2695eccc823839d4aa Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Sat, 24 Jun 2017 06:49:48 +0200 Subject: [PATCH 39/68] Change message structure --- lib/Facebook.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Facebook.js b/lib/Facebook.js index 2d2abcc3f..03c8b2217 100644 --- a/lib/Facebook.js +++ b/lib/Facebook.js @@ -613,7 +613,9 @@ function Facebookbot(configuration) { var attachment_upload_api = { upload: function(attachment, cb) { var message = { - attachment: attachment + message : { + attachment: attachment + } }; request.post('https://' + api_host + '/v2.6/me/message_attachments?access_token=' + configuration.access_token, From 10debc23327409f37cd3b89680bda022502d4a1e Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Sat, 24 Jun 2017 06:51:05 +0200 Subject: [PATCH 40/68] Add attachment upload api example --- examples/facebook_bot.js | 148 ++++++++------------------------------- 1 file changed, 30 insertions(+), 118 deletions(-) diff --git a/examples/facebook_bot.js b/examples/facebook_bot.js index 29e0ed41f..e51695113 100755 --- a/examples/facebook_bot.js +++ b/examples/facebook_bot.js @@ -1,137 +1,23 @@ -/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ______ ______ ______ __ __ __ ______ - /\ == \ /\ __ \ /\__ _\ /\ \/ / /\ \ /\__ _\ - \ \ __< \ \ \/\ \ \/_/\ \/ \ \ _"-. \ \ \ \/_/\ \/ - \ \_____\ \ \_____\ \ \_\ \ \_\ \_\ \ \_\ \ \_\ - \/_____/ \/_____/ \/_/ \/_/\/_/ \/_/ \/_/ - - -This is a sample Facebook bot built with Botkit. - -This bot demonstrates many of the core features of Botkit: - -* Connect to Facebook's Messenger APIs -* Receive messages based on "spoken" patterns -* Reply to messages -* Use the conversation system to ask questions -* Use the built in storage system to store and retrieve information - for a user. - -# RUN THE BOT: - - Follow the instructions here to set up your Facebook app and page: - - -> https://developers.facebook.com/docs/messenger-platform/implementation - - Run your bot from the command line: - - app_secret= page_token= verify_token= node facebook_bot.js [--lt [--ltsubdomain LOCALTUNNEL_SUBDOMAIN]] - - Use the --lt option to make your bot available on the web through localtunnel.me. - -# USE THE BOT: - - Find your bot inside Facebook to send it a direct message. - - Say: "Hello" - - The bot will reply "Hello!" - - Say: "who are you?" - - The bot will tell you its name, where it running, and for how long. - - Say: "Call me " - - Tell the bot your nickname. Now you are friends. - - Say: "who am I?" - - The bot will tell you your nickname, if it knows one for you. - - Say: "shutdown" - - The bot will ask if you are sure, and then shut itself down. - - Make sure to invite your bot into other channels using /invite @! - -# EXTEND THE BOT: - - Botkit has many features for building cool and useful bots! - - Read all about it here: - - -> http://howdy.ai/botkit - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - - -if (!process.env.page_token) { - console.log('Error: Specify page_token in environment'); - process.exit(1); -} - -if (!process.env.verify_token) { - console.log('Error: Specify verify_token in environment'); - process.exit(1); -} - -if (!process.env.app_secret) { - console.log('Error: Specify app_secret in environment'); - process.exit(1); -} - var Botkit = require('../lib/Botkit.js'); -var os = require('os'); -var commandLineArgs = require('command-line-args'); -var localtunnel = require('localtunnel'); - -const ops = commandLineArgs([ - {name: 'lt', alias: 'l', args: 1, description: 'Use localtunnel.me to make your bot available on the web.', - type: Boolean, defaultValue: false}, - {name: 'ltsubdomain', alias: 's', args: 1, - description: 'Custom subdomain for the localtunnel.me URL. This option can only be used together with --lt.', - type: String, defaultValue: null}, - ]); - -if(ops.lt === false && ops.ltsubdomain !== null) { - console.log("error: --ltsubdomain can only be used together with --lt."); - process.exit(); -} var controller = Botkit.facebookbot({ debug: true, log: true, - access_token: process.env.page_token, - verify_token: process.env.verify_token, - app_secret: process.env.app_secret, + access_token: 'EAAShWXeInZCcBAGD9z7ffW3Dmflwh2X8otTTH1R1OzBniNe6vQPyGduijVwk68Of3r1nZAVte76LdQ00P2qSCQip5hbnqxpaGZAFEibAiDZCHHd3JE0caYzD3cHP7U3rEnSSghMcTITCesrgsWWDhT6SyF7dl5HwJINvht0HFwZDZD', + verify_token: 'pass;1234', + app_secret: '197fc98968cd0197cd8c838e9b68e466', validate_requests: true, // Refuse any requests that don't come from FB on your receive webhook, must provide FB_APP_SECRET in environment variables }); var bot = controller.spawn({ }); -controller.setupWebserver(process.env.port || 3000, function(err, webserver) { +controller.setupWebserver(1337, function(err, webserver) { controller.createWebhookEndpoints(webserver, bot, function() { console.log('ONLINE!'); - if(ops.lt) { - var tunnel = localtunnel(process.env.port || 3000, {subdomain: ops.ltsubdomain}, function(err, tunnel) { - if (err) { - console.log(err); - process.exit(); - } - console.log("Your bot is available on the web at the following URL: " + tunnel.url + '/facebook/receive'); - }); - - tunnel.on('close', function() { - console.log("Your bot is no longer available on the web at the localtunnnel.me URL."); - process.exit(); - }); - } }); }); - controller.api.messenger_profile.greeting('Hello! I\'m a Botkit bot!'); controller.api.messenger_profile.get_started('sample_get_started_payload'); controller.api.messenger_profile.menu([{ @@ -201,6 +87,32 @@ controller.hears(['code'], 'message_received,facebook_postback', function(bot, m }); }); +controller.hears(['attachment_upload'], 'message_received', function(bot, message) { + var attachment = { + "type":"image", + "payload":{ + "url":"https://botlist.co/system/BotList/Bot/logos/000/000/091/medium/icon2.png", + "is_reusable": true + } + }; + + controller.api.attachment_upload.upload(attachment, function (err, attachmentId) { + if(err) { + // Error + } else { + var image = { + "attachment":{ + "type":"image", + "payload": { + "attachment_id": attachmentId + } + } + }; + bot.reply(message, image); + } + }); +}); + controller.hears(['quick'], 'message_received', function(bot, message) { bot.reply(message, { From a91d6c199b40d6170feaf25a4d296a2afab0df8c Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Sat, 24 Jun 2017 06:55:36 +0200 Subject: [PATCH 41/68] Change image url --- examples/facebook_bot.js | 2 +- npm-debug.log | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 npm-debug.log diff --git a/examples/facebook_bot.js b/examples/facebook_bot.js index e51695113..37556ac6b 100755 --- a/examples/facebook_bot.js +++ b/examples/facebook_bot.js @@ -91,7 +91,7 @@ controller.hears(['attachment_upload'], 'message_received', function(bot, messag var attachment = { "type":"image", "payload":{ - "url":"https://botlist.co/system/BotList/Bot/logos/000/000/091/medium/icon2.png", + "url":"https://pbs.twimg.com/profile_images/803642201653858305/IAW1DBPw_400x400.png", "is_reusable": true } }; diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 000000000..deca7db99 --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,24 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'start' ] +2 info using npm@3.10.8 +3 info using node@v6.9.1 +4 verbose stack Error: missing script: start +4 verbose stack at run (/usr/local/lib/node_modules/npm/lib/run-script.js:151:19) +4 verbose stack at /usr/local/lib/node_modules/npm/lib/run-script.js:61:5 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:356:5 +4 verbose stack at checkBinReferences_ (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:320:45) +4 verbose stack at final (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:354:3) +4 verbose stack at then (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:124:5) +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:311:12 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16 +4 verbose stack at tryToString (fs.js:455:3) +4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:442:12) +5 verbose cwd /Users/SOAT-OLA/works/projects/botkit +6 error Darwin 16.5.0 +7 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "start" +8 error node v6.9.1 +9 error npm v3.10.8 +10 error missing script: start +11 error If you need help, you may report this error at: +11 error +12 verbose exit [ 1, true ] From 1da1b3d56b83629029196dbd9506143493e0b676 Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Sat, 24 Jun 2017 07:01:36 +0200 Subject: [PATCH 42/68] add an example to facebook readme file --- docs/readme-facebook.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/readme-facebook.md b/docs/readme-facebook.md index 3c335ad48..825ced647 100644 --- a/docs/readme-facebook.md +++ b/docs/readme-facebook.md @@ -20,6 +20,7 @@ Table of Contents * [Simulate typing](#simulate-typing) * [Silent and No Notifications](#silent-and-no-notifications) * [Messenger code API](#messenger-code-api) +* [Attachment upload API](#attachment-upload-api) * [Running Botkit with an Express server](#use-botkit-for-facebook-messenger-with-an-express-web-server) ## Getting Started @@ -506,6 +507,38 @@ controller.api.messenger_profile.get_target_audience(function (err, data) { ``` +## Attachment upload API + +Attachment upload API allows you to upload an attachment that you may later send out to many users, without having to repeatedly upload the same data each time it is sent : + + +```js +var attachment = { + "type":"image", + "payload":{ + "url":"https://pbs.twimg.com/profile_images/803642201653858305/IAW1DBPw_400x400.png", + "is_reusable": true + } + }; + + controller.api.attachment_upload.upload(attachment, function (err, attachmentId) { + if(err) { + // Error + } else { + var image = { + "attachment":{ + "type":"image", + "payload": { + "attachment_id": attachmentId + } + } + }; + bot.reply(message, image); + } + }); + +``` + ## Use BotKit for Facebook Messenger with an Express web server Instead of the web server generated with setupWebserver(), it is possible to use a different web server to receive webhooks, as well as serving web pages. From 7a523321f41080217b0429dac8a5c3692d2b602e Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 11:48:18 -0500 Subject: [PATCH 43/68] Merge in twilio sms bot --- docs/provisioning/twilio-sms.md | 40 ++++++++++ .../readme-twiliosms.md | 80 ++++++++++++++++++- .../twilio_sms_bot.js | 0 lib/CiscoSparkbot.js | 2 +- lib/ConsoleBot.js | 2 +- lib/Studio.js | 5 ++ lib/TwilioSMSBot.js | 8 +- 7 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 docs/provisioning/twilio-sms.md rename readme-twiliosms.md => docs/readme-twiliosms.md (55%) rename twilio_sms_bot.js => examples/twilio_sms_bot.js (100%) diff --git a/docs/provisioning/twilio-sms.md b/docs/provisioning/twilio-sms.md new file mode 100644 index 000000000..20c5a67fe --- /dev/null +++ b/docs/provisioning/twilio-sms.md @@ -0,0 +1,40 @@ +# Configure Botkit and Twilio SMS + +Setting up a bot for Twilio SMS is one of the easiest experiences for bot developers! Follow these steps carefully to configure your bot. + +### 1. Install Botkit + +The easiest path to creating a new bot for Twilio SMS is through Botkit Studio. [Sign up for an account here](https://studio.botkit.ai/signup/). This method will provide a guided path to hosting, along with other useful tools for creating and managing your bot. + +For advanced users looking to run their own code, you will need to [install Botkit](../readme-twilio-sms.md#getting-started) and run it before your bot can be configured with Twilio SMS. + +### 2. Create a new bot in the Twilio Developer Console + +Login and click `Get Started` in [Twilio SMS Developer Console](https://www.twilio.com/console/sms/dashboard). You will be taken through the process of obtaining a number to use with your bot. + +At this point you can use the Twilio wizard to help you create an application, or build one directly by clicking `Messanging Services`. You can give it a friendly, and chose `Mixed` for use case. + +Check the box `Process Inbound Messages` and under request URL, type the name of your request url. + +By default in Botkit, this is: +https://*mybot.yoururl.com*/sms/receive + +### 3. Collect your tokens + +Next, visit [your console Dashboard](https://www.twilio.com/console) and copy your `Account SID` and `Auth Token`. You will use these in the next step along with your assignedmobile number to setup Botkit. + +### 4. Run your bot with variables set + + [Follow these instructions](../readme-TwilioSMS.md#getting-started) to run your bot locally, or by using a third-party service such as [Glitch](https://glitch.com) or [Heroku](https://heroku.com). + + You will need the following environment variables when running your bot: + +* TWILIO_ACCOUNT_SID= Your account's SID collected in step 3 above. +* TWILIO_AUTH_TOKEN= Your account's Auth Token collected in step 3 above. +* TWILIO_NUMBER= The number you were assigned in step 2 above. + +You should now be able to text message your number the words `Hello` and receive a friendly reply back! + +### Additional resources + +Read more about making bots for this platform in the [Twilio Developer Portal](https://www.twilio.com/console). diff --git a/readme-twiliosms.md b/docs/readme-twiliosms.md similarity index 55% rename from readme-twiliosms.md rename to docs/readme-twiliosms.md index 88d65b584..6efde3a07 100644 --- a/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -34,7 +34,7 @@ Twilio will send `POST` request to this address every time a user sends an SMS t The second preference ("Primary handler fails") is your backup plan. The URI Twilio should `POST` to in case your primary handler is unavailable. You can leave this field in blank for now but keep in mind this is useful for error handling (e.g. to notify users that your bot is unavailable). -5) Run the example Twilio SMS bot included in Botkit's repository ([`./twilio_sms_bot.js`](twilio_sms_bot.js)). Copy and paste the example bot's code into a new JavaScript file (e.g. `twilio_sms_bot.js`) in your current working directory and run the following command on your terminal: +5) Run the example Twilio SMS bot included in Botkit's repository ([`twilio_sms_bot.js`](../examples/twilio_sms_bot.js)). Copy and paste the example bot's code into a new JavaScript file (e.g. `twilio_sms_bot.js`) in your current working directory and run the following command on your terminal: ```bash $ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_NUMBER= node twilio_sms_bot.js @@ -46,6 +46,80 @@ $ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWIL Try the following messages: `Hi`, `Call me bob`, `what's my name?` -### What now? +## Usage -Head over to [Botkit's core guide](https://github.com/howdyai/botkit/blob/master/docs/readme.md) to know how to build bots! +*Note: This document assumes that you are familiarized with Botkit and Twilio's Programmable SMS API* + +To connect your bot to Twilio you must point a Messaging webhook to http://your_host/sms/receive, after doing so, every Twilio message will be sent to that address. + +Then you need to write your bot. First, create a TwilioSMSBot instance and pass an object with your configuration properties: + +* `account_sid`: found in your [Twilio Console Dashboard](https://www.twilio.com/console) +* `auth_token`: found in your [Twilio Console Dashboard](https://www.twilio.com/console) +* `twilio_number`: your app's phone number, found in your [Phone Numbers Dashboard](https://www.twilio.com/console/phone-numbers/dashboard) **The phone number format must be: `+15551235555`** + +```js +const TwilioSMSBot = require('botkit-sms') +const controller = TwilioSMSBot({ + account_sid: process.env.TWILIO_ACCOUNT_SID, + auth_token: process.env.TWILIO_AUTH_TOKEN, + twilio_number: process.env.TWILIO_NUMBER +}) +``` + +`spawn()` your bot instance: + +```js +let bot = controller.spawn({}) +``` + +Then you need to set up your Web server and create the webhook endpoints so your app can receive Twilio's messages: + +```js +controller.setupWebserver(process.env.PORT, function (err, webserver) { + controller.createWebhookEndpoints(controller.webserver, bot, function () { + console.log('TwilioSMSBot is online!') + }) +}) +``` + +And finally, you can setup listeners for specific messages, like you would in any other `botkit` bot: + +```js +controller.hears(['hi', 'hello'], 'message_received', (bot, message) => { + bot.startConversation(message, (err, convo) => { + convo.say('Hi, I am Oliver, an SMS bot! :D') + convo.ask('What is your name?', (res, convo) => { + convo.say(`Nice to meet you, ${res.text}!`) + convo.next() + }) + }) +}) + +controller.hears('.*', 'message_received', (bot, message) => { + bot.reply(message, 'huh?') +}) +``` + +See full example in the `examples` directory of this repo. + + +## Documentation + +* [Get Started](readme.md) +* [Botkit Studio API](readme-studio.md) +* [Function index](readme.md#developing-with-botkit) +* [Extending Botkit with Plugins and Middleware](middleware.md) + * [List of current plugins](readme-middlewares.md) +* [Storing Information](storage.md) +* [Logging](logging.md) +* Platforms + * [Slack](readme-slack.md) + * [Cisco Spark](readme-ciscospark.md) + * [Facebook Messenger](readme-facebook.md) + * [Twilio IPM](readme-twilioipm.md) + * [Microsoft Bot Framework](readme-botframework.md) +* Contributing to Botkit + * [Contributing to Botkit Core](../CONTRIBUTING.md) + * [Building Middleware/plugins](howto/build_middleware.md) + * [Building platform connectors](howto/build_connector.md) diff --git a/twilio_sms_bot.js b/examples/twilio_sms_bot.js similarity index 100% rename from twilio_sms_bot.js rename to examples/twilio_sms_bot.js diff --git a/lib/CiscoSparkbot.js b/lib/CiscoSparkbot.js index f72911db4..c25e52b94 100644 --- a/lib/CiscoSparkbot.js +++ b/lib/CiscoSparkbot.js @@ -76,7 +76,7 @@ function Sparkbot(configuration) { '** Serving webhook endpoints for Cisco Spark Platform at: ' + 'http://' + controller.config.hostname + ':' + controller.config.port + '/ciscospark/receive'); webserver.post('/ciscospark/receive', function(req, res) { - res.sendStatus(200) + res.sendStatus(200); controller.handleWebhookPayload(req, res, bot); }); diff --git a/lib/ConsoleBot.js b/lib/ConsoleBot.js index fc46d9b54..98cee7aa9 100644 --- a/lib/ConsoleBot.js +++ b/lib/ConsoleBot.js @@ -24,7 +24,7 @@ function TextBot(configuration) { }; bot.createConversation = function(message, cb) { - botkit.createConversation(this, message, cb) + botkit.createConversation(this, message, cb); }; bot.startConversation = function(message, cb) { diff --git a/lib/Studio.js b/lib/Studio.js index cf71168f5..b369780d7 100644 --- a/lib/Studio.js +++ b/lib/Studio.js @@ -611,6 +611,11 @@ module.exports = function(controller) { x = md5(bot.config.TWILIO_IPM_SERVICE_SID); break; + case 'twiliosms': + x = md5(bot.botkit.config.account_sid); + break; + + case 'ciscospark': x = md5(bot.botkit.config.ciscospark_access_token); break; diff --git a/lib/TwilioSMSBot.js b/lib/TwilioSMSBot.js index dbad130a7..b2f5ea7a5 100644 --- a/lib/TwilioSMSBot.js +++ b/lib/TwilioSMSBot.js @@ -29,15 +29,21 @@ function TwilioSMS(configuration) { twilioSMS.defineBot(function(botkit, config) { var bot = { + type: 'twiliosms', botkit: botkit, config: config || {}, utterances: botkit.utterances }; bot.startConversation = function(message, cb) { - botkit.startConversation(this, message, cb); + botkit.startConversation(bot, message, cb); }; + bot.createConversation = function(message, cb) { + botkit.createConversation(bot, message, cb); + }; + + bot.send = function(message, cb) { var client = new twilio.RestClient( From 6e3cb2d284da8e70f479bb6d1d2a34eafda02b1a Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 12:06:47 -0500 Subject: [PATCH 44/68] add links to twilio sms docs --- docs/examples.md | 2 ++ docs/logging.md | 3 +-- docs/middleware.md | 5 +---- docs/readme-botframework.md | 1 + docs/readme-ciscospark.md | 1 + docs/readme-facebook.md | 1 + docs/readme-middlewares.md | 1 + docs/readme-slack.md | 5 +++-- docs/readme-studio.md | 1 + docs/readme-twilioipm.md | 1 + docs/readme-twiliosms.md | 1 + docs/readme.md | 4 +++- docs/storage.md | 2 +- readme.md | 2 ++ 14 files changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index aadd245c2..c4bb07357 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -9,6 +9,8 @@ These examples are included in the Botkit [Github repo](https://github.com/howdy [facebook_bot.js](https://github.com/howdyai/botkit/blob/master/examples/facebook_bot.js) An example bot that can be connected to your Facebook page. Useful as a basis for creating your first bot! +[twilio_sms_bot.js](https://github.com/howdyai/botkit/blob/master/examples/twilio_sms_bot.js) An example bot that can be connected to your Twilio SMS service. Useful as a basis for creating your first bot! + [twilio_ipm_bot.js](https://github.com/howdyai/botkit/blob/master/examples/twilio_ipm_bot.js) An example bot that can be connected to your Twilio IP Messaging client. Useful as a basis for creating your first bot! [botframework_bot.js](https://github.com/howdyai/botkit/blob/master/examples/botframework_bot.js) An example bot that can be connected to the Microsoft Bot Framework network. Useful as a basis for creating your first bot! diff --git a/docs/logging.md b/docs/logging.md index 418874501..981cdf9cf 100644 --- a/docs/logging.md +++ b/docs/logging.md @@ -1,5 +1,3 @@ - - ### Writing your own logging module By default, your bot will log to the standard JavaScript `console` object @@ -47,6 +45,7 @@ Note: with Winston, we must use the syslog.levels over the default or else some * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/middleware.md b/docs/middleware.md index 8eafa1801..acc884954 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -1,7 +1,3 @@ - - - - ## Middleware The functionality of Botkit can be extended using middleware @@ -197,6 +193,7 @@ controller.middleware.capture.use(function(bot, message, convo, next) { * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-botframework.md b/docs/readme-botframework.md index cf031adf3..66014eae4 100644 --- a/docs/readme-botframework.md +++ b/docs/readme-botframework.md @@ -221,6 +221,7 @@ You can easily turn on the typing indicator on platforms that support that behav * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-ciscospark.md b/docs/readme-ciscospark.md index 3436bb55a..bc4a5d4f0 100644 --- a/docs/readme-ciscospark.md +++ b/docs/readme-ciscospark.md @@ -268,6 +268,7 @@ controller.on('bot_space_join', function(bot, message) { * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-facebook.md b/docs/readme-facebook.md index 3c335ad48..588398547 100644 --- a/docs/readme-facebook.md +++ b/docs/readme-facebook.md @@ -525,6 +525,7 @@ Here is an example of [using an Express web server alongside BotKit for Facebook * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-middlewares.md b/docs/readme-middlewares.md index 455af01c5..3731cb3b1 100644 --- a/docs/readme-middlewares.md +++ b/docs/readme-middlewares.md @@ -121,6 +121,7 @@ We would love to hear about it! [Contact the Howdy team](https://howdy.ai/) to b * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-slack.md b/docs/readme-slack.md index 30c124e11..fd5a4e947 100644 --- a/docs/readme-slack.md +++ b/docs/readme-slack.md @@ -22,7 +22,7 @@ Table of Contents --- ## Getting Started -1) Install Botkit on your hosting platform of choice [more info here](readme.md#installation). +1) Install Botkit on your hosting platform of choice [more info here](readme.md#installation). 2) First make a bot integration inside of your Slack channel. Go here: @@ -949,7 +949,7 @@ controller.setupWebserver(process.env.port, function(err, webserver) { res.send('Success!'); } }); - + // If not also opening an RTM connection controller.startTicking(); }); @@ -985,6 +985,7 @@ var controller = Botkit.slackbot({ * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-studio.md b/docs/readme-studio.md index 40d2bc1d2..ddbe1c765 100644 --- a/docs/readme-studio.md +++ b/docs/readme-studio.md @@ -357,6 +357,7 @@ controller.studio.beforeThread('search', 'results', function(convo, next) { * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-twilioipm.md b/docs/readme-twilioipm.md index 31214cf06..13c06fa58 100644 --- a/docs/readme-twilioipm.md +++ b/docs/readme-twilioipm.md @@ -302,6 +302,7 @@ controller.on('onChannelAdded', function(bot, message){ * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme-twiliosms.md b/docs/readme-twiliosms.md index 6efde3a07..a9d1b0721 100644 --- a/docs/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -117,6 +117,7 @@ See full example in the `examples` directory of this repo. * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/readme.md b/docs/readme.md index 7995f878b..721b3f859 100755 --- a/docs/readme.md +++ b/docs/readme.md @@ -18,7 +18,8 @@ it is ready to be connected to a stream of incoming messages. Currently, Botkit * [Slack Slash Commands](http://api.slack.com/slash-commands) * [Cisco Spark Webhooks](https://developer.ciscospark.com/webhooks-explained.html) * [Facebook Messenger Webhooks](https://developers.facebook.com/docs/messenger-platform/implementation) -* [Twilio IP Messaging](https://www.twilio.com/user/account/ip-messaging/getting-started) +* [Twilio SMS](https://www.twilio.com/console/sms/dashboard) +* [Twilio IP Messaging](https://www.twilio.com/console/chat/dashboard) * [Microsoft Bot Framework](http://botframework.com/) Read more about [connecting your bot to Slack](readme-slack.md#connecting-your-bot-to-slack), [connecting your bot to Cisco Spark](readme-ciscospark.md#getting-started), [connecting your bot to Facebook](readme-facebook.md#getting-started), [connecting your bot to Twilio](readme-twilioipm.md#getting-started), @@ -941,6 +942,7 @@ Here is an example of [using an Express web server alongside Botkit](https://git * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/docs/storage.md b/docs/storage.md index b55b8c684..4323dfcc5 100644 --- a/docs/storage.md +++ b/docs/storage.md @@ -47,7 +47,6 @@ var controller = Botkit.slackbot({ ``` - ## Documentation * [Get Started](readme.md) @@ -61,6 +60,7 @@ var controller = Botkit.slackbot({ * [Slack](readme-slack.md) * [Cisco Spark](readme-ciscospark.md) * [Facebook Messenger](readme-facebook.md) + * [Twilio SMS](readme-twiliosms.md) * [Twilio IPM](readme-twilioipm.md) * [Microsoft Bot Framework](readme-botframework.md) * Contributing to Botkit diff --git a/readme.md b/readme.md index 1973432ba..0ff5027cf 100644 --- a/readme.md +++ b/readme.md @@ -24,6 +24,7 @@ Botkit features a comprehensive set of tools to deal with popular messaging plat * [Slack](docs/readme-slack.md) * [Cisco Spark](docs/readme-ciscospark.md) * [Facebook Messenger and Facebook @Workplace](docs/readme-facebook.md) +* [Twilio SMS Messaging](docs/readme-twiliosms.md) * [Twilio IP Messaging](docs/readme-twilioipm.md) * [Microsoft Bot Framework](docs/readme-botframework.md) * Yours? [info@howdy.ai](mailto:info@howdy.ai) @@ -174,6 +175,7 @@ npm test -- --bail * [Slack](docs/readme-slack.md) * [Cisco Spark](docs/readme-ciscospark.md) * [Facebook Messenger](docs/readme-facebook.md) + * [Twilio SMS](docs/readme-twiliosms.md) * [Twilio IPM](docs/readme-twilioipm.md) * [Microsoft Bot Framework](docs/readme-botframework.md) * Contributing to Botkit From ffd14d9ea34fbb4a11523c953335ca300dc97bdb Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 12:14:49 -0500 Subject: [PATCH 45/68] formatting of markdown --- docs/readme-twiliosms.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/readme-twiliosms.md b/docs/readme-twiliosms.md index a9d1b0721..9ec098331 100644 --- a/docs/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -12,15 +12,15 @@ This document covers the Twilio Programmable SMS API implementation details only 2) Register a developer account with Twilio. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. -After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. + After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. -**Twilio Account SID and Auth Token** + **Twilio Account SID and Auth Token** -These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) + These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) -**Twilio Number** + **Twilio Number** -You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` + You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` 4) Configure your Twilio Number. Head to the [Phone Numbers](https://www.twilio.com/console/phone-numbers) in your Twilio Console and select the phone number you will use for your SMS bot. From 79361d9d188468f7dbdefc8e4ba46ae2f123c457 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 12:15:41 -0500 Subject: [PATCH 46/68] adjustments to readme --- docs/readme-twiliosms.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/readme-twiliosms.md b/docs/readme-twiliosms.md index 9ec098331..4462bdcca 100644 --- a/docs/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -12,17 +12,17 @@ This document covers the Twilio Programmable SMS API implementation details only 2) Register a developer account with Twilio. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. - After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. +> After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. - **Twilio Account SID and Auth Token** +> **Twilio Account SID and Auth Token** - These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) +> These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) - **Twilio Number** +> **Twilio Number** - You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` +> You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` -4) Configure your Twilio Number. Head to the [Phone Numbers](https://www.twilio.com/console/phone-numbers) in your Twilio Console and select the phone number you will use for your SMS bot. +3) Configure your Twilio Number. Head to the [Phone Numbers](https://www.twilio.com/console/phone-numbers) in your Twilio Console and select the phone number you will use for your SMS bot. Under the *Messaging* section, select "Webhooks/TwiML" as your *Configure with* preference. Two more fields will pop up: ***A message comes in***, and ***Primary handler fails***. From a7cb5c898d0605b2f93f00104f988b013d89c7a8 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 12:18:03 -0500 Subject: [PATCH 47/68] adjustments to readme --- docs/readme-twiliosms.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/readme-twiliosms.md b/docs/readme-twiliosms.md index 4462bdcca..5d0f30cb4 100644 --- a/docs/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -12,39 +12,39 @@ This document covers the Twilio Programmable SMS API implementation details only 2) Register a developer account with Twilio. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. -> After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. + After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. -> **Twilio Account SID and Auth Token** + **Twilio Account SID and Auth Token** -> These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) + These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) -> **Twilio Number** + **Twilio Number** -> You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` + You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` 3) Configure your Twilio Number. Head to the [Phone Numbers](https://www.twilio.com/console/phone-numbers) in your Twilio Console and select the phone number you will use for your SMS bot. -Under the *Messaging* section, select "Webhooks/TwiML" as your *Configure with* preference. Two more fields will pop up: ***A message comes in***, and ***Primary handler fails***. + Under the *Messaging* section, select "Webhooks/TwiML" as your *Configure with* preference. Two more fields will pop up: ***A message comes in***, and ***Primary handler fails***. -The first one is the type of handler you will use to respond to Twilio webhooks. Select "Webhook" and input the URI of your endpoint (e.g. `https://mysmsbot.localtunnel.me/sms/receive`) and select `HTTP POST` as your handling method. + The first one is the type of handler you will use to respond to Twilio webhooks. Select "Webhook" and input the URI of your endpoint (e.g. `https://mysmsbot.localtunnel.me/sms/receive`) and select `HTTP POST` as your handling method. -Twilio will send `POST` request to this address every time a user sends an SMS to your Twilio Number. + Twilio will send `POST` request to this address every time a user sends an SMS to your Twilio Number. -> By default Botkit will serve content from `https://YOURSERVER/sms/receive`. If you are not running your bot on a public, SSL-enabled internet address, you can use a tool like [ngrok.io](http://ngrok.io/) or [localtunnel.me](localtunnel.me) to expose your local development enviroment to the outside world for the purposes of testing your SMS bot. + > By default Botkit will serve content from `https://YOURSERVER/sms/receive`. If you are not running your bot on a public, SSL-enabled internet address, you can use a tool like [ngrok.io](http://ngrok.io/) or [localtunnel.me](localtunnel.me) to expose your local development enviroment to the outside world for the purposes of testing your SMS bot. -The second preference ("Primary handler fails") is your backup plan. The URI Twilio should `POST` to in case your primary handler is unavailable. You can leave this field in blank for now but keep in mind this is useful for error handling (e.g. to notify users that your bot is unavailable). + The second preference ("Primary handler fails") is your backup plan. The URI Twilio should `POST` to in case your primary handler is unavailable. You can leave this field in blank for now but keep in mind this is useful for error handling (e.g. to notify users that your bot is unavailable). -5) Run the example Twilio SMS bot included in Botkit's repository ([`twilio_sms_bot.js`](../examples/twilio_sms_bot.js)). Copy and paste the example bot's code into a new JavaScript file (e.g. `twilio_sms_bot.js`) in your current working directory and run the following command on your terminal: +4) Run the example Twilio SMS bot included in Botkit's repository ([`twilio_sms_bot.js`](../examples/twilio_sms_bot.js)). Copy and paste the example bot's code into a new JavaScript file (e.g. `twilio_sms_bot.js`) in your current working directory and run the following command on your terminal: -```bash -$ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_NUMBER= node twilio_sms_bot.js -``` + ```bash + $ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_NUMBER= node twilio_sms_bot.js + ``` -> Note: Remember to run localtunnel or ngrok to expose your local development environment to the outside world. For example, in localtunnel run `lt --port 5000 --subdomain mysmsbot` (See note on step 4) + > Note: Remember to run localtunnel or ngrok to expose your local development environment to the outside world. For example, in localtunnel run `lt --port 5000 --subdomain mysmsbot` (See note on step 4) 6) Your bot should be online! Grab your phone and text `hi` to your Twilio Number and you will get a `Hello.` message back! -Try the following messages: `Hi`, `Call me bob`, `what's my name?` + Try the following messages: `Hi`, `Call me bob`, `what's my name?` ## Usage From 4f8ddfa4460e003ea3ac38d83c3c4128e3d1e232 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 12:20:02 -0500 Subject: [PATCH 48/68] Update readme-twiliosms.md --- docs/readme-twiliosms.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/readme-twiliosms.md b/docs/readme-twiliosms.md index 5d0f30cb4..1708200aa 100644 --- a/docs/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -12,39 +12,39 @@ This document covers the Twilio Programmable SMS API implementation details only 2) Register a developer account with Twilio. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. - After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. + After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. - **Twilio Account SID and Auth Token** + **Twilio Account SID and Auth Token** - These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) + These values are available on your [Twilio Account Settings](https://www.twilio.com/user/account/settings) page on the Twilio Console. Copy both the SID and token values (located under API Credentials) - **Twilio Number** + **Twilio Number** - You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` + You should have purchased a Twilio Number. You will send/receive messages using this phone number. Example: `+19098765432` 3) Configure your Twilio Number. Head to the [Phone Numbers](https://www.twilio.com/console/phone-numbers) in your Twilio Console and select the phone number you will use for your SMS bot. - Under the *Messaging* section, select "Webhooks/TwiML" as your *Configure with* preference. Two more fields will pop up: ***A message comes in***, and ***Primary handler fails***. + Under the *Messaging* section, select "Webhooks/TwiML" as your *Configure with* preference. Two more fields will pop up: ***A message comes in***, and ***Primary handler fails***. - The first one is the type of handler you will use to respond to Twilio webhooks. Select "Webhook" and input the URI of your endpoint (e.g. `https://mysmsbot.localtunnel.me/sms/receive`) and select `HTTP POST` as your handling method. + The first one is the type of handler you will use to respond to Twilio webhooks. Select "Webhook" and input the URI of your endpoint (e.g. `https://mysmsbot.localtunnel.me/sms/receive`) and select `HTTP POST` as your handling method. - Twilio will send `POST` request to this address every time a user sends an SMS to your Twilio Number. + Twilio will send `POST` request to this address every time a user sends an SMS to your Twilio Number. - > By default Botkit will serve content from `https://YOURSERVER/sms/receive`. If you are not running your bot on a public, SSL-enabled internet address, you can use a tool like [ngrok.io](http://ngrok.io/) or [localtunnel.me](localtunnel.me) to expose your local development enviroment to the outside world for the purposes of testing your SMS bot. + > By default Botkit will serve content from `https://YOURSERVER/sms/receive`. If you are not running your bot on a public, SSL-enabled internet address, you can use a tool like [ngrok.io](http://ngrok.io/) or [localtunnel.me](localtunnel.me) to expose your local development enviroment to the outside world for the purposes of testing your SMS bot. - The second preference ("Primary handler fails") is your backup plan. The URI Twilio should `POST` to in case your primary handler is unavailable. You can leave this field in blank for now but keep in mind this is useful for error handling (e.g. to notify users that your bot is unavailable). + The second preference ("Primary handler fails") is your backup plan. The URI Twilio should `POST` to in case your primary handler is unavailable. You can leave this field in blank for now but keep in mind this is useful for error handling (e.g. to notify users that your bot is unavailable). 4) Run the example Twilio SMS bot included in Botkit's repository ([`twilio_sms_bot.js`](../examples/twilio_sms_bot.js)). Copy and paste the example bot's code into a new JavaScript file (e.g. `twilio_sms_bot.js`) in your current working directory and run the following command on your terminal: - ```bash - $ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_NUMBER= node twilio_sms_bot.js - ``` + ```bash + $ TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_NUMBER= node twilio_sms_bot.js + ``` - > Note: Remember to run localtunnel or ngrok to expose your local development environment to the outside world. For example, in localtunnel run `lt --port 5000 --subdomain mysmsbot` (See note on step 4) + > Note: Remember to run localtunnel or ngrok to expose your local development environment to the outside world. For example, in localtunnel run `lt --port 5000 --subdomain mysmsbot` (See note on step 4) 6) Your bot should be online! Grab your phone and text `hi` to your Twilio Number and you will get a `Hello.` message back! - Try the following messages: `Hi`, `Call me bob`, `what's my name?` + Try the following messages: `Hi`, `Call me bob`, `what's my name?` ## Usage From 571a3e00ebebf24d791dafdc3c1d691c8797741e Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 12:22:10 -0500 Subject: [PATCH 49/68] add twilio sms provisioning doc --- docs/provisioning/readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/provisioning/readme.md b/docs/provisioning/readme.md index cfe5b5d3f..8e3d357e5 100644 --- a/docs/provisioning/readme.md +++ b/docs/provisioning/readme.md @@ -11,6 +11,9 @@ To help Botkit developers, we are pulling out detailed provisioning documents fo #### [Cisco Spark](cisco-spark.md) +#### [SMS from Twilio](twiliosms.md) + + ## Documentation * [Get Started](../../readme.md) @@ -24,6 +27,7 @@ To help Botkit developers, we are pulling out detailed provisioning documents fo * [Slack](../readme-slack.md) * [Cisco Spark](../readme-ciscospark.md) * [Facebook Messenger](../readme-facebook.md) + * [Twilio SMS](https://../readme-twiliosms.md) * [Twilio IPM](https://../readme-twilioipm.md) * [Microsoft Bot Framework](../readme-botframework.md) * Contributing to Botkit From 379027d14897404804da173f06b73f7bcefdc08d Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 12:22:37 -0500 Subject: [PATCH 50/68] Update readme.md --- docs/provisioning/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/provisioning/readme.md b/docs/provisioning/readme.md index 8e3d357e5..cacc889f1 100644 --- a/docs/provisioning/readme.md +++ b/docs/provisioning/readme.md @@ -11,7 +11,7 @@ To help Botkit developers, we are pulling out detailed provisioning documents fo #### [Cisco Spark](cisco-spark.md) -#### [SMS from Twilio](twiliosms.md) +#### [SMS from Twilio](twilio-sms.md) ## Documentation From 62bed34e2050d5f329d0d38a64cc6c228bd4eef0 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 13:50:55 -0500 Subject: [PATCH 51/68] add changelog update package version number --- __test__/lib/Botkit.test.js | 6 ++++-- changelog.md | 19 +++++++++++++++++++ package.json | 2 +- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/__test__/lib/Botkit.test.js b/__test__/lib/Botkit.test.js index 06a3eb450..bd040d362 100644 --- a/__test__/lib/Botkit.test.js +++ b/__test__/lib/Botkit.test.js @@ -5,7 +5,8 @@ let botkit; jest.mock('../../lib/CoreBot', () => 'corebot'); jest.mock('../../lib/SlackBot', () => 'slackbot'); jest.mock('../../lib/Facebook', () => 'facebook'); -jest.mock('../../lib/TwilioIPMBot', () => 'twilio'); +jest.mock('../../lib/TwilioIPMBot', () => 'twilioipm'); +jest.mock('../../lib/TwilioSMSBot', () => 'twiliosms'); jest.mock('../../lib/BotFramework', () => 'botframework'); jest.mock('../../lib/CiscoSparkbot', () => 'spark'); jest.mock('../../lib/ConsoleBot', () => 'console'); @@ -19,7 +20,8 @@ test('exports bot interfaces', () => { expect(botkit.core).toBe('corebot'); expect(botkit.slackbot).toBe('slackbot'); expect(botkit.facebookbot).toBe('facebook'); - expect(botkit.twilioipmbot).toBe('twilio'); + expect(botkit.twilioipmbot).toBe('twilioipm'); + expect(botkit.twiliosmsbot).toBe('twiliosms'); expect(botkit.botframeworkbot).toBe('botframework'); expect(botkit.sparkbot).toBe('spark'); expect(botkit.consolebot).toBe('console'); diff --git a/changelog.md b/changelog.md index 1838229e1..02f72d8af 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,24 @@ # Change Log +[View the official Botkit roadmap](https://github.com/howdyai/botkit/projects/7) for upcoming changes and features. + +[Want to contribute? Read our guide!](https://github.com/howdyai/botkit/blob/master/CONTRIBUTING.md) + + +## 0.5.5 + +*Introducing Botkit for SMS!* Botkit bots can now send and receive messages using Twilio's Programmable SMS API! +Huge thanks to @krismuniz who spearheaded this effort! [Read all about Twilio SMS here](docs/readme-twilio-sms.md) + +*New unit tests* have been added, thanks to the ongoing efforts of @colestrode, @amplicity and others. +This release includes coverage of the Botkit core library and the Slack API library. +This is an [ongoing effort](https://github.com/howdyai/botkit/projects/3), and we encourage interested developers to get involved! + +Add missing error callback to catch Slack condition where incoming messages do not match a team in the database. +[PR #887](https://github.com/howdyai/botkit/pull/887) thanks to @alecl! + + + ## 0.5.4 Fix for [#806](https://github.com/howdyai/botkit/issues/806) - new version of websocket didn't play nice with Slack's message servers diff --git a/package.json b/package.json index 7df5c9897..70fbcec6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "botkit", - "version": "0.5.4", + "version": "0.5.5", "description": "Building blocks for Building Bots", "main": "lib/Botkit.js", "dependencies": { From e50324c0c1c707262a4902aa8ee5b06acf5af49a Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 13:58:47 -0500 Subject: [PATCH 52/68] updates to changelog --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index 02f72d8af..79802f3c0 100644 --- a/changelog.md +++ b/changelog.md @@ -17,7 +17,11 @@ This is an [ongoing effort](https://github.com/howdyai/botkit/projects/3), and w Add missing error callback to catch Slack condition where incoming messages do not match a team in the database. [PR #887](https://github.com/howdyai/botkit/pull/887) thanks to @alecl! +Fixed confusing parameter in JSON storage system. `delete()` methods now expect object id as first parameter. [PR #854](https://github.com/howdyai/botkit/pull/854) thanks to @mehamasum! +All example bot scripts have been moved into the [examples/](examples/) folder. Thanks @colestrode! + +Fixes an instance where Botkit was not automatically responding to incoming webhooks from Cisco with a 200 status. [PR #843](https://github.com/howdyai/botkit/pull/843) ## 0.5.4 From 7e9a1cd2300e8e4dd7830fea39b54cd593e735ca Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 14:05:59 -0500 Subject: [PATCH 53/68] update dependency versions --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 70fbcec6b..b64e356c5 100644 --- a/package.json +++ b/package.json @@ -9,19 +9,19 @@ "body-parser": "^1.17.1", "botbuilder": "^3.7.0", "botkit-studio-sdk": "^1.0.2", - "ciscospark": "^0.7.69", + "ciscospark": "^1.1.6", "clone": "2.1.1", "command-line-args": "^4.0.2", "crypto": "0.0.3", "express": "^4.15.2", - "https-proxy-agent": "^1.0.0", + "https-proxy-agent": "^2.0.0", "jfs": "^0.2.6", "localtunnel": "^1.8.2", "md5": "^2.2.1", "mustache": "^2.3.0", - "promise": "^7.1.1", + "promise": "^8.0.0", "request": "^2.81.0", - "twilio": "^2.11.1", + "twilio": "^3.4.0", "ware": "^1.3.0", "ws": "^2.2.2" }, From ba64ec6478fa4787b5abe4a8662abe1c77a25d65 Mon Sep 17 00:00:00 2001 From: Ouadie Lahdioui Date: Tue, 27 Jun 2017 21:16:43 +0200 Subject: [PATCH 54/68] Clean up facebook_bot.js --- examples/facebook_bot.js | 174 ++++++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 30 deletions(-) diff --git a/examples/facebook_bot.js b/examples/facebook_bot.js index 37556ac6b..c5ee94b1e 100755 --- a/examples/facebook_bot.js +++ b/examples/facebook_bot.js @@ -1,20 +1,160 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ______ ______ ______ __ __ __ ______ + /\ == \ /\ __ \ /\__ _\ /\ \/ / /\ \ /\__ _\ + \ \ __< \ \ \/\ \ \/_/\ \/ \ \ _"-. \ \ \ \/_/\ \/ + \ \_____\ \ \_____\ \ \_\ \ \_\ \_\ \ \_\ \ \_\ + \/_____/ \/_____/ \/_/ \/_/\/_/ \/_/ \/_/ + + +This is a sample Facebook bot built with Botkit. + +This bot demonstrates many of the core features of Botkit: + +* Connect to Facebook's Messenger APIs +* Receive messages based on "spoken" patterns +* Reply to messages +* Use the conversation system to ask questions +* Use the built in storage system to store and retrieve information + for a user. + +# RUN THE BOT: + + Follow the instructions here to set up your Facebook app and page: + + -> https://developers.facebook.com/docs/messenger-platform/implementation + + Run your bot from the command line: + + app_secret= page_token= verify_token= node facebook_bot.js [--lt [--ltsubdomain LOCALTUNNEL_SUBDOMAIN]] + + Use the --lt option to make your bot available on the web through localtunnel.me. + +# USE THE BOT: + + Find your bot inside Facebook to send it a direct message. + + Say: "Hello" + + The bot will reply "Hello!" + + Say: "who are you?" + + The bot will tell you its name, where it running, and for how long. + + Say: "Call me " + + Tell the bot your nickname. Now you are friends. + + Say: "who am I?" + + The bot will tell you your nickname, if it knows one for you. + + Say: "shutdown" + + The bot will ask if you are sure, and then shut itself down. + + Make sure to invite your bot into other channels using /invite @! + +# EXTEND THE BOT: + + Botkit has many features for building cool and useful bots! + + Read all about it here: + + -> http://howdy.ai/botkit + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + +if (!process.env.page_token) { + console.log('Error: Specify page_token in environment'); + process.exit(1); +} + +if (!process.env.verify_token) { + console.log('Error: Specify verify_token in environment'); + process.exit(1); +} + +if (!process.env.app_secret) { + console.log('Error: Specify app_secret in environment'); + process.exit(1); +} + var Botkit = require('../lib/Botkit.js'); +var os = require('os'); +var commandLineArgs = require('command-line-args'); +var localtunnel = require('localtunnel'); + +const ops = commandLineArgs([ + {name: 'lt', alias: 'l', args: 1, description: 'Use localtunnel.me to make your bot available on the web.', + type: Boolean, defaultValue: false}, + {name: 'ltsubdomain', alias: 's', args: 1, + description: 'Custom subdomain for the localtunnel.me URL. This option can only be used together with --lt.', + type: String, defaultValue: null}, + ]); + +if(ops.lt === false && ops.ltsubdomain !== null) { + console.log("error: --ltsubdomain can only be used together with --lt."); + process.exit(); +} var controller = Botkit.facebookbot({ debug: true, log: true, - access_token: 'EAAShWXeInZCcBAGD9z7ffW3Dmflwh2X8otTTH1R1OzBniNe6vQPyGduijVwk68Of3r1nZAVte76LdQ00P2qSCQip5hbnqxpaGZAFEibAiDZCHHd3JE0caYzD3cHP7U3rEnSSghMcTITCesrgsWWDhT6SyF7dl5HwJINvht0HFwZDZD', - verify_token: 'pass;1234', - app_secret: '197fc98968cd0197cd8c838e9b68e466', + access_token: process.env.page_token, + verify_token: process.env.verify_token, + app_secret: process.env.app_secret, validate_requests: true, // Refuse any requests that don't come from FB on your receive webhook, must provide FB_APP_SECRET in environment variables }); var bot = controller.spawn({ }); -controller.setupWebserver(1337, function(err, webserver) { +controller.setupWebserver(process.env.port || 3000, function(err, webserver) { controller.createWebhookEndpoints(webserver, bot, function() { console.log('ONLINE!'); + if(ops.lt) { + var tunnel = localtunnel(process.env.port || 3000, {subdomain: ops.ltsubdomain}, function(err, tunnel) { + if (err) { + console.log(err); + process.exit(); + } + console.log("Your bot is available on the web at the following URL: " + tunnel.url + '/facebook/receive'); + }); + + tunnel.on('close', function() { + console.log("Your bot is no longer available on the web at the localtunnnel.me URL."); + process.exit(); + }); + } + }); +}); + + +controller.hears(['attachment_upload'], 'message_received', function(bot, message) { + var attachment = { + "type":"image", + "payload":{ + "url":"https://pbs.twimg.com/profile_images/803642201653858305/IAW1DBPw_400x400.png", + "is_reusable": true + } + }; + + controller.api.attachment_upload.upload(attachment, function (err, attachmentId) { + if(err) { + // Error + } else { + var image = { + "attachment":{ + "type":"image", + "payload": { + "attachment_id": attachmentId + } + } + }; + bot.reply(message, image); + } }); }); @@ -87,32 +227,6 @@ controller.hears(['code'], 'message_received,facebook_postback', function(bot, m }); }); -controller.hears(['attachment_upload'], 'message_received', function(bot, message) { - var attachment = { - "type":"image", - "payload":{ - "url":"https://pbs.twimg.com/profile_images/803642201653858305/IAW1DBPw_400x400.png", - "is_reusable": true - } - }; - - controller.api.attachment_upload.upload(attachment, function (err, attachmentId) { - if(err) { - // Error - } else { - var image = { - "attachment":{ - "type":"image", - "payload": { - "attachment_id": attachmentId - } - } - }; - bot.reply(message, image); - } - }); -}); - controller.hears(['quick'], 'message_received', function(bot, message) { bot.reply(message, { From b2f83345e52df1a0e948d1a603f991c9529ce87b Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 14:23:53 -0500 Subject: [PATCH 55/68] reverse out change to twilio dependency for now due to conflicts with twilio ipm connector --- changelog.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 79802f3c0..f2f642282 100644 --- a/changelog.md +++ b/changelog.md @@ -23,6 +23,8 @@ All example bot scripts have been moved into the [examples/](examples/) folder. Fixes an instance where Botkit was not automatically responding to incoming webhooks from Cisco with a 200 status. [PR #843](https://github.com/howdyai/botkit/pull/843) +Updated dependencies to latest: twilio, ciscospark, https-proxy-agent, promise + ## 0.5.4 Fix for [#806](https://github.com/howdyai/botkit/issues/806) - new version of websocket didn't play nice with Slack's message servers diff --git a/package.json b/package.json index b64e356c5..9627af12b 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "mustache": "^2.3.0", "promise": "^8.0.0", "request": "^2.81.0", - "twilio": "^3.4.0", + "twilio": "^2.11.1", "ware": "^1.3.0", "ws": "^2.2.2" }, From 07b7833869cf95d6aa714ba9b946e5633314b7dd Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 14:56:52 -0500 Subject: [PATCH 56/68] Merge in new facebook api --- changelog.md | 4 ++++ lib/Facebook.js | 2 +- npm-debug.log | 24 ------------------------ 3 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 npm-debug.log diff --git a/changelog.md b/changelog.md index f2f642282..eeec58a0a 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,10 @@ This is an [ongoing effort](https://github.com/howdyai/botkit/projects/3), and w Add missing error callback to catch Slack condition where incoming messages do not match a team in the database. [PR #887](https://github.com/howdyai/botkit/pull/887) thanks to @alecl! +Add support for Facebook attachment upload api [PR #899](https://github.com/howdyai/botkit/pull/899) thanks @ouadie-lahdioui! +Read docs about this feature [here](docs/readme-facebook.md#attachment-upload-api) + + Fixed confusing parameter in JSON storage system. `delete()` methods now expect object id as first parameter. [PR #854](https://github.com/howdyai/botkit/pull/854) thanks to @mehamasum! All example bot scripts have been moved into the [examples/](examples/) folder. Thanks @colestrode! diff --git a/lib/Facebook.js b/lib/Facebook.js index 03c8b2217..db977a773 100644 --- a/lib/Facebook.js +++ b/lib/Facebook.js @@ -613,7 +613,7 @@ function Facebookbot(configuration) { var attachment_upload_api = { upload: function(attachment, cb) { var message = { - message : { + message: { attachment: attachment } }; diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index deca7db99..000000000 --- a/npm-debug.log +++ /dev/null @@ -1,24 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/usr/local/bin/node', '/usr/local/bin/npm', 'start' ] -2 info using npm@3.10.8 -3 info using node@v6.9.1 -4 verbose stack Error: missing script: start -4 verbose stack at run (/usr/local/lib/node_modules/npm/lib/run-script.js:151:19) -4 verbose stack at /usr/local/lib/node_modules/npm/lib/run-script.js:61:5 -4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:356:5 -4 verbose stack at checkBinReferences_ (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:320:45) -4 verbose stack at final (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:354:3) -4 verbose stack at then (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:124:5) -4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:311:12 -4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16 -4 verbose stack at tryToString (fs.js:455:3) -4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:442:12) -5 verbose cwd /Users/SOAT-OLA/works/projects/botkit -6 error Darwin 16.5.0 -7 error argv "/usr/local/bin/node" "/usr/local/bin/npm" "start" -8 error node v6.9.1 -9 error npm v3.10.8 -10 error missing script: start -11 error If you need help, you may report this error at: -11 error -12 verbose exit [ 1, true ] From 8d7bc4b0469b72e7117e447e1e24c3ebafcb1dca Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 14:58:30 -0500 Subject: [PATCH 57/68] Fix for issue #768 --- lib/Slackbot_worker.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Slackbot_worker.js b/lib/Slackbot_worker.js index e3aeb4211..25f1512ab 100755 --- a/lib/Slackbot_worker.js +++ b/lib/Slackbot_worker.js @@ -735,12 +735,12 @@ module.exports = function(botkit, config) { if (message.text) { message.text = message.text.trim(); - } - var direct_mention = new RegExp('^\<\@' + bot.identity.id + '\>', 'i'); + var direct_mention = new RegExp('^\<\@' + bot.identity.id + '\>', 'i'); - message.text = message.text.replace(direct_mention, '') - .replace(/^\s+/, '').replace(/^\:\s+/, '').replace(/^\s+/, ''); + message.text = message.text.replace(direct_mention, '') + .replace(/^\s+/, '').replace(/^\:\s+/, '').replace(/^\s+/, ''); + } cb(botkit.tasks[t].convos[c]); return; From f31e796127e1810df90b66f4553654eeb2c937c2 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 15:00:38 -0500 Subject: [PATCH 58/68] update changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index eeec58a0a..0fba4edf4 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,7 @@ Add missing error callback to catch Slack condition where incoming messages do n Add support for Facebook attachment upload api [PR #899](https://github.com/howdyai/botkit/pull/899) thanks @ouadie-lahdioui! Read docs about this feature [here](docs/readme-facebook.md#attachment-upload-api) +Fixed issue with Slack message menus. [PR #769](https://github.com/howdyai/botkit/pull/769) Fixed confusing parameter in JSON storage system. `delete()` methods now expect object id as first parameter. [PR #854](https://github.com/howdyai/botkit/pull/854) thanks to @mehamasum! From 945da7b257647b2fddc4a7b6bd3dc74e86630d0f Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 15:31:07 -0500 Subject: [PATCH 59/68] better handling of slack message menus --- lib/SlackBot.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/SlackBot.js b/lib/SlackBot.js index f2fa292f8..77e107bbe 100755 --- a/lib/SlackBot.js +++ b/lib/SlackBot.js @@ -264,6 +264,11 @@ function Slackbot(configuration) { // this allows button clicks to respond to asks message.text = message.actions[0].value; + // handle message menus + if (message.actions[0].selected_options) { + message.text = message.actions[0].selected_options[0].value; + } + message.type = 'interactive_message_callback'; slack_botkit.trigger('interactive_message_callback', [bot, message]); From 4d093034412ebb76693d06baf16254978db5224b Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Tue, 27 Jun 2017 15:40:01 -0500 Subject: [PATCH 60/68] typo in changelog --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 0fba4edf4..0c8762e5b 100644 --- a/changelog.md +++ b/changelog.md @@ -8,7 +8,7 @@ ## 0.5.5 *Introducing Botkit for SMS!* Botkit bots can now send and receive messages using Twilio's Programmable SMS API! -Huge thanks to @krismuniz who spearheaded this effort! [Read all about Twilio SMS here](docs/readme-twilio-sms.md) +Huge thanks to @krismuniz who spearheaded this effort! [Read all about Twilio SMS here](docs/readme-twiliosms.md) *New unit tests* have been added, thanks to the ongoing efforts of @colestrode, @amplicity and others. This release includes coverage of the Botkit core library and the Slack API library. From 54944c5951593bcf4b14da739ba040687619e2d2 Mon Sep 17 00:00:00 2001 From: Peter Swimm Date: Tue, 27 Jun 2017 16:16:20 -0500 Subject: [PATCH 61/68] Linked to Twilio prov doc --- docs/readme-twiliosms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/readme-twiliosms.md b/docs/readme-twiliosms.md index 1708200aa..3c95d93af 100644 --- a/docs/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -10,7 +10,7 @@ This document covers the Twilio Programmable SMS API implementation details only 1) Install Botkit [more info here](readme.md#installation) -2) Register a developer account with Twilio. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. +2) [Register a developer account with Twilio](https://github.com/howdyai/botkit/blob/master/docs/provisioning/twilio-sms.md. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. From f67a671ed689ffbbb5ad4b46821c96933353e4bf Mon Sep 17 00:00:00 2001 From: Peter Swimm Date: Tue, 27 Jun 2017 16:16:52 -0500 Subject: [PATCH 62/68] typo --- docs/readme-twiliosms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/readme-twiliosms.md b/docs/readme-twiliosms.md index 3c95d93af..41fe26e84 100644 --- a/docs/readme-twiliosms.md +++ b/docs/readme-twiliosms.md @@ -10,7 +10,7 @@ This document covers the Twilio Programmable SMS API implementation details only 1) Install Botkit [more info here](readme.md#installation) -2) [Register a developer account with Twilio](https://github.com/howdyai/botkit/blob/master/docs/provisioning/twilio-sms.md. Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. +2) [Register a developer account with Twilio](https://github.com/howdyai/botkit/blob/master/docs/provisioning/twilio-sms.md). Once you've got it, head to the [Get Started with SMS](https://www.twilio.com/console/sms/getting-started/basics) page in your Twilio Console. After completing the tutorial above you should have all three values to get your bot running: A **Twilio Account SID**, a **Twilio Auth Token**, and a **Twilio Number**. From 0d5c1ee29ca5cea2af09397caec39a7ae6ab4ad5 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Mon, 24 Jul 2017 15:04:10 -0500 Subject: [PATCH 63/68] Fix for issue #963: prune empty button arrays off of facebook carousel attachments --- lib/Studio.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/Studio.js b/lib/Studio.js index b369780d7..69213dc98 100644 --- a/lib/Studio.js +++ b/lib/Studio.js @@ -402,6 +402,15 @@ module.exports = function(controller) { // blank text, not allowed with attachment message.text = null; + // remove blank button array if specified + if (message.attachment.payload.elements) { + for (var e = 0; e < message.attachment.payload.elements.length; e++) { + if (!message.attachment.payload.elements[e].buttons || !message.attachment.payload.elements[e].buttons.length) { + delete(message.attachment.payload.elements[e].buttons); + } + } + } + } // handle Facebook quick replies From 5087fc283a72ccb04ae4b316047033fec2b57ce7 Mon Sep 17 00:00:00 2001 From: jonchurch Date: Wed, 26 Jul 2017 19:13:00 -0400 Subject: [PATCH 64/68] remove events api presence caveat from slack docs --- docs/readme-slack.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/readme-slack.md b/docs/readme-slack.md index fd5a4e947..bb5ba9f0f 100644 --- a/docs/readme-slack.md +++ b/docs/readme-slack.md @@ -913,9 +913,6 @@ The [Events API](https://api.slack.com/events-api) is a streamlined way to build During development, a tool such as [localtunnel.me](http://localtunnel.me) is useful for temporarily exposing a compatible webhook url to Slack while running Botkit privately. -Note: Currently [presence](https://api.slack.com/docs/presence) is not supported by Slack Events API, so bot users will appear offline, but will still function normally. -Developers may want to create an RTM connection in order to make the bot appear online - see note below. - ### To get started with the Events API: 1. Create a [Slack App](https://api.slack.com/apps/new) From 4ad74010e2120434b4bb276af3af0464f5b110eb Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Thu, 27 Jul 2017 15:27:16 -0500 Subject: [PATCH 65/68] Fix issue with startPrivateConversationWithPersonId --- lib/CiscoSparkbot.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/CiscoSparkbot.js b/lib/CiscoSparkbot.js index c25e52b94..ffe50314c 100644 --- a/lib/CiscoSparkbot.js +++ b/lib/CiscoSparkbot.js @@ -331,8 +331,12 @@ function Sparkbot(configuration) { convo.on('sent', function(sent_message) { // update this convo so that future messages will match // since the source message did not have this info in it. - convo.source_message.user = message.user; + convo.source_message.user = message_options.toPersonEmail; convo.source_message.channel = sent_message.roomId; + + convo.context.user = convo.source_message.user; + convo.context.channel = convo.source_message.channel; + }); cb(null, convo); }); @@ -344,18 +348,10 @@ function Sparkbot(configuration) { */ bot.startPrivateConversationWithPersonId = function(personId, cb) { - var message_options = {}; - - message_options.toPersonId = personId; - - botkit.startTask(bot, message_options, function(task, convo) { - convo.on('sent', function(sent_message) { - // update this convo so that future messages will match - // since the source message did not have this info in it. - convo.source_message.user = message.user; - convo.source_message.channel = sent_message.roomId; - }); - cb(null, convo); + controller.api.people.get(personId).then(function(identity) { + bot.startPrivateConversation({user: identity.emails[0]}, cb); + }).catch(function(err) { + cb(err); }); }; From 4e8d764d8a5b2d74da65f9aa8a6b6a0c41e4c084 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Thu, 27 Jul 2017 16:19:05 -0500 Subject: [PATCH 66/68] Fix mentions in Cisco Spark (fix for #940 #749 #661) --- lib/CiscoSparkbot.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/CiscoSparkbot.js b/lib/CiscoSparkbot.js index ffe50314c..09c9651fd 100644 --- a/lib/CiscoSparkbot.js +++ b/lib/CiscoSparkbot.js @@ -210,9 +210,20 @@ function Sparkbot(configuration) { if (message.original_message.html) { // strip the mention & HTML from the message - var pattern = new RegExp('^\\.*?\<\/spark\-mention\>'); + var pattern = new RegExp('^(\)?\.*?\<\/spark\-mention\>', 'im'); + if (!message.original_message.html.match(pattern)) { + var encoded_id = controller.identity.id; + var decoded = new Buffer(encoded_id,'base64').toString('ascii'); + + // this should look like ciscospark://us/PEOPLE/ + var matches; + if (matches = decoded.match(/ciscospark\:\/\/.*\/(.*)/im)) { + pattern = new RegExp('^(\)?\.*?\<\/spark\-mention\>', 'im'); + } + } var action = message.original_message.html.replace(pattern, ''); + // strip the remaining HTML tags action = action.replace(/\<.*?\>/img, ''); From 9e7502fdc4fe8fd11e8e744c84a5964b81406e23 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Thu, 27 Jul 2017 16:27:16 -0500 Subject: [PATCH 67/68] fix some linter errors --- lib/CiscoSparkbot.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/CiscoSparkbot.js b/lib/CiscoSparkbot.js index 09c9651fd..5e64d76fb 100644 --- a/lib/CiscoSparkbot.js +++ b/lib/CiscoSparkbot.js @@ -212,14 +212,14 @@ function Sparkbot(configuration) { // strip the mention & HTML from the message var pattern = new RegExp('^(\)?\.*?\<\/spark\-mention\>', 'im'); if (!message.original_message.html.match(pattern)) { - var encoded_id = controller.identity.id; - var decoded = new Buffer(encoded_id,'base64').toString('ascii'); - - // this should look like ciscospark://us/PEOPLE/ - var matches; - if (matches = decoded.match(/ciscospark\:\/\/.*\/(.*)/im)) { - pattern = new RegExp('^(\)?\.*?\<\/spark\-mention\>', 'im'); - } + var encoded_id = controller.identity.id; + var decoded = new Buffer(encoded_id, 'base64').toString('ascii'); + + // this should look like ciscospark://us/PEOPLE/ + var matches; + if (matches = decoded.match(/ciscospark\:\/\/.*\/(.*)/im)) { + pattern = new RegExp('^(\)?\.*?\<\/spark\-mention\>', 'im'); + } } var action = message.original_message.html.replace(pattern, ''); @@ -362,7 +362,7 @@ function Sparkbot(configuration) { controller.api.people.get(personId).then(function(identity) { bot.startPrivateConversation({user: identity.emails[0]}, cb); }).catch(function(err) { - cb(err); + cb(err); }); }; From e70512554efa6fcf95c605f14ed3b91cd1165bf3 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Thu, 27 Jul 2017 16:29:43 -0500 Subject: [PATCH 68/68] update package and changelog --- changelog.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 0c8762e5b..49df7a2e4 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,14 @@ [Want to contribute? Read our guide!](https://github.com/howdyai/botkit/blob/master/CONTRIBUTING.md) +## 0.5.6 + +Fix for Botkit Studio-powered bots: Facebook attachments can now be added without buttons + +Fix for Cisco Spark: Bot mentions will now reliably be pruned from message, regardless of what client originated the message + +Fix for Cisco Spark: startPrivateConversationWithPersonID has been fixed. + ## 0.5.5 *Introducing Botkit for SMS!* Botkit bots can now send and receive messages using Twilio's Programmable SMS API! diff --git a/package.json b/package.json index 9627af12b..467bf504b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "botkit", - "version": "0.5.5", + "version": "0.5.6", "description": "Building blocks for Building Bots", "main": "lib/Botkit.js", "dependencies": {