├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── app.js ├── app.json ├── img ├── Logo-2C-121px-TM.png ├── canphone.png ├── chess.png ├── danger-man-at-work-hi.png ├── evolution.png ├── example.jpeg ├── family.png ├── icon.png ├── linkedin.png ├── logo.png ├── medium.png ├── robot.png ├── so-logo.png ├── tumblr.png └── youtube.png ├── node └── .jshintrc ├── package.json ├── privacy.rtf ├── public └── index.html ├── script.json └── script ├── ADDKEYWORDSTEP2.json ├── ADDKEYWORD_BUTTONSTEP2.json ├── ARCHITECTURE.json ├── BIO.json ├── BUSINESS.json ├── CONTACT.json ├── CUSTOM.json ├── EDUCATION.json ├── EFFECTIVE.json ├── EMAIL.json ├── HELLO.json ├── HOME.json ├── I_WANT_ONE.json ├── JOKES.json ├── LANGUAGES.json ├── MARKETING.json ├── RECRUITERS.json ├── ROBOT.json ├── SALES.json ├── SENDMESSAGE.json ├── SOCIAL.json ├── SOFTWARE.json ├── SUPPORT.json └── THUMBS.json /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | pids 4 | node_modules 5 | .npm 6 | *.dat 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## July 8, 2016 4 | 5 | * Implemented v1.1 features including: quick replies, message echoes, message reads, sending read receipts, sending typing indicators, sending gifs/videos/audio/files, adding metadata to sent messages, phone number button type 6 | 7 | ## May 11, 2016 8 | 9 | * Initial launch of the sample app including all features launched at F8 -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to messenger-platform-samples 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Pull Requests 6 | We actively welcome your pull requests. 7 | 8 | 1. Fork the repo and create your branch from `master`. 9 | 2. If you've added code that should be tested, add tests. 10 | 3. If you've changed APIs, update the documentation. 11 | 4. Ensure the test suite passes. 12 | 5. Make sure your code lints. 13 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 14 | 15 | ## Contributor License Agreement ("CLA") 16 | In order to accept your pull request, we need you to submit a CLA. You only need 17 | to do this once to work on any of Facebook's open source projects. 18 | 19 | Complete your CLA here: 20 | 21 | ## Issues 22 | We use GitHub issues to track public bugs. Please ensure your description is 23 | clear and has sufficient instructions to be able to reproduce the issue. 24 | 25 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe 26 | disclosure of security bugs. In those cases, please go through the process 27 | outlined on that page and do not file a public issue. 28 | 29 | ## Coding Style 30 | * 2 spaces for indentation rather than tabs 31 | * 80 character line length 32 | 33 | ## License 34 | By contributing to messenger-platform-samples, you agree that your contributions will be licensed under its BSD license. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-present, Facebook, Inc. All rights reserved. 2 | 3 | You are hereby granted a non-exclusive, worldwide, royalty-free license to use, 4 | copy, modify, and distribute this software in source code or binary form for use in connection with the web services and APIs provided by Facebook. 5 | 6 | As with any software that integrates with the Facebook platform, your use of 7 | this software is subject to the Facebook Developer Principles and Policies 8 | [http://developers.facebook.com/policy/]. This copyright notice shall be 9 | included in all copies or substantial portions of the software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DMS Software Bot. A simple conversation bot for Facebook 2 | 3 | This project is an example server for Messenger Platform built in Node.js. It was forked from the Facebook example. 4 | 5 | With this app, you can build a structued conversation to communicate with your clients. 6 | 7 | You can also see examples of the different types of Structured Messages like buttons, carousel, quick reply, etc. 8 | 9 | It contains the following functionality: 10 | 11 | * Webhook (specifically for Messenger Platform events) 12 | * Send API 13 | * Web Plugins 14 | * Messenger Platform v1.1 features 15 | * Simple Emoji support 16 | * Custom keyword responses 17 | * Structured conversation support 18 | 19 | Follow the [walk-through](https://developers.facebook.com/docs/messenger-platform/quickstart) to learn about settting up your own FB robot in more detail. This project can be used as a substitute for the github project in the tutorial. 20 | 21 | ## License 22 | 23 | See the LICENSE file in the root directory of this source tree. Feel free to use and modify the code. 24 | 25 | ## Get Started 26 | 27 | 1. Sign up for you own Github account 28 | 2. Fork this project so that you can edit it 29 | 3. Review the steps in the Facebook [walk-through] (https://developers.facebook.com/docs/messenger-platform/quickstart) to setup your Page. Go ahead an do step 1. 30 | 4. Sign up for a Heroku account 31 | 5. Hit this button to setup the app in Heroku. 32 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/matthewericfisher/fb-robot) 33 | 7. Pick a name for your app and remember it 34 | 8. In the Facebook console, get the App Secret from the main Settings page. Add it to the Heroku setup window 35 | 9. In the Facebook console, generate the Page Access Token from the Messenger -> Settings tab. Add it to the Heroku setup window 36 | 10. Pick a password as your Validation Token. 37 | 11. 'Deploy for Free' in Heroku 38 | 12. In the Facebook console, hit +Add Product and pick Webhooks. The URL will be https://your-bot-name.herokuapp.com/webhook. 'your-bot-name' will be replaced with the Heroku app name that you chose. Add your Validation Token in the proper field. Subscribe to all the message types for delivery. 39 | 40 | Thats it. If everything is good, you can open your Page in Messenger and the bot will respond to the 'home' prompt. The bot will only respond to the Page adminstrator and other people under the 'Roles' page in Facebook. 41 | 42 | To get the bot open to the world you have to go through a review process. It took less than a week for my bot. 43 | 44 | ## Adding context to your bot 45 | The script.json file will guide the bot to the content. The script.json associates keywords with filenames under the script directory. The HOME keyword is associated with script/HOME.json for example. You can edit the file in Github with the pencil icon. The keywords and filenames are in capital letters but the user can type in mixed case. 46 | 47 | The last line in the file is a URL for the thumbs up button. The attachements the bot can look at the incoming URL and respond as if something was typed in. You can get the URL for FB images from the Heroku logs. 48 | 49 | The files in the script directory give you examples of the various widgets that FB allows. You can copy the files and change the details for your own bot. The syntax is precise so be careful when making changes. The missing or trailing comma is the easiest mistake to make. You can use http://jsonlint.com to validate the json. 50 | 51 | You can make new files in the script directory through Github. Once you have your new file complete make sure to add the proper keywords to the script.json master file. 52 | 53 | ##Add images 54 | You have to upload images to the Github project before you can use them, https://help.github.com/articles/adding-a-file-to-a-repository/ 55 | 56 | Once the image is uploaded then you can refer to the image in your json files. There are several examples in the project. The URL has to be exact so be careful on the typing. You can paste the URL into your browser to see if it is correct. The image should appear if all is well. 57 | 58 | ## Re-Deploy on Heroku 59 | 60 | Once your changes are made and committed on Github, you will need to restart the bot on Heroku. Go to the 'Deploy' tab in the app dashboard. Associate the app to your Github project with the Github button, you only need to do this once. Down at the bottom of the page, hit the 'Deploy' button to restart. You can 'Enable Automatic Deployment' but hitting the button manually seems a bit quicker for me. 61 | 62 | ## Check your bot's logs on heroku (Thanks to Esther Crawford for this bit) 63 | 64 | If there's a bug in your code, checking the heroku logs is the best way to figure out what's going wrong. Here's how: 65 | 66 | 1. Install the heroku toolbelt: https://toolbelt.heroku.com/ These are power tools that let you do a lot more than what Heroku dashboard alone allows. 67 | 68 | 2. Next, open your preferred terminal app. On OSX the default Terminal app will work fine here. 69 | 70 | 3. Log in to the heroku toolbelt with the following command: 71 | 72 | heroku login 73 | 74 | If the command heroku isn't found, try restarting your terminal app. Once logged in you should be able to list all of your heroku apps like so: 75 | 76 | heroku apps 77 | 78 | which should give you something like this: 79 | 80 | $ heroku apps 81 | === My Apps 82 | your-app 83 | 84 | 4. Now you can check the logs of your heroku app like so: 85 | 86 | heroku logs -a your-app 87 | 88 | This will give you a dump of your most recent app logs. They will look something like the following. Can you spot the error below? 89 | 90 | 2016-05-09T14:08:34.966358+00:00 heroku[slug-compiler]: Slug compilation started 91 | 2016-05-09T14:08:34.966363+00:00 heroku[slug-compiler]: Slug compilation finished 92 | 2016-05-09T14:08:34.946344+00:00 heroku[web.1]: State changed from up to starting 93 | 2016-05-09T14:08:34.945605+00:00 heroku[web.1]: Restarting 94 | 2016-05-09T14:08:37.860802+00:00 heroku[web.1]: Stopping all processes with SIGTERM 95 | 2016-05-09T14:08:39.493078+00:00 heroku[web.1]: Process exited with status 143 96 | 2016-05-09T14:08:41.182450+00:00 heroku[web.1]: Starting process with command `npm start` 97 | 2016-05-09T14:08:45.818995+00:00 app[web.1]: 98 | 2016-05-09T14:08:45.819017+00:00 app[web.1]: > smooch-bot-example@1.0.0 start /app 99 | 2016-05-09T14:08:45.819018+00:00 app[web.1]: > node heroku 100 | 2016-05-09T14:08:45.819019+00:00 app[web.1]: 101 | 2016-05-09T14:08:46.601444+00:00 app[web.1]: module.js:433 102 | 2016-05-09T14:08:46.601454+00:00 app[web.1]: throw err; 103 | 2016-05-09T14:08:46.601455+00:00 app[web.1]: ^ 104 | 2016-05-09T14:08:46.601456+00:00 app[web.1]: 105 | 2016-05-09T14:08:46.601457+00:00 app[web.1]: SyntaxError: /app/script.json: Unexpected token } 106 | 2016-05-09T14:08:46.601458+00:00 app[web.1]: at Object.parse (native) 107 | 2016-05-09T14:08:46.601458+00:00 app[web.1]: at Object.Module._extensions..json (module.js:430:27) 108 | 2016-05-09T14:08:46.601459+00:00 app[web.1]: at Module.load (module.js:357:32) 109 | 2016-05-09T14:08:46.601460+00:00 app[web.1]: at Function.Module._load (module.js:314:12) 110 | 2016-05-09T14:08:46.601460+00:00 app[web.1]: at Module.require (module.js:367:17) 111 | 2016-05-09T14:08:46.601461+00:00 app[web.1]: at require (internal/module.js:20:19) 112 | 2016-05-09T14:08:46.601462+00:00 app[web.1]: at Object. (/app/script.js:6:21) 113 | 2016-05-09T14:08:46.601473+00:00 app[web.1]: at Module._compile (module.js:413:34) 114 | 2016-05-09T14:08:46.601474+00:00 app[web.1]: at Object.Module._extensions..js (module.js:422:10) 115 | 2016-05-09T14:08:46.601474+00:00 app[web.1]: at Module.load (module.js:357:32) 116 | 117 | Did you notice the `SyntaxError` part? It looks like there's a problem in my script.json. If I inspect that file in github I'll see that indeed, I have a stray comma at the end if the second to last line. 118 | 119 | 120 | 121 | After I remove that comma and redeploy, everything will return to normal. 122 | 123 | ## How do I deploy my fixes to Heroku? 124 | 125 | Great question! Now that you've found your bug and fixed it, you want to redeploy your app. With Heroku you can trigger a deployment using git. Without going into detail, git is a code versioning system it's where github gets its name. Git is the software, github.com is a separate company that hosts git code repositories. If you're using a Mac you should already have git installed. Although git is a very complex tool, it's worth [learning if you're eager](https://www.atlassian.com/git/tutorials/what-is-git), but for this guide's purposes we'll be using only the most basic concepts of git, `pull`ing changes from a remote github repository, `commit`ing changes, and then `push`ing those changes out to a remote repository. 126 | 127 | 1. To deploy using git you first have to download a copy of your heroku app's code, like so: 128 | 129 | git clone https://github.com/your-github-username/your-app 130 | 131 | Note that git will prompt you to enter your github credentials. 132 | 133 | 2. This will create a new git copy of your code in a new folder. You can go into that folder like so: 134 | 135 | cd your-app 136 | 137 | 3. Now you can use the heroku toolbelt to link this git copy up to your heroku app with the following command: 138 | 139 | heroku git:remote -a your-app 140 | 141 | 4. Once that's done, you can now deploy to heroku directly from this directory. If you've made any fixes on github directly, be sure to sync them here like so: 142 | 143 | git pull origin master 144 | git push heroku master 145 | 146 | 5. You can also make changes to your local copy of the code. To do this, edit whatever file you wish in your preferred text editor, and then commit and push them up to github. You'll add a commit message, which is a short sentence decribing what you changed. 147 | 148 | git commit -a -m 'Your commit message' 149 | git push origin master 150 | 151 | Then, you can deploy those changes to heroku in the same way: 152 | 153 | git push heroku master 154 | 155 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the license found in the 6 | * LICENSE file in the root directory of this source tree. 7 | * 8 | */ 9 | 10 | /* jshint node: true, devel: true */ 11 | 'use strict'; 12 | 13 | var customRules = {}; 14 | const 15 | bodyParser = require('body-parser'), 16 | crypto = require('crypto'), 17 | express = require('express'), 18 | https = require('https'), 19 | request = require('request'); 20 | 21 | var fs = require('fs'); 22 | 23 | const _ = require('lodash'); 24 | const scriptRules = require('./script.json'); 25 | const jokes = require('./script/JOKES.json'); 26 | 27 | 28 | var previousMessageHash = {}; 29 | var senderContext = {}; 30 | var isStopped = false; 31 | 32 | 33 | var app = express(); 34 | 35 | app.set('port', process.env.PORT || 5000); 36 | app.use(bodyParser.json({ verify: verifyRequestSignature })); 37 | app.use(express.static('public')); 38 | 39 | /* 40 | * Be sure to setup your config values before running this code. You can 41 | * set them using environment variables 42 | * 43 | */ 44 | 45 | // App Secret can be retrieved from the App Dashboard 46 | const APP_SECRET = process.env.APP_SECRET ; 47 | 48 | // Arbitrary value used to validate a webhook 49 | const VALIDATION_TOKEN = process.env.VALIDATION_TOKEN; 50 | 51 | // Generate a page access token for your page from the App Dashboard 52 | const PAGE_ACCESS_TOKEN = process.env.PAGE_ACCESS_TOKEN; 53 | 54 | if (!(APP_SECRET && VALIDATION_TOKEN && PAGE_ACCESS_TOKEN)) { 55 | console.error("Missing config values"); 56 | process.exit(1); 57 | } 58 | 59 | /* 60 | * Use your own validation token. Check that the token used in the Webhook 61 | * setup is the same token used here. 62 | * 63 | */ 64 | app.get('/webhook', function(req, res) { 65 | if (req.query['hub.mode'] === 'subscribe' && 66 | req.query['hub.verify_token'] === VALIDATION_TOKEN) { 67 | console.log("Validating webhook"); 68 | res.status(200).send(req.query['hub.challenge']); 69 | } else { 70 | console.error("Failed validation. Make sure the validation tokens match."); 71 | res.sendStatus(403); 72 | } 73 | }); 74 | 75 | 76 | /* 77 | * All callbacks for Messenger are POST-ed. They will be sent to the same 78 | * webhook. Be sure to subscribe your app to your page to receive callbacks 79 | * for your page. 80 | * https://developers.facebook.com/docs/messenger-platform/product-overview/setup#subscribe_app 81 | * 82 | */ 83 | app.post('/webhook', function (req, res) { 84 | 85 | var data = req.body; 86 | // Make sure this is a page subscription 87 | if (data.object == 'page') { 88 | // Iterate over each entry 89 | // There may be multiple if batched 90 | data.entry.forEach(function(pageEntry) { 91 | var pageID = pageEntry.id; 92 | var timeOfEvent = pageEntry.time; 93 | 94 | // Iterate over each messaging event 95 | pageEntry.messaging.forEach(function(messagingEvent) { 96 | if (messagingEvent.optin) { 97 | receivedAuthentication(messagingEvent); 98 | } else if (messagingEvent.message) { 99 | receivedMessage(messagingEvent); 100 | } else if (messagingEvent.delivery) { 101 | receivedDeliveryConfirmation(messagingEvent); 102 | } else if (messagingEvent.postback) { 103 | receivedPostback(messagingEvent); 104 | } else if (messagingEvent.read) { 105 | receivedMessageRead(messagingEvent); 106 | } else { 107 | console.log("Webhook received unknown messagingEvent: ", messagingEvent); 108 | } 109 | }); 110 | }); 111 | 112 | // Assume all went well. 113 | // 114 | // You must send back a 200, within 20 seconds, to let us know you've 115 | // successfully received the callback. Otherwise, the request will time out. 116 | res.sendStatus(200); 117 | } 118 | }); 119 | 120 | /* 121 | * Verify that the callback came from Facebook. Using the App Secret from 122 | * the App Dashboard, we can verify the signature that is sent with each 123 | * callback in the x-hub-signature field, located in the header. 124 | * 125 | * https://developers.facebook.com/docs/graph-api/webhooks#setup 126 | * 127 | */ 128 | function verifyRequestSignature(req, res, buf) { 129 | var signature = req.headers["x-hub-signature"]; 130 | 131 | if (!signature) { 132 | // For testing, let's log an error. In production, you should throw an 133 | // error. 134 | console.error("Couldn't validate the signature with app secret:" + APP_SECRET); 135 | } else { 136 | var elements = signature.split('='); 137 | var method = elements[0]; 138 | var signatureHash = elements[1]; 139 | 140 | var expectedHash = crypto.createHmac('sha1', APP_SECRET) 141 | .update(buf) 142 | .digest('hex'); 143 | 144 | if (signatureHash != expectedHash) { 145 | throw new Error("Couldn't validate the request signature: " + APP_SECRET); 146 | } 147 | } 148 | } 149 | 150 | /* 151 | * Authorization Event 152 | * 153 | * The value for 'optin.ref' is defined in the entry point. For the "Send to 154 | * Messenger" plugin, it is the 'data-ref' field. Read more at 155 | * https://developers.facebook.com/docs/messenger-platform/webhook-reference/authentication 156 | * 157 | */ 158 | function receivedAuthentication(event) { 159 | if(isStopped == true) 160 | { 161 | return; 162 | } 163 | var data = req.body; 164 | var senderID = event.sender.id; 165 | var recipientID = event.recipient.id; 166 | var timeOfAuth = event.timestamp; 167 | 168 | // The 'ref' field is set in the 'Send to Messenger' plugin, in the 'data-ref' 169 | // The developer can set this to an arbitrary value to associate the 170 | // authentication callback with the 'Send to Messenger' click event. This is 171 | // a way to do account linking when the user clicks the 'Send to Messenger' 172 | // plugin. 173 | var passThroughParam = event.optin.ref; 174 | 175 | console.log("Received authentication for user %d and page %d with pass " + 176 | "through param '%s' at %d", senderID, recipientID, passThroughParam, 177 | timeOfAuth); 178 | 179 | // When an authentication is received, we'll send a message back to the sender 180 | // to let them know it was successful. 181 | sendTextMessage(senderID, "Authentication successful"); 182 | } 183 | 184 | var firstName = "undefined"; 185 | var lastName = "undefined"; 186 | 187 | /* 188 | * Message Event 189 | * 190 | * This event is called when a message is sent to your page. The 'message' 191 | * object format can vary depending on the kind of message that was received. 192 | * Read more at https://developers.facebook.com/docs/messenger-platform/webhook-reference/message-received 193 | * 194 | * For this example, we're going to echo any text that we get. If we get some 195 | * special keywords ('button', 'generic', 'receipt'), then we'll send back 196 | * examples of those bubbles to illustrate the special message bubbles we've 197 | * created. If we receive a message with an attachment (image, video, audio), 198 | * then we'll simply confirm that we've received the attachment. 199 | * 200 | */ 201 | function receivedMessage(event) { 202 | callGetLocaleAPI(event, handleReceivedMessage); 203 | } 204 | 205 | function handleReceivedMessage(event) { 206 | var senderID = event.sender.id; 207 | var recipientID = event.recipient.id; 208 | var timeOfMessage = event.timestamp; 209 | var message = event.message; 210 | 211 | 212 | var isEcho = message.is_echo; 213 | var messageId = message.mid; 214 | var appId = message.app_id; 215 | var metadata = message.metadata; 216 | 217 | // You may get a text or attachment but not both 218 | var messageText = message.text; 219 | var messageAttachments = message.attachments; 220 | var quickReply = message.quick_reply; 221 | 222 | if (isEcho) { 223 | // Just logging message echoes to console 224 | console.log("Received echo for message %s and app %d with metadata %s", 225 | messageId, appId, metadata); 226 | return; 227 | } else if (quickReply) { 228 | var quickReplyPayload = quickReply.payload; 229 | // console.log("Quick reply for message %s with payload %s", 230 | // messageId, quickReplyPayload); 231 | 232 | messageText = quickReplyPayload; 233 | sendCustomMessage(senderID,messageText); 234 | return; 235 | } 236 | 237 | if (messageText) { 238 | if((isStopped == true) && (messageText !== "start")){ 239 | return; 240 | } 241 | console.log("Received message for user %d and page %d at %d with message: %s", 242 | senderID, recipientID, timeOfMessage,messageText); 243 | 244 | // If we receive a text message, check to see if it matches any special 245 | // keywords and send back the corresponding example. Otherwise, just echo 246 | // the text we received. 247 | switch (messageText.toLowerCase()) { 248 | case 'image': 249 | sendImageMessage(senderID, "http://messengerdemo.parseapp.com/img/rift.png"); 250 | break; 251 | 252 | case 'gif': 253 | sendGifMessage(senderID); 254 | break; 255 | 256 | case 'audio': 257 | sendAudioMessage(senderID); 258 | break; 259 | 260 | case 'video': 261 | sendVideoMessage(senderID); 262 | break; 263 | 264 | case 'file': 265 | sendFileMessage(senderID); 266 | break; 267 | 268 | case 'button': 269 | sendButtonMessage(senderID); 270 | break; 271 | 272 | case 'generic': 273 | sendGenericMessage(senderID); 274 | break; 275 | 276 | case 'receipt': 277 | sendReceiptMessage(senderID); 278 | break; 279 | 280 | case 'quick reply': 281 | sendQuickReply(senderID); 282 | break 283 | 284 | case 'read receipt': 285 | sendReadReceipt(senderID); 286 | break 287 | 288 | case 'typing on': 289 | sendTypingOn(senderID); 290 | break 291 | 292 | case 'typing off': 293 | sendTypingOff(senderID); 294 | break 295 | 296 | case 'user info': 297 | if(firstName) 298 | sendTextMessage(senderID,firstName); 299 | break 300 | 301 | case 'add menu': 302 | addPersistentMenu(); 303 | break 304 | 305 | case 'remove menu': 306 | removePersistentMenu(); 307 | break 308 | 309 | case 'stop': // Stop the Bot from responding if the admin sends this messages 310 | if(senderID == 1073962542672604) { 311 | console.log("Stoppping bot"); 312 | isStopped = true; 313 | } 314 | break 315 | 316 | case 'start': // start up again 317 | if(senderID == 1073962542672604) { 318 | console.log("Starting bot"); 319 | isStopped = false; 320 | } 321 | break 322 | 323 | default: 324 | sendEnteredMessage(senderID, messageText); 325 | 326 | } 327 | } else if (messageAttachments) { 328 | if(messageAttachments[0].payload.url) 329 | sendJsonMessage(senderID, messageAttachments[0].payload.url); 330 | } 331 | } 332 | 333 | 334 | /* 335 | * Delivery Confirmation Event 336 | * 337 | * This event is sent to confirm the delivery of a message. Read more about 338 | * these fields at https://developers.facebook.com/docs/messenger-platform/webhook-reference/message-delivered 339 | * 340 | */ 341 | 342 | function receivedDeliveryConfirmation(event) { 343 | if(isStopped == true) 344 | { 345 | return; 346 | } 347 | var senderID = event.sender.id; 348 | var recipientID = event.recipient.id; 349 | var delivery = event.delivery; 350 | var messageIDs = delivery.mids; 351 | var watermark = delivery.watermark; 352 | var sequenceNumber = delivery.seq; 353 | 354 | if (messageIDs) { 355 | messageIDs.forEach(function(messageID) { 356 | console.log("Received delivery confirmation for message ID: %s", 357 | messageID); 358 | }); 359 | } 360 | 361 | console.log("All message before %d were delivered.", watermark); 362 | } 363 | 364 | 365 | /* 366 | * Postback Event 367 | * 368 | * This event is called when a postback is tapped on a Structured Message. 369 | * https://developers.facebook.com/docs/messenger-platform/webhook-reference/postback-received 370 | * 371 | */ 372 | 373 | function receivedPostback(event) { 374 | if(isStopped == true) 375 | { 376 | return; 377 | } 378 | callGetLocaleAPI(event, handleReceivedPostback); 379 | } 380 | 381 | function handleReceivedPostback(event) { 382 | var senderID = event.sender.id; 383 | var recipientID = event.recipient.id; 384 | var timeOfPostback = event.timestamp; 385 | 386 | // The 'payload' param is a developer-defined field which is set in a postback 387 | // button for Structured Messages. 388 | var payload = event.postback.payload; 389 | 390 | console.log("Received postback for user %d and page %d with payload '%s' " + 391 | "at %d", senderID, recipientID, payload, timeOfPostback); 392 | 393 | // When a postback is called, we'll send a message back to the sender to 394 | // let them know it was successful 395 | sendCustomMessage(senderID,payload); 396 | } 397 | 398 | /* 399 | * Message Read Event 400 | * 401 | * This event is called when a previously-sent message has been read. 402 | * https://developers.facebook.com/docs/messenger-platform/webhook-reference/message-read 403 | * 404 | */ 405 | function receivedMessageRead(event) { 406 | if(isStopped == true) 407 | { 408 | return; 409 | } 410 | var senderID = event.sender.id; 411 | var recipientID = event.recipient.id; 412 | 413 | // All messages before watermark (a timestamp) or sequence have been seen. 414 | var watermark = event.read.watermark; 415 | var sequenceNumber = event.read.seq; 416 | 417 | console.log("Received message read event for watermark %d and sequence " + 418 | "number %d", watermark, sequenceNumber); 419 | } 420 | 421 | /* 422 | * Send an image using the Send API. 423 | * 424 | */ 425 | function sendImageMessage(recipientId, path) { 426 | var messageData = { 427 | recipient: { 428 | id: recipientId 429 | }, 430 | message: { 431 | attachment: { 432 | type: "image", 433 | payload: { 434 | url: path 435 | } 436 | } 437 | } 438 | }; 439 | 440 | callSendAPI(messageData); 441 | } 442 | 443 | /* 444 | * Send a Gif using the Send API. 445 | * 446 | */ 447 | function sendGifMessage(recipientId) { 448 | var messageData = { 449 | recipient: { 450 | id: recipientId 451 | }, 452 | message: { 453 | attachment: { 454 | type: "image", 455 | payload: { 456 | url: "http://messengerdemo.parseapp.com/img/instagram_logo.gif" 457 | } 458 | } 459 | } 460 | }; 461 | 462 | callSendAPI(messageData); 463 | } 464 | 465 | /* 466 | * Send audio using the Send API. 467 | * 468 | */ 469 | function sendAudioMessage(recipientId) { 470 | var messageData = { 471 | recipient: { 472 | id: recipientId 473 | }, 474 | message: { 475 | attachment: { 476 | type: "audio", 477 | payload: { 478 | url: "http://messengerdemo.parseapp.com/audio/sample.mp3" 479 | } 480 | } 481 | } 482 | }; 483 | 484 | callSendAPI(messageData); 485 | } 486 | 487 | /* 488 | * Send a video using the Send API. 489 | * 490 | */ 491 | function sendVideoMessage(recipientId) { 492 | var messageData = { 493 | recipient: { 494 | id: recipientId 495 | }, 496 | message: { 497 | attachment: { 498 | type: "video", 499 | payload: { 500 | url: "http://messengerdemo.parseapp.com/video/allofus480.mov" 501 | } 502 | } 503 | } 504 | }; 505 | 506 | callSendAPI(messageData); 507 | } 508 | 509 | /* 510 | * Send a video using the Send API. 511 | * 512 | */ 513 | function sendFileMessage(recipientId) { 514 | var messageData = { 515 | recipient: { 516 | id: recipientId 517 | }, 518 | message: { 519 | attachment: { 520 | type: "file", 521 | payload: { 522 | url: "http://messengerdemo.parseapp.com/files/test.txt" 523 | } 524 | } 525 | } 526 | }; 527 | 528 | callSendAPI(messageData); 529 | } 530 | 531 | function sendSingleJsonMessage(recipientId,filename) { 532 | try { 533 | filename = "./script/" + filename; 534 | var json = require(filename); 535 | var fullMessage = { recipient: { id: recipientId }}; 536 | fullMessage.message = json; 537 | callSendAPI(fullMessage); 538 | } 539 | catch (e) 540 | { 541 | console.log("error in sendSingleJsonMessage " + e.message + " " + filename + " " + fullMessage); 542 | } 543 | } 544 | 545 | /* 546 | Special handling for message that the sender typed in 547 | */ 548 | 549 | function sendEnteredMessage(recipientId,messageText) { 550 | var emojiString = ["😀","😁","😂","😃","😄","😅","😆","😇","😈","👿","😉","😊","☺️","😋","😌","😍","😎","😏","😐","😑","😒","😓","😔","😕","😖","😗","😘","😙","😚","😛","😜","😝","😞","😟","😠","😡","😢","😣","😤","😥","😦","😧","😨","😩","😪","😫","😬","😭","😮","😯","😰","😱","😲","😳","😴","😵","😶","😷","😸","😹","😺","😻","😼","😽","😾","😿","🙀","👣","👤","👥","👶","👶🏻","👶🏼","👶🏽","👶🏾","👶🏿","👦","👦🏻","👦🏼","👦🏽","👦🏾","👦🏿","👧","👧🏻","👧🏼","👧🏽","👧🏾","👧🏿","👨","👨🏻","👨🏼","👨🏽","👨🏾","👨🏿","👩","👩🏻","👩🏼","👩🏽","👩🏾","👩🏿","👪","👨‍👩‍👧","👨‍👩‍👧‍👦","👨‍👩‍👦‍👦","👨‍👩‍👧‍👧","👩‍👩‍👦","👩‍👩‍👧","👩‍👩‍👧‍👦","👩‍👩‍👦‍👦","👩‍👩‍👧‍👧","👨‍👨‍👦","👨‍👨‍👧","👨‍👨‍👧‍👦","👨‍👨‍👦‍👦","👨‍👨‍👧‍👧","👫","👬","👭","👯","👰","👰🏻","👰🏼","👰🏽","👰🏾","👰🏿","👱","👱🏻","👱🏼","👱🏽","👱🏾","👱🏿","👲","👲🏻","👲🏼","👲🏽","👲🏾","👲🏿","👳","👳🏻","👳🏼","👳🏽","👳🏾","👳🏿","👴","👴🏻","👴🏼","👴🏽","👴🏾","👴🏿","👵","👵🏻","👵🏼","👵🏽","👵🏾","👵🏿","👮","👮🏻","👮🏼","👮🏽","👮🏾","👮🏿","👷","👷🏻","👷🏼","👷🏽","👷🏾","👷🏿","👸","👸🏻","👸🏼","👸🏽","👸🏾","👸🏿","💂","💂🏻","💂🏼","💂🏽","💂🏾","💂🏿","👼","👼🏻","👼🏼","👼🏽","👼🏾","👼🏿","🎅","🎅🏻","🎅🏼","🎅🏽","🎅🏾","🎅🏿","👻","👹","👺","💩","💀","👽","👾","🙇","🙇🏻","🙇🏼","🙇🏽","🙇🏾","🙇🏿","💁","💁🏻","💁🏼","💁🏽","💁🏾","💁🏿","🙅","🙅🏻","🙅🏼","🙅🏽","🙅🏾","🙅🏿","🙆","🙆🏻","🙆🏼","🙆🏽","🙆🏾","🙆🏿","🙋","🙋🏻","🙋🏼","🙋🏽","🙋🏾","🙋🏿","🙎","🙎🏻","🙎🏼","🙎🏽","🙎🏾","🙎🏿","🙍","🙍🏻","🙍🏼","🙍🏽","🙍🏾","🙍🏿","💆","💆🏻","💆🏼","💆🏽","💆🏾","💆🏿","💇","💇🏻","💇🏼","💇🏽","💇🏾","💇🏿","💑","👩‍❤️‍👩","👨‍❤️‍👨","💏","👩‍❤️‍💋‍👩","👨‍❤️‍💋‍👨","🙌","🙌🏻","🙌🏼","🙌🏽","🙌🏾","🙌🏿","👏","👏🏻","👏🏼","👏🏽","👏🏾","👏🏿","👂","👂🏻","👂🏼","👂🏽","👂🏾","👂🏿","👀","👃","👃🏻","👃🏼","👃🏽","👃🏾","👃🏿","👄","💋","👅","💅","💅🏻","💅🏼","💅🏽","💅🏾","💅🏿","👋","👋🏻","👋🏼","👋🏽","👋🏾","👋🏿","👍","👍🏻","👍🏼","👍🏽","👍🏾","👍🏿","👎","👎🏻","👎🏼","👎🏽","👎🏾","👎🏿","☝","☝🏻","☝🏼","☝🏽","☝🏾","☝🏿","👆","👆🏻","👆🏼","👆🏽","👆🏾","👆🏿","👇","👇🏻","👇🏼","👇🏽","👇🏾","👇🏿","👈","👈🏻","👈🏼","👈🏽","👈🏾","👈🏿","👉","👉🏻","👉🏼","👉🏽","👉🏾","👉🏿","👌","👌🏻","👌🏼","👌🏽","👌🏾","👌🏿","✌","✌🏻","✌🏼","✌🏽","✌🏾","✌🏿","👊","👊🏻","👊🏼","👊🏽","👊🏾","👊🏿","✊","✊🏻","✊🏼","✊🏽","✊🏾","✊🏿","✋","✋🏻","✋🏼","✋🏽","✋🏾","✋🏿","💪","💪🏻","💪🏼","💪🏽","💪🏾","💪🏿","👐","👐🏻","👐🏼","👐🏽","👐🏾","👐🏿","🙏","🙏🏻","🙏🏼","🙏🏽","🙏🏾","🙏🏿","🌱","🌲","🌳","🌴","🌵","🌷","🌸","🌹","🌺","🌻","🌼","💐","🌾","🌿","🍀","🍁","🍂","🍃","🍄","🌰","🐀","🐁","🐭","🐹","🐂","🐃","🐄","🐮","🐅","🐆","🐯","🐇","🐰","🐈","🐱","🐎","🐴","🐏","🐑","🐐","🐓","🐔","🐤","🐣","🐥","🐦","🐧","🐘","🐪","🐫","🐗","🐖","🐷","🐽","🐕","🐩","🐶","🐺","🐻","🐨","🐼","🐵","🙈","🙉","🙊","🐒","🐉","🐲","🐊","🐍","🐢","🐸","🐋","🐳","🐬","🐙","🐟","🐠","🐡","🐚","🐌","🐛","🐜","🐝","🐞","🐾","⚡️","🔥","🌙","☀️","⛅️","☁️","💧","💦","☔️","💨","❄️","🌟","⭐️","🌠","🌄","🌅","🌈","🌊","🌋","🌌","🗻","🗾","🌐","🌍","🌎","🌏","🌑","🌒","🌓","🌔","🌕","🌖","🌗","🌘","🌚","🌝","🌛","🌜","🌞","🍅","🍆","🌽","🍠","🍇","🍈","🍉","🍊","🍋","🍌","🍍","🍎","🍏","🍐","🍑","🍒","🍓","🍔","🍕","🍖","🍗","🍘","🍙","🍚","🍛","🍜","🍝","🍞","🍟","🍡","🍢","🍣","🍤","🍥","🍦","🍧","🍨","🍩","🍪","🍫","🍬","🍭","🍮","🍯","🍰","🍱","🍲","🍳","🍴","🍵","☕️","🍶","🍷","🍸","🍹","🍺","🍻","🍼","🎀","🎁","🎂","🎃","🎄","🎋","🎍","🎑","🎆","🎇","🎉","🎊","🎈","💫","✨","💥","🎓","👑","🎎","🎏","🎐","🎌","🏮","💍","❤️","💔","💌","💕","💞","💓","💗","💖","💘","💝","💟","💜","💛","💚","💙","🏃","🏃🏻","🏃🏼","🏃🏽","🏃🏾","🏃🏿","🚶","🚶🏻","🚶🏼","🚶🏽","🚶🏾","🚶🏿","💃","💃🏻","💃🏼","💃🏽","💃🏾","💃🏿","🚣","🚣🏻","🚣🏼","🚣🏽","🚣🏾","🚣🏿","🏊","🏊🏻","🏊🏼","🏊🏽","🏊🏾","🏊🏿","🏄","🏄🏻","🏄🏼","🏄🏽","🏄🏾","🏄🏿","🛀","🛀🏻","🛀🏼","🛀🏽","🛀🏾","🛀🏿","🏂","🎿","⛄️","🚴","🚴🏻","🚴🏼","🚴🏽","🚴🏾","🚴🏿","🚵","🚵🏻","🚵🏼","🚵🏽","🚵🏾","🚵🏿","🏇","🏇🏻","🏇🏼","🏇🏽","🏇🏾","🏇🏿","⛺️","🎣","⚽️","🏀","🏈","⚾️","🎾","🏉","⛳️","🏆","🎽","🏁","🎹","🎸","🎻","🎷","🎺","🎵","🎶","🎼","🎧","🎤","🎭","🎫","🎩","🎪","🎬","🎨","🎯","🎱","🎳","🎰","🎲","🎮","🎴","🃏","🀄️","🎠","🎡","🎢","🚃","🚞","🚂","🚋","🚝","🚄","🚅","🚆","🚇","🚈","🚉","🚊","🚌","🚍","🚎","🚐","🚑","🚒","🚓","🚔","🚨","🚕","🚖","🚗","🚘","🚙","🚚","🚛","🚜","🚲","🚏","⛽️","🚧","🚦","🚥","🚀","🚁","✈️","💺","⚓️","🚢","🚤","⛵️","🚡","🚠","🚟","🛂","🛃","🛄","🛅","💴","💶","💷","💵","🗽","🗿","🌁","🗼","⛲️","🏰","🏯","🌇","🌆","🌃","🌉","🏠","🏡","🏢","🏬","🏭","🏣","🏤","🏥","🏦","🏨","🏩","💒","⛪️","🏪","🏫","🇦🇺","🇦🇹","🇧🇪","🇧🇷","🇨🇦","🇨🇱","🇨🇳","🇨🇴","🇩🇰","🇫🇮","🇫🇷","🇩🇪","🇭🇰","🇮🇳","🇮🇩","🇮🇪","🇮🇱","🇮🇹","🇯🇵","🇰🇷","🇲🇴","🇲🇾","🇲🇽","🇳🇱","🇳🇿","🇳🇴","🇵🇭","🇵🇱","🇵🇹","🇵🇷","🇷🇺","🇸🇦","🇸🇬","🇿🇦","🇪🇸","🇸🇪","🇨🇭","🇹🇷","🇬🇧","🇺🇸","🇦🇪","🇻🇳","⌚️","📱","📲","💻","⏰","⏳","⌛️","📷","📹","🎥","📺","📻","📟","📞","☎️","📠","💽","💾","💿","📀","📼","🔋","🔌","💡","🔦","📡","💳","💸","💰","💎","🌂","👝","👛","👜","💼","🎒","💄","👓","👒","👡","👠","👢","👞","👟","👙","👗","👘","👚","👕","👔","👖","🚪","🚿","🛁","🚽","💈","💉","💊","🔬","🔭","🔮","🔧","🔪","🔩","🔨","💣","🚬","🔫","🔖","📰","🔑","✉️","📩","📨","📧","📥","📤","📦","📯","📮","📪","📫","📬","📭","📄","📃","📑","📈","📉","📊","📅","📆","🔅","🔆","📜","📋","📖","📓","📔","📒","📕","📗","📘","📙","📚","📇","🔗","📎","📌","✂️","📐","📍","📏","🚩","📁","📂","✒️","✏️","📝","🔏","🔐","🔒","🔓","📣","📢","🔈","🔉","🔊","🔇","💤","🔔","🔕","💭","💬","🚸","🔍","🔎","🚫","⛔️","📛","🚷","🚯","🚳","🚱","📵","🔞","🉑","🉐","💮","㊙️","㊗️","🈴","🈵","🈲","🈶","🈚️","🈸","🈺","🈷","🈹","🈳","🈂","🈁","🈯️","💹","❇️","✳️","❎","✅","✴️","📳","📴","🆚","🅰","🅱","🆎","🆑","🅾","🆘","🆔","🅿️","🚾","🆒","🆓","🆕","🆖","🆗","🆙","🏧","♈️","♉️","♊️","♋️","♌️","♍️","♎️","♏️","♐️","♑️","♒️","♓️","🚻","🚹","🚺","🚼","♿️","🚰","🚭","🚮","▶️","◀️","🔼","🔽","⏩","⏪","⏫","⏬","➡️","⬅️","⬆️","⬇️","↗️","↘️","↙️","↖️","↕️","↔️","🔄","↪️","↩️","⤴️","⤵️","🔀","🔁","🔂","#⃣","0⃣","1⃣","2⃣","3⃣","4⃣","5⃣","6⃣","7⃣","8⃣","9⃣","🔟","🔢","🔤","🔡","🔠","ℹ️","📶","🎦","🔣","➕","➖","〰","➗","✖️","✔️","🔃","™","©","®","💱","💲","➰","➿","〽️","❗️","❓","❕","❔","‼️","⁉️","❌","⭕️","💯","🔚","🔙","🔛","🔝","🔜","🌀","Ⓜ️","⛎","🔯","🔰","🔱","⚠️","♨️","♻️","💢","💠","♠️","♣️","♥️","♦️","☑️","⚪️","⚫️","🔘","🔴","🔵","🔺","🔻","🔸","🔹","🔶","🔷","▪️","▫️","⬛️","⬜️","◼️","◻️","◾️","◽️","🔲","🔳","🕐","🕑","🕒","🕓","🕔","🕕","🕖","🕗","🕘","🕙","🕚","🕛","🕜","🕝","🕞","🕟","🕠","🕡","🕢","🕣","🕤","🕥","🕦","🕧"] 551 | 552 | console.log("sendEnteredMessage "+ messageText); 553 | 554 | if( previousMessageHash[recipientId] === 'send a message') { 555 | sendTextMessage(1073962542672604, messageText); // send a message to Matthew directly 556 | } 557 | else if( senderContext[recipientId].state === 'addKeywordStep1') { 558 | addKeywordStep2(recipientId,messageText); 559 | } 560 | else if( senderContext[recipientId].state === 'addKeywordText') { 561 | addKeywordTextStep2(recipientId,messageText); 562 | } 563 | else if( senderContext[recipientId].state === 'addKeywordButton') { 564 | addKeywordButtonStep2(recipientId,messageText); 565 | } 566 | else if (emojiString.indexOf(messageText.substring(0,2)) > -1) { 567 | var maxLength = emojiString.length; 568 | var random = Math.floor(Math.random() * maxLength); 569 | messageText = emojiString[random]; 570 | sendTextMessage(recipientId,messageText); 571 | } 572 | else { 573 | sendCustomMessage(recipientId,messageText); 574 | } 575 | } 576 | 577 | function sendCustomMessage(recipientId,messageText) { 578 | 579 | console.log("sendCustoMessage "+ messageText); 580 | 581 | switch (messageText.toLowerCase()) { 582 | 583 | case 'joke': 584 | sendJoke(recipientId); 585 | break 586 | 587 | case 'image': 588 | sendRandomImage(recipientId); 589 | break 590 | 591 | case 'who': 592 | sendLocale(recipientId); 593 | break 594 | 595 | case 'add keyword': 596 | addKeywordStep1(recipientId); 597 | break 598 | 599 | case 'list keywords': 600 | sendKeywordList(recipientId); 601 | break 602 | 603 | case 'addkeyword_text': 604 | addKeywordText(recipientId); 605 | break 606 | 607 | case 'addkeyword_button': 608 | addKeywordButton(recipientId); 609 | break 610 | 611 | case 'addkeyword_button1': 612 | addKeywordButtonStep3(recipientId,1); 613 | break 614 | 615 | case 'addkeyword_button2': 616 | addKeywordButtonStep3(recipientId,2); 617 | break 618 | 619 | case 'addkeyword_button3': 620 | addKeywordButtonStep3(recipientId,3); 621 | break 622 | 623 | 624 | default: 625 | sendJsonMessage(recipientId,messageText); 626 | 627 | } 628 | previousMessageHash[recipientId] = messageText.toLowerCase(); 629 | } 630 | 631 | function sendJsonMessage(recipientId,keyword) { 632 | console.log("sendJsonMessage " + keyword); 633 | if (_.has(scriptRules, keyword.toUpperCase())) { 634 | sendSingleJsonMessage(recipientId,scriptRules[keyword.toUpperCase()]); 635 | } 636 | else if (_.has(customRules, keyword.toUpperCase())) { 637 | sendSingleJsonMessage(recipientId,customRules[keyword.toUpperCase()]); 638 | } 639 | else { 640 | sendSingleJsonMessage(recipientId,"HOME.json"); 641 | } 642 | } 643 | 644 | /* 645 | * Send a text message using the Send API. 646 | * 647 | */ 648 | function sendTextMessage(recipientId, messageText) { 649 | var messageData = { 650 | "recipient": { 651 | "id": recipientId 652 | }, 653 | "message": { 654 | "text": messageText, 655 | "metadata": "DEVELOPER_DEFINED_METADATA" 656 | } 657 | }; 658 | 659 | callSendAPI(messageData); 660 | } 661 | 662 | /* 663 | * Send a Joke with Quick Reply buttons. 664 | * 665 | */ 666 | function sendJoke(recipientId) { 667 | 668 | var jokeString = ""; 669 | 670 | while( jokeString === "") 671 | { 672 | var random = Math.floor(Math.random() * jokes.length); 673 | if(jokes[random].joke.length < 320) // better be a least one good joke :) 674 | jokeString = jokes[random].joke; 675 | } 676 | 677 | var messageData = { 678 | recipient: { 679 | id: recipientId 680 | }, 681 | message: { 682 | text: jokeString, 683 | quick_replies: [ 684 | { 685 | "content_type":"text", 686 | "title":"Another 😂", 687 | "payload":"joke" 688 | }, 689 | { 690 | "content_type":"text", 691 | "title":"Home", 692 | "payload":"home" 693 | } 694 | ] 695 | } 696 | }; 697 | 698 | callSendAPI(messageData); 699 | } 700 | 701 | /* 702 | * Send the user information back, the bot grabs this for every message 703 | * 704 | */ 705 | function sendLocale(recipientId) { 706 | 707 | var nameString = firstName + " " + lastName; 708 | 709 | var messageData = { 710 | recipient: { 711 | id: recipientId 712 | }, 713 | message: { 714 | text: nameString, 715 | quick_replies: [ 716 | { 717 | "content_type":"text", 718 | "title":"Home", 719 | "payload":"home" 720 | } 721 | ] 722 | } 723 | }; 724 | 725 | callSendAPI(messageData); 726 | } 727 | 728 | /* 729 | * Simple example of an external http call with parsing. 730 | * 731 | */ 732 | function sendRandomImage(recipientId) { 733 | sendImageMessage(recipientId,"https://unsplash.it/400/600/?random"); 734 | } 735 | 736 | /* 737 | * Send a button message using the Send API. 738 | * 739 | */ 740 | function sendButtonMessage(recipientId) { 741 | var messageData = { 742 | recipient: { 743 | id: recipientId 744 | }, 745 | message: { 746 | attachment: { 747 | type: "template", 748 | payload: { 749 | template_type: "button", 750 | text: "This is test text", 751 | buttons:[{ 752 | type: "web_url", 753 | url: "https://www.oculus.com/en-us/rift/", 754 | title: "Open Web URL" 755 | }, { 756 | type: "postback", 757 | title: "Trigger Postback", 758 | payload: "DEVELOPED_DEFINED_PAYLOAD" 759 | }, { 760 | type: "phone_number", 761 | title: "Call Phone Number", 762 | payload: "+16505551234" 763 | }] 764 | } 765 | } 766 | } 767 | }; 768 | 769 | callSendAPI(messageData); 770 | } 771 | 772 | /* 773 | * Send a Structured Message (Generic Message type) using the Send API. 774 | * 775 | */ 776 | function sendGenericMessage(recipientId) { 777 | var messageData = { 778 | recipient: { 779 | id: recipientId 780 | }, 781 | message: 782 | { 783 | "attachment": { 784 | "type": "template", 785 | "payload": { 786 | "template_type": "generic", 787 | "elements": [ 788 | { 789 | "title": "Bots", 790 | "subtitle": "The rise of the Facebook Bot!", 791 | "item_url": "http://www.dynamic-memory.com/", 792 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/robot.png", 793 | "buttons": [ 794 | { 795 | "type": "postback", 796 | "title": "What is this Bot?", 797 | "payload": "What is this Robot?" 798 | }, 799 | { 800 | "type": "postback", 801 | "title": "Your Business Bot", 802 | "payload": "business" 803 | }, 804 | { 805 | "type": "postback", 806 | "title": "I want a Bot!", 807 | "payload": "I want one" 808 | } 809 | ] 810 | }, 811 | { 812 | "title": "DMS Software", 813 | "subtitle": "Software Engineering is awesome", 814 | "item_url": "http://www.dynamic-memory.com/", 815 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/evolution.png", 816 | "buttons": [ 817 | { 818 | "type": "postback", 819 | "title": "Contact", 820 | "payload": "Contact" 821 | }, 822 | { 823 | "type": "postback", 824 | "title": "Social media", 825 | "payload": "Social media" 826 | }, 827 | { 828 | "type": "postback", 829 | "title": "Matthew's bio", 830 | "payload": "bio" 831 | } 832 | ] 833 | }, 834 | { 835 | "title": "Custom Examples", 836 | "subtitle": "A few small apps to give an idea of the possibilites", 837 | "item_url": "https://dynamic-memory.com", 838 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/danger-man-at-work-hi.png", 839 | "buttons": [ 840 | { 841 | "type": "postback", 842 | "title": "Tell me a joke 😜", 843 | "payload": "joke" 844 | }, 845 | { 846 | "type": "postback", 847 | "title": "Random Image", 848 | "payload": "image" 849 | }, 850 | { 851 | "type": "postback", 852 | "title": "Who am I?", 853 | "payload": "who" 854 | } 855 | ] 856 | }, 857 | { 858 | "title": "Bot Examples", 859 | "subtitle": "Some great bots", 860 | "item_url": "https://developers.facebook.com/products/messenger/", 861 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/example.jpeg", 862 | "buttons": [ 863 | { 864 | "type": "web_url", 865 | "url": "https://www.messenger.com/t/HealthTap", 866 | "title": "Health Tap" 867 | }, 868 | { 869 | "type": "web_url", 870 | "url": "http://www.messenger.com/t/EstherBot", 871 | "title": "Esther's cool bot" 872 | }, 873 | { 874 | "type": "web_url", 875 | "url": "http://www.messenger.com/t/techcrunch", 876 | "title": "TechCrunch news bot" 877 | } 878 | ] 879 | } 880 | ] 881 | } 882 | } 883 | } 884 | }; 885 | 886 | callSendAPI(messageData); 887 | } 888 | 889 | /* 890 | * Send a receipt message using the Send API. 891 | * 892 | */ 893 | function sendReceiptMessage(recipientId) { 894 | // Generate a random receipt ID as the API requires a unique ID 895 | var receiptId = "order" + Math.floor(Math.random()*1000); 896 | 897 | var messageData = { 898 | recipient: { 899 | id: recipientId 900 | }, 901 | message:{ 902 | attachment: { 903 | type: "template", 904 | payload: { 905 | template_type: "receipt", 906 | recipient_name: "Peter Chang", 907 | order_number: receiptId, 908 | currency: "USD", 909 | payment_method: "Visa 1234", 910 | timestamp: "1428444852", 911 | elements: [{ 912 | title: "Oculus Rift", 913 | subtitle: "Includes: headset, sensor, remote", 914 | quantity: 1, 915 | price: 599.00, 916 | currency: "USD", 917 | image_url: "http://messengerdemo.parseapp.com/img/riftsq.png" 918 | }, { 919 | title: "Samsung Gear VR", 920 | subtitle: "Frost White", 921 | quantity: 1, 922 | price: 99.99, 923 | currency: "USD", 924 | image_url: "http://messengerdemo.parseapp.com/img/gearvrsq.png" 925 | }], 926 | address: { 927 | street_1: "1 Hacker Way", 928 | street_2: "", 929 | city: "Menlo Park", 930 | postal_code: "94025", 931 | state: "CA", 932 | country: "US" 933 | }, 934 | summary: { 935 | subtotal: 698.99, 936 | shipping_cost: 20.00, 937 | total_tax: 57.67, 938 | total_cost: 626.66 939 | }, 940 | adjustments: [{ 941 | name: "New Customer Discount", 942 | amount: -50 943 | }, { 944 | name: "$100 Off Coupon", 945 | amount: -100 946 | }] 947 | } 948 | } 949 | } 950 | }; 951 | 952 | callSendAPI(messageData); 953 | } 954 | 955 | /* 956 | * Send a message with Quick Reply buttons. 957 | * 958 | */ 959 | function sendQuickReply(recipientId) { 960 | var messageData = { 961 | recipient: { 962 | id: recipientId 963 | }, 964 | message: { 965 | text: "Some regular buttons and a location test", 966 | metadata: "DEVELOPER_DEFINED_METADATA", 967 | quick_replies: [ 968 | { 969 | "content_type":"text", 970 | "title":"Action", 971 | "payload":"DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_ACTION" 972 | }, 973 | { 974 | "content_type":"text", 975 | "title":"Something else", 976 | "payload":"DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_SOMETHING" 977 | }, 978 | { 979 | "content_type":"location", 980 | "title":"Send Location", 981 | "payload":"DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_LOCATION" 982 | } 983 | ] 984 | } 985 | }; 986 | 987 | callSendAPI(messageData); 988 | } 989 | 990 | /* 991 | * Send a read receipt to indicate the message has been read 992 | * 993 | */ 994 | function sendReadReceipt(recipientId) { 995 | console.log("Sending a read receipt to mark message as seen"); 996 | 997 | var messageData = { 998 | recipient: { 999 | id: recipientId 1000 | }, 1001 | sender_action: "mark_seen" 1002 | }; 1003 | 1004 | callSendAPI(messageData); 1005 | } 1006 | 1007 | /* 1008 | * Turn typing indicator on 1009 | * 1010 | */ 1011 | function sendTypingOn(recipientId) { 1012 | console.log("Turning typing indicator on"); 1013 | 1014 | var messageData = { 1015 | recipient: { 1016 | id: recipientId 1017 | }, 1018 | sender_action: "typing_on" 1019 | }; 1020 | 1021 | callSendAPI(messageData); 1022 | } 1023 | 1024 | /* 1025 | * Turn typing indicator off 1026 | * 1027 | */ 1028 | function sendTypingOff(recipientId) { 1029 | console.log("Turning typing indicator off"); 1030 | 1031 | var messageData = { 1032 | recipient: { 1033 | id: recipientId 1034 | }, 1035 | sender_action: "typing_off" 1036 | }; 1037 | 1038 | callSendAPI(messageData); 1039 | } 1040 | 1041 | 1042 | /* 1043 | * Call the Send API. The message data goes in the body. If successful, we'll 1044 | * get the message id in a response 1045 | * 1046 | */ 1047 | function callSendAPI(messageData) { 1048 | request({ 1049 | uri: 'https://graph.facebook.com/v2.6/me/messages', 1050 | qs: { access_token: PAGE_ACCESS_TOKEN }, 1051 | method: 'POST', 1052 | json: messageData 1053 | 1054 | }, function (error, response, body) { 1055 | if (!error && response.statusCode == 200) { 1056 | var recipientId = body.recipient_id; 1057 | var messageId = body.message_id; 1058 | 1059 | if (messageId) { 1060 | console.log("Successfully sent message with id %s to recipient %s", 1061 | messageId, recipientId); 1062 | } else { 1063 | console.log("Successfully called Send API for recipient %s", 1064 | recipientId); 1065 | } 1066 | } else { 1067 | console.error("Unable to send message. :" + response.error); 1068 | } 1069 | }); 1070 | } 1071 | 1072 | /* 1073 | * Call the Get Locale API. The message data goes in the body. If successful, we'll 1074 | * get the message id in a response 1075 | * 1076 | */ 1077 | function callGetLocaleAPI(event, handleReceived) { 1078 | var userID = event.sender.id; 1079 | var http = require('https'); 1080 | var path = '/v2.6/' + userID +'?fields=first_name,last_name,profile_pic,locale,timezone,gender&access_token=' + PAGE_ACCESS_TOKEN; 1081 | var options = { 1082 | host: 'graph.facebook.com', 1083 | path: path 1084 | }; 1085 | 1086 | if(senderContext[userID]) 1087 | { 1088 | firstName = senderContext[userID].firstName; 1089 | lastName = senderContext[userID].lastName; 1090 | console.log("found " + JSON.stringify(senderContext[userID])); 1091 | if(!firstName) 1092 | firstName = "undefined"; 1093 | if(!lastName) 1094 | lastName = "undefined"; 1095 | handleReceived(event); 1096 | return; 1097 | } 1098 | 1099 | var req = http.get(options, function(res) { 1100 | //console.log('STATUS: ' + res.statusCode); 1101 | //console.log('HEADERS: ' + JSON.stringify(res.headers)); 1102 | 1103 | // Buffer the body entirely for processing as a whole. 1104 | var bodyChunks = []; 1105 | res.on('data', function(chunk) { 1106 | // You can process streamed parts here... 1107 | bodyChunks.push(chunk); 1108 | }).on('end', function() { 1109 | var body = Buffer.concat(bodyChunks); 1110 | var bodyObject = JSON.parse(body); 1111 | firstName = bodyObject.first_name; 1112 | lastName = bodyObject.last_name; 1113 | if(!firstName) 1114 | firstName = "undefined"; 1115 | if(!lastName) 1116 | lastName = "undefined"; 1117 | senderContext[userID] = {}; 1118 | senderContext[userID].firstName = firstName; 1119 | senderContext[userID].lastName = lastName; 1120 | console.log("defined " + JSON.stringify(senderContext)); 1121 | handleReceived(event); 1122 | }) 1123 | }); 1124 | req.on('error', function(e) { 1125 | console.log('ERROR: ' + e.message); 1126 | }); 1127 | } 1128 | 1129 | 1130 | function addPersistentMenu(){ 1131 | request({ 1132 | url: 'https://graph.facebook.com/v2.6/me/messenger_profile', 1133 | qs: { access_token: PAGE_ACCESS_TOKEN }, 1134 | method: 'POST', 1135 | json:{ 1136 | "get_started":{ 1137 | "payload":"GET_STARTED_PAYLOAD" 1138 | } 1139 | } 1140 | }, function(error, response, body) { 1141 | console.log("Add persistent menu " + response) 1142 | if (error) { 1143 | console.log('Error sending messages: ', error) 1144 | } else if (response.body.error) { 1145 | console.log('Error: ', response.body.error) 1146 | } 1147 | }) 1148 | request({ 1149 | url: 'https://graph.facebook.com/v2.6/me/messenger_profile', 1150 | qs: { access_token: PAGE_ACCESS_TOKEN }, 1151 | method: 'POST', 1152 | json:{ 1153 | "persistent_menu":[ 1154 | { 1155 | "locale":"default", 1156 | "composer_input_disabled":true, 1157 | "call_to_actions":[ 1158 | { 1159 | "title":"Home", 1160 | "type":"postback", 1161 | "payload":"HOME" 1162 | }, 1163 | { 1164 | "title":"Nested Menu Example", 1165 | "type":"nested", 1166 | "call_to_actions":[ 1167 | { 1168 | "title":"Who am I", 1169 | "type":"postback", 1170 | "payload":"WHO" 1171 | }, 1172 | { 1173 | "title":"Joke", 1174 | "type":"postback", 1175 | "payload":"joke" 1176 | }, 1177 | { 1178 | "title":"Contact Info", 1179 | "type":"postback", 1180 | "payload":"CONTACT" 1181 | } 1182 | ] 1183 | }, 1184 | { 1185 | "type":"web_url", 1186 | "title":"Latest News", 1187 | "url":"http://foxnews.com", 1188 | "webview_height_ratio":"full" 1189 | } 1190 | ] 1191 | }, 1192 | { 1193 | "locale":"zh_CN", 1194 | "composer_input_disabled":false 1195 | } 1196 | ] 1197 | } 1198 | 1199 | }, function(error, response, body) { 1200 | console.log(response) 1201 | if (error) { 1202 | console.log('Error sending messages: ', error) 1203 | } else if (response.body.error) { 1204 | console.log('Error: ', response.body.error) 1205 | } 1206 | }) 1207 | 1208 | } 1209 | 1210 | function removePersistentMenu(){ 1211 | request({ 1212 | url: 'https://graph.facebook.com/v2.6/me/thread_settings', 1213 | qs: { access_token: PAGE_ACCESS_TOKEN }, 1214 | method: 'POST', 1215 | json:{ 1216 | setting_type : "call_to_actions", 1217 | thread_state : "existing_thread", 1218 | call_to_actions:[ ] 1219 | } 1220 | 1221 | }, function(error, response, body) { 1222 | console.log(response) 1223 | if (error) { 1224 | console.log('Error sending messages: ', error) 1225 | } else if (response.body.error) { 1226 | console.log('Error: ', response.body.error) 1227 | } 1228 | }) 1229 | } 1230 | 1231 | function addKeywordStep1(recipientId) 1232 | { 1233 | sendTextMessage(recipientId,"The keyword will drive the actions by the Bot. The user can type in the keyword or it can be triggered by a link. The keyword can contain letters, numbers and spaces. Please type in the keyword:"); 1234 | senderContext[recipientId].state = "addKeywordStep1"; 1235 | } 1236 | 1237 | function addKeywordStep2(recipientId, messageText) 1238 | { 1239 | senderContext[recipientId].keyword = messageText; 1240 | senderContext[recipientId].state = "addKeywordStep2"; 1241 | sendJsonMessage(recipientId,"addKeywordStep2"); 1242 | } 1243 | 1244 | function stateMachineError(recipientId) 1245 | { 1246 | sendTextMessage(recipientId,"Sorry the Bot is confused. We will have to start again."); 1247 | senderContext[recipientId].state = ""; 1248 | senderContext[recipientId].keyword = ""; 1249 | } 1250 | 1251 | function addKeywordText(recipientId) 1252 | { 1253 | console.log("addKeywordText " + JSON.stringify(senderContext)); 1254 | 1255 | if( senderContext[recipientId].state === "addKeywordStep2") 1256 | { 1257 | sendTextMessage(recipientId,"Please type in the text to be sent to the user when this keyword is used."); 1258 | senderContext[recipientId].state = "addKeywordText"; 1259 | } 1260 | else 1261 | { 1262 | stateMachineError(recipientId); 1263 | } 1264 | } 1265 | 1266 | function addKeywordTextStep2(recipientId,messageText) 1267 | { 1268 | if( senderContext[recipientId].state === "addKeywordText") 1269 | { 1270 | var filename = senderContext[recipientId].keyword.toUpperCase()+ ".json"; 1271 | var contents = '{"text": "' + messageText + '" }'; 1272 | console.log("contents: "+contents); 1273 | fs.writeFile("script/"+filename, contents, function(err) { 1274 | if(err) { 1275 | return console.log(err); 1276 | } 1277 | console.log("The file was saved!"); 1278 | senderContext[recipientId].state = ""; 1279 | customRules[senderContext[recipientId].keyword.toUpperCase()] = senderContext[recipientId].keyword.toUpperCase(); 1280 | sendTextMessage(recipientId,"The keyword has been added. Please type in the keyword to see the response."); 1281 | 1282 | /* 1283 | fs.readFile(filename, function read(err, data) { 1284 | if (err) { 1285 | throw err; 1286 | } 1287 | 1288 | // Invoke the next step here however you like 1289 | console.log("file contains: " + data); 1290 | }); 1291 | */ 1292 | } 1293 | ); 1294 | } 1295 | else 1296 | { 1297 | stateMachineError(recipientId); 1298 | } 1299 | } 1300 | 1301 | function addKeywordButton(recipientId) 1302 | { 1303 | console.log("addKeywordButton " + JSON.stringify(senderContext)); 1304 | 1305 | if( senderContext[recipientId].state === "addKeywordStep2") 1306 | { 1307 | sendTextMessage(recipientId,"Please type in the title for the button."); 1308 | senderContext[recipientId].state = "addKeywordButton"; 1309 | } 1310 | else 1311 | { 1312 | stateMachineError(recipientId); 1313 | } 1314 | } 1315 | 1316 | function addKeywordButtonStep2(recipientId, messageText) 1317 | { 1318 | if( senderContext[recipientId].state === "addKeywordButton") 1319 | { 1320 | senderContext[recipientId].state = "addKeywordButtonStep2"; 1321 | sendSingleJsonMessage(recipientId,"ADDKEYWORD_BUTTONSTEP2.json"); 1322 | } 1323 | else 1324 | { 1325 | stateMachineError(recipientId); 1326 | } 1327 | } 1328 | 1329 | function addKeywordButtonStep3(recipientId, buttonCount) 1330 | { 1331 | if( senderContext[recipientId].state === "addKeywordButtonStep2") 1332 | { 1333 | senderContext[recipientId].state = "addKeywordButtonStep3"; 1334 | senderContext[recipientId].buttonCount = buttonCount; 1335 | sendSingleJsonMessage(recipientId,"ADDKEYWORD_BUTTONSTEP3.json"); 1336 | } 1337 | else 1338 | { 1339 | stateMachineError(recipientId); 1340 | } 1341 | } 1342 | 1343 | function sendKeywordList(recipientId) 1344 | { 1345 | // if (customRules.length > 0) 1346 | if (1) 1347 | { 1348 | var keys = Object.keys(customRules); 1349 | 1350 | for (var p in keys) 1351 | { 1352 | if (keys.hasOwnProperty(p)) 1353 | { 1354 | sendTextMessage(recipientId,keys[p]); 1355 | } 1356 | } 1357 | } 1358 | else 1359 | { 1360 | sendTextMessage(recipientId,"No custom keywords defined yet"); 1361 | } 1362 | return; 1363 | } 1364 | 1365 | 1366 | // Start server 1367 | // Webhooks must be available via SSL with a certificate signed by a valid 1368 | // certificate authority. 1369 | app.listen(app.get('port'), function() { 1370 | console.log('Node app is running on port', app.get('port')); 1371 | }); 1372 | 1373 | module.exports = app; 1374 | 1375 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DMS Software Bot", 3 | "description": "An example Facebook Bot.", 4 | "repository": "https://github.com/matthewericfisher/fb-robot", 5 | "logo": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/icon.png", 6 | "env": { 7 | "APP_SECRET": { 8 | "description": "The App Secret from the Facebook Settings page", 9 | "required": true 10 | }, 11 | "PAGE_ACCESS_TOKEN": { 12 | "description": "Page Access Token from the Facebook Messenger Settings page", 13 | "required": true 14 | }, 15 | "VALIDATION_TOKEN": { 16 | "description": "Validation Token from Facebook Webhooks setup page. If you forget this, you must +Add Product and select Webhooks", 17 | "required": true 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /img/Logo-2C-121px-TM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/Logo-2C-121px-TM.png -------------------------------------------------------------------------------- /img/canphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/canphone.png -------------------------------------------------------------------------------- /img/chess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/chess.png -------------------------------------------------------------------------------- /img/danger-man-at-work-hi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/danger-man-at-work-hi.png -------------------------------------------------------------------------------- /img/evolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/evolution.png -------------------------------------------------------------------------------- /img/example.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/example.jpeg -------------------------------------------------------------------------------- /img/family.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/family.png -------------------------------------------------------------------------------- /img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/icon.png -------------------------------------------------------------------------------- /img/linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/linkedin.png -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/logo.png -------------------------------------------------------------------------------- /img/medium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/medium.png -------------------------------------------------------------------------------- /img/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/robot.png -------------------------------------------------------------------------------- /img/so-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/so-logo.png -------------------------------------------------------------------------------- /img/tumblr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/tumblr.png -------------------------------------------------------------------------------- /img/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/matthewericfisher/fb-robot/e65fcccb2b89f597853d5aabdcb0a2d8e962a94a/img/youtube.png -------------------------------------------------------------------------------- /node/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "messenger-get-started", 3 | "version": "1.0.0", 4 | "description": "Get started example for Messenger Platform", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "node app.js", 8 | "lint": "jshint --exclude node_modules .", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://source.developers.google.com/p/messenger-get-started/r/default" 14 | }, 15 | "author": "Facebook", 16 | "license": "ISC", 17 | "dependencies": { 18 | "body-parser": "^1.15.0", 19 | "lodash": "^4.6.1", 20 | "config": "^1.20.4", 21 | "express": "^4.13.4", 22 | "request": "^2.72.0" 23 | }, 24 | "engines": { 25 | "node": "~4.1.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /privacy.rtf: -------------------------------------------------------------------------------- 1 | 400: Invalid request 2 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | Messenger Demo 13 | 14 | 15 | 32 | 33 |

Messenger Demo

34 | 35 |
36 |

The "Send to Messenger" plugin will trigger an authentication callback to your webhook.

37 | 38 |
44 |
45 |
46 | 47 |
48 |

The "Message Us" plugin takes the user directly to Messenger and into a thread with your Page.

49 | 50 |
55 |
56 |
57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /script.json: -------------------------------------------------------------------------------- 1 | { 2 | "HOME" : "HOME.json", 3 | "WHAT IS THIS ROBOT?" : "HELLO.json", 4 | "HOW DOES IT WORK?" : "ROBOT.json", 5 | "I WANT ONE" : "I_WANT_ONE.json", 6 | "SOCIAL MEDIA" : "SOCIAL.json", 7 | "CONTACT" : "CONTACT.json", 8 | "CUSTOM" : "CUSTOM.json", 9 | "SEND A MESSAGE" : "SENDMESSAGE.json", 10 | "GET EMAIL ADDRESS" : "EMAIL.json", 11 | "RECRUITERS" : "RECRUITERS.json", 12 | "BIO" : "BIO.json", 13 | "HELLO" : "HELLO.json", 14 | "HI" : "HELLO.json", 15 | "MENU" : "HELLO.json", 16 | "ROBOT" : "ROBOT.json", 17 | "EDUCATION": "EDUCATION.json", 18 | "SOFTWARE": "SOFTWARE.json", 19 | "EFFECTIVE": "EFFECTIVE.json", 20 | "LANGUAGES": "LANGUAGES.json", 21 | "ARCHITECTURE": "ARCHITECTURE.json", 22 | "BUSINESS": "BUSINESS.json", 23 | "MARKETING": "MARKETING.json", 24 | "SALES": "SALES.json", 25 | "SUPPORT": "SUPPORT.json", 26 | "ADDKEYWORDSTEP2": "ADDKEYWORDSTEP2.json", 27 | "HTTPS://SCONTENT.XX.FBCDN.NET/T39.1997-6/851557_369239266556155_759568595_N.PNG?_NC_AD=Z-M": "THUMBS.json" 28 | } 29 | -------------------------------------------------------------------------------- /script/ADDKEYWORDSTEP2.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "The new keyword must be associated with a template, only text is currently supported.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Text", 7 | "payload":"ADDKEYWORD_TEXT" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /script/ADDKEYWORD_BUTTONSTEP2.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "A button template may have up to three buttons. How many would you like?", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"One", 7 | "payload":"ADDKEYWORD_BUTTON1" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Two", 12 | "payload":"ADDKEYWORD_BUTTON2" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Three", 17 | "payload":"ADDKEYWORD_BUTTON3" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /script/ARCHITECTURE.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Matthew specializes in high performance, low latency, high throughput software architectures. He has proven experience in the Finance and Telecom industries. Millions of users, Billions of messages a day and microsecond latency are the current metrics for similar systems.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Education", 7 | "payload":"Education" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Software", 12 | "payload":"software" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Languages", 17 | "payload":"languages" 18 | }, 19 | { 20 | "content_type":"text", 21 | "title":"Architecture", 22 | "payload":"architecture" 23 | }, 24 | { 25 | "content_type":"text", 26 | "title":"Home", 27 | "payload":"home" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /script/BIO.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Thanks for your interest. Matthew has had a great software career. What would you like to know?", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Education", 7 | "payload":"Education" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Software", 12 | "payload":"software" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Languages", 17 | "payload":"languages" 18 | }, 19 | { 20 | "content_type":"text", 21 | "title":"Architecture", 22 | "payload":"architecture" 23 | }, 24 | { 25 | "content_type":"text", 26 | "title":"Home", 27 | "payload":"home" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /script/BUSINESS.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Your business can benefit from having a bot like this one. The bot can be an effective customer contact tool for marketing, sales and customer support. You can increase profits and lower costs by engaging with your customers on a more personalized basis with a bot.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Marketing", 7 | "payload":"marketing" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Sales", 12 | "payload":"sales" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Customer Support", 17 | "payload":"support" 18 | }, 19 | { 20 | "content_type":"text", 21 | "title":"Home", 22 | "payload":"Home" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /script/CONTACT.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "template", 4 | "payload": { 5 | "template_type": "generic", 6 | "elements": [ 7 | { 8 | "title": "Contact", 9 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/canphone.png", 10 | "buttons": [ 11 | { 12 | "type": "postback", 13 | "title": "Send a message", 14 | "payload": "Send a message" 15 | }, 16 | { 17 | "type": "web_url", 18 | "url": "http://www.dynamic-memory.com/", 19 | "title": "DMS Software website" 20 | }, 21 | { 22 | "type": "postback", 23 | "title": "Get email address", 24 | "payload": "Get email address" 25 | } 26 | ] 27 | } 28 | ] 29 | } 30 | } 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /script/CUSTOM.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "template", 4 | "payload": { 5 | "template_type": "button", 6 | "text": "Select action", 7 | "buttons":[{ 8 | "type": "postback", 9 | "title": "Add new keyword", 10 | "payload": "add keyword" 11 | }, { 12 | "type": "postback", 13 | "title": "List keywords", 14 | "payload": "list keywords" 15 | }] 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /script/EDUCATION.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Matthew holds a Bachelor's degree in Computer Science from The Ohio State University", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Education", 7 | "payload":"Education" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Software", 12 | "payload":"Software" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Languages", 17 | "payload":"Languages" 18 | }, 19 | { 20 | "content_type":"text", 21 | "title":"Architecture", 22 | "payload":"Architecture" 23 | }, 24 | { 25 | "content_type":"text", 26 | "title":"Home", 27 | "payload":"Home" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /script/EFFECTIVE.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Effective Software Engineering focuses on industrial systems where nothing is ever perfect. Time is short, human resources are missing, existing software is broken, etc. The Effective Software Engineer works within these business constraints to deliver the best solutions possible.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Education", 7 | "payload":"Education" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Software", 12 | "payload":"Software" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Languages", 17 | "payload":"Languages" 18 | }, 19 | { 20 | "content_type":"text", 21 | "title":"Architecture", 22 | "payload":"Architecture" 23 | }, 24 | { 25 | "content_type":"text", 26 | "title":"Home", 27 | "payload":"Home" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /script/EMAIL.json: -------------------------------------------------------------------------------- 1 | { 2 | "text":"matthew@dynamic-memory.com" 3 | } 4 | -------------------------------------------------------------------------------- /script/HELLO.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "template", 4 | "payload": { 5 | "template_type": "button", 6 | "text": "This is the personal assistant bot for Matthew Fisher, CEO of DMS Software. You can found out more about DMS Software, bots and other cool stuff. Type 'home' at anytime to start again", 7 | "buttons":[ 8 | { 9 | "type": "postback", 10 | "title": "Home", 11 | "payload": "home" 12 | } 13 | 14 | ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /script/HOME.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "template", 4 | "payload": { 5 | "template_type": "generic", 6 | "elements": [ 7 | { 8 | "title": "Bots", 9 | "subtitle": "The rise of the Facebook Bot!", 10 | "item_url": "http://www.dynamic-memory.com/", 11 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/robot.png", 12 | "buttons": [ 13 | { 14 | "type": "postback", 15 | "title": "What is this Bot?", 16 | "payload": "What is this Robot?" 17 | }, 18 | { 19 | "type": "postback", 20 | "title": "Your Business Bot", 21 | "payload": "business" 22 | }, 23 | { 24 | "type": "postback", 25 | "title": "I want a Bot!", 26 | "payload": "I want one" 27 | } 28 | ] 29 | }, 30 | { 31 | "title": "DMS Software", 32 | "subtitle": "Software Engineering is awesome", 33 | "item_url": "http://www.dynamic-memory.com/", 34 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/evolution.png", 35 | "buttons": [ 36 | { 37 | "type": "postback", 38 | "title": "Contact", 39 | "payload": "Contact" 40 | }, 41 | { 42 | "type": "postback", 43 | "title": "Social media", 44 | "payload": "Social media" 45 | }, 46 | { 47 | "type": "postback", 48 | "title": "Matthew's bio", 49 | "payload": "bio" 50 | } 51 | ] 52 | }, 53 | { 54 | "title": "Custom Examples", 55 | "subtitle": "A few small apps to give an idea of the possibilites", 56 | "item_url": "https://dynamic-memory.com", 57 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/danger-man-at-work-hi.png", 58 | "buttons": [ 59 | { 60 | "type": "postback", 61 | "title": "Tell me a joke 😜", 62 | "payload": "joke" 63 | }, 64 | { 65 | "type": "postback", 66 | "title": "Random Image", 67 | "payload": "image" 68 | }, 69 | { 70 | "type": "postback", 71 | "title": "Who am I?", 72 | "payload": "who" 73 | } 74 | ] 75 | }, 76 | { 77 | "title": "Bot Examples", 78 | "subtitle": "Some great bots", 79 | "item_url": "https://developers.facebook.com/products/messenger/", 80 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/example.jpeg", 81 | "buttons": [ 82 | { 83 | "type": "web_url", 84 | "url": "https://www.messenger.com/t/HealthTap", 85 | "title": "Health Tap" 86 | }, 87 | { 88 | "type": "web_url", 89 | "url": "http://www.messenger.com/t/helloestherbot", 90 | "title": "Esther's cool bot" 91 | }, 92 | { 93 | "type": "web_url", 94 | "url": "http://www.messenger.com/t/techcrunch", 95 | "title": "TechCrunch news bot" 96 | } 97 | ] 98 | } 99 | ] 100 | } 101 | } 102 | } 103 | 104 | 105 | -------------------------------------------------------------------------------- /script/I_WANT_ONE.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "template", 4 | "payload": { 5 | "template_type": "button", 6 | "text": "Matthew wrote this bot himself for fun and profit. Simple personal bots are available free from ChatFuel.com. If you would like helping setting up a ChatFull bot or a Custom bot, please contact DMS Software, dynamic-memory.com. You can customize this Bot using this Bot! Just hit Customize to get started.", 7 | "buttons":[ 8 | { 9 | "type": "postback", 10 | "title": "Customize this bot", 11 | "payload": "custom" 12 | }, 13 | { 14 | "type": "web_url", 15 | "url": "http://www.dynamic-memory.com", 16 | "title": "DMS Software" 17 | }, 18 | { 19 | "type": "postback", 20 | "title": "Home", 21 | "payload": "home" 22 | } 23 | ] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /script/JOKES.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "joke": "I met a Dutch girl with inflatable shoes last week, phoned her up to arrange a date but unfortunately she'd popped her clogs." }, 3 | { "joke": "So I said 'Do you want a game of Darts? ' He said, 'OK then', I said nearest to bull starts'. He said, 'Baa', I said, 'Moo', he said, You're closest'." }, 4 | { "joke": "The other day I sent my girlfriend a huge pile of snow. I rang her up; I said 'Did you get my drift? '" }, 5 | { "joke": "So I went down the local supermarket, I said, 'I want to make a complaint, this vinegar's got lumps in it', he said, 'Those are pickled onions'." }, 6 | { "joke": "I saw this bloke chatting up a cheetah; I thought, 'He's trying to pull a fast one'." }, 7 | { "joke": "So I said to this train driver 'I want to go to Paris'. He said 'Eurostar? ' I said, 'I've been on telly but I'm no Dean Martin'." }, 8 | { "joke": "I said to the Gym instructor 'Can you teach me to do the splits? ' He said, 'How flexible are you? ' I said, 'I can't make Tuesdays'." }, 9 | { "joke": "But I'll tell you what I love doing more than anything: trying to pack myself in a small suitcase. I can hardly contain myself." }, 10 | { "joke": "I went to the Chinese restaurant and this duck came up to me with a red rose and says 'Your eyes sparkle like diamonds'. I said, 'Waiter, I asked for a-ROMATIC duck'." }, 11 | { "joke": "So this bloke says to me, 'Can I come in your house and talk about your carpets? ' I thought, 'That's all I need, a Je-hoover's witness'." }, 12 | { "joke": "I rang up British Telecom, I said, 'I want to report a nuisance caller', he said 'Not you again'." }, 13 | { "joke": "I was having dinner with a world chess champion and there was a check tablecloth. It took him two hours to pass me the salt." }, 14 | { "joke": "He said, 'You remind me of a pepper-pot', I said 'I'll take that as a condiment'." }, 15 | { "joke": "I was in the supermarket and I saw this man and woman wrapped in a barcode. I said, 'Are you two an item? '" }, 16 | { "joke": "A lorry-load of tortoises crashed into a trainload of terrapins, I thought, 'That's a turtle disaster'." }, 17 | { "joke": "Four fonts walk into a bar the barman says 'Oi - get out! We don't want your type in here'" }, 18 | { "joke": "A three-legged dog walks into a saloon in the Old West. He slides up to the bar and announces: 'I'm looking for the man who shot my paw.'" }, 19 | { "joke": "Two antennas meet on a roof, fall in love and get married. The ceremony wasn't much, but the reception was excellent." }, 20 | { "joke": "Two hydrogen atoms walk into a bar. One says, 'I've lost my electron.' The other says, 'Are you sure? ' The first replies, 'Yes, I'm positive...'" }, 21 | { "joke": "A jumper cable walks into a bar. The bartender says, 'I'll serve you but don't start anything.'" }, 22 | { "joke": "A sandwich walks into a bar. The bartender says, 'Sorry we don't serve food in here.'" }, 23 | { "joke": "A man walks into a bar with a slab of asphalt under his arm and says: 'A beer please, and one for the road.'" }, 24 | { "joke": "Two cannibals are eating a clown. One says to the other: 'Does this taste funny to you? '" }, 25 | { "joke": "'Doc, I can't stop singing 'The Green, Green Grass of Home.' That sounds like Tom Jones Syndrome. Is it common? It's Not Unusual.'" }, 26 | { "joke": "Two cows standing next to each other in a field. Daisy says to Dolly, 'I was artificially inseminated this morning. I don't believe you', said Dolly. It's true, no bull!' exclaimed Daisy." }, 27 | { "joke": "An invisible man marries an invisible woman. The kids were nothing to look at either." }, 28 | { "joke": "I went to buy some camouflage trousers the other day but I couldn't find any." }, 29 | { "joke": "I went to the butcher's the other day to bet him 50 bucks that he couldn't reach the meat off the top shelf. He said, 'No, the steaks are too high.'" }, 30 | { "joke": "I went to a seafood disco last week and pulled a mussel." }, 31 | { "joke": "A man goes into a bar and says, 'Can I have a bottle of less? What's that? ', asks the barman, 'Is it the name of a beer? I don't know', replies the man, 'but my doctor says I have to drink it.'" }, 32 | { "joke": "A man returns from an exotic holiday and is feeling very ill. He goes to see his doctor, and is immediately rushed to the hospital to undergo some tests. The man wakes up after the tests in a private room at the hospital, and the phone by his bed rings. 'This is your doctor. We have the results back from your tests and we have found you have an extremely nasty disease called M.A.D.S. It's a combination of Measles, AIDS, Diphtheria, and Shingles!' Oh my gosh', cried the man, 'What are you going to do, doctor? ' Well we're going to put you on a diet of pizzas, pancakes, and pita bread.' replied the doctor. Will that cure me? ' asked the man. The doctor replied, 'Well no, but, it's the only food we can slide under the door.'" }, 33 | { "joke": "A man strolls into a lingerie shop and asks the assistant: Do you have a see-through negligee, size 46-48-52? ' The assistant looks bewildered. 'What the heck would you want to see through that for? '!" }, 34 | { "joke": "Did you hear about the Buddhist who refused the offer of Novocain during his root canal work? He wanted to transcend dental medication." }, 35 | { "joke": "Pete goes for a job on a building site as an odd-job man. The foreman asks him what he can do. I can do anything' says Pete. Can you make tea? ' asks the foreman. Sure, yes', replies Pete. 'I can make a great cup of tea. Can you drive a forklift? ' asks the foreman, Good grief!' replies Pete. 'How big is the teapot? '" }, 36 | { "joke": "Stevie Wonder got a cheese grater for his birthday. He said it was the most violent book he'd ever read." }, 37 | { "joke": "A man is stopped by an angry neighbour. 'I'd just left the house this morning to collect my newspaper when that evil Doberman of yours went for me! I'm astounded', said the dog's owner. 'I've been feeding that fleabag for seven years and it's never got the paper for me.'" }, 38 | { "joke": "A man visits his doctor: Doc, I think I'm losing it', he says',I'm forever dreaming I wrote Lord Of The Rings. Hmm. One moment', replies the doctor, consulting his medical book. Ah yes, now I see... you've been Tolkien in your sleep.'" }, 39 | { "joke": "A police officer on a motorcycle pulls alongside a man driving around the M25 in an open-topped sports car and flags him down. The policeman solemnly approaches the car. Sir, I'm sorry to tell you your wife fell out a mile back', he says. Oh, thank goodness', the man replies. 'I thought I was going deaf.'" }, 40 | { "joke": "Two men walking their dogs pass each other in a graveyard. The first man says to the second, 'Morning. No', says the second man. 'Just walking the dog.'" }, 41 | { "joke": "A brain went into a bar and said, 'Can I have a pint of lager please, mate? No way', said the barman. 'You're already out of your head.'" }, 42 | { "joke": "A man walks into a surgery. 'Doctor!' he cries. 'I think I'm shrinking! I'm sorry sir, there are no appointments at the moment', says the physician. 'You'll just have to be a little patient.'" }, 43 | { "joke": "A grizzly bear walks into a pub and says, 'Can I have a pint of lager..............................................................................................................................and a packet of crisps please.' To which the barman replies, 'Why the big paws? '" }, 44 | { "joke": "What do you call cheese that isn't yours? Nacho cheese." }, 45 | { "joke": "A man is horribly run over by a mobile library. The van screeches to a halt, the man still screaming in agony with his limbs torn apart. The driver's door opens, a woman steps out, leans down and whispers, 'Ssshhhhh...'" }, 46 | { "joke": "A woman goes into a US sporting goods store to buy a rifle. 'It's for my husband', she tells the clerk. Did he tell you what gauge to get? ' asks the clerk. Are you kidding? ' she says. 'He doesn't even know that I'm going to shoot him!'" }, 47 | { "joke": "A couple are dining in a restaurant when the man suddenly slides under the table. A waitress, noticing that the woman is glancing nonchalantly around the room, wanders over to check that there's no funny business going on. Excuse me, madam', she smarms, 'but I think your husband has just slid under the table. No he hasn't', the woman replies. 'As a matter of fact, he's just walked in.'" }, 48 | { "joke": "An old man takes his two grandchildren to see the new Scooby-Doo film. When he returns home, his wife asks if he enjoyed himself. Well', he starts, 'if it wasn't for those pesky kids...!'" }, 49 | { "joke": "The Olympic committee has just announced that Origami is to be introduced in the next Olympic Games. Unfortunately it will only be available on paper view." }, 50 | { "joke": "Late one evening, a man is watching television when his phone rings. 'Hello? ' he answers. 'Is that 77777? ' sounds a desperate voice on other end of the phone. Er, yes it is', replies the man puzzled. Thank goodness!' cries the caller relieved. 'Can you ring 999 for me? I've got my finger stuck in the number seven.'" }, 51 | { "joke": "A man strolls into his local grocer's and says, 'Three pounds of potatoes, please. No, no, no', replies the owner, shaking his head, 'it's kilos nowadays, mate... Oh', apologises the man, 'three pounds of kilos, please.'" }, 52 | { "joke": "God is talking to one of his angels. He says, 'Boy, I just created a 24-hour period of alternating light and darkness on Earth. What are you going to do now? ' asks the angel. Call it a day', says God." }, 53 | { "joke": "Two tramps walk past a church and start to read the gravestones. The first tramp says, 'Good grief - this bloke was 182! Oh yeah? ' says the other.'What was his name? Miles from London.'" }, 54 | { "joke": "A bloke walks into work one day and says to a colleague, 'Do you like my new shirt - it's made out of the finest silk and got loads of cactuses over it. Cacti', says the co-worker. Forget my tie', says the bloke. 'Look at my shirt!'" }, 55 | { "joke": "1110011010001011111? 010011010101100111011!" }, 56 | { "joke": "What did the plumber say when he wanted to divorce his wife? Sorry, but it's over, Flo!" }, 57 | { "joke": "Two crisps were walking down a road when a taxi pulled up alongside them and said 'Do you want a lift? One of the crisps replied, 'No thanks, we're Walkers!'" }, 58 | { "joke": "Man: (to friend) I'm taking my wife on an African Safari. Friend: Wow! What would you do if a vicious lion attacked your wife? Man: Nothing. Friend: Nothing? You wouldn't do anything? Man: Too right. I'd let the stupid lion fend for himself!" }, 59 | { "joke": "A wife was having a go at her husband. 'Look at Mr Barnes across the road', she moaned. 'Every morning when he goes to work, he kisses his wife goodbye. Why don't you do that? Because I haven't been introduced to her yet', replied her old man." }, 60 | { "joke": "'Where are you going on holiday? ' John asked Trevor. We're off to Thailand this year', Trevor replied. Oh; aren't you worried that the very hot weather might disagree with your wife? ' asked John. It wouldn't dare', said Trevor." }, 61 | { "joke": "Two women were standing at a funeral. 'I blame myself for his death', said the wife. Why? ' said her friend. Because I shot him', said the wife." }, 62 | { "joke": "A woman goes into a clothes shop, 'Can I try that dress on in the window please? ' she asks. I'm sorry madam', replies the shop assistant, 'but you'll have to use the changing-rooms like everyone else.'" }, 63 | { "joke": "Van Gogh goes into a pub and his mate asks him if he wants a drink. No thanks', said Vincent, 'I've got one ear.'" }, 64 | { "joke": "A pony walks into a pub. The publican says, 'What's the matter with you? Oh it's nothing', says the pony. 'I'm just a little horse!'" }, 65 | { "joke": "A white horse walks into a bar, pulls up a stool, and orders a pint. The landlord pours him a tall frothy mug and say, 'You know, we have a drink named after you.' To which the white horse replies, 'What, Eric? '" }, 66 | { "joke": "Two drunk men sat in a pub. One says to the other, 'Does your watch tell the time? The other replies, 'No, mate. You have to look at it.'" }, 67 | { "joke": "A man goes into a pub with a newt sitting on his shoulder. That's a nice newt', says the landlord, 'What's he called? Tiny', replies the man. Why's that? ' asks the landlord. Because he's my newt', says the man." }, 68 | { "joke": "Doctor: I have some bad news and some very bad news. Patient: Well, you might as well give me the bad news first. Doctor: The lab called with your test results. They said you have 24 hours to live. Patient: 24 HOURS! That's terrible!! WHAT could be WORSE? What's the very bad news? Doctor: I've been trying to reach you since yesterday." }, 69 | { "joke": "Two men are chatting in a pub one day. How did you get those scars on your nose? ' said one. From glasses', said the other. Well why don't you try contact lenses? ' asked the first. Because they don't hold as much beer', said the second." }, 70 | { "joke": "A man went to the doctor, 'Look doc', he said, 'I can't stop my hands from shaking. Do you drink much? ' asked the doctor. No', replied the man, 'I spill most of it.'" }, 71 | { "joke": "Man goes to the doctor, 'Doctor, doctor. I keep seeing fish everywhere. Have you seen an optician? ' asks the doctor. Look I told you,' snapped the patient, 'It's fish that I see.'" }, 72 | { "joke": "After a car crash one of the drivers was lying injured on the pavement. Don't worry', said a policeman who's first on the scene,' a Red Cross nurse is coming. Oh no', moaned the victim, 'Couldn't I have a blonde, cheerful one instead? '" }, 73 | { "joke": "A policeman walked over to a parked car and asked the driver if the car was licensed. 'Of course it is', said the driver. Great, I'll have a beer then', said the policeman." }, 74 | { "joke": "A policeman stops a woman and asks for her licence. Madam', he says, 'It says here that you should be wearing glasses. Well', replies the woman, 'I have contacts. Listen, love', says the copper, 'I don't care who you know; You're nicked!'" }, 75 | { "joke": "A policeman stopped a motorist in the centre of town one evening. 'Would you mind blowing into this bag, sir? ' asked the policeman. Why? ' asked the driver. Because my chips are too hot', replied the policeman." }, 76 | { "joke": "Whizzing round a sharp bend on a country road a motorist ran over a large dog. A distraught farmer's wife ran over to the dead animal. I'm so very sorry', said the driver, 'I'll replace him, of course. Well, I don't know', said the farmer's wife, 'Are you any good at catching rats? '" }, 77 | { "joke": "Waiter, this coffee tastes like dirt! Yes sir, that's because it was ground this morning." }, 78 | { "joke": "Waiter, what is this stuff? That's bean salad sir. I know what it's been, but what is it now?" }, 79 | { "joke": "Waiter: And how did you find your steak sir? Customer: I just flipped a chip over, and there it was!" }, 80 | { "joke": "A guy goes into a pet shop and asks for a wasp. The owner tells him they don't sell wasps, to which the man says, 'Well you've got one in the window.'" }, 81 | { "joke": "A man goes into a fish shop and says, 'I'd like a piece of cod, please.' Fishmonger says, 'It won't be long sir. Well, it had better be fat then', replies the man." }, 82 | { "joke": "Man: Doctor, I've just swallowed a pillow. Doctor: How do you feel? Man: A little down in the mouth." }, 83 | { "joke": "Two goldfish are in a tank. One turns to the other and says, 'Do you know how to drive this thing? '" }, 84 | { "joke": "A tortoise goes to the police station to report being mugged by three snails. 'What happened? ' says the policeman. I don't know', says the tortoise. 'It was all so quick.'" }, 85 | { "joke": "Little girl: Grandpa, can you make a sound like a frog? Grandpa: I suppose so sweetheart. Why do you want me to make a sound like a frog? ' Little girl: Because Mum said that when you croak, we're going to Disneyland." }, 86 | { "joke": "Mother: Why are you home from school so early? Son: I was the only one in the class who could answer a question. Mother: Oh, really? What was the question? Son: Who threw the rubber at the headmaster?" }, 87 | { "joke": "A man's credit card was stolen but he decided not to report it because the thief was spending less than his wife did." }, 88 | { "joke": "A newly-wed couple had recently opened a joint bank account. 'Darling', said the man. 'The bank has returned that cheque you wrote last week. Great', said the woman. 'What shall I spend it on next? '" }, 89 | { "joke": "A man goes into a fish and chip shop and orders fish and chips twice. The shop owner says, 'I heard you the first time.'" }, 90 | { "joke": "A tramp approached a well-dressed man. 'Ten pence for a cup of tea, Guv? ' He asked. The man gave him the money and after for five minutes said, 'So where's my cup of tea then? '" }, 91 | { "joke": "A neutron walks into a pub. 'I'd like a beer', he says. The landlord promptly serves him a beer. 'How much will that be? ' asks the neutron. For you? ' replies the landlord, 'No charge.'" }, 92 | { "joke": "A woman goes to the doctor and says, 'Doctor, my husband limps because his left leg is an inch shorter than his right leg. What would you do in his case? Probably limp, too', says the doc." }, 93 | { "joke": "Three monks are meditating in the Himalayas. One year passes in silence, and one of them says to the other, 'Pretty cold up here isn't it? ' Another year passes and the second monk says, 'You know, you are quite right.' Another year passes and the third monk says, 'Hey, I'm going to leave unless you two stop jabbering!'" }, 94 | { "joke": "A murderer, sitting in the electric chair, was about to be executed. 'Have you any last requests? ' asked the prison guard. Yes', replied the murderer. 'Will you hold my hand? '" }, 95 | { "joke": "A highly excited man rang up for an ambulance. 'Quickly, come quickly', he shouted, 'My wife's about to have a baby. Is this her first baby? ' asked the operator. No, you fool', came the reply, 'It's her husband.'" }, 96 | { "joke": "A passer-by spots a fisherman by a river. 'Is this a good river for fish? ' he asks. Yes', replies the fisherman, 'It must be. I can't get any of them to come out.'" }, 97 | { "joke": "A man went to visit a friend and was amazed to find him playing chess with his dog. He watched the game in astonishment for a while. 'I can hardly believe my eyes!' he exclaimed. 'That's the smartest dog I've ever seen.' His friend shook his head. 'Nah, he's not that bright. I beat him three games in five.'" }, 98 | { "joke": "A termite walks into a pub and says, 'Is the bar tender here? '" }, 99 | { "joke": "A skeleton walks into a pub one night and sits down on a stool. The landlord asks, 'What can I get you? ' The skeleton says, 'I'll have a beer, thanks' The landlord passes him a beer and asks 'Anything else? ' The skeleton nods. 'Yeah...a mop...'" }, 100 | { "joke": "A snake slithers into a pub and up to the bar. The landlord says, 'I'm sorry, but I can't serve you. What? Why not? ' asks the snake. Because', says the landlord, 'You can't hold your drink.'" }, 101 | { "joke": "Descartes walks into a pub. 'Would you like a beer sir? ' asks the landlord politely. Descartes replies, 'I think not' and ping! he vanishes." }, 102 | { "joke": "A cowboy walked into a bar, dressed entirely in paper. It wasn't long before he was arrested for rustling." }, 103 | { "joke": "A fish staggers into a bar. 'What can I get you? ' asks the landlord. The fish croaks 'Water...'" }, 104 | { "joke": "Two vampires walked into a bar and called for the landlord. I'll have a glass of blood', said one. I'll have a glass of plasma', said the other. Okay', replied the landlord, 'That'll be one blood and one blood lite.'" }, 105 | { "joke": "How many existentialists does it take to change a light bulb? Two. One to screw it in, and one to observe how the light bulb itself symbolises a single incandescent beacon of subjective reality in a netherworld of endless absurdity, reaching towards the ultimate horror of a maudlin cosmos of bleak, hostile nothingness." }, 106 | { "joke": "A team of scientists were nominated for the Nobel Prize. They had used dental equipment to discover and measure the smallest particles yet known to man. They became known as 'The Graders of the Flossed Quark...'" }, 107 | { "joke": "A truck carrying copies of Roget's Thesaurus overturned on the highway. The local newspaper reported that onlookers were 'stunned, overwhelmed, astonished, bewildered and dumbfounded.'" }, 108 | { "joke": "'My wife is really immature. It's pathetic. Every time I take a bath, she comes in and sinks all my little boats.'" }, 109 | { "joke": "'How much will it cost to have the tooth extracted? ' asked the patient. '50 pounds', replied the dentist. '50 pounds for a few moments' work? !' asked the patient. 'The dentist smiled, and replied, 'Well, if you want better value for money, I can extract it very, very slowly...'" }, 110 | { "joke": "A doctor thoroughly examined his patient and said, 'Look I really can't find any reason for this mysterious affliction. It's probably due to drinking.' The patient sighed and snapped, 'In that case, I'll come back when you're damn well sober!'" }, 111 | { "joke": "Doctor: Tell me nurse, how is that boy doing; the one who ate all those 5p pieces? Nurse: Still no change doctor." }, 112 | { "joke": "Doctor: Did you take the patient's temperature nurse? Nurse: No doctor. Is it missing?" }, 113 | { "joke": "A depressed man turned to his friend in the pub and said, 'I woke up this morning and felt so bad that I tried to kill myself by taking 50 aspirin. Oh man, that's really bad', said his friend, 'What happened? ' The first man sighed and said, 'After the first two, I felt better.'" }, 114 | { "joke": "A famous blues musician died. His tombstone bore the inscription, 'Didn't wake up this morning...'" }, 115 | { "joke": "A businessman was interviewing a nervous young woman for a position in his company. He wanted to find out something about her personality, so he asked, 'If you could have a conversation with someone living or dead, who would it be? ' The girl thought about the question: 'The living one', she replied." }, 116 | { "joke": "Manager to interviewee: For this job we need someone who is responsible. Interviewee to Manager: I'm your man then - in my last job, whenever anything went wrong, I was responsible." }, 117 | { "joke": "A businessman turned to a colleague and asked, 'So, how many people work at your office? ' His friend shrugged and replied, 'Oh about half of them.'" }, 118 | { "joke": "'How long have I been working at that office? As a matter of fact, I've been working there ever since they threatened to sack me.'" }, 119 | { "joke": "In a courtroom, a mugger was on trial. The victim, asked if she recognised the defendant, said, 'Yes, that's him. I saw him clear as day. I'd remember his face anywhere.' Unable to contain himself, the defendant burst out with, 'She's lying! I was wearing a mask!'" }, 120 | { "joke": "As Sid sat down to a big plate of chips and gravy down the local pub, a mate of his came over and said, 'Here Sid, me old pal. I thought you were trying to get into shape? And here you are with a high-fat meal and a pint of stout!' Sid looked up and replied, 'I am getting into shape. The shape I've chosen is a sphere.'" }, 121 | { "joke": "Man in pub: How much do you charge for one single drop of whisky? Landlord: That would be free sir. Man in pub: Excellent. Drip me a glass full." }, 122 | { "joke": "I once went to a Doctor Who restaurant. For starters I had Dalek bread." }, 123 | { "joke": "A restaurant nearby had a sign in the window which said 'We serve breakfast at any time', so I ordered French toast in the Renaissance." }, 124 | { "joke": "I phoned up the builder's yard yesterday. I said, 'Can I have a skip outside my house? '. The builder said, 'Sure. Do what you want. It's your house.'" }, 125 | { "joke": "What's the diference between a sock and a camera? A sock takes five toes and a camera takes four toes!" }, 126 | { "joke": "Woman on phone: I'd like to complain about these incontinence pants I bought from you! Shopkeeper: Certainly madam, where are you ringing from? Woman on phone: From the waist down!" }, 127 | { "joke": "Knock knock." }, 128 | { "joke": "Two Oranges in a pub, one says to the other 'Your round.'." }, 129 | { "joke": "Guy : 'Doc, I've got a cricket ball stuck up my backside.' Doc : 'How's that? ' Guy : 'Don't you start...'" }, 130 | { "joke": "Two cows standing in a field. One turns to the other and says 'Moo!' The other one says 'Damn, I was just about to say that!'." }, 131 | { "joke": "A vampire bat arrives back at the roost with his face full of blood. All the bats get excited and ask where he got it from. Follow me', he says and off they fly over hills, over rivers and into a dark forest. See that tree over there', he says. WELL I DIDN'T!!'." }, 132 | { "joke": "A man goes into a bar and orders a pint. After a few minutes he hears a voice that says, 'Nice shoes'. He looks around but the whole bar is empty apart from the barman at the other end of the bar. A few minutes later he hears the voice again. This time it says, 'I like your shirt'. He beckons the barman over and tells him what's been happening to which the barman replies, 'Ah, that would be the nuts sir. They're complimentary'!" }, 133 | { "joke": "A man was siting in a restaurant waiting for his meal when a big king prawn comes flying across the room and hits him on the back of the head. He turns around and the waiter said, 'That's just for starters'." }, 134 | { "joke": "Doctor! I have a serious problem, I can never remember what i just said. When did you first notice this problem? What problem?" }, 135 | { "joke": "Now, most dentist's chairs go up and down, don't they? The one I was in went back and forwards. I thought, 'This is unusual'. Then the dentist said to me, 'Mitsuku, get out of the filing cabinet'." }, 136 | { "joke": "I was reading this book, 'The History of Glue'. I couldn't put it down." }, 137 | { "joke": "The other day someone left a piece of plastacine in my bedroom. I didn't know what to make of it." }, 138 | { "joke": "When I was at school people used to throw gold bars at me. I was the victim of bullion." }, 139 | { "joke": "I was playing the piano in a bar and this elephant walked in and started crying his eyes out. I said 'Do you recognise the tune?' He said 'No, I recognise the ivory.'" }, 140 | { "joke": "I went in to a pet shop. I said, 'Can I buy a goldfish?' The guy said, 'Do you want an aquarium?' I said, 'I don't care what star sign it is.'" }, 141 | { "joke": "My mate Sid was a victim of I.D. theft. Now we just call him S." }, 142 | { "joke": "David Hasselhoff walks into a bar and says to the barman, 'I want you to call me David Hoff'. The barman replies 'Sure thing Dave... no hassle'" }, 143 | { "joke": "Chuck Norris makes onions cry." }, 144 | { "joke": "Chuck Norris can delete the Recycling Bin." }, 145 | { "joke": "Bill Gates lives in constant fear that Chuck Norris' PC will crash." }, 146 | { "joke": "Ghosts are actually caused by Chuck Norris killing people faster than Death can process them." }, 147 | { "joke": "Chuck Norris can build a snowman out of rain." }, 148 | { "joke": "Chuck Norris can strangle you with a cordless phone." }, 149 | { "joke": "Chuck Norris can drown a fish." }, 150 | { "joke": "Chuck Norris can play the violin with a piano" }, 151 | { "joke": "When Chuck Norris enters a room, he doesn't turn the lights on, he turns the dark off." }, 152 | { "joke": "Chuck Norris once had a heart attack; his heart lost." }, 153 | { "joke": "When Chuck Norris looks in a mirror the mirror shatters, because not even glass is stupid enough to get in between Chuck Norris and Chuck Norris." }, 154 | { "joke": "Brett Favre can throw a football over 50 yards. Chuck Norris can throw Brett Favre even further." }, 155 | { "joke": "The last digit of pi is Chuck Norris. He is the end of all things." }, 156 | { "joke": "Chuck Norris does not know where you live, but he knows where you will die." }, 157 | { "joke": "Bullets dodge Chuck Norris." }, 158 | { "joke": "A Handicap parking sign does not signify that this spot is for handicapped people. It is actually in fact a warning, that the spot belongs to Chuck Norris and that you will be handicapped if you park there." }, 159 | { "joke": "Chuck Norris' calendar goes straight from March 31st to April 2nd, no one fools Chuck Norris." }, 160 | { "joke": "If you spell Chuck Norris wrong on Google it doesn't say, 'Did you mean Chuck Norris?' It simply replies, 'Run while you still have the chance.'" }, 161 | { "joke": "Chuck Norris can do a wheelie on a unicycle." }, 162 | { "joke": "Once a cobra bit Chuck Norris' leg. After five days of excruciating pain, the cobra died." }, 163 | { "joke": "When Chuck Norris gives you the finger, he's telling you how many seconds you have left to live." }, 164 | { "joke": "Chuck Norris doesn't have hair on his testicles, because hair does not grow on steel." }, 165 | { "joke": "Chuck Norris can kill two stones with one bird." }, 166 | { "joke": "Chuck Norris was once on Celebrity Wheel of Fortune and was the first to spin. The next 29 minutes of the show consisted of everyone standing around awkwardly, waiting for the wheel to stop." }, 167 | { "joke": "Leading hand sanitizers claim they can kill 99.9 percent of germs. Chuck Norris can kill 100 percent of whatever he wants." }, 168 | { "joke": "There is no such thing as global warming. Chuck Norris was cold, so he turned the sun up." }, 169 | { "joke": "Chuck Norris can set ants on fire with a magnifying glass. At night." }, 170 | { "joke": "It takes Chuck Norris 20 minutes to watch 60 Minutes." }, 171 | { "joke": "In an average living room there are 1,242 objects Chuck Norris could use to kill you, including the room itself." }, 172 | { "joke": "Behind every successful man, there is a woman. Behind every dead man, there is Chuck Norris." }, 173 | { "joke": "Chuck Norris destroyed the periodic table, because Chuck Norris only recognizes the element of surprise." }, 174 | { "joke": "Chuck Norris got his drivers license at the age of 16 Seconds." }, 175 | { "joke": "With the rising cost of gasoline, Chuck Norris is beginning to worry about his drinking habit." }, 176 | { "joke": "The square root of Chuck Norris is pain. Do not try to square Chuck Norris, the result is death." } 177 | ] 178 | -------------------------------------------------------------------------------- /script/LANGUAGES.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Matthew is a C/C++ expert with a strong grasp on Java, Perl, Python, JavaScript, JSP, and PHP. He dabbles in Objective-C, Swift, Node and Scala.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Education", 7 | "payload":"Education" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Software", 12 | "payload":"Software" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Languages", 17 | "payload":"Languages" 18 | }, 19 | { 20 | "content_type":"text", 21 | "title":"Architecture", 22 | "payload":"Architecture" 23 | }, 24 | { 25 | "content_type":"text", 26 | "title":"Home", 27 | "payload":"Home" 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /script/MARKETING.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "A bot is a great way to communicate business information to your potential clients. The bot can give then options about information, for example a class schedule at a Yoga studio. Further, a user can opt-in for more target information, for example a city could have bot notify users of upcoming local events.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Get started!", 7 | "payload":"contact" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Home", 12 | "payload":"Home" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /script/RECRUITERS.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Thanks for your interest. Matthew is fully engaged currently. Feel free to contact him with highend opportunities however.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Contact", 7 | "payload":"Contact" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Maybe later", 12 | "payload":"home" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /script/ROBOT.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "template", 4 | "payload": { 5 | "template_type": "button", 6 | "text": "This bot is a mashup of Facebook, Heroku, GitHub, JavaScript and JSON. You can make your own with no coding! This bot is partly based on an example bot by Esther Crawford and team. See Github for the code", 7 | "buttons":[ 8 | { 9 | "type": "web_url", 10 | "url": "https://www.messenger.com/t/helloestherbot", 11 | "title": "Esther's Robot" 12 | }, 13 | { 14 | "type": "web_url", 15 | "url": "https://github.com/matthewericfisher/fb-robot", 16 | "title": "Matthew's Robot source" 17 | }, 18 | { 19 | "type": "postback", 20 | "title": "Home", 21 | "payload": "home" 22 | } 23 | 24 | ] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /script/SALES.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "A bot can display your merchandise and even take payments. A bot can be a whole new sales channel for your business!", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Get started!", 7 | "payload":"contact" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Home", 12 | "payload":"Home" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /script/SENDMESSAGE.json: -------------------------------------------------------------------------------- 1 | { 2 | "text":"Please type a message to Matthew:" 3 | } 4 | -------------------------------------------------------------------------------- /script/SOCIAL.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "template", 4 | "payload": { 5 | "template_type": "generic", 6 | "elements": [ 7 | { 8 | "title": "LinkedIn", 9 | "item_url": "https://www.linkedin.com/in/matthewericfisher", 10 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/linkedin.png" 11 | }, 12 | { 13 | "title": "Medium", 14 | "item_url": "https://medium.com/@matthewericfisher", 15 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/medium.png" 16 | }, 17 | { 18 | "title": "StackOverflow", 19 | "item_url": "http://stackoverflow.com/users/6577680/matthew-fisher?tab=profile", 20 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/so-logo.png" 21 | }, 22 | { 23 | "title": "Tumblr", 24 | "item_url": "https://matthewericfisher.tumblr.com", 25 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/tumblr.png" 26 | }, 27 | { 28 | "title": "YouTube", 29 | "item_url": "https://www.youtube.com/user/MemoryLeakDMS", 30 | "image_url": "https://raw.githubusercontent.com/matthewericfisher/fb-robot/master/img/youtube.png" 31 | } 32 | ] 33 | } 34 | } 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /script/SOFTWARE.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Matthew has a passion for Software Engineering in all its phases. He has developed a strategy termed Effective Software Engineering. Click below to learn more about Effective Software Engineerining or hop over to the Tumblr blog", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Why Effective?", 7 | "payload":"EFFECTIVE" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"We need it!", 12 | "payload":"contact" 13 | }, 14 | { 15 | "content_type":"text", 16 | "title":"Home", 17 | "payload":"Home" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /script/SUPPORT.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "A customer support bot will be the standard in the coming years. The bot can guide your clients to the proper with a minimum of fuss. Support costs will be reduced along with client wait times.", 3 | "quick_replies": [ 4 | { 5 | "content_type":"text", 6 | "title":"Get started!", 7 | "payload":"contact" 8 | }, 9 | { 10 | "content_type":"text", 11 | "title":"Home", 12 | "payload":"Home" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /script/THUMBS.json: -------------------------------------------------------------------------------- 1 | { 2 | "attachment": { 3 | "type": "image", 4 | "payload": { 5 | "url": "https://scontent.xx.fbcdn.net/t39.1997-6/851557_369239266556155_759568595_n.png?_nc_ad=z-m" 6 | } 7 | } 8 | } 9 | 10 | 11 | --------------------------------------------------------------------------------