Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Commit f8583ec

Browse files
authored
Merge pull request #3 from howdyai/master
Merge
2 parents e102bc3 + 354a917 commit f8583ec

15 files changed

+1011
-400
lines changed

Dockerfile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM library/node:slim
2+
3+
COPY . /app
4+
5+
RUN cd /app \
6+
&& npm install --production
7+
8+
WORKDIR /app

changelog.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Change Log
22

3+
## 0.2.2
4+
5+
Add support for Slack Interactive Messages.
6+
7+
Add example of Slack button application that provides a bot that uses interactive messages.
8+
9+
New functionality in Slack bot: Botkit will track spawned Slack bots and route incoming webhooks to pre-existing RTM bots. This enables RTM bots to reply to interactive messages and slash commands.
10+
11+
## 0.2.1
12+
13+
Improves Slack RTM reconnects thanks to @selfcontained [PR #274](https://github.com/howdyai/botkit/pull/274)
14+
315
## 0.2
416

517
Adds support for Twilio IP Messenging bots
+332
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
______ ______ ______ __ __ __ ______
3+
/\ == \ /\ __ \ /\__ _\ /\ \/ / /\ \ /\__ _\
4+
\ \ __< \ \ \/\ \ \/_/\ \/ \ \ _"-. \ \ \ \/_/\ \/
5+
\ \_____\ \ \_____\ \ \_\ \ \_\ \_\ \ \_\ \ \_\
6+
\/_____/ \/_____/ \/_/ \/_/\/_/ \/_/ \/_/
7+
8+
9+
This is a sample Slack Button application that adds a bot to one or many slack teams.
10+
11+
# RUN THE APP:
12+
Create a Slack app. Make sure to configure the bot user!
13+
-> https://api.slack.com/applications/new
14+
-> Add the Redirect URI: http://localhost:3000/oauth
15+
Run your bot from the command line:
16+
clientId=<my client id> clientSecret=<my client secret> port=3000 node slackbutton_bot_interactivemsg.js
17+
# USE THE APP
18+
Add the app to your Slack by visiting the login page:
19+
-> http://localhost:3000/login
20+
After you've added the app, try talking to your bot!
21+
# EXTEND THE APP:
22+
Botkit has many features for building cool and useful bots!
23+
Read all about it here:
24+
-> http://howdy.ai/botkit
25+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
26+
27+
/* Uses the slack button feature to offer a real time bot to multiple teams */
28+
var Botkit = require('../lib/Botkit.js');
29+
30+
if (!process.env.clientId || !process.env.clientSecret || !process.env.port) {
31+
console.log('Error: Specify clientId clientSecret and port in environment');
32+
process.exit(1);
33+
}
34+
35+
36+
var controller = Botkit.slackbot({
37+
// interactive_replies: true, // tells botkit to send button clicks into conversations
38+
json_file_store: './db_slackbutton_bot/',
39+
}).configureSlackApp(
40+
{
41+
clientId: process.env.clientId,
42+
clientSecret: process.env.clientSecret,
43+
scopes: ['bot'],
44+
}
45+
);
46+
47+
controller.setupWebserver(process.env.port,function(err,webserver) {
48+
controller.createWebhookEndpoints(controller.webserver);
49+
50+
controller.createOauthEndpoints(controller.webserver,function(err,req,res) {
51+
if (err) {
52+
res.status(500).send('ERROR: ' + err);
53+
} else {
54+
res.send('Success!');
55+
}
56+
});
57+
});
58+
59+
60+
// just a simple way to make sure we don't
61+
// connect to the RTM twice for the same team
62+
var _bots = {};
63+
function trackBot(bot) {
64+
_bots[bot.config.token] = bot;
65+
}
66+
67+
68+
controller.on('interactive_message_callback', function(bot, message) {
69+
70+
var ids = message.callback_id.split(/\-/);
71+
var user_id = ids[0];
72+
var item_id = ids[1];
73+
74+
controller.storage.users.get(user_id, function(err, user) {
75+
76+
if (!user) {
77+
user = {
78+
id: user_id,
79+
list: []
80+
}
81+
}
82+
83+
for (var x = 0; x < user.list.length; x++) {
84+
if (user.list[x].id == item_id) {
85+
if (message.actions[0].value=='flag') {
86+
user.list[x].flagged = !user.list[x].flagged;
87+
}
88+
if (message.actions[0].value=='delete') {
89+
user.list.splice(x,1);
90+
}
91+
}
92+
}
93+
94+
95+
var reply = {
96+
text: 'Here is <@' + user_id + '>s list:',
97+
attachments: [],
98+
}
99+
100+
for (var x = 0; x < user.list.length; x++) {
101+
reply.attachments.push({
102+
title: user.list[x].text + (user.list[x].flagged? ' *FLAGGED*' : ''),
103+
callback_id: user_id + '-' + user.list[x].id,
104+
attachment_type: 'default',
105+
actions: [
106+
{
107+
"name":"flag",
108+
"text": ":waving_black_flag: Flag",
109+
"value": "flag",
110+
"type": "button",
111+
},
112+
{
113+
"text": "Delete",
114+
"name": "delete",
115+
"value": "delete",
116+
"style": "danger",
117+
"type": "button",
118+
"confirm": {
119+
"title": "Are you sure?",
120+
"text": "This will do something!",
121+
"ok_text": "Yes",
122+
"dismiss_text": "No"
123+
}
124+
}
125+
]
126+
})
127+
}
128+
129+
bot.replyInteractive(message, reply);
130+
controller.storage.users.save(user);
131+
132+
133+
});
134+
135+
});
136+
137+
138+
controller.on('create_bot',function(bot,config) {
139+
140+
if (_bots[bot.config.token]) {
141+
// already online! do nothing.
142+
} else {
143+
bot.startRTM(function(err) {
144+
145+
if (!err) {
146+
trackBot(bot);
147+
}
148+
149+
bot.startPrivateConversation({user: config.createdBy},function(err,convo) {
150+
if (err) {
151+
console.log(err);
152+
} else {
153+
convo.say('I am a bot that has just joined your team');
154+
convo.say('You must now /invite me to a channel so that I can be of use!');
155+
}
156+
});
157+
158+
});
159+
}
160+
161+
});
162+
163+
164+
// Handle events related to the websocket connection to Slack
165+
controller.on('rtm_open',function(bot) {
166+
console.log('** The RTM api just connected!');
167+
});
168+
169+
controller.on('rtm_close',function(bot) {
170+
console.log('** The RTM api just closed');
171+
// you may want to attempt to re-open
172+
});
173+
174+
175+
controller.hears(['add (.*)'],'direct_mention,direct_message',function(bot,message) {
176+
177+
controller.storage.users.get(message.user, function(err, user) {
178+
179+
if (!user) {
180+
user = {
181+
id: message.user,
182+
list: []
183+
}
184+
}
185+
186+
user.list.push({
187+
id: message.ts,
188+
text: message.match[1],
189+
});
190+
191+
bot.reply(message,'Added to list. Say `list` to view or manage list.');
192+
193+
controller.storage.users.save(user);
194+
195+
});
196+
});
197+
198+
199+
controller.hears(['list','tasks'],'direct_mention,direct_message',function(bot,message) {
200+
201+
controller.storage.users.get(message.user, function(err, user) {
202+
203+
if (!user) {
204+
user = {
205+
id: message.user,
206+
list: []
207+
}
208+
}
209+
210+
if (!user.list || !user.list.length) {
211+
user.list = [
212+
{
213+
'id': 1,
214+
'text': 'Test Item 1'
215+
},
216+
{
217+
'id': 2,
218+
'text': 'Test Item 2'
219+
},
220+
{
221+
'id': 3,
222+
'text': 'Test Item 3'
223+
}
224+
]
225+
}
226+
227+
var reply = {
228+
text: 'Here is your list. Say `add <item>` to add items.',
229+
attachments: [],
230+
}
231+
232+
for (var x = 0; x < user.list.length; x++) {
233+
reply.attachments.push({
234+
title: user.list[x].text + (user.list[x].flagged? ' *FLAGGED*' : ''),
235+
callback_id: message.user + '-' + user.list[x].id,
236+
attachment_type: 'default',
237+
actions: [
238+
{
239+
"name":"flag",
240+
"text": ":waving_black_flag: Flag",
241+
"value": "flag",
242+
"type": "button",
243+
},
244+
{
245+
"text": "Delete",
246+
"name": "delete",
247+
"value": "delete",
248+
"style": "danger",
249+
"type": "button",
250+
"confirm": {
251+
"title": "Are you sure?",
252+
"text": "This will do something!",
253+
"ok_text": "Yes",
254+
"dismiss_text": "No"
255+
}
256+
}
257+
]
258+
})
259+
}
260+
261+
bot.reply(message, reply);
262+
263+
controller.storage.users.save(user);
264+
265+
});
266+
267+
});
268+
269+
controller.hears('interactive', 'direct_message', function(bot, message) {
270+
271+
bot.reply(message, {
272+
attachments:[
273+
{
274+
title: 'Do you want to interact with my buttons?',
275+
callback_id: '123',
276+
attachment_type: 'default',
277+
actions: [
278+
{
279+
"name":"yes",
280+
"text": "Yes",
281+
"value": "yes",
282+
"type": "button",
283+
},
284+
{
285+
"name":"no",
286+
"text": "No",
287+
"value": "no",
288+
"type": "button",
289+
}
290+
]
291+
}
292+
]
293+
});
294+
});
295+
296+
297+
controller.hears('^stop','direct_message',function(bot,message) {
298+
bot.reply(message,'Goodbye');
299+
bot.rtm.close();
300+
});
301+
302+
controller.on(['direct_message','mention','direct_mention'],function(bot,message) {
303+
bot.api.reactions.add({
304+
timestamp: message.ts,
305+
channel: message.channel,
306+
name: 'robot_face',
307+
},function(err) {
308+
if (err) { console.log(err) }
309+
bot.reply(message,'I heard you loud and clear boss.');
310+
});
311+
});
312+
313+
controller.storage.teams.all(function(err,teams) {
314+
315+
if (err) {
316+
throw new Error(err);
317+
}
318+
319+
// connect all teams with bots up to slack!
320+
for (var t in teams) {
321+
if (teams[t].bot) {
322+
controller.spawn(teams[t]).startRTM(function(err, bot) {
323+
if (err) {
324+
console.log('Error connecting bot to Slack:',err);
325+
} else {
326+
trackBot(bot);
327+
}
328+
});
329+
}
330+
}
331+
332+
});

examples/slackbutton_incomingwebhooks.js

100755100644
File mode changed.

facebook_bot.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,14 @@ var os = require('os');
8181
var commandLineArgs = require('command-line-args');
8282
var localtunnel = require('localtunnel');
8383

84-
const cli = commandLineArgs([
84+
const ops = commandLineArgs([
8585
{name: 'lt', alias: 'l', args: 1, description: 'Use localtunnel.me to make your bot available on the web.',
8686
type: Boolean, defaultValue: false},
8787
{name: 'ltsubdomain', alias: 's', args: 1,
8888
description: 'Custom subdomain for the localtunnel.me URL. This option can only be used together with --lt.',
8989
type: String, defaultValue: null},
9090
]);
9191

92-
const ops = cli.parse();
9392
if(ops.lt === false && ops.ltsubdomain !== null) {
9493
console.log("error: --ltsubdomain can only be used together with --lt.");
9594
process.exit();

0 commit comments

Comments
 (0)