├── .gitattributes ├── Chapter01 ├── .gitignore ├── app.js ├── iisnode.yml └── package.json ├── Chapter02 ├── .gitignore ├── app.js ├── iisnode.yml └── package.json ├── Chapter03 ├── app.js └── package.json ├── Chapter04 ├── app.js └── package.json ├── Chapter05 ├── app.js └── package.json ├── Chapter06 ├── app.js.txt └── package.json ├── Chapter07 ├── server.js.txt └── utils.js.txt ├── Chapter08 ├── app.js.txt └── package.json ├── Chapter09 └── server.js.txt ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /Chapter01/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | azure.err 3 | *.publishsettings -------------------------------------------------------------------------------- /Chapter01/app.js: -------------------------------------------------------------------------------- 1 | var twilio = require("twilio"); 2 | var express = require('express'); 3 | 4 | var accountSid = '<< Your Twilio Account SID >>'; // Your Account SID from www.twilio.com/console 5 | var authToken = '<< Your Twilio Auth Token >>'; // Your Auth Token from www.twilio.com/console 6 | 7 | var client = new twilio.RestClient(accountSid, authToken); 8 | var app = express(); 9 | 10 | app.post('/receive', function (request, response) { 11 | var twiml = new twilio.TwimlResponse(); 12 | twiml.message(request.body.From); 13 | 14 | response.writeHead(200, {'Content-Type': 'text/xml'}); 15 | response.end(twiml.toString()); 16 | }); 17 | 18 | app.get('/send', function (req, res) { 19 | client.messages.create({ 20 | body: 'Hi, this is TwilioBot', 21 | to: '+14806000000', // Text this number - please replace with your own 22 | from: '+14805000000' // From a valid Twilio number - please replace with your own 23 | }, function(err, message) { 24 | res.send('This is the message id sent: ' + message.sid); 25 | }); 26 | }); 27 | 28 | app.listen(process.env.port, function () { 29 | console.log('TwilioBot listening...'); 30 | }); 31 | -------------------------------------------------------------------------------- /Chapter01/iisnode.yml: -------------------------------------------------------------------------------- 1 | # For documentation see https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/iisnode.yml 2 | 3 | # loggingEnabled: false 4 | # debuggingEnabled: false 5 | # devErrorsEnabled: false 6 | # node_env: production 7 | # nodeProcessCountPerApplication: 1 8 | # maxConcurrentRequestsPerProcess: 1024 9 | # maxNamedPipeConnectionRetry: 24 10 | # namedPipeConnectionRetryDelay: 250 11 | # maxNamedPipeConnectionPoolSize: 512 12 | # maxNamedPipePooledConnectionAge: 30000 13 | # asyncCompletionThreadCount: 0 14 | # initialRequestBufferSize: 4096 15 | # maxRequestBufferSize: 65536 16 | # watchedFiles: *.js;iisnode.yml;node_modules\* 17 | # uncFileChangesPollingInterval: 5000 18 | # gracefulShutdownTimeout: 60000 19 | # logDirectoryNameSuffix: logs 20 | # debuggerPortRange: 5058-6058 21 | # debuggerPathSegment: debug 22 | # maxLogFileSizeInKB: 128 23 | # appendToExistingLog: false 24 | # logFileFlushInterval: 5000 25 | # flushResponse: false 26 | # enableXFF: false 27 | # promoteServerVars: -------------------------------------------------------------------------------- /Chapter01/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package", 3 | "version": "1.0.0", 4 | "description": "TwilioSmsBot", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Ed Freitas", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "^4.13.4", 13 | "twilio": "^2.9.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter02/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | azure.err 3 | *.publishsettings -------------------------------------------------------------------------------- /Chapter02/app.js: -------------------------------------------------------------------------------- 1 | var skype = require('botbuilder'); 2 | var express = require('express'); 3 | var azure = require('azure-storage'); 4 | 5 | var app = express(); 6 | 7 | var APP_ID = ''; 8 | var APP_SECRET = ''; 9 | 10 | var AZURE_ACCOUNT = ''; 11 | var AZURE_KEY = ''; 12 | var AZURE_TABLE = 'HolidaysHRBot'; 13 | 14 | var tableSvc = azure.createTableService(AZURE_ACCOUNT, AZURE_KEY); 15 | 16 | var authenticated = false; 17 | var holidays = false; 18 | var sick = false; 19 | var userId = ''; 20 | var userName = ''; 21 | var userEntity = undefined; 22 | 23 | var botService = new skype.ChatConnector({ 24 | appId: APP_ID, 25 | appPassword: APP_SECRET 26 | }); 27 | 28 | var bot = new skype.UniversalBot(botService); 29 | 30 | app.post('/api/messages', botService.listen()); 31 | 32 | userVerification = function(session) { 33 | session.send('Hey, let me verify your user id ' + userId + ' (' + userName + '), bear with me...'); 34 | 35 | tableSvc.retrieveEntity(AZURE_TABLE, userId, userName, function entityQueried(error, entity) { 36 | if (!error) { 37 | authenticated = true; 38 | userEntity = entity; 39 | 40 | session.send('I have verified your id, how can I help you? Type a) for Holidays, b) for Sick Leave.'); 41 | } 42 | else { 43 | session.send('Could not find: ' + userName + ', please make sure you use proper casing :)'); 44 | } 45 | }); 46 | }; 47 | 48 | cleanUserId = function(userId) { 49 | var posi = userId.indexOf(':'); 50 | return (posi > 0) ? userId.substring(posi + 1) : userId; 51 | }; 52 | 53 | BotBrain = function(session) { 54 | var orig = session.message.text; 55 | var content = orig.toLowerCase(); 56 | var from = session.message.user.name; 57 | 58 | if (authenticated) { 59 | if (content === 'a)') { 60 | holidays = true; 61 | session.send('Please indicate how many vacation days you will be requesting, i.e.: 3'); 62 | } 63 | else if (content === 'b)') { 64 | sick = true; 65 | session.send('Please indicate how many sick days you will be requesting, i.e.: 2'); 66 | } 67 | else if (content !== 'a)' && content !== 'b)') { 68 | if (holidays) { 69 | session.send(userName + '(' + userId + ')' + ', you have chosen to take ' + content + ' holiday(s). Session ended.'); 70 | sick = false; 71 | authenticated = false; 72 | } 73 | else if (sick) { 74 | session.send(userName + '(' + userId + ')' + ', you have chosen to take ' + content + ' sick day(s). Session ended.'); 75 | holidays = false; 76 | authenticated = false; 77 | } 78 | else if (!holidays && !sick) { 79 | session.send('I can only process vacation or sick leave requests. Please try again.'); 80 | } 81 | } 82 | } 83 | else { 84 | authenticated = false, holidays = false, sick = false; 85 | userId = '', userName = '', userEntity = undefined; 86 | 87 | if (content === 'hi') { 88 | session.send('Hello ' + cleanUserId(from) + ', I shall verify your identify...'); 89 | session.send('Can you please your provide your FirstName-LastName? (please use the - between them)'); 90 | } 91 | else if (content !== '') { 92 | userId = cleanUserId(from); 93 | userName = orig; 94 | 95 | if (userName.indexOf('-') > 1) { 96 | userVerification(session); 97 | } 98 | else { 99 | session.send('Hi, please provide your FirstName-LastName (please use the - between them) or say hi :)'); 100 | } 101 | } 102 | } 103 | }; 104 | 105 | bot.dialog('/', function (session) { 106 | BotBrain(session); 107 | }); 108 | 109 | app.get('/', function (req, res) { 110 | res.send('SkypeBot listening...'); 111 | }); 112 | 113 | //app.listen(3979, function () { 114 | app.listen(process.env.port, function () { 115 | console.log('SkypeBot listening...'); 116 | }); 117 | -------------------------------------------------------------------------------- /Chapter02/iisnode.yml: -------------------------------------------------------------------------------- 1 | # For documentation see https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/iisnode.yml 2 | 3 | # loggingEnabled: false 4 | # debuggingEnabled: false 5 | # devErrorsEnabled: false 6 | # node_env: production 7 | # nodeProcessCountPerApplication: 1 8 | # maxConcurrentRequestsPerProcess: 1024 9 | # maxNamedPipeConnectionRetry: 24 10 | # namedPipeConnectionRetryDelay: 250 11 | # maxNamedPipeConnectionPoolSize: 512 12 | # maxNamedPipePooledConnectionAge: 30000 13 | # asyncCompletionThreadCount: 0 14 | # initialRequestBufferSize: 4096 15 | # maxRequestBufferSize: 65536 16 | # watchedFiles: *.js;iisnode.yml;node_modules\* 17 | # uncFileChangesPollingInterval: 5000 18 | # gracefulShutdownTimeout: 60000 19 | # logDirectoryNameSuffix: logs 20 | # debuggerPortRange: 5058-6058 21 | # debuggerPathSegment: debug 22 | # maxLogFileSizeInKB: 128 23 | # appendToExistingLog: false 24 | # logFileFlushInterval: 5000 25 | # flushResponse: false 26 | # enableXFF: false 27 | # promoteServerVars: -------------------------------------------------------------------------------- /Chapter02/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "skypebot", 3 | "version": "1.0.0", 4 | "description": "A Skype HR Bot", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Ed Freitas", 10 | "license": "ISC", 11 | "dependencies": { 12 | "azure-storage": "^1.0.1", 13 | "botbuilder": "^3.4.4", 14 | "express": "^4.13.4" 15 | }, 16 | "engines": { 17 | "node": ">=5.6.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Chapter03/app.js: -------------------------------------------------------------------------------- 1 | var TwitterPackage = require('twitter'); 2 | var secret = require("./secret"); 3 | var Twitter = new TwitterPackage(secret); 4 | var request = require('request'); 5 | 6 | padLeft = function (str, paddingChar, length) { 7 | var s = new String(str); 8 | 9 | if ((str.length < length) && (paddingChar.toString().length > 0)) 10 | { 11 | for (var i = 0; i < (length - str.length) ; i++) 12 | s = paddingChar.toString().charAt(0).concat(s); 13 | } 14 | 15 | return s; 16 | }; 17 | 18 | GetDate = function() { 19 | var dateObj = new Date(); 20 | var month = dateObj.getUTCMonth() + 1; //months from 1-12 21 | var day = dateObj.getUTCDate(); 22 | var year = dateObj.getUTCFullYear(); 23 | 24 | return year + '-' + padLeft(month.toString(), '0', 2) + '-' + padLeft(day.toString(), '0', 2); 25 | }; 26 | 27 | FlightNumberOk = function(str) { 28 | var posi = str.indexOf('KL'); 29 | var fn = str.substring(posi); 30 | return (posi >= 0 && fn.length === 6) ? fn : ''; 31 | }; 32 | 33 | var fd = ''; 34 | 35 | GetFlightDetails = function(fn) { 36 | var dt = GetDate(); 37 | var rq = 'http://fox.klm.com/fox/json/flightstatuses?flightNumber=' + fn + '&departureDate=' + dt; 38 | 39 | request(rq, function (error, response, body) { 40 | if (!error && response.statusCode == 200) { 41 | fd = body; 42 | } 43 | }) 44 | }; 45 | 46 | Twitter.stream('statuses/filter', {track: '#FlightBot'}, function(stream) { 47 | 48 | stream.on('data', function(tweet) { 49 | var statusObj = {status: "Hi @" + tweet.user.screen_name + ", Thanks for reaching out. We are missing the flight number."}; 50 | 51 | var fn = FlightNumberOk(tweet.text); 52 | 53 | if (fn !== '') { 54 | GetFlightDetails(fn); 55 | } 56 | 57 | setTimeout(function() { 58 | console.log ('fd: ' + fd); 59 | 60 | if (fd !== undefined) { 61 | var ff = JSON.parse(fd); 62 | statusObj = {status: "scheduledArrivalDateTime: " + ff.flights[0].operatingFlightLeg.scheduledArrivalDateTime}; 63 | } 64 | 65 | Twitter.post('statuses/update', statusObj, function(error, tweetReply, response) { 66 | if (error){ 67 | console.log(error); 68 | } 69 | console.log(tweetReply.text); 70 | }); 71 | }, 1500); 72 | }); 73 | 74 | stream.on('error', function(error) { 75 | console.log(error); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /Chapter03/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "package", 3 | "version": "1.0.0", 4 | "description": "FlightBot", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Ed Freitas", 10 | "license": "ISC", 11 | "dependencies": { 12 | "request": "^2.75.0", 13 | "twitter": "^1.4.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter04/app.js: -------------------------------------------------------------------------------- 1 | var Bot = require('slackbots'); 2 | var rq = require('request'); 3 | 4 | var token = ''; 5 | 6 | var settings = { 7 | token: '', 8 | name: 'quotebot' 9 | }; 10 | 11 | var bot = new Bot(settings); 12 | 13 | isChatMsg = function (msg) { 14 | return msg.type === 'message'; 15 | }; 16 | 17 | isFromQuoteBot = function (msg) { 18 | return msg.username === 'quotebot'; 19 | }; 20 | 21 | isMentioningQuote = function (msg) { 22 | return msg.text.toLowerCase().indexOf('getquote') > -1; 23 | }; 24 | 25 | replyWithRandomQuote = function (bot, oMsg) { 26 | var options = { 27 | url: 'https://theysaidso.p.mashape.com/quote?query=software', 28 | headers: { 29 | 'User-Agent': 'request', 30 | 'X-Mashape-Key': token 31 | } 32 | }; 33 | 34 | rq(options, function (error, response, body) { 35 | 36 | if (!error && response.statusCode == 200) { 37 | bot.postMessageToChannel(bot.channels[0].name, body); 38 | } 39 | }) 40 | }; 41 | 42 | bot.on('message', function (msg) { 43 | if (isChatMsg(msg) && 44 | !isFromQuoteBot(msg) && 45 | isMentioningQuote(msg)) { 46 | replyWithRandomQuote(bot, msg); 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /Chapter04/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quotebot", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Ed Freitas", 10 | "license": "ISC", 11 | "dependencies": { 12 | "request": "^2.76.0", 13 | "slackbots": "^0.5.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter05/app.js: -------------------------------------------------------------------------------- 1 | var telegramBot = require('node-telegram-bot-api'); 2 | var sentiment = require('sentiment'); 3 | 4 | var token ='267449059:AAGzHJFlDkzOG5SxyOJJT2yHsiC06Ut6ySE'; 5 | 6 | var api = new telegramBot(token, {polling: true}); 7 | 8 | api.onText(/\/help/, function(msg, match) { 9 | var fromId = msg.from.id; 10 | api.sendMessage(fromId, "I can help you in getting the sentiments of any text you send to me."); 11 | }); 12 | 13 | api.onText(/\/start/, function(msg, match) { 14 | var fromId = msg.from.id; 15 | api.sendMessage(fromId, "They call me MadansFirstTelegramBot. " + 16 | "I can help you in getting the sentiments of any text you send to me. "+ 17 | "To help you i just have few commands.\n/help\n/start\n/sentiments"); 18 | }); 19 | 20 | var opts = { 21 | reply_markup: JSON.stringify( 22 | { 23 | force_reply: true 24 | } 25 | )}; 26 | 27 | api.onText(/\/sentiments/, function(msg, match) { 28 | var fromId = msg.from.id; 29 | api.sendMessage(fromId, "Alright! So you need sentiments of a text from me. "+ 30 | "I can help you in that. Just send me the text.", opts) 31 | .then(function (sended) { 32 | var chatId = sended.chat.id; 33 | var messageId = sended.message_id; 34 | api.onReplyToMessage(chatId, messageId, function (message) { 35 | //call a function to get sentiments here... 36 | var sentival = sentiment(message.text); 37 | api.sendMessage(fromId,"So sentiments for your text are, Score:" + sentival.score +" Comparative:"+sentival.comparative); 38 | }); 39 | }); 40 | 41 | }); 42 | 43 | 44 | console.log("MadansFirstTelegramBot has started. Start conversations in your Telegram."); 45 | 46 | -------------------------------------------------------------------------------- /Chapter05/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telegrambot", 3 | "version": "1.0.0", 4 | "description": "\"A Telegram Bot for Sentiment Analysis\"", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Madan Bhintade", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "^4.14.0", 13 | "sentiment": "^2.0.0" 14 | }, 15 | "engines": { 16 | "node": ">=5.6.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Chapter06/app.js.txt: -------------------------------------------------------------------------------- 1 | var Botkit = require('Botkit'); 2 | var os = require('os'); 3 | 4 | var mongojs = require('mongojs'); 5 | var db = mongojs('127.0.0.1:27017/BotDB',['ReferenceDocuments']); 6 | 7 | var controller = Botkit.slackbot({ 8 | debug: false 9 | }); 10 | 11 | var bot = controller.spawn({ 12 | token: "xoxb-93316802544-VsDuvHwRiPgxppomh0nxazdE" 13 | }).startRTM(); 14 | 15 | 16 | controller.hears('hello',['direct_message','direct_mention','mention'],function(bot,message) { 17 | bot.reply(message,'Hello there!'); 18 | db.ReferenceDocuments.find({title:"Newsletter Template"},function (err, docs) { 19 | bot.reply(message,'I have a document with title:'+ docs[0].title); 20 | }) 21 | 22 | }); 23 | 24 | controller.hears(['docs','template','research documentation','documents'], 25 | ['direct_message','direct_mention','mention'],function(bot,message) { 26 | bot.startConversation(message, askForKeywords); 27 | }); 28 | 29 | askForKeywords = function(response, convo) { 30 | convo.ask("Pl. type the word or keywords for document search.", function(response, convo) { 31 | convo.say("Awesome! Wait for a moment. Will search documents for word(s) *" + response.text +"*"); 32 | searchDocuments(response, convo); 33 | convo.next(); 34 | }); 35 | } 36 | 37 | searchDocuments = function(response, convo) { 38 | //db.ReferenceDocuments.createIndex( { keywords: "text" } ) 39 | var qtext ="\""+response.text+"\""; 40 | db.ReferenceDocuments.find({$text:{$search:qtext}},{},{limit:3},function (err, docs) { 41 | var attachments = []; 42 | docs.forEach(function(d) { 43 | var attachment= { 44 | "title": d.title, 45 | "title_link": d.url, 46 | "text": d.description, 47 | "color": '#3AA3E3', 48 | "footer": "From Amazon S3 | Version " +d.version 49 | }; 50 | attachments.push(attachment); 51 | }); 52 | 53 | convo.say({ 54 | text: '*Document(s):*', 55 | attachments: attachments, 56 | }) 57 | }); 58 | } 59 | 60 | db.on('error', function (err) { 61 | console.log('Database error', err) 62 | }) 63 | 64 | db.on('connect', function () { 65 | console.log('Database connected') 66 | }) 67 | 68 | 69 | -------------------------------------------------------------------------------- /Chapter06/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "slackbot", 3 | "version": "1.0.0", 4 | "description": "A Slack Bot called DocMan for providing information and documents", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Madan Bhintade", 10 | "license": "ISC", 11 | "dependencies": { 12 | "botkit": "^0.4.0" 13 | }, 14 | "engines": { 15 | "node": ">=5.6.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter07/server.js.txt: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var bodyParser = require('body-parser'); 3 | var request = require('request'); 4 | var moment = require('moment'); 5 | var Guid = require('guid'); 6 | var utils = require('./utils.js'); 7 | 8 | var app = express(); 9 | 10 | app.use(bodyParser.json()); 11 | app.use(bodyParser.urlencoded({ extended: true })); 12 | 13 | var DocumentClient = require('documentdb').DocumentClient; 14 | var host = "https://botdb.documents.azure.com:443/"; 15 | var masterKey = "NpxDXr67utlhuknzEhRM5jWszGnBO8i9PkkdP78HVThx2DWhgCZyo2NZlVTzZWbkSSNJ1K7fRkNbCkgEkUHKgw=="; 16 | var docclient = new DocumentClient(host, { masterKey: masterKey }); 17 | 18 | var payloadm; 19 | 20 | app.get('/', function (req, res) { 21 | res.send('This is my Facebook Messenger Bot - Whos Off Bot Server'); 22 | }); 23 | 24 | // for facebook verification 25 | app.get('/webhook', function (req, res) { 26 | if (req.query['hub.verify_token'] === 'whosoffbot_verify_token') { 27 | res.status(200).send(req.query['hub.challenge']); 28 | } else { 29 | res.status(403).send('Invalid verify token'); 30 | } 31 | }); 32 | 33 | app.post('/webhook', function (req, res) { 34 | var tday; 35 | var events = req.body.entry[0].messaging; 36 | for (i = 0; i < events.length; i++) { 37 | var event = events[i]; 38 | 39 | if (event.message && event.message.text) { 40 | if (event.message.text.indexOf('hi') > -1) { 41 | sendMessageWithInitialOptions(event.sender.id); 42 | } 43 | else if (event.message.text.indexOf('@') > -1) { 44 | if (utils.isvalidateInput(event.message.text)) { 45 | sendMessage(event.sender.id, { 'text': 'Sure! Let me set up your meeting for '+payloadm }); 46 | if (payloadm=='Today'){ 47 | tday = moment().format("MM/DD/YYYY"); 48 | } 49 | else if (payloadm=='Tomorrow'){ 50 | tday = moment().add(1, 'day').format("MM/DD/YYYY"); 51 | } 52 | processMeetingDetails(event.message.text, tday + ' ', event.sender.id); 53 | } 54 | else { 55 | console.log('Invalid format!'); 56 | sendMessage(event.sender.id, { 'text': 'Pl. input meeting details e.g. Team Meeting@10:00to11:00' }); 57 | } 58 | } 59 | } 60 | else if (event.postback && event.postback.payload) { 61 | payload = event.postback.payload; 62 | // Handle a payload from this sender 63 | console.log(JSON.stringify(payload)); 64 | if (payload == 'SCHEDULE A MEETING') { 65 | sendMessageWithScheduleOptions(event.sender.id); 66 | } 67 | else if (payload == 'SCHEDULETODAY') { 68 | payloadm='Today'; 69 | sendMessage(event.sender.id, { 'text': 'Pl. provide meeting details e.g. Team Meeting@10:00to11:00' }); 70 | } 71 | else if (payload == 'SCHEDULETOMORROW') { 72 | payloadm='Tomorrow'; 73 | sendMessage(event.sender.id, { 'text': 'Pl. provide meeting details e.g. Team Meeting@10:00to11:00' }); 74 | } 75 | else if (payload=='WHOS OFF WHEN'){ 76 | sendMessageWithAllScheduleOptions(event.sender.id); 77 | } 78 | else if (payload == 'ALLSCHEDULETODAY') { 79 | sendMessage(event.sender.id, 'Meeting(s) Scheduled for Today as..'); 80 | var tilltonight = moment().add(1, 'day').startOf('day').unix(); 81 | var startnow = moment().unix(); 82 | showWhosIsBusyWhen(event.sender.id, startnow, tilltonight); 83 | } 84 | else if (payload == 'ALLSCHEDULETOMORROW') { 85 | sendMessage(event.sender.id, 'Meeting(s) Scheduled for tomorrow as..'); 86 | var tilltomnight = moment().add(2, 'day').startOf('day').unix(); 87 | var starttonight = moment().endOf('day').unix(); 88 | showWhosIsBusyWhen(event.sender.id, starttonight, tilltomnight); 89 | } 90 | } 91 | 92 | } 93 | res.sendStatus(200); 94 | }); 95 | 96 | function sendMessageWithInitialOptions(recipientId) { 97 | messageData = { 98 | 'attachment': { 99 | 'type': 'template', 100 | 'payload': { 101 | 'template_type': 'button', 102 | 'text': 'Pl. Select your options', 103 | 'buttons': [{ 104 | 'type': 'postback', 105 | 'title': 'Schedule a Meetting', 106 | 'payload': 'SCHEDULE A MEETING' 107 | }, { 108 | 'type': 'postback', 109 | 'title': 'Whos Off When', 110 | 'payload': 'WHOS OFF WHEN', 111 | }, { 112 | 'type': 'postback', 113 | 'title': 'My Schedule', 114 | 'payload': 'MY SCHEDULE' 115 | }] 116 | } 117 | } 118 | }; 119 | sendMessage(recipientId, messageData); 120 | }; 121 | 122 | function sendMessageWithScheduleOptions(recipientId) { 123 | messageData = { 124 | 'attachment': { 125 | 'type': 'template', 126 | 'payload': { 127 | 'template_type': 'button', 128 | 'text': 'Select day to schedule a meeting', 129 | 'buttons': [{ 130 | 'type': 'postback', 131 | 'title': 'Today', 132 | 'payload': 'SCHEDULETODAY' 133 | }, { 134 | 'type': 'postback', 135 | 'title': 'Tomorrow', 136 | 'payload': 'SCHEDULETOMORROW', 137 | }] 138 | } 139 | } 140 | }; 141 | sendMessage(recipientId, messageData); 142 | }; 143 | 144 | function processMeetingDetails(str, todaysdate, recipientId) { 145 | var title, stime, etime, starttime, endtime, ownername 146 | 147 | //parsing input provided for extracting meeting information 148 | title = str.substring(0, str.indexOf('@')); 149 | stime = str.substring(title.length + 1, str.indexOf('to')) + ':00'; 150 | etime = str.substring(str.indexOf('to') + 2, str.length) + ':00'; 151 | 152 | starttime = moment(todaysdate + stime).unix(); 153 | endtime = moment(todaysdate + etime).unix(); 154 | 155 | console.log(starttime + ' to ' + endtime + ' title' + title); 156 | //function to get Fb User Name 157 | utils.getUserName(recipientId, function (d) { 158 | ownername = d; 159 | var objMeeting = new utils.meeting(Guid.raw(), recipientId, ownername, starttime, endtime, title) 160 | CheckMeetingsIfExistsOrInsert(objMeeting); 161 | }); 162 | } 163 | 164 | function CheckMeetingsIfExistsOrInsert(objMeeting) { 165 | var querySpec = { 166 | query: 'SELECT * FROM Events b WHERE (b.ownerid= @id) and (@start between b.startdatetime and b.enddatetime)', 167 | parameters: [ 168 | { 169 | name: '@id', 170 | value: objMeeting.ownerid 171 | }, 172 | { 173 | name: '@start', 174 | value: objMeeting.startdatetime 175 | } 176 | ] 177 | }; 178 | 179 | docclient.queryDocuments('dbs/EventsDB/colls/Events', querySpec).toArray(function (err, results) { 180 | console.log(objMeeting.title); 181 | if (results.length === 0) { 182 | console.log('No data found' + objMeeting.title); 183 | var documentDefinition = { 184 | 'id': objMeeting.id, 185 | 'ownerid': objMeeting.ownerid, 186 | 'owner': objMeeting.owner, 187 | 'startdatetime': objMeeting.startdatetime, 188 | 'enddatetime': objMeeting.enddatetime, 189 | 'title': objMeeting.title 190 | }; 191 | docclient.createDocument('dbs/EventsDB/colls/Events', documentDefinition, function (err, document) { 192 | if (err) return console.log(err); 193 | console.log('Created A Meeting with id : ', document.id); 194 | sendMessage(objMeeting.ownerid, { 'text': 'Meeting has been scheduled.' }); 195 | }); 196 | } else { 197 | console.log('Data found'); 198 | sendMessage(objMeeting.ownerid, { 'text': 'Meeting exists for this schedule. Pl. schedule another time.' }); 199 | } 200 | }); 201 | } 202 | 203 | function sendMessageWithAllScheduleOptions(recipientId) { 204 | messageData = { 205 | 'attachment': { 206 | 'type': 'template', 207 | 'payload': { 208 | 'template_type': 'button', 209 | 'text': 'Select your schedule for', 210 | 'buttons': [{ 211 | 'type': 'postback', 212 | 'title': 'Today', 213 | 'payload': 'ALLSCHEDULETODAY' 214 | }, { 215 | 'type': 'postback', 216 | 'title': 'Tomorrow', 217 | 'payload': 'ALLSCHEDULETOMORROW', 218 | }] 219 | } 220 | } 221 | }; 222 | sendMessage(recipientId, messageData); 223 | }; 224 | 225 | function showWhosIsBusyWhen(recipientId,start, end) { 226 | var querySpec = { 227 | query: 'SELECT * FROM Events b WHERE b.startdatetime<= @end and b.startdatetime>= @start ORDER BY b.startdatetime', 228 | parameters: [ 229 | { 230 | name: '@end', 231 | value: end 232 | }, 233 | { 234 | name: '@start', 235 | value: start 236 | } 237 | ] 238 | }; 239 | docclient.queryDocuments('dbs/EventsDB/colls/Events', querySpec).toArray(function (err, results) { 240 | if (results.length > 0) { 241 | sendMessageWithMeetingsOwnerInList(recipientId, results) 242 | } 243 | }); 244 | } 245 | 246 | function sendMessageWithMeetingsOwnerInList(recipientId, results) { 247 | var card; 248 | var cards = []; 249 | var messageData; 250 | 251 | messageData = { 252 | attachment: { 253 | type: 'template', 254 | payload: { 255 | template_type: 'generic', 256 | elements: [] 257 | } 258 | } 259 | }; 260 | 261 | for (i = 0; i < results.length; i++) { 262 | card = { 263 | title: results[i].title, 264 | item_url: 'https://myorgmeetings.com/' + results[i].id, 265 | image_url: '', 266 | subtitle: 'Your confirmed meeting.', 267 | buttons: [ 268 | { 269 | type: 'web_url', 270 | url: 'https://myorgmeetings.com/' + results[i].id, 271 | title: utils.getFormattedDay(results[i].startdatetime) 272 | }, 273 | { 274 | type: 'web_url', 275 | url: 'https://myorgmeetings.com/' + results[i].id, 276 | title: results[i].owner 277 | }, 278 | { 279 | type: 'web_url', 280 | url: 'https://myorgmeetings.com/' + results[i].id, 281 | title: utils.getFormattedTime(results[i].startdatetime, results[i].enddatetime) 282 | } 283 | ] 284 | }; 285 | cards.push(card); 286 | } 287 | 288 | messageData.attachment.payload.elements = cards; 289 | sendMessage(recipientId, messageData); 290 | }; 291 | 292 | function sendMessage(recipientId, message) { 293 | request({ 294 | url: 'https://graph.facebook.com/v2.6/me/messages', 295 | qs: { access_token: 'EAAQo1ecZCQhUBAD1JQubPmkFtq5VVvfKwdeovOZCjog4QSadk7fZCgfGx8qx52H1H8ZBQ9SrgM3DGBJ8Ypux50T4Pj9ZCAAtinFda8SftZCIH32YjFuYdIuIxsLeSBCCInhK9czUe3RSETnPZCQjAeZAE55L65XcXe4DCnjkuVeYLcnQhKOWkaLK' }, 296 | method: 'POST', 297 | json: { 298 | recipient: { id: recipientId }, 299 | message: message, 300 | } 301 | }, function (error, response, body) { 302 | if (error) { 303 | console.log('Error sending message: ', error); 304 | } else if (response.body.error) { 305 | console.log('Error: ', response.body.error); 306 | } 307 | }); 308 | }; 309 | 310 | app.listen((process.env.PORT || 8080)); -------------------------------------------------------------------------------- /Chapter07/utils.js.txt: -------------------------------------------------------------------------------- 1 | //Test Meeting@11:00to12:00 2 | var moment = require('moment'); 3 | var https = require('https'); 4 | 5 | function isvalidateInput(str) { 6 | var pattern = /^\w+[a-z A-Z_]+?\@[0-9]{1,2}\:[0-9]{1,2}\w[to][0-9]{1,2}:[0-9]{1,2}$/; 7 | if (str.match(pattern) == null) { 8 | return false; 9 | } else { 10 | return true; 11 | } 12 | 13 | }; 14 | exports.isvalidateInput = isvalidateInput; 15 | 16 | function getFormattedTime(tsfrom, tsto) { 17 | var timeString = moment.unix(tsfrom).format("HH:mm") + ' - ' + moment.unix(tsto).format("HH:mm") 18 | return timeString; 19 | }; 20 | exports.getFormattedTime =getFormattedTime; 21 | 22 | function getFormattedDay(tsfrom) { 23 | var dateString = moment.unix(tsfrom).format("MMM, DD"); 24 | return dateString; 25 | }; 26 | exports.getFormattedDay =getFormattedDay; 27 | 28 | function meeting(id,recipientId,ownername,strstartdatetime,strenddatetime,strtitle){ 29 | this.id=id; 30 | this.ownerid=recipientId; 31 | this.owner=ownername; 32 | this.startdatetime=strstartdatetime; 33 | this.enddatetime=strenddatetime; 34 | this.title=strtitle; 35 | }; 36 | exports.meeting =meeting; 37 | 38 | function getUserName(uid,callback){ 39 | https.get("https://graph.facebook.com/v2.6/" + uid + "?fields=first_name,last_name&access_token=EAAQo1ecZCQhUBAD1JQubPmkFtq5VVvfKwdeovOZCjog4QSadk7fZCgfGx8qx52H1H8ZBQ9SrgM3DGBJ8Ypux50T4Pj9ZCAAtinFda8SftZCIH32YjFuYdIuIxsLeSBCCInhK9czUe3RSETnPZCQjAeZAE55L65XcXe4DCnjkuVeYLcnQhKOWkaLK", function(res) { 40 | var d = ''; 41 | var i; 42 | arr = []; 43 | res.on('data', function(chunk) { 44 | d += chunk; 45 | }); 46 | res.on('end', function() { 47 | var e = JSON.parse(d); 48 | callback(e.first_name); 49 | }); 50 | }); 51 | }; 52 | exports.getUserName =getUserName; 53 | 54 | -------------------------------------------------------------------------------- /Chapter08/app.js.txt: -------------------------------------------------------------------------------- 1 | var irc = require('irc'); 2 | var client = new irc.Client('irc.freenode.net', 'BugTrackerIRCBot', { 3 | autoConnect: false 4 | }); 5 | client.connect(5, function(serverReply) { 6 | console.log("Connected!\n", serverReply); 7 | client.join('#BugsChannel', function(input) { 8 | console.log("Joined #BugsChannel"); 9 | client.say('#BugsChannel', "Hi, there. I am an IRC Bot which track bugs or defects for your team.\n I can help you using following commands.\n BUGREPORT \n BUG # "); 10 | }); 11 | }); 12 | 13 | var DocumentClient = require('documentdb').DocumentClient; 14 | var host = "https://botdb.documents.azure.com:443/"; 15 | var masterKey = ""; 16 | var docclient = new DocumentClient(host, {masterKey: masterKey}); 17 | 18 | client.addListener('message', function (from, to, text) { 19 | var str = text; 20 | if (str.indexOf('BUGREPORT') === -1){ 21 | if (str.indexOf('BUG #') === -1){ 22 | client.say('#BugsChannel', "I could not get that!\n Send me commands like,\n BUGREPORT \n BUG # "); 23 | } 24 | else { 25 | client.say('#BugsChannel', "So you need info about "+text); 26 | client.say('#BugsChannel', "Wait for a moment!"); 27 | var t= text.substring(6,text.length); 28 | var temp = t.trim(); 29 | var querySpec = { 30 | query: 'SELECT * FROM Bugs b WHERE b.id= @id', 31 | parameters: [ 32 | { 33 | name: '@id', 34 | value: temp 35 | } 36 | ] 37 | }; 38 | docclient.queryDocuments('dbs/BugDB/colls/Bugs', querySpec).toArray(function (err, results) { 39 | if (results.length>0){ 40 | client.say('#BugsChannel', "["+ results[0].url+"] [Status]: "+results[0].status+" [Title]:"+results[0].title); 41 | }else{ 42 | client.say('#BugsChannel', 'No bugs found.'); 43 | } 44 | }); 45 | } 46 | } 47 | else{ 48 | client.say('#BugsChannel', "So you need a Bug Report!"); 49 | client.say('#BugsChannel', "Wait for a moment!"); 50 | var querySpec = { 51 | query: 'SELECT * FROM Bugs b WHERE b.status= @status', 52 | parameters: [ 53 | { 54 | name: '@status', 55 | value: 'Open' 56 | } 57 | ] 58 | }; 59 | docclient.queryDocuments('dbs/BugDB/colls/Bugs', querySpec).toArray(function (err, results) { 60 | client.say('#BugsChannel','Total Open Bugs:'+results.length); 61 | }); 62 | var querySpec = { 63 | query: 'SELECT * FROM Bugs b WHERE b.status= @status', 64 | parameters: [ 65 | { 66 | name: '@status', 67 | value: 'Closed' 68 | } 69 | ] 70 | }; 71 | docclient.queryDocuments('dbs/BugDB/colls/Bugs', querySpec).toArray(function (err, results) { 72 | client.say('#BugsChannel','Total Closed Bugs:'+results.length); 73 | }); 74 | } 75 | 76 | }); 77 | -------------------------------------------------------------------------------- /Chapter08/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ircbot", 3 | "version": "1.0.0", 4 | "description": "A Bug Tracking Agent for Teams", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Madan Bhintade", 10 | "license": "ISC", 11 | "dependencies": { 12 | "documentdb": "^1.10.0", 13 | "irc": "^0.5.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter09/server.js.txt: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var http = require('http'); 3 | var Bot = require('@kikinteractive/kik'); 4 | var request = require('request'); 5 | 6 | var username = ""; 7 | var password = ""; 8 | var accesstoken = password + ''; 9 | 10 | var fromUserName; 11 | 12 | // Configure the bot 13 | var bot = new Bot({ 14 | username: 'sforcebot', 15 | apiKey: '' 16 | }); 17 | 18 | 19 | var jsforce = require('jsforce'); 20 | var conn = new jsforce.Connection(); 21 | 22 | bot.onTextMessage(/^hi|hello|how|hey$/i, (incoming, next) => { 23 | bot.getUserProfile(incoming.from) 24 | .then((user) => { 25 | fromUserName = user.username; 26 | incoming.reply('Hello,I am the SForce Bot. I provide your CRM information just by chatting.'); 27 | 28 | bot.send(Bot.Message.text('Select any option...') 29 | .addResponseKeyboard(['Closing This Month', 'Closing Next Month']) 30 | , fromUserName); 31 | }); 32 | }); 33 | 34 | 35 | bot.onTextMessage(/^Closing This Month/i, (incoming, next) => { 36 | incoming.reply('Opportunities for this month...!'); 37 | conn.login(username, accesstoken, function (err, res) { 38 | if (err) { return console.error(err); } 39 | console.log(res.id); 40 | var records = []; 41 | var qry = "SELECT Account.Name,Name,Amount FROM Opportunity WHERE CloseDate = THIS_MONTH ORDER BY AMOUNT DESC" 42 | conn.query(qry, function (err, result) { 43 | if (err) { return console.error(err); } 44 | rec = result.records; 45 | rec.forEach(function (d) { 46 | bot.send(Bot.Message.text(d.Name + ' for ' + d.Account.Name + ' worth ' + d.Amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' })) 47 | .addResponseKeyboard(['Closing This Month', 'Closing Next Month']), fromUserName); 48 | }); 49 | }); 50 | }); 51 | 52 | 53 | }); 54 | 55 | bot.onTextMessage(/^Closing Next Month/i, (incoming, next) => { 56 | incoming.reply('Finding your opportunities for next month...!'); 57 | conn.login(username, accesstoken, function (err, res) { 58 | if (err) { return console.error(err); } 59 | console.log(res.id); 60 | var records = []; 61 | var qry = "SELECT Account.Name,Name,Amount FROM Opportunity WHERE CloseDate = NEXT_MONTH ORDER BY AMOUNT DESC" 62 | conn.query(qry, function (err, result) { 63 | if (err) { return console.error(err); } 64 | rec = result.records; 65 | rec.forEach(function (d) { 66 | bot.send(Bot.Message.text(d.Name + ' for ' + d.Account.Name + ' worth ' + d.Amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' })) 67 | .addResponseKeyboard(['Closing This Month', 'Closing Next Month']), fromUserName); 68 | }); 69 | }); 70 | }); 71 | 72 | }); 73 | 74 | // Set up your server and start listening 75 | var server = http 76 | .createServer(bot.incoming()) 77 | .listen(process.env.PORT || 8080); 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Building Bots with Node.js 2 | This is the code repository for [Building Bots with Node.js](https://www.packtpub.com/application-development/building-bots-nodejs?utm_source=github&utm_medium=repository&utm_campaign=9781786465450), published by [Packt](https://www.packtpub.com/). It contains all the supporting project files necessary to work through the book from start to finish. 3 | ## About the Book 4 | The bots are taking over and we're all for it! Messenger-based bots will be the dominant software UI for the next generation of applications – even Slack, Telegram, and Facebook are driving a new approach where "threads are the new apps." 5 | ### Instructions and Navigations 6 | All of the codes are organized as per the chapters, each folder has the codes related to that chapter or appendix. 7 | For example: Building-Bots-with-Nodejs/Chapter05/package.json 8 | 9 | The code will look like the following: 10 | ``` 11 | { 12 | "name": "telegrambot", 13 | "version": "1.0.0", 14 | "description": "\"A Telegram Bot for Sentiment Analysis\"", 15 | "main": "app.js", 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | ``` 20 | 21 | Following is the software-hardware list: 22 | 23 | | Chapter | Software required | Hardware required | OS required | 24 | | ------------- | ------------- | ------------- | ------------- | 25 | | 01-09 | Node.js | PC or laptop with at least 2 GB of RAM (4 recommended) | OS Independent although Windows 8 or above recommended | 26 | 27 | ## Related Products 28 | 29 | 30 | * [Building Bots with Microsoft Bot Framework](https://www.packtpub.com/application-development/building-bots-microsoft-bot-framework?utm_source=github&utm_medium=repository&utm_campaign=9781786463104) 31 | 32 | 33 | * [Instant Simple Botting with PHP](https://www.packtpub.com/networking-and-servers/instant-simple-botting-php-instant?utm_source=github&utm_medium=repository&utm_campaign=9781782169291) 34 | 35 | 36 | * [Building Slack Bots](https://www.packtpub.com/application-development/building-slack-bots?utm_source=github&utm_medium=repository&utm_campaign=9781786460806) 37 | 38 | 39 | 40 | ### Suggestions and Feedback 41 | 42 | [Click here](https://docs.google.com/forms/d/e/1FAIpQLSe5qwunkGf6PUvzPirPDtuy1Du5Rlzew23UBp2S-P3wB-GcwQ/viewform) if you have any feedback or suggestions. 43 | --------------------------------------------------------------------------------