-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathbot.js
267 lines (211 loc) · 6.19 KB
/
bot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
'use strict'
const
debug = require('debug')('bot'),
EventEmitter = require('events'),
client = require('./client'),
aws = require('./aws')
class Bot extends EventEmitter {
/**
* Constructor
*
* @param {object} store - The team's store
*/
constructor(store) {
debug('constructor:store %j', store)
super()
this.store = store || {}
}
/**
* Brain getter
*
* @return {Object} the bot's brain
*/
get brain() {
debug('brain:get %j', this.store.brain)
return this.store.brain || {}
}
/**
* Brain setter
*
* @param {object} brain - the brain to set
*/
set brain(brain) {
debug('brain:set %j', brain)
this.store.brain = brain
}
/**
* Access Info
*
* @return {String} the current team id
*/
get auth() {
debug('auth %j', this.store.auth)
return this.store.auth
}
/**
* Team Id
*
* @return {String} the current team id
*/
get team_id() {
debug('token %j', this.auth)
return this.auth.team_id
}
/**
* API Token
*
* @return {String} the team's API token
*/
get token() {
debug('token %j', this.auth)
if (this.auth.bot) return this.auth.bot.bot_access_token
else return this.auth.access_token
}
/**
* Channel
*
* @param {object} payload - The message payload
* @return {String} the payload's channel
*/
getChannel(payload) {
debug('getChannel %j', payload)
let event = payload.event
// Interactive Messages
if (payload.channel) return payload.channel.id
// Slash Commands
if (payload.channel_id) return payload.channel_id
// Events API
if (event && event.channel) return event.channel
if (event && event.item) return event.item.channel
}
/**
* Send Reply
*
* @param {object} payload - The original message payload
* @param {object} message - The message to reply with
* @param {boolean} ephemeral - Flag to make the message ephemeral
* @return {Promise} A promise with the API response
*/
reply(payload, message, ephemeral) {
debug('reply:payload %j', payload)
debug('reply:message %j', message)
debug('reply:ephemeral', ephemeral)
let channel = this.getChannel(payload)
// convert the string message to a message object
if (typeof(message) === 'string') message = { text: message }
// invalid ephemeral requests
if (!payload.response_url && ephemeral)
return Promise.reject("Message can't be private")
// slash commands and interactive messages
if (payload.response_url) {
if (!ephemeral && !message.response_type) message.response_type = 'in_channel'
return client.api(payload.response_url, message)
}
// incoming webhooks
if (this.auth.incoming_webhook && !channel && !message.channel)
return client.api(this.auth.incoming_webhook.url, message)
// fallback
return this.say(message)
}
/**
* Send Private Reply
*
* @param {object} payload - The original message payload
* @param {object} message - The message to reply with
* @return {Promise} A promise with the API response
*/
replyPrivate(payload, message) {
debug('replyPrivate:payload %j', payload)
debug('replyPrivate:message %j', message)
return this.reply(payload, message, true)
}
/**
* Send Message
*
* @param {object} message - The message to post
* @return {Promise} A promise with the API result
*/
say(message) {
debug('say %j', message)
return client.api('chat.postMessage', message)
}
/**
* Send data to Slack's API
*
* @param {string} endPoint - The method name or url (optional - defaults to chat.postMessage)
* @param {object} data - The JSON payload to send
* @return {Promise} A promise with the API response
*/
send(endPoint, data) {
debug('send %j', message)
return client.api(endPoint, message)
}
/**
* Event handler for incoming messages
*
* @param {mixed} args - Any number of event names to listen to. The last will be the callback
* @return {Promise} A promise with callback results
*/
on(names) {
debug('on', arguments)
let callback = null
let args = Array.prototype.slice.call(arguments)
let len = args.length
// determine if a callback was passed in
if (len > 1 && typeof(args[len - 1]) === "function")
callback = args.pop()
return new Promise(resolve => {
if (!callback) callback = resolve
args.forEach(name => super.on(name, callback))
})
}
/**
* Listen for specific message text
*
* @param {RegExp} regex - The RegEx of what to match
* @param {Function} callback - The callback to run when matched
* @return {Promise} A promise with callback results
*/
hears(regex, callback) {
debug('hears', regex)
return this.on('*', (payload, bot) => {
debug('hears:payload %j', payload)
let match = null
// slash commands
if (payload.text)
match = payload.text.match(regex)
// events
if (payload.event && payload.event.text)
match = payload.event.text.match(regex)
return new Promise(resolve => {
debug('hears:match', match)
if (!callback) callback = resolve
if (match) callback(payload, bot, match)
})
})
}
/**
* Dispatch to listeners
*
* @param {Object} payload - The payload
* @return {Promise} A promise with the events that were notified
*/
dispatch(payload) {
debug('dispatch %j', payload)
// ignore bots
if (payload.bot_id || (payload.event && payload.event.bot_id)) return
let events = ['*']
// notify incoming message by type
if (payload.type) events.push(payload.type)
// notify event triggered by event type
if (payload.event) events.push('event', payload.event.type)
// notify slash command by command
if (payload.command) events.push('slash_command', payload.command)
// notify webhook triggered by trigger word
if (payload.trigger_word) events.push('webhook', payload.trigger_word)
// notify message button triggered by callback_id
if (payload.callback_id) events.push('interactive_message', payload.callback_id)
events.forEach(name => this.emit(name, payload, this))
}
}
module.exports = Bot