1+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+ ______ ______ ______ __ __ __ ______
3+ /\ == \ /\ __ \ /\__ _\ /\ \/ / /\ \ /\__ _\
4+ \ \ __< \ \ \/\ \ \/_/\ \/ \ \ _"-. \ \ \ \/_/\ \/
5+ \ \_____\ \ \_____\ \ \_\ \ \_\ \_\ \ \_\ \ \_\
6+ \/_____/ \/_____/ \/_/ \/_/\/_/ \/_/ \/_/
7+
8+
9+ This is a sample Slack bot built with Botkit.
10+
11+ This bot demonstrates many of the core features of Botkit:
12+
13+ * Connect to Slack using the real time API
14+ * Receive messages based on "spoken" patterns
15+ * Reply to messages
16+ * Use the conversation system to ask questions
17+ * Use the built in storage system to store and retrieve information
18+ for a user.
19+
20+ # RUN THE BOT:
21+
22+ Get a Bot token from Slack:
23+
24+ -> http://my.slack.com/services/new/bot
25+
26+ Run your bot from the command line:
27+
28+ token=<MY TOKEN> node slack_bot.js
29+
30+ # USE THE BOT:
31+
32+ Find your bot inside Slack to send it a direct message.
33+
34+ Say: "Hello"
35+
36+ The bot will reply "Hello!"
37+
38+ Say: "who are you?"
39+
40+ The bot will tell you its name, where it is running, and for how long.
41+
42+ Say: "Call me <nickname>"
43+
44+ Tell the bot your nickname. Now you are friends.
45+
46+ Say: "who am I?"
47+
48+ The bot will tell you your nickname, if it knows one for you.
49+
50+ Say: "shutdown"
51+
52+ The bot will ask if you are sure, and then shut itself down.
53+
54+ Make sure to invite your bot into other channels using /invite @<my bot>!
55+
56+ # EXTEND THE BOT:
57+
58+ Botkit has many features for building cool and useful bots!
59+
60+ Read all about it here:
61+
62+ -> http://howdy.ai/botkit
63+
64+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
65+
66+ process . env . token = 'xoxb-125328283350-dcs7J8cxhCvQHCfO2L69z38u' ;
67+ if ( ! process . env . token ) {
68+ console . log ( 'Error: Specify token in environment' ) ;
69+ process . exit ( 1 ) ;
70+ }
71+
72+ var Botkit = require ( 'botkit/lib/Botkit.js' ) ;
73+ var os = require ( 'os' ) ;
74+
75+ var controller = Botkit . slackbot ( {
76+ debug : true ,
77+ } ) ;
78+
79+ var bot = controller . spawn ( {
80+ token : process . env . token
81+ } ) . startRTM ( ) ;
82+
83+ let gdq = require ( './gdq-schedule' ) ;
84+
85+ controller . hears ( [ 'hello' , 'hi' ] , 'direct_message,direct_mention,mention' , function ( bot , message ) {
86+
87+ bot . api . reactions . add ( {
88+ timestamp : message . ts ,
89+ channel : message . channel ,
90+ name : 'robot_face' ,
91+ } , function ( err , res ) {
92+ if ( err ) {
93+ bot . botkit . log ( 'Failed to add emoji reaction :(' , err ) ;
94+ }
95+ } ) ;
96+
97+
98+ controller . storage . users . get ( message . user , function ( err , user ) {
99+ if ( user && user . name ) {
100+ bot . reply ( message , 'Hello ' + user . name + '!!' ) ;
101+ } else {
102+ bot . reply ( message , 'Hello.' ) ;
103+ }
104+ } ) ;
105+ } ) ;
106+
107+ controller . hears ( [ '(start|stop) book shopping mode' ] , 'direct_message,direct_mention,mention' , ( bot , message ) => {
108+ let isStarting = message . match [ 1 ] . toLowerCase ( ) === 'start' ;
109+ controller . storage . users . get ( message . user , ( err , user ) => {
110+ if ( ! user ) {
111+ user = {
112+ id : message . user ,
113+ isBookShopping : false
114+ } ;
115+ }
116+ if ( isStarting ) {
117+ if ( user . isBookShopping ) {
118+ bot . reply ( message , 'You are already in book shopping mode!' ) ;
119+ } else {
120+ user . isBookShopping = true ;
121+ controller . storage . users . save ( user , ( err , id ) => bot . reply ( message , 'Okay, book shopping mode enabled.' ) ) ;
122+ }
123+ } else {
124+ if ( ! user . isBookShopping ) {
125+ bot . reply ( message , 'You haven\'t even started book shopping mode yet.' ) ;
126+ } else {
127+ user . isBookShopping = false ;
128+ controller . storage . users . save ( user , ( err , id ) => bot . reply ( message , 'Okay, book shopping mode disabled.' ) ) ;
129+ }
130+ }
131+ } ) ;
132+ } ) ;
133+
134+ controller . hears ( [ 'call me (.*)' , 'my name is (.*)' ] , 'direct_message,direct_mention,mention' , function ( bot , message ) {
135+ var name = message . match [ 1 ] ;
136+ controller . storage . users . get ( message . user , function ( err , user ) {
137+ if ( ! user ) {
138+ user = {
139+ id : message . user ,
140+ } ;
141+ }
142+ user . name = name ;
143+ controller . storage . users . save ( user , function ( err , id ) {
144+ bot . reply ( message , 'Got it. I will call you ' + user . name + ' from now on.' ) ;
145+ } ) ;
146+ } ) ;
147+ } ) ;
148+
149+ controller . hears ( [ 'what is my name' , 'who am i' ] , 'direct_message,direct_mention,mention' , function ( bot , message ) {
150+
151+ controller . storage . users . get ( message . user , function ( err , user ) {
152+ if ( user && user . name ) {
153+ bot . reply ( message , 'Your name is ' + user . name ) ;
154+ } else {
155+ bot . startConversation ( message , function ( err , convo ) {
156+ if ( ! err ) {
157+ convo . say ( 'I do not know your name yet!' ) ;
158+ convo . ask ( 'What should I call you?' , function ( response , convo ) {
159+ convo . ask ( 'You want me to call you `' + response . text + '`?' , [
160+ {
161+ pattern : 'yes' ,
162+ callback : function ( response , convo ) {
163+ // since no further messages are queued after this,
164+ // the conversation will end naturally with status == 'completed'
165+ convo . next ( ) ;
166+ }
167+ } ,
168+ {
169+ pattern : 'no' ,
170+ callback : function ( response , convo ) {
171+ // stop the conversation. this will cause it to end with status == 'stopped'
172+ convo . stop ( ) ;
173+ }
174+ } ,
175+ {
176+ default : true ,
177+ callback : function ( response , convo ) {
178+ convo . repeat ( ) ;
179+ convo . next ( ) ;
180+ }
181+ }
182+ ] ) ;
183+
184+ convo . next ( ) ;
185+
186+ } , { 'key' : 'nickname' } ) ; // store the results in a field called nickname
187+
188+ convo . on ( 'end' , function ( convo ) {
189+ if ( convo . status == 'completed' ) {
190+ bot . reply ( message , 'OK! I will update my dossier...' ) ;
191+
192+ controller . storage . users . get ( message . user , function ( err , user ) {
193+ if ( ! user ) {
194+ user = {
195+ id : message . user ,
196+ } ;
197+ }
198+ user . name = convo . extractResponse ( 'nickname' ) ;
199+ controller . storage . users . save ( user , function ( err , id ) {
200+ bot . reply ( message , 'Got it. I will call you ' + user . name + ' from now on.' ) ;
201+ } ) ;
202+ } ) ;
203+
204+
205+ } else {
206+ // this happens if the conversation ended prematurely for some reason
207+ bot . reply ( message , 'OK, nevermind!' ) ;
208+ }
209+ } ) ;
210+ }
211+ } ) ;
212+ }
213+ } ) ;
214+ } ) ;
215+
216+
217+ controller . hears ( [ 'shutdown' ] , 'direct_message,direct_mention,mention' , function ( bot , message ) {
218+
219+ bot . startConversation ( message , function ( err , convo ) {
220+
221+ convo . ask ( 'Are you sure you want me to shutdown?' , [
222+ {
223+ pattern : bot . utterances . yes ,
224+ callback : function ( response , convo ) {
225+ convo . say ( 'Bye!' ) ;
226+ convo . next ( ) ;
227+ setTimeout ( function ( ) {
228+ process . exit ( ) ;
229+ } , 3000 ) ;
230+ }
231+ } ,
232+ {
233+ pattern : bot . utterances . no ,
234+ default : true ,
235+ callback : function ( response , convo ) {
236+ convo . say ( '*Phew!*' ) ;
237+ convo . next ( ) ;
238+ }
239+ }
240+ ] ) ;
241+ } ) ;
242+ } ) ;
243+
244+
245+ controller . hears ( [ 'uptime' , 'identify yourself' , 'who are you' , 'what is your name' ] ,
246+ 'direct_message,direct_mention,mention' , function ( bot , message ) {
247+
248+ var hostname = os . hostname ( ) ;
249+ var uptime = formatUptime ( process . uptime ( ) ) ;
250+
251+ bot . reply ( message ,
252+ ':robot_face: I am a bot named <@' + bot . identity . name +
253+ '>. I have been running for ' + uptime + ' on ' + hostname + '.' ) ;
254+
255+ } ) ;
256+
257+ controller . hears ( [ 'gdq' ] , 'direct_message,direct_mention,mention' , ( b , m ) => {
258+ gdq ( )
259+ . then ( g => {
260+ if ( g && g . length ) {
261+ bot . reply ( m , {
262+ attachments : g . slice ( 0 , 5 ) . map ( e => ( {
263+ author_name : e . runners ,
264+ title : e . title ,
265+ text : `Starts at *${ e . start . format ( 'h:mm A' ) } * and has an estimate of _${ e . estimate } _, so expected to end at *${ e . ends . format ( 'h:mm A' ) } *.` ,
266+ footer : 'GDQ' ,
267+ footer_icon : 'https://gamesdonequick.com/static/res/img/favicon/favicon.ico' ,
268+ mrkdwn_in : [ 'text' ]
269+ } ) )
270+ } ) ;
271+ } else {
272+ bot . reply ( m , 'Sorry, I got nothin\'.' ) ;
273+ }
274+ } )
275+ } ) ;
276+
277+ controller . hears ( 'interactive' , 'direct_message' , function ( bot , message ) {
278+
279+ bot . reply ( message , {
280+ attachments : [
281+ {
282+ title : 'Do you want to interact with my buttons?' ,
283+ callback_id : '123' ,
284+ attachment_type : 'default' ,
285+ actions : [
286+ {
287+ "name" : "yes" ,
288+ "text" : "Yes" ,
289+ "value" : "yes" ,
290+ "type" : "button" ,
291+ } ,
292+ {
293+ "name" : "no" ,
294+ "text" : "No" ,
295+ "value" : "no" ,
296+ "type" : "button" ,
297+ }
298+ ]
299+ }
300+ ]
301+ } ) ;
302+ } ) ;
303+
304+ function formatUptime ( uptime ) {
305+ var unit = 'second' ;
306+ if ( uptime > 60 ) {
307+ uptime = uptime / 60 ;
308+ unit = 'minute' ;
309+ }
310+ if ( uptime > 60 ) {
311+ uptime = uptime / 60 ;
312+ unit = 'hour' ;
313+ }
314+ if ( uptime != 1 ) {
315+ unit = unit + 's' ;
316+ }
317+
318+ uptime = uptime + ' ' + unit ;
319+ return uptime ;
320+ }
0 commit comments