slack-smart-bot 0.9.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +5 -1
- data/README.md +80 -175
- data/lib/slack-smart-bot.rb +95 -1276
- data/lib/slack-smart-bot_rules.rb +50 -69
- data/lib/slack/smart-bot/comm.rb +197 -0
- data/lib/slack/smart-bot/commands/general/bot_help.rb +74 -0
- data/lib/slack/smart-bot/commands/general/bot_status.rb +41 -0
- data/lib/slack/smart-bot/commands/general/bye_bot.rb +17 -0
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +24 -0
- data/lib/slack/smart-bot/commands/general/stop_using_rules.rb +44 -0
- data/lib/slack/smart-bot/commands/general/use_rules.rb +48 -0
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +64 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +87 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +63 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +21 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +26 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +28 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +53 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +57 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +20 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +27 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +30 -0
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +41 -0
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +48 -0
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +32 -0
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +37 -0
- data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +38 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +42 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +35 -0
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +94 -0
- data/lib/slack/smart-bot/listen.rb +36 -0
- data/lib/slack/smart-bot/process.rb +169 -0
- data/lib/slack/smart-bot/process_first.rb +201 -0
- data/lib/slack/smart-bot/treat_message.rb +139 -0
- data/lib/slack/smart-bot/utils.rb +299 -0
- metadata +71 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d14d69e55b288d326662672ab780c11801f6210c9b6c312c27192039e05598d
|
4
|
+
data.tar.gz: 073cf649b0b011e03fe8ebd0cb40e3163e4fcea38b139e58b0f1e92bb6e98084
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2969998ea41b817c4924b1ab850e7f7690d6c65b2e8954768104d19712ce9b649727405b58106d9c6c6828b9eeb23c8bd2359251cbf3c4878856c266d4ddd85
|
7
|
+
data.tar.gz: c7ac1ffd674ea068b06e81de18c8176edb416b77d2f1f2ad3729bc4c42c2578c8cca7271d17573f9bcde779e6d5771e4069fea8b0fe8a20526dd5d936a4caa73
|
data/.yardopts
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Slack Smart Bot
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/slack-smart-bot.svg)](https://rubygems.org/gems/slack-smart-bot)
|
4
|
+
[![Build Status](https://travis-ci.com/MarioRuiz/slack-smart-bot.svg?branch=master)](https://github.com/MarioRuiz/slack-smart-bot)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/github/MarioRuiz/slack-smart-bot/badge.svg?branch=master)](https://coveralls.io/github/MarioRuiz/slack-smart-bot?branch=master)
|
4
6
|
|
5
7
|
Create a Slack bot that is really smart and so easy to expand.
|
6
8
|
|
@@ -13,18 +15,22 @@ slack-smart-bot can create bots on demand, create shortcuts, run ruby code... ju
|
|
13
15
|
- [Installation and configuration](#installation-and-configuration)
|
14
16
|
- [Usage](#usage)
|
15
17
|
* [creating the MASTER BOT](#creating-the-master-bot)
|
16
|
-
* [How to access the
|
17
|
-
* [
|
18
|
-
* [
|
19
|
-
|
20
|
-
* [
|
18
|
+
* [How to access the Smart Bot](#how-to-access-the-smart-bot)
|
19
|
+
* [Bot Help](#bot-help)
|
20
|
+
* [Bot Management](#bot-management)
|
21
|
+
+ [Cloud Bots](#cloud-bots)
|
22
|
+
* [Extending rules to other channels](#extending-rules-to-other-channels)
|
23
|
+
* [Using rules from other channels](#using-rules-from-other-channels)
|
24
|
+
* [Running Ruby code on a conversation](#running-ruby-code-on-a-conversation)
|
25
|
+
* [Sending notifications](#sending-notifications)
|
26
|
+
* [Shortcuts](#shortcuts)
|
27
|
+
* [Routines](#routines)
|
21
28
|
* [Tips](#tips)
|
22
29
|
+ [Send a file](#send-a-file)
|
23
30
|
+ [Download a file](#download-a-file)
|
24
31
|
- [Contributing](#contributing)
|
25
32
|
- [License](#license)
|
26
33
|
|
27
|
-
|
28
34
|
## Installation and configuration
|
29
35
|
|
30
36
|
$ gem install slack-smart-bot
|
@@ -80,8 +86,9 @@ You can get one by any of these options:
|
|
80
86
|
### creating the MASTER BOT
|
81
87
|
Let's guess the file you created was called my_smart_bot.rb so, just run it:
|
82
88
|
```
|
83
|
-
ruby my_smart_bot.rb
|
89
|
+
nohup ruby my_smart_bot.rb&
|
84
90
|
```
|
91
|
+
nohup will prevent the terminal to send the signal exception: SIGHUP and kill the bot. & will run the process in background. You can use instead: `ruby my_smart_bot.rb & disown`
|
85
92
|
|
86
93
|
After the run, it will be generated a rules file with the same name but adding _rules, in this example: my_smart_bot_rules.rb
|
87
94
|
|
@@ -92,7 +99,8 @@ You can add all the rules you want for your bot in the rules file, this is an ex
|
|
92
99
|
```ruby
|
93
100
|
def rules(user, command, processed, dest)
|
94
101
|
from = user.name
|
95
|
-
|
102
|
+
display_name = user.profile.display_name
|
103
|
+
|
96
104
|
case command
|
97
105
|
|
98
106
|
# help: `echo SOMETHING`
|
@@ -106,7 +114,7 @@ def rules(user, command, processed, dest)
|
|
106
114
|
# help:
|
107
115
|
when /^go\sto\ssleep/i
|
108
116
|
unless @questions.keys.include?(from)
|
109
|
-
ask
|
117
|
+
ask "do you want me to take a siesta?"
|
110
118
|
else
|
111
119
|
case @questions[from]
|
112
120
|
when /yes/i, /yep/i, /sure/i
|
@@ -119,7 +127,7 @@ def rules(user, command, processed, dest)
|
|
119
127
|
respond "Thanks, I'm happy to be awake"
|
120
128
|
else
|
121
129
|
respond "I don't understand"
|
122
|
-
ask
|
130
|
+
ask "are you sure do you want me to sleep? (yes or no)"
|
123
131
|
end
|
124
132
|
end
|
125
133
|
|
@@ -128,231 +136,128 @@ def rules(user, command, processed, dest)
|
|
128
136
|
# help: It will run the process and report the results when done
|
129
137
|
# help:
|
130
138
|
when /^run something/i
|
131
|
-
respond "Running"
|
139
|
+
respond "Running"
|
132
140
|
|
133
141
|
process_to_run = "ruby -v"
|
134
|
-
process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
|
135
142
|
stdout, stderr, status = Open3.capture3(process_to_run)
|
136
143
|
if stderr == ""
|
137
144
|
if stdout == ""
|
138
|
-
respond "#{user.name}: Nothing returned."
|
145
|
+
respond "#{user.name}: Nothing returned."
|
139
146
|
else
|
140
|
-
respond "#{user.name}: #{stdout}"
|
147
|
+
respond "#{user.name}: #{stdout}"
|
141
148
|
end
|
142
149
|
else
|
143
|
-
respond "#{user.name}: #{stderr}"
|
150
|
+
respond "#{user.name}: #{stdout} #{stderr}"
|
144
151
|
end
|
145
152
|
|
146
153
|
else
|
147
154
|
unless processed
|
148
|
-
|
149
|
-
respond "#{firstname}: #{resp}?"
|
155
|
+
dont_understand()
|
150
156
|
end
|
151
157
|
end
|
152
158
|
end
|
153
159
|
|
154
160
|
```
|
155
|
-
### How to access the
|
161
|
+
### How to access the Smart Bot
|
156
162
|
You can access the bot directly on the MASTER CHANNEL, on a secondary channel where the bot is running and directly by opening a private chat with the bot, in this case the conversation will be just between you and the bot.
|
157
163
|
|
158
|
-
|
159
|
-
Some of the commands are available always even when the bot is not listening to you but it is running
|
160
|
-
|
161
|
-
**_`bot help`_**
|
162
|
-
|
163
|
-
**_`bot what can I do?`_**
|
164
|
-
|
165
|
-
>It will display all the commands we can use
|
166
|
-
>What is displayed by this command is what is written on your rules file like this: #help: THE TEXT TO SHOW
|
167
|
-
|
168
|
-
**_`Hello Bot`_**
|
169
|
-
|
170
|
-
**_`Hello THE_NAME_OF_THE_BOT`_**
|
171
|
-
|
172
|
-
>Also apart of Hello you can use Hallo, Hi, Hola, What's up, Hey, Hæ
|
173
|
-
|
174
|
-
>Bot starts listening to you
|
175
|
-
|
176
|
-
>If you want to avoid a single message to be treated by the smart bot, start the message by -
|
177
|
-
|
178
|
-
**_`Bye Bot`_**
|
179
|
-
|
180
|
-
**_`Bye THE_NAME_OF_THE_BOT`_**
|
181
|
-
|
182
|
-
>Also apart of Bye you can use Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu
|
183
|
-
|
184
|
-
>Bot stops listening to you
|
185
|
-
|
186
|
-
**_`exit bot`_**
|
187
|
-
|
188
|
-
**_`quit bot`_**
|
189
|
-
|
190
|
-
**_`close bot`_**
|
191
|
-
|
192
|
-
>The bot stops running and also stops all the bots created from this master channel
|
193
|
-
|
194
|
-
>You can use this command only if you are an admin user and you are on the master channel
|
195
|
-
|
196
|
-
**_`start bot`_**
|
197
|
-
|
198
|
-
**_`start this bot`_**
|
199
|
-
|
200
|
-
>The bot will start to listen
|
201
|
-
|
202
|
-
>You can use this command only if you are an admin user
|
203
|
-
|
204
|
-
**_`pause bot`_**
|
205
|
-
|
206
|
-
**_`pause this bot`_**
|
207
|
-
|
208
|
-
>The bot will pause so it will listen only to admin commands
|
209
|
-
|
210
|
-
>You can use this command only if you are an admin user
|
211
|
-
|
212
|
-
**_`bot status`_**
|
213
|
-
|
214
|
-
>Displays the status of the bot
|
215
|
-
|
216
|
-
>If on master channel and admin user also it will display info about bots created
|
217
|
-
|
218
|
-
**_`create bot on CHANNEL_NAME`_**
|
219
|
-
|
220
|
-
>Creates a new bot on the channel specified.
|
221
|
-
|
222
|
-
>slack-smart-bot will create a default rules file specific for your channel.
|
223
|
-
You can edit it and add the rules you want.
|
224
|
-
As soon as you save the file after editing it will become available on your channel.
|
225
|
-
|
226
|
-
>It will work only if you are on Master channel
|
227
|
-
|
228
|
-
**_`kill bot on CHANNEL_NAME`_**
|
229
|
-
|
230
|
-
>Kills the bot on the specified channel
|
231
|
-
|
232
|
-
>Only works if you are on Master channel and you created that bot or you are an admin user
|
233
|
-
|
234
|
-
**_`notify MESSAGE`_**
|
235
|
-
|
236
|
-
**_`notify all MESSAGE`_**
|
237
|
-
|
238
|
-
>It will send a notificaiton message to all bot channels
|
239
|
-
|
240
|
-
>It will send a notification message to all channels the bot joined and private conversations with the bot
|
241
|
-
|
242
|
-
>Only works if you are on Master channel and you are an admin user
|
243
|
-
|
244
|
-
|
245
|
-
### Available commands only when listening to you or on demand or in a private conversation with the Smart Bot
|
246
|
-
|
247
|
-
All the commands described on here or on your specific Rules file can be used when the bot is listening to you or on demand or in a private conversation with the Smart Bot.
|
248
|
-
|
249
|
-
For the bot to start listening to you you need to use the "Hi bot" command or one of the aliases
|
250
|
-
|
251
|
-
Also you can call any of these commands on demand by using:
|
252
|
-
|
253
|
-
**_`!THE_COMMAND`_**
|
254
|
-
|
255
|
-
**_`@BOT_NAME THE_COMMAND`_**
|
256
|
-
|
257
|
-
**_`BOT_NAME THE_COMMAND`_**
|
258
|
-
|
259
|
-
Apart of the specific commands you define on the rules file of the channel, you can use:
|
260
|
-
|
261
|
-
**_`ruby RUBY_CODE`_**
|
262
|
-
|
263
|
-
**_`code RUBY_CODE`_**
|
264
|
-
|
265
|
-
>runs the code supplied and returns the output. Also you can send a Ruby file. Examples:
|
266
|
-
|
267
|
-
>code puts (34344/99)*(34+14)
|
268
|
-
|
269
|
-
>ruby require 'json'; res=[]; 20.times {res<<rand(100)}; my_json={result: res}; puts my_json.to_json
|
270
|
-
|
271
|
-
>Also it is possible to attach a Ruby file.
|
272
|
-
|
273
|
-
**_`add shortcut NAME: COMMAND`_**
|
274
|
-
|
275
|
-
**_`add shortcut for all NAME: COMMAND`_**
|
276
|
-
|
277
|
-
**_`shortchut NAME: COMMAND`_**
|
164
|
+
On a Smart Bot channel you will be able to run some of the commands just by writing a command, for example: `bot help`
|
278
165
|
|
279
|
-
|
166
|
+
Some commands will be only available when the Smart Bot is listening to you. For the Smart Bot to start listening to you just say: `hi bot`. When the Smart Bot is listening to you, you can skip a message to be treated by the bot by starting the message with '-', for example: `- this message won't be treated`. When you want the Smart Bot Stop listening to you: `bye bot`. If you are on a direct conversation with the Smart Bot then it will be on *listening* mode all the time.
|
280
167
|
|
281
|
-
|
168
|
+
All the specific commands of the bot are specified on your rules file and can be added or changed accordingly. We usually call those commands: *rules*. Those rules are only available when the bot is listening to you.
|
282
169
|
|
283
|
-
|
170
|
+
Another way to run a command/rule is by asking *on demand*. In this case it is not necessary that the bot is listening to you.
|
284
171
|
|
285
|
-
|
286
|
-
|
172
|
+
To run a command on demand:
|
173
|
+
`!THE_COMMAND`
|
174
|
+
`@NAME_OF_BOT THE_COMMAND`
|
175
|
+
`NAME_OF_BOT THE_COMMAND`
|
287
176
|
|
288
|
-
|
177
|
+
Also you can always call the Smart Bot from any channel, even from channels without a running Smart Bot. You can use the External Call on Demand: `@NAME_OF_BOT on #CHANNEL_NAME COMMAND`. In this case you will call the bot on #CHANNEL_NAME.
|
289
178
|
|
290
|
-
|
179
|
+
### Bot Help
|
180
|
+
To get a full list of all commands and rules for a specific Smart Bot: `bot help`. It will show only the specific available commands for the user requesting.
|
291
181
|
|
292
|
-
|
182
|
+
If you want to search just for a specific command: `bot help COMMAND`
|
293
183
|
|
294
|
-
|
184
|
+
To show only the specific rules of the Smart Bot defined on the rules file: `bot rules` or `bot rules COMMAND`
|
295
185
|
|
296
|
-
|
186
|
+
### Bot Management
|
187
|
+
To create a new bot on a channel, run on MASTER CHANNEL: `create bot on CHANNEL`. The admins of this new bot on that channel will be the MASTER ADMINS, the creator of the bot and the creator of that channel. It will create a new rules file linked to this new bot.
|
297
188
|
|
298
|
-
|
189
|
+
You can kill any bot running on any channel if you are an admin of that bot: `kill bot on CHANNEL`
|
299
190
|
|
300
|
-
|
191
|
+
If you want to pause a bot, from the channel of the bot: `pause bot`. To start it again: `start bot`
|
301
192
|
|
302
|
-
|
193
|
+
To see the status of the bots, on the MASTER CHANNEL: `bot status`
|
303
194
|
|
304
|
-
|
195
|
+
To close the Master Bot, run on MASTER CHANNEL: `exit bot`
|
305
196
|
|
306
|
-
|
197
|
+
#### Cloud Bots
|
198
|
+
If you want to create a bot that will be running on a different machine: `create cloud bot on CHANNEL`. Even though the cloud bots are running on different machines, the management can be done through the MASTER CHANNEL. The new cloud bot will be managed by your Master Bot like the others, closing, pausing...
|
307
199
|
|
308
|
-
|
200
|
+
Cloud Bots are typically used to run commands on specific environments or even different OS or networks.
|
309
201
|
|
310
|
-
|
202
|
+
### Extending rules to other channels
|
203
|
+
If you want to extend the use of your specific rules on a Bot Channel to a third channel you can use the command: `extend rules to CHANNEL`
|
311
204
|
|
312
|
-
|
205
|
+
From that moment everybody part of that channel will be able to run the specific rules from the other channel but just on demand, for example: `!run something`
|
313
206
|
|
314
|
-
|
207
|
+
To stop allowing it: `stop using rules on CHANNEL`
|
315
208
|
|
316
|
-
|
209
|
+
### Using rules from other channels
|
210
|
+
To be able to access the rules from other channel, first of all you need to be a member of that channel. Then on a private conversation with the Smart Bot or from another bot channel: `use rules from CHANNEL`
|
317
211
|
|
318
|
-
|
212
|
+
When you want to stop using those rules with the bot: `stop using rules from CHANNEL`
|
319
213
|
|
320
|
-
|
214
|
+
Also you can always call the Smart Bot from any channel, even from channels without a running Smart Bot. You can use the External Call on Demand: `@NAME_OF_BOT on #CHANNEL_NAME COMMAND`. In this case you will call the bot on #CHANNEL_NAME.
|
321
215
|
|
322
|
-
|
216
|
+
### Running Ruby code on a conversation
|
217
|
+
You can run Ruby code by using the command: `ruby THE_CODE`. For example: `!ruby require 'json'; res=[]; 20.times {res<<rand(100)}; my_json={result: res}; puts my_json.to_json`
|
323
218
|
|
324
|
-
|
219
|
+
Also it is possible to attach a Ruby file and the Smart Bot will run and post the output. You need to select Ruby as file format.
|
325
220
|
|
326
|
-
|
221
|
+
### Sending notifications
|
222
|
+
You can send notifications from MASTER CHANNEL by using `notify MESSAGE`. All Bot Channels will be notified.
|
327
223
|
|
224
|
+
If you want to send a notification message to all channels the bot joined and direct conversations with the bot: `notify all MESSAGE`
|
328
225
|
|
329
|
-
|
330
|
-
**_`@BOT_NAME on #CHANNEL_NAME COMMAND`_**
|
226
|
+
And if you want to send a notification message to the specified channel and to its extended channels: `notify #CHANNEL MESSAGE`
|
331
227
|
|
332
|
-
|
228
|
+
### Shortcuts
|
229
|
+
Sometimes your commands or rules are too long and you want to add a shortcut to be executed.
|
333
230
|
|
334
|
-
|
231
|
+
If you have for example a rule like this: `run tests on customers android app` and you want to add a shortcut: `add shortcut run tca: run tests on customers android app`
|
335
232
|
|
336
|
-
|
233
|
+
From that moment you will be able to run the command: `run tca`
|
337
234
|
|
338
|
-
|
235
|
+
That shortcut will be available for you, in case you want to make it available for everybody on the channel: `add shortcut for all Spanish account: ruby require 'iso/iban'; 10.times {puts ISO::IBAN.random('ES')}`
|
339
236
|
|
340
|
-
|
237
|
+
To see available shortcuts: `see shortcuts` and to delete a particular shortcut: `delete shortcut NAME`
|
341
238
|
|
342
|
-
|
239
|
+
### Routines
|
240
|
+
To add specific commands to be run automatically every certain amount of time or a specific time: `add routine NAME every NUMBER PERIOD COMMAND` or `add routine NAME at TIME COMMAND`
|
343
241
|
|
344
|
-
|
242
|
+
Examples:
|
243
|
+
`add routine run_tests every 3h run tests on customers`
|
244
|
+
`add routine clean_db at 17:05 clean customers temp db`
|
345
245
|
|
346
|
-
|
246
|
+
Also instead of adding a Command to be executed, you can attach a file, then the routine will be created and the attached file will be executed on the criteria specified. Only Master Admins are allowed to use it this way.
|
347
247
|
|
348
|
-
|
248
|
+
Other routine commands:
|
249
|
+
* `pause routine NAME`
|
250
|
+
* `start routine NAME`
|
251
|
+
* `remove routine NAME`
|
252
|
+
* `run routine NAME`
|
253
|
+
* `see routines`
|
349
254
|
|
350
255
|
### Tips
|
351
256
|
|
352
257
|
#### Send a file
|
353
258
|
|
354
259
|
```ruby
|
355
|
-
send_file(to, msg, filepath, title, format, type = "text")
|
260
|
+
#send_file(to, msg, filepath, title, format, type = "text")
|
356
261
|
send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'title', 'text/plain', "text")
|
357
262
|
send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'title', 'image/jpeg', "jpg")
|
358
263
|
```
|
data/lib/slack-smart-bot.rb
CHANGED
@@ -6,49 +6,90 @@ require "json"
|
|
6
6
|
require "logger"
|
7
7
|
require "fileutils"
|
8
8
|
require "open3"
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
require "nice_http"
|
10
|
+
require "nice_hash"
|
11
|
+
|
12
|
+
require_relative "slack/smart-bot/comm"
|
13
|
+
require_relative "slack/smart-bot/listen"
|
14
|
+
require_relative "slack/smart-bot/treat_message"
|
15
|
+
require_relative "slack/smart-bot/process_first"
|
16
|
+
require_relative "slack/smart-bot/process"
|
17
|
+
require_relative "slack/smart-bot/utils"
|
18
|
+
|
19
|
+
TESTING_SLACK_SMART_BOT ||= false
|
20
|
+
unless TESTING_SLACK_SMART_BOT
|
21
|
+
if ARGV.size == 0
|
22
|
+
CHANNEL = MASTER_CHANNEL
|
23
|
+
ON_MASTER_BOT = true
|
24
|
+
ADMIN_USERS = MASTER_USERS
|
25
|
+
RULES_FILE = "#{$0.gsub(".rb", "_rules.rb")}" unless defined?(RULES_FILE)
|
26
|
+
unless File.exist?(RULES_FILE)
|
27
|
+
default_rules = (__FILE__).gsub(/\.rb$/, "_rules.rb")
|
28
|
+
FileUtils.copy_file(default_rules, RULES_FILE)
|
29
|
+
end
|
30
|
+
STATUS_INIT = :on
|
31
|
+
SHORTCUTS_FILE = "slack-smart-bot_shortcuts_#{CHANNEL}.rb".gsub(" ", "_")
|
32
|
+
else
|
33
|
+
ON_MASTER_BOT = false
|
34
|
+
CHANNEL = ARGV[0]
|
35
|
+
ADMIN_USERS = ARGV[1].split(",")
|
36
|
+
RULES_FILE = ARGV[2]
|
37
|
+
STATUS_INIT = ARGV[3].to_sym
|
38
|
+
SHORTCUTS_FILE = "slack-smart-bot_shortcuts_#{CHANNEL}.rb".gsub(" ", "_")
|
18
39
|
end
|
19
|
-
STATUS_INIT = :on
|
20
|
-
else
|
21
|
-
ON_MASTER_BOT = false
|
22
|
-
CHANNEL = ARGV[0]
|
23
|
-
ADMIN_USERS = ARGV[1].split(",")
|
24
|
-
RULES_FILE = ARGV[2]
|
25
|
-
STATUS_INIT = ARGV[3].to_sym
|
26
40
|
end
|
27
41
|
|
28
|
-
SHORTCUTS_FILE = "slack-smart-bot_shortcuts_#{CHANNEL}.rb".gsub(" ", "_")
|
29
|
-
|
30
42
|
class SlackSmartBot
|
31
43
|
attr_accessor :config, :client
|
32
44
|
attr_reader :master_bot_id, :channel_id
|
33
|
-
|
45
|
+
geml = Gem.loaded_specs.values.select { |x| x.name == "slack-smart-bot" }[0]
|
46
|
+
if geml.nil?
|
47
|
+
version = ""
|
48
|
+
else
|
49
|
+
version = geml.version.to_s
|
50
|
+
end
|
51
|
+
VERSION = version
|
34
52
|
|
35
53
|
def initialize(config)
|
36
54
|
Dir.mkdir("./logs") unless Dir.exist?("./logs")
|
37
55
|
Dir.mkdir("./shortcuts") unless Dir.exist?("./shortcuts")
|
56
|
+
Dir.mkdir("./routines") unless Dir.exist?("./routines")
|
38
57
|
logfile = File.basename(RULES_FILE.gsub("_rules_", "_logs_"), ".rb") + ".log"
|
39
58
|
@logger = Logger.new("./logs/#{logfile}")
|
40
59
|
config_log = config.dup
|
41
60
|
config_log.delete(:token)
|
42
61
|
config[:silent] = false unless config.key?(:silent)
|
62
|
+
config[:testing] = false unless config.key?(:testing)
|
43
63
|
@logger.info "Initializing bot: #{config_log.inspect}"
|
44
64
|
|
65
|
+
File.new("./buffer.log", "w") if config[:testing]
|
66
|
+
|
45
67
|
config[:channel] = CHANNEL
|
46
68
|
self.config = config
|
47
69
|
|
48
70
|
Slack.configure do |conf|
|
49
71
|
conf.token = config[:token]
|
50
72
|
end
|
51
|
-
|
73
|
+
restarts = 0
|
74
|
+
created = false
|
75
|
+
while restarts < 200 and !created
|
76
|
+
begin
|
77
|
+
@logger.info "Connecting #{config_log.inspect}"
|
78
|
+
self.client = Slack::RealTime::Client.new(start_method: :rtm_connect)
|
79
|
+
created = true
|
80
|
+
rescue Exception => e
|
81
|
+
restarts += 1
|
82
|
+
if restarts < 200
|
83
|
+
@logger.fatal "*" * 50
|
84
|
+
@logger.fatal "Rescued on creation: #{e.inspect}"
|
85
|
+
@logger.info "Waiting 60 seconds to retry. restarts: #{restarts}"
|
86
|
+
puts "#{Time.now}: Not able to create client. Waiting 60 seconds to retry: #{config_log.inspect}"
|
87
|
+
sleep 60
|
88
|
+
else
|
89
|
+
exit!
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
52
93
|
|
53
94
|
@listening = Array.new
|
54
95
|
|
@@ -56,6 +97,7 @@ class SlackSmartBot
|
|
56
97
|
@shortcuts = Hash.new()
|
57
98
|
@shortcuts[:all] = Hash.new()
|
58
99
|
@rules_imported = Hash.new()
|
100
|
+
@routines = Hash.new()
|
59
101
|
|
60
102
|
if File.exist?("./shortcuts/#{SHORTCUTS_FILE}")
|
61
103
|
file_sc = IO.readlines("./shortcuts/#{SHORTCUTS_FILE}").join
|
@@ -64,6 +106,8 @@ class SlackSmartBot
|
|
64
106
|
end
|
65
107
|
end
|
66
108
|
|
109
|
+
get_routines()
|
110
|
+
|
67
111
|
if ON_MASTER_BOT and File.exist?($0.gsub(".rb", "_bots.rb"))
|
68
112
|
get_bots_created()
|
69
113
|
if @bots_created.kind_of?(Hash)
|
@@ -90,11 +134,27 @@ class SlackSmartBot
|
|
90
134
|
begin
|
91
135
|
user_info = client.web_client.users_info(user: "#{"@" if config[:nick][0] != "@"}#{config[:nick]}")
|
92
136
|
config[:nick_id] = user_info.user.id
|
137
|
+
rescue Slack::Web::Api::Errors::TooManyRequestsError
|
138
|
+
@logger.fatal "TooManyRequestsError"
|
139
|
+
abort("TooManyRequestsError please re run the bot and be sure of executing first: killall ruby")
|
93
140
|
rescue Exception => stack
|
94
141
|
@logger.fatal stack
|
95
142
|
abort("The bot user specified on settings: #{config[:nick]}, doesn't exist on Slack. Execution aborted")
|
96
143
|
end
|
97
144
|
|
145
|
+
begin
|
146
|
+
@admin_users_id = []
|
147
|
+
ADMIN_USERS.each do |au|
|
148
|
+
user_info = client.web_client.users_info(user: "@#{au}")
|
149
|
+
@admin_users_id << user_info.user.id
|
150
|
+
end
|
151
|
+
rescue Slack::Web::Api::Errors::TooManyRequestsError
|
152
|
+
@logger.fatal "TooManyRequestsError"
|
153
|
+
abort("TooManyRequestsError please re run the bot and be sure of executing first: killall ruby")
|
154
|
+
rescue Exception => stack
|
155
|
+
abort("The admin user specified on settings: #{ADMIN_USERS.join(", ")}, doesn't exist on Slack. Execution aborted")
|
156
|
+
end
|
157
|
+
|
98
158
|
client.on :hello do
|
99
159
|
m = "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com."
|
100
160
|
puts m
|
@@ -108,6 +168,13 @@ class SlackSmartBot
|
|
108
168
|
unless config[:silent]
|
109
169
|
respond "Smart Bot started v#{VERSION}#{version_message}\nIf you want to know what I can do for you: `bot help`.\n`bot rules` if you want to display just the specific rules of this channel.\nYou can talk to me privately if you prefer it."
|
110
170
|
end
|
171
|
+
@routines.each do |ch, rout|
|
172
|
+
rout.each do |k, v|
|
173
|
+
if !v[:running] and v[:channel_name] == CHANNEL
|
174
|
+
create_routine_thread(k)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
111
178
|
end
|
112
179
|
|
113
180
|
@status = STATUS_INIT
|
@@ -118,6 +185,14 @@ class SlackSmartBot
|
|
118
185
|
@channel_id = @channels_id[CHANNEL].dup
|
119
186
|
@master_bot_id = @channels_id[MASTER_CHANNEL].dup
|
120
187
|
|
188
|
+
get_routines()
|
189
|
+
if @routines.key?(@channel_id)
|
190
|
+
@routines[@channel_id].each do |k, v|
|
191
|
+
@routines[@channel_id][k][:running] = false
|
192
|
+
end
|
193
|
+
end
|
194
|
+
update_routines()
|
195
|
+
|
121
196
|
client.on :close do |_data|
|
122
197
|
m = "Connection closing, exiting. #{Time.now}"
|
123
198
|
@logger.info m
|
@@ -133,1261 +208,5 @@ class SlackSmartBot
|
|
133
208
|
self
|
134
209
|
end
|
135
210
|
|
136
|
-
def update_bots_file
|
137
|
-
file = File.open($0.gsub(".rb", "_bots.rb"), "w")
|
138
|
-
bots_created = @bots_created.dup
|
139
|
-
bots_created.each { |k, v| v[:thread] = "" }
|
140
|
-
file.write bots_created.inspect
|
141
|
-
file.close
|
142
|
-
end
|
143
|
-
|
144
|
-
def get_bots_created
|
145
|
-
if File.exist?($0.gsub(".rb", "_bots.rb"))
|
146
|
-
if !defined?(@datetime_bots_created) or @datetime_bots_created!=File.mtime($0.gsub(".rb", "_bots.rb"))
|
147
|
-
file_conf = IO.readlines($0.gsub(".rb", "_bots.rb")).join
|
148
|
-
if file_conf.to_s() == ""
|
149
|
-
@bots_created = {}
|
150
|
-
else
|
151
|
-
@bots_created = eval(file_conf)
|
152
|
-
end
|
153
|
-
@datetime_bots_created = File.mtime($0.gsub(".rb", "_bots.rb"))
|
154
|
-
@bots_created.each do |k,v| # to be compatible with old versions
|
155
|
-
v[:extended] = [] unless v.key?(:extended)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def update_shortcuts_file
|
162
|
-
file = File.open("./shortcuts/#{SHORTCUTS_FILE}", "w")
|
163
|
-
file.write @shortcuts.inspect
|
164
|
-
file.close
|
165
|
-
end
|
166
|
-
|
167
|
-
def update_rules_imported
|
168
|
-
file = File.open("./rules/rules_imported.rb", "w")
|
169
|
-
file.write @rules_imported.inspect
|
170
|
-
file.close
|
171
|
-
end
|
172
|
-
|
173
|
-
def get_channels_name_and_id
|
174
|
-
#todo: add pagination for case more than 1000 channels on the workspace
|
175
|
-
channels = client.web_client.conversations_list(
|
176
|
-
types: 'private_channel,public_channel',
|
177
|
-
limit: '1000',
|
178
|
-
exclude_archived: 'true').channels
|
179
|
-
|
180
|
-
@channels_id = Hash.new()
|
181
|
-
@channels_name = Hash.new()
|
182
|
-
channels.each do |ch|
|
183
|
-
unless ch.is_archived
|
184
|
-
@channels_id[ch.name] = ch.id
|
185
|
-
@channels_name[ch.id] = ch.name
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
#help: ===================================
|
191
|
-
#help:
|
192
|
-
#help: *Commands from Channels without a bot:*
|
193
|
-
#help:
|
194
|
-
#help: ----------------------------------------------
|
195
|
-
#help:
|
196
|
-
#help: `@BOT_NAME on #CHANNEL_NAME COMMAND`
|
197
|
-
#help: `@BOT_NAME #CHANNEL_NAME COMMAND`
|
198
|
-
#help: It will run the supplied command using the rules on the channel supplied.
|
199
|
-
#help: You need to join the specified channel to be able to use those rules.
|
200
|
-
#help: Also you can use this command to call another bot from a channel with a running bot.
|
201
|
-
def listen
|
202
|
-
@salutations = [config[:nick], config[:nick_id], "bot", "smart"]
|
203
|
-
get_bots_created()
|
204
|
-
client.on :message do |data|
|
205
|
-
if data.channel[0] == "D" or data.channel[0] == "C" or data.channel[0] == "G" #Direct message or Channel or Private Channel
|
206
|
-
dest = data.channel
|
207
|
-
else # not treated
|
208
|
-
dest = nil
|
209
|
-
end
|
210
|
-
#todo: sometimes data.user is nil, check the problem.
|
211
|
-
@logger.warn "!dest is nil. user: #{data.user}, channel: #{data.channel}, message: #{data.text}" if dest.nil?
|
212
|
-
if !data.files.nil? and data.files.size == 1 and data.text.to_s == '' and data.files[0].filetype == "ruby"
|
213
|
-
data.text = 'ruby'
|
214
|
-
end
|
215
|
-
typem = :dont_treat
|
216
|
-
if !dest.nil? and !data.text.nil? and !data.text.to_s.match?(/^\s*$/)
|
217
|
-
if data.text.match(/^<@#{config[:nick_id]}>\s(on\s)?<#(\w+)\|(.+)>\s*:?\s*(.*)/im)
|
218
|
-
channel_rules = $2
|
219
|
-
channel_rules_name = $3
|
220
|
-
# to be treated only on the bot of the requested channel
|
221
|
-
if @channel_id == channel_rules
|
222
|
-
data.text = $4
|
223
|
-
typem = :on_call
|
224
|
-
end
|
225
|
-
|
226
|
-
elsif dest == @master_bot_id
|
227
|
-
if ON_MASTER_BOT #only to be treated on master mot channel
|
228
|
-
typem = :on_master
|
229
|
-
end
|
230
|
-
elsif @bots_created.key?(dest)
|
231
|
-
if @channel_id == dest #only to be treated by the bot on the channel
|
232
|
-
typem = :on_bot
|
233
|
-
end
|
234
|
-
elsif dest[0]=="D" #Direct message
|
235
|
-
if ON_MASTER_BOT #only to be treated by master bot
|
236
|
-
typem = :on_dm
|
237
|
-
end
|
238
|
-
elsif dest[0]=="G" #private group
|
239
|
-
if ON_MASTER_BOT #only to be treated by master bot
|
240
|
-
typem = :on_pg
|
241
|
-
end
|
242
|
-
elsif dest[0]=='C'
|
243
|
-
#only to be treated on the channel of the bot. excluding running ruby
|
244
|
-
if !ON_MASTER_BOT and @bots_created[@channel_id][:extended].include?(@channels_name[dest]) and
|
245
|
-
!data.text.match?(/^!?\s*(ruby|code)\s+/)
|
246
|
-
typem = :on_extended
|
247
|
-
elsif ON_MASTER_BOT and data.text.match?(/^!?\s*(ruby|code)\s+/) #or in case of running ruby, the master bot
|
248
|
-
@bots_created.each do |k,v|
|
249
|
-
if v.key?(:extended) and v[:extended].include?(@channels_name[dest])
|
250
|
-
typem = :on_extended
|
251
|
-
break
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
end
|
256
|
-
end
|
257
|
-
unless typem == :dont_treat
|
258
|
-
begin
|
259
|
-
command = data.text
|
260
|
-
|
261
|
-
#todo: when changed @questions user_id then move user_info inside the ifs to avoid calling it when not necessary
|
262
|
-
user_info = client.web_client.users_info(user: data.user)
|
263
|
-
|
264
|
-
#when added special characters on the message
|
265
|
-
if command.size >= 2 and
|
266
|
-
((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_"))
|
267
|
-
command = command[1..-2]
|
268
|
-
end
|
269
|
-
|
270
|
-
#ruby file attached
|
271
|
-
if !data.files.nil? and data.files.size == 1 and
|
272
|
-
(command.match?(/^(ruby|code)\s*$/) or (command.match?(/^\s*$/) and data.files[0].filetype == "ruby") or
|
273
|
-
(typem==:on_call and data.files[0].filetype == "ruby"))
|
274
|
-
res = Faraday.new("https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" }).get(data.files[0].url_private)
|
275
|
-
command += " ruby" if command!='ruby'
|
276
|
-
command = "#{command} #{res.body.to_s.force_encoding("UTF-8")}"
|
277
|
-
end
|
278
|
-
|
279
|
-
if typem == :on_call
|
280
|
-
command = "!" + command unless command[0] == "!" or command.match?(/^\s*$/)
|
281
|
-
|
282
|
-
#todo: add pagination for case more than 1000 channels on the workspace
|
283
|
-
channels = client.web_client.conversations_list(
|
284
|
-
types: 'private_channel,public_channel',
|
285
|
-
limit: '1000',
|
286
|
-
exclude_archived: 'true').channels
|
287
|
-
channel_found = channels.detect { |c| c.name == channel_rules_name }
|
288
|
-
members = client.web_client.conversations_members(channel: @channels_id[channel_rules_name]).members unless channel_found.nil?
|
289
|
-
if channel_found.nil?
|
290
|
-
@logger.fatal "Not possible to find the channel #{channel_rules_name}"
|
291
|
-
elsif channel_found.name == MASTER_CHANNEL
|
292
|
-
respond "You cannot use the rules from Master Channel on any other channel.", dest
|
293
|
-
elsif @status != :on
|
294
|
-
respond "The bot in that channel is not :on", dest
|
295
|
-
elsif data.user == channel_found.creator or members.include?(data.user)
|
296
|
-
res = process_first(user_info.user, command, dest, channel_rules, typem, data.files)
|
297
|
-
else
|
298
|
-
respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", dest
|
299
|
-
end
|
300
|
-
|
301
|
-
elsif @questions.keys.include?(user_info.user.name)
|
302
|
-
#todo: @questions key should be the id not the name. change it everywhere
|
303
|
-
dest = data.channel
|
304
|
-
res = process_first(user_info.user, command, dest, @channel_id, typem, data.files)
|
305
|
-
|
306
|
-
elsif ON_MASTER_BOT and typem ==:on_extended and
|
307
|
-
command.size > 0 and command[0] != "-"
|
308
|
-
# to run ruby only from the master bot for the case more than one extended
|
309
|
-
res = process_first(user_info.user, command, dest, @channel_id, typem, data.files)
|
310
|
-
|
311
|
-
elsif !ON_MASTER_BOT and @bots_created[@channel_id].key?(:extended) and
|
312
|
-
@bots_created[@channel_id][:extended].include?(@channels_name[data.channel]) and
|
313
|
-
command.size > 0 and command[0] != "-"
|
314
|
-
res = process_first(user_info.user, command, dest, @channel_id, typem, data.files)
|
315
|
-
elsif (dest[0] == "D" or @channel_id == data.channel or data.user == config[:nick_id]) and
|
316
|
-
command.size > 0 and command[0] != "-"
|
317
|
-
res = process_first(user_info.user, command, dest, data.channel, typem, data.files)
|
318
|
-
# if @botname on #channel_rules: do something
|
319
|
-
end
|
320
|
-
rescue Exception => stack
|
321
|
-
@logger.fatal stack
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
@logger.info "Bot listening"
|
327
|
-
client.start!
|
328
|
-
end
|
329
|
-
|
330
|
-
def process_first(user, text, dest, dchannel, typem, files)
|
331
|
-
nick = user.name
|
332
|
-
rules_file = ""
|
333
|
-
|
334
|
-
if typem == :on_call
|
335
|
-
rules_file = RULES_FILE
|
336
|
-
|
337
|
-
elsif dest[0] == "C" or dest[0] == "G" # on a channel or private channel
|
338
|
-
rules_file = RULES_FILE
|
339
|
-
|
340
|
-
if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
|
341
|
-
unless @bots_created.key?(@rules_imported[user.id][dchannel])
|
342
|
-
get_bots_created()
|
343
|
-
end
|
344
|
-
if @bots_created.key?(@rules_imported[user.id][dchannel])
|
345
|
-
rules_file = @bots_created[@rules_imported[user.id][dchannel]][:rules_file]
|
346
|
-
end
|
347
|
-
end
|
348
|
-
elsif dest[0] == "D" and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) #direct message
|
349
|
-
unless @bots_created.key?(@rules_imported[user.id][user.id])
|
350
|
-
get_bots_created()
|
351
|
-
end
|
352
|
-
if @bots_created.key?(@rules_imported[user.id][user.id])
|
353
|
-
rules_file = @bots_created[@rules_imported[user.id][user.id]][:rules_file]
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
if nick == config[:nick] #if message is coming from the bot
|
358
|
-
begin
|
359
|
-
case text
|
360
|
-
when /^Bot has been (closed|killed) by/i
|
361
|
-
if CHANNEL == @channels_name[dchannel]
|
362
|
-
@logger.info "#{nick}: #{text}"
|
363
|
-
exit!
|
364
|
-
end
|
365
|
-
when /^Changed status on (.+) to :(.+)/i
|
366
|
-
channel_name = $1
|
367
|
-
status = $2
|
368
|
-
if ON_MASTER_BOT or CHANNEL == channel_name
|
369
|
-
@bots_created[@channels_id[channel_name]][:status] = status.to_sym
|
370
|
-
update_bots_file()
|
371
|
-
if CHANNEL == channel_name
|
372
|
-
@logger.info "#{nick}: #{text}"
|
373
|
-
else #on master bot
|
374
|
-
@logger.info "Changed status on #{channel_name} to :#{status}"
|
375
|
-
end
|
376
|
-
end
|
377
|
-
when /extended the rules from (.+) to be used on (.+)\.$/i
|
378
|
-
from_name = $1
|
379
|
-
to_name = $2
|
380
|
-
if ON_MASTER_BOT and @bots_created[@channels_id[from_name]][:cloud]
|
381
|
-
@bots_created[@channels_id[from_name]][:extended] << to_name
|
382
|
-
@bots_created[@channels_id[from_name]][:extended].uniq!
|
383
|
-
update_bots_file()
|
384
|
-
end
|
385
|
-
|
386
|
-
when /removed the access to the rules of (.+) from (.+)\.$/i
|
387
|
-
from_name = $1
|
388
|
-
to_name = $2
|
389
|
-
if ON_MASTER_BOT and @bots_created[@channels_id[from_name]][:cloud]
|
390
|
-
@bots_created[@channels_id[from_name]][:extended].delete(to_name)
|
391
|
-
update_bots_file()
|
392
|
-
end
|
393
|
-
|
394
|
-
end
|
395
|
-
|
396
|
-
return :next #don't continue analyzing
|
397
|
-
rescue Exception => stack
|
398
|
-
@logger.fatal stack
|
399
|
-
return :next
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
|
-
#only for shortcuts
|
404
|
-
if text.match(/^@?(#{config[:nick]}):*\s+(.+)\s*/im) or
|
405
|
-
text.match(/^()!\s*(.+)\s*/im) or
|
406
|
-
text.match(/^()<@#{config[:nick_id]}>\s+(.+)\s*/im)
|
407
|
-
command = $2
|
408
|
-
addexcl = true
|
409
|
-
else
|
410
|
-
addexcl = false
|
411
|
-
command = text.downcase.lstrip.rstrip
|
412
|
-
end
|
413
|
-
if command.scan(/^(shortcut|sc)\s+(.+)/i).any? or
|
414
|
-
(@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or
|
415
|
-
(@shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command))
|
416
|
-
command = $2.downcase unless $2.nil?
|
417
|
-
if @shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)
|
418
|
-
text = @shortcuts[nick][command].dup
|
419
|
-
elsif @shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)
|
420
|
-
text = @shortcuts[:all][command].dup
|
421
|
-
else
|
422
|
-
respond "Shortcut not found", dest unless dest[0]=="C" and dchannel != dest #on extended channel
|
423
|
-
return :next
|
424
|
-
end
|
425
|
-
text = "!" + text if addexcl and text[0] != "!"
|
426
|
-
end
|
427
|
-
|
428
|
-
if @questions.keys.include?(nick)
|
429
|
-
command = @questions[nick]
|
430
|
-
@questions[nick] = text
|
431
|
-
else
|
432
|
-
command = text
|
433
|
-
end
|
434
|
-
begin
|
435
|
-
t = Thread.new do
|
436
|
-
begin
|
437
|
-
processed = process(user, command, dest, dchannel, rules_file, typem)
|
438
|
-
@logger.info "command: #{nick}> #{command}" if processed
|
439
|
-
on_demand = false
|
440
|
-
if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or
|
441
|
-
command.match(/^()!(.+)/im) or
|
442
|
-
command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im)
|
443
|
-
command = $2
|
444
|
-
on_demand = true
|
445
|
-
end
|
446
|
-
if @status == :on and
|
447
|
-
(@questions.keys.include?(nick) or
|
448
|
-
(@listening.include?(nick) and typem!=:on_extended) or
|
449
|
-
dest[0] == "D" or on_demand)
|
450
|
-
@logger.info "command: #{nick}> #{command}" unless processed
|
451
|
-
#todo: verify this
|
452
|
-
|
453
|
-
if dest[0] == "C" or dest[0] == "G" or (dest[0]=="D" and typem==:on_call)
|
454
|
-
if typem!=:on_call and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
|
455
|
-
if @bots_created.key?(@rules_imported[user.id][dchannel])
|
456
|
-
if @bots_created[@rules_imported[user.id][dchannel]][:status] != :on
|
457
|
-
respond "The bot on that channel is not :on", dest
|
458
|
-
rules_file = ""
|
459
|
-
end
|
460
|
-
end
|
461
|
-
end
|
462
|
-
unless rules_file.empty?
|
463
|
-
begin
|
464
|
-
eval(File.new(rules_file).read) if File.exist?(rules_file)
|
465
|
-
rescue Exception => stack
|
466
|
-
@logger.fatal "ERROR ON RULES FILE: #{rules_file}"
|
467
|
-
@logger.fatal stack
|
468
|
-
end
|
469
|
-
if defined?(rules)
|
470
|
-
command[0] = "" if command[0] == "!"
|
471
|
-
command.gsub!(/^@\w+:*\s*/, "")
|
472
|
-
if method(:rules).arity == 4
|
473
|
-
rules(user, command, processed, dest)
|
474
|
-
else
|
475
|
-
rules(user, command, processed, dest, files)
|
476
|
-
end
|
477
|
-
else
|
478
|
-
@logger.warn "It seems like rules method is not defined"
|
479
|
-
end
|
480
|
-
end
|
481
|
-
elsif @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id)
|
482
|
-
if @bots_created.key?(@rules_imported[user.id][user.id])
|
483
|
-
if @bots_created[@rules_imported[user.id][user.id]][:status] == :on
|
484
|
-
begin
|
485
|
-
eval(File.new(rules_file).read) if File.exist?(rules_file)
|
486
|
-
rescue Exception => stack
|
487
|
-
@logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
|
488
|
-
@logger.fatal stack
|
489
|
-
end
|
490
|
-
else
|
491
|
-
respond "The bot on <##{@rules_imported[user.id][user.id]}|#{@bots_created[@rules_imported[user.id][user.id]][:channel_name]}> is not :on", dest
|
492
|
-
rules_file = ""
|
493
|
-
end
|
494
|
-
end
|
495
|
-
|
496
|
-
unless rules_file.empty?
|
497
|
-
if defined?(rules)
|
498
|
-
command[0] = "" if command[0] == "!"
|
499
|
-
command.gsub!(/^@\w+:*\s*/, "")
|
500
|
-
if method(:rules).arity == 4
|
501
|
-
rules(user, command, processed, dest)
|
502
|
-
else
|
503
|
-
rules(user, command, processed, dest, files)
|
504
|
-
end
|
505
|
-
else
|
506
|
-
@logger.warn "It seems like rules method is not defined"
|
507
|
-
end
|
508
|
-
end
|
509
|
-
else
|
510
|
-
@logger.info "it is a direct message with no rules file selected so no rules file executed."
|
511
|
-
unless processed
|
512
|
-
resp = ["what", "huh", "sorry", "what do you mean", "I don't understand"].sample
|
513
|
-
respond "#{resp}?", dest
|
514
|
-
end
|
515
|
-
end
|
516
|
-
end
|
517
|
-
rescue Exception => stack
|
518
|
-
@logger.fatal stack
|
519
|
-
end
|
520
|
-
end
|
521
|
-
rescue => e
|
522
|
-
@logger.error "exception: #{e.inspect}"
|
523
|
-
end
|
524
|
-
end
|
525
|
-
|
526
|
-
#help: ===================================
|
527
|
-
#help:
|
528
|
-
#help: *General commands:*
|
529
|
-
#help:
|
530
|
-
def process(user, command, dest, dchannel, rules_file, typem)
|
531
|
-
from = user.name
|
532
|
-
display_name = user.profile.display_name
|
533
|
-
processed = true
|
534
|
-
|
535
|
-
if typem == :on_master or typem == :on_bot or typem ==:on_pg or typem == :on_dm
|
536
|
-
case command
|
537
|
-
|
538
|
-
#help: ----------------------------------------------
|
539
|
-
#help: `Hello Bot`
|
540
|
-
#help: `Hello Smart`
|
541
|
-
#help: `Hello THE_NAME_OF_THE_BOT`
|
542
|
-
#help: Also apart of Hello you can use _Hallo, Hi, Hola, What's up, Hey, Hæ_
|
543
|
-
#help: Bot starts listening to you
|
544
|
-
#help: If you want to avoid a single message to be treated by the smart bot, start the message by -
|
545
|
-
#help:
|
546
|
-
when /^(Hello|Hallo|Hi|Hola|What's\sup|Hey|Hæ)\s(#{@salutations.join("|")})\s*$/i
|
547
|
-
if @status == :on
|
548
|
-
greetings = ["Hello", "Hallo", "Hi", "Hola", "What's up", "Hey", "Hæ"].sample
|
549
|
-
respond "#{greetings} #{display_name}", dest
|
550
|
-
if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) and dest[0] == "D"
|
551
|
-
respond "You are using specific rules for channel: <##{@rules_imported[user.id][user.id]}>", dest
|
552
|
-
elsif @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel) and (dest[0] == "C" or dest[0] == "G")
|
553
|
-
respond "You are using specific rules for channel: <##{@rules_imported[user.id][dchannel]}>", dest
|
554
|
-
end
|
555
|
-
@listening << from unless @listening.include?(from)
|
556
|
-
end
|
557
|
-
|
558
|
-
#help: ----------------------------------------------
|
559
|
-
#help: `Bye Bot`
|
560
|
-
#help: `Bye Smart`
|
561
|
-
#help: `Bye NAME_OF_THE_BOT`
|
562
|
-
#help: Also apart of Bye you can use _Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu_
|
563
|
-
#help: Bot stops listening to you
|
564
|
-
#help:
|
565
|
-
when /^(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i
|
566
|
-
if @status == :on
|
567
|
-
bye = ["Bye", "Bæ", "Good Bye", "Adiós", "Ciao", "Bless", "Bless bless", "Adeu"].sample
|
568
|
-
respond "#{bye} #{display_name}", dest
|
569
|
-
@listening.delete(from)
|
570
|
-
end
|
571
|
-
|
572
|
-
#help: ----------------------------------------------
|
573
|
-
#help: `bot help`
|
574
|
-
#help: `bot what can I do?`
|
575
|
-
#help: `bot rules`
|
576
|
-
#help: it will display this help
|
577
|
-
#help: `bot rules` will show only the specific rules for this channel.
|
578
|
-
when /^bot\s+(rules|help)/i, /^bot,? what can I do/i
|
579
|
-
if $1.to_s.match?(/rules/i)
|
580
|
-
specific = true
|
581
|
-
else
|
582
|
-
specific = false
|
583
|
-
end
|
584
|
-
help_message_rules = ''
|
585
|
-
if !specific
|
586
|
-
help_message = IO.readlines(__FILE__).join
|
587
|
-
if ADMIN_USERS.include?(from) #admin user
|
588
|
-
respond "*Commands for administrators:*\n#{help_message.scan(/#\s*help\s*admin:(.*)/).join("\n")}", dest
|
589
|
-
end
|
590
|
-
if ON_MASTER_BOT and (dest[0] == "C" or dest[0] == "G")
|
591
|
-
respond "*Commands only on Master Channel <##{@master_bot_id}>:*\n#{help_message.scan(/#\s*help\s*master:(.*)/).join("\n")}", dest
|
592
|
-
end
|
593
|
-
respond help_message.scan(/#\s*help\s*:(.*)/).join("\n"), dest
|
594
|
-
end
|
595
|
-
if dest[0] == "C" or dest[0] == "G" # on a channel
|
596
|
-
if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
|
597
|
-
if @bots_created.key?(@rules_imported[user.id][dchannel])
|
598
|
-
respond "*You are using rules from another channel: <##{@rules_imported[user.id][dchannel]}>. These are the specific commands for that channel:*", dest
|
599
|
-
end
|
600
|
-
end
|
601
|
-
help_message_rules = IO.readlines(rules_file).join
|
602
|
-
respond help_message_rules.scan(/#\s*help\s*:(.*)/).join("\n"), dest
|
603
|
-
elsif dest[0] == "D" and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) #direct message
|
604
|
-
if @bots_created.key?(@rules_imported[user.id][user.id])
|
605
|
-
respond "*You are using rules from channel: <##{@rules_imported[user.id][user.id]}>. These are the specific commands for that channel:*", dest
|
606
|
-
help_message_rules = IO.readlines(rules_file).join
|
607
|
-
respond help_message_rules.scan(/#\s*help\s*:(.*)/).join("\n"), dest
|
608
|
-
end
|
609
|
-
end
|
610
|
-
if specific
|
611
|
-
unless rules_file.empty?
|
612
|
-
begin
|
613
|
-
eval(File.new(rules_file).read) if File.exist?(rules_file)
|
614
|
-
end
|
615
|
-
end
|
616
|
-
if defined?(git_project) and git_project.to_s!='' and help_message_rules != ''
|
617
|
-
respond "Git project: #{git_project}", dest
|
618
|
-
else
|
619
|
-
def git_project() '' end
|
620
|
-
def project_folder() '' end
|
621
|
-
end
|
622
|
-
|
623
|
-
else
|
624
|
-
respond "Slack Smart Bot Github project: https://github.com/MarioRuiz/slack-smart-bot", dest
|
625
|
-
end
|
626
|
-
|
627
|
-
#help: ===================================
|
628
|
-
#help:
|
629
|
-
#help: *These commands will run only when on a private conversation with the bot:*
|
630
|
-
#help:
|
631
|
-
#help: ----------------------------------------------
|
632
|
-
#help: `use rules from CHANNEL`
|
633
|
-
#help: it will use the rules from the specified channel.
|
634
|
-
#help: you need to be part of that channel to be able to use the rules.
|
635
|
-
#help:
|
636
|
-
when /^use rules (from\s+)<#C\w+\|(.+)>/i, /^use rules (from\s+)(.+)/i
|
637
|
-
channel = $2
|
638
|
-
#todo: add pagination for case more than 1000 channels on the workspace
|
639
|
-
channels = client.web_client.conversations_list(
|
640
|
-
types: 'private_channel,public_channel',
|
641
|
-
limit: '1000',
|
642
|
-
exclude_archived: 'true').channels
|
643
|
-
|
644
|
-
channel_found = channels.detect { |c| c.name == channel }
|
645
|
-
members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil?
|
646
|
-
|
647
|
-
if channel_found.nil?
|
648
|
-
respond "The channel you are trying to use doesn't exist", dest
|
649
|
-
elsif channel_found.name == MASTER_CHANNEL
|
650
|
-
respond "You cannot use the rules from Master Channel on any other channel.", dest
|
651
|
-
elsif !@bots_created.key?(@channels_id[channel])
|
652
|
-
respond "There is no bot running on that channel.", dest
|
653
|
-
elsif @bots_created.key?(@channels_id[channel]) and @bots_created[@channels_id[channel]][:status] != :on
|
654
|
-
respond "The bot in that channel is not :on", dest
|
655
|
-
else
|
656
|
-
if user.id == channel_found.creator or members.include?(user.id)
|
657
|
-
@rules_imported[user.id] = {} unless @rules_imported.key?(user.id)
|
658
|
-
if dest[0] == "C" or dest[0] == "G" #todo: take in consideration bots that are not master
|
659
|
-
@rules_imported[user.id][dchannel] = channel_found.id
|
660
|
-
else
|
661
|
-
@rules_imported[user.id][user.id] = channel_found.id
|
662
|
-
end
|
663
|
-
update_rules_imported() if ON_MASTER_BOT
|
664
|
-
respond "I'm using now the rules from <##{channel_found.id}>", dest
|
665
|
-
def git_project() "" end
|
666
|
-
def project_folder() "" end
|
667
|
-
else
|
668
|
-
respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", dest
|
669
|
-
end
|
670
|
-
end
|
671
|
-
|
672
|
-
#help: ----------------------------------------------
|
673
|
-
#help: `stop using rules from CHANNEL`
|
674
|
-
#help: it will stop using the rules from the specified channel.
|
675
|
-
#help:
|
676
|
-
when /^stop using rules (from\s+)<#\w+\|(.+)>/i, /^stop using rules (from\s+)(.+)/i
|
677
|
-
channel = $2
|
678
|
-
if @channels_id.key?(channel)
|
679
|
-
channel_id = @channels_id[channel]
|
680
|
-
else
|
681
|
-
channel_id = channel
|
682
|
-
end
|
683
|
-
if dest[0] == "C" or dest[0] == "G" #channel
|
684
|
-
if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
|
685
|
-
if @rules_imported[user.id][dchannel] != channel_id
|
686
|
-
respond "You are not using those rules.", dest
|
687
|
-
else
|
688
|
-
@rules_imported[user.id].delete(dchannel)
|
689
|
-
update_rules_imported() if ON_MASTER_BOT
|
690
|
-
respond "You won't be using those rules from now on.", dest
|
691
|
-
def git_project() "" end
|
692
|
-
def project_folder() "" end
|
693
|
-
end
|
694
|
-
else
|
695
|
-
respond "You were not using those rules.", dest
|
696
|
-
end
|
697
|
-
else #direct message
|
698
|
-
if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id)
|
699
|
-
if @rules_imported[user.id][user.id] != channel_id
|
700
|
-
respond "You are not using those rules.", dest
|
701
|
-
else
|
702
|
-
@rules_imported[user.id].delete(user.id)
|
703
|
-
update_rules_imported() if ON_MASTER_BOT
|
704
|
-
respond "You won't be using those rules from now on.", dest
|
705
|
-
def git_project() "" end
|
706
|
-
def project_folder() "" end
|
707
|
-
end
|
708
|
-
else
|
709
|
-
respond "You were not using those rules.", dest
|
710
|
-
end
|
711
|
-
end
|
712
|
-
|
713
|
-
#helpadmin: ----------------------------------------------
|
714
|
-
#helpadmin: `exit bot`
|
715
|
-
#helpadmin: `quit bot`
|
716
|
-
#helpadmin: `close bot`
|
717
|
-
#helpadmin: The bot stops running and also stops all the bots created from this master channel
|
718
|
-
#helpadmin: You can use this command only if you are an admin user and you are on the master channel
|
719
|
-
#helpadmin:
|
720
|
-
when /^exit\sbot\s*$/i, /^quit\sbot\s*$/i, /^close\sbot\s*$/i
|
721
|
-
if ON_MASTER_BOT
|
722
|
-
if ADMIN_USERS.include?(from) #admin user
|
723
|
-
unless @questions.keys.include?(from)
|
724
|
-
ask("are you sure?", command, from, dest)
|
725
|
-
else
|
726
|
-
case @questions[from]
|
727
|
-
when /yes/i, /yep/i, /sure/i
|
728
|
-
respond "Game over!", dest
|
729
|
-
respond "Ciao #{display_name}!", dest
|
730
|
-
@bots_created.each { |key, value|
|
731
|
-
value[:thread] = ""
|
732
|
-
send_msg_channel(key, "Bot has been closed by #{from}")
|
733
|
-
sleep 0.5
|
734
|
-
}
|
735
|
-
update_bots_file()
|
736
|
-
sleep 0.5
|
737
|
-
exit!
|
738
|
-
when /no/i, /nope/i, /cancel/i
|
739
|
-
@questions.delete(from)
|
740
|
-
respond "Thanks, I'm happy to be alive", dest
|
741
|
-
else
|
742
|
-
respond "I don't understand", dest
|
743
|
-
ask("are you sure do you want me to close? (yes or no)", "quit bot", from, dest)
|
744
|
-
end
|
745
|
-
end
|
746
|
-
else
|
747
|
-
respond "Only admin users can kill me", dest
|
748
|
-
end
|
749
|
-
else
|
750
|
-
respond "To do this you need to be an admin user in the master channel: <##{@master_bot_id}>", dest
|
751
|
-
end
|
752
|
-
|
753
|
-
#helpadmin: ----------------------------------------------
|
754
|
-
#helpadmin: `start bot`
|
755
|
-
#helpadmin: `start this bot`
|
756
|
-
#helpadmin: the bot will start to listen
|
757
|
-
#helpadmin: You can use this command only if you are an admin user
|
758
|
-
#helpadmin:
|
759
|
-
when /^start\s(this\s)?bot$/i
|
760
|
-
if ADMIN_USERS.include?(from) #admin user
|
761
|
-
respond "This bot is running and listening from now on. You can pause again: pause this bot", dest
|
762
|
-
@status = :on
|
763
|
-
unless ON_MASTER_BOT
|
764
|
-
send_msg_channel MASTER_CHANNEL, "Changed status on #{CHANNEL} to :on"
|
765
|
-
end
|
766
|
-
else
|
767
|
-
respond "Only admin users can change my status", dest
|
768
|
-
end
|
769
|
-
|
770
|
-
#helpadmin: ----------------------------------------------
|
771
|
-
#helpadmin: `pause bot`
|
772
|
-
#helpadmin: `pause this bot`
|
773
|
-
#helpadmin: the bot will pause so it will listen only to admin commands
|
774
|
-
#helpadmin: You can use this command only if you are an admin user
|
775
|
-
#helpadmin:
|
776
|
-
when /^pause\s(this\s)?bot$/i
|
777
|
-
if ADMIN_USERS.include?(from) #admin user
|
778
|
-
respond "This bot is paused from now on. You can start it again: start this bot", dest
|
779
|
-
respond "zZzzzzZzzzzZZZZZZzzzzzzzz", dest
|
780
|
-
@status = :paused
|
781
|
-
unless ON_MASTER_BOT
|
782
|
-
send_msg_channel MASTER_CHANNEL, "Changed status on #{CHANNEL} to :paused"
|
783
|
-
end
|
784
|
-
else
|
785
|
-
respond "Only admin users can put me on pause", dest
|
786
|
-
end
|
787
|
-
|
788
|
-
#helpadmin: ----------------------------------------------
|
789
|
-
#helpadmin: `bot status`
|
790
|
-
#helpadmin: Displays the status of the bot
|
791
|
-
#helpadmin: If on master channel and admin user also it will display info about bots created
|
792
|
-
#helpadmin:
|
793
|
-
when /^bot\sstatus/i
|
794
|
-
get_bots_created()
|
795
|
-
gems_remote = `gem list slack-smart-bot --remote`
|
796
|
-
version_remote = gems_remote.to_s().scan(/slack-smart-bot \((\d+\.\d+\.\d+)/).join
|
797
|
-
version_message = ""
|
798
|
-
if version_remote != VERSION
|
799
|
-
version_message = " There is a new available version: #{version_remote}."
|
800
|
-
end
|
801
|
-
require 'socket'
|
802
|
-
ip_address = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
|
803
|
-
respond "*#{Socket.gethostname} (#{ip_address})*\n\tStatus: #{@status}.\n\tVersion: #{VERSION}.#{version_message}\n\tRules file: #{File.basename RULES_FILE} ", dest
|
804
|
-
if @status == :on
|
805
|
-
respond "I'm listening to [#{@listening.join(", ")}]", dest
|
806
|
-
if ON_MASTER_BOT and ADMIN_USERS.include?(from)
|
807
|
-
|
808
|
-
@bots_created.each do |k,v|
|
809
|
-
msg = []
|
810
|
-
msg << "`#{v[:channel_name]}` (#{k}):"
|
811
|
-
msg << "\tcreator: #{v[:creator_name]}"
|
812
|
-
msg << "\tadmins: #{v[:admins]}"
|
813
|
-
msg << "\tstatus: #{v[:status]}"
|
814
|
-
msg << "\tcreated: #{v[:created]}"
|
815
|
-
msg << "\trules: #{v[:rules_file]}"
|
816
|
-
msg << "\textended: #{v[:extended]}"
|
817
|
-
msg << "\tcloud: #{v[:cloud]}"
|
818
|
-
if ON_MASTER_BOT and v.key?(:cloud) and v[:cloud]
|
819
|
-
msg << "\trunner: `ruby #{$0} \"#{v[:channel_name]}\" \"#{v[:admins]}\" \"#{v[:rules_file]}\" on&`"
|
820
|
-
end
|
821
|
-
respond msg.join("\n"), dest
|
822
|
-
end
|
823
|
-
end
|
824
|
-
end
|
825
|
-
|
826
|
-
#helpmaster: ----------------------------------------------
|
827
|
-
#helpmaster: `notify MESSAGE`
|
828
|
-
#helpmaster: `notify all MESSAGE`
|
829
|
-
#helpmaster: It will send a notificaiton message to all bot channels
|
830
|
-
#helpmaster: It will send a notification message to all channels the bot joined and private conversations with the bot
|
831
|
-
#helpmaster: Only works if you are on Master channel and you are an admin user
|
832
|
-
#helpmaster:
|
833
|
-
when /^notify\s+(all)?\s*(.+)\s*$/i
|
834
|
-
if ON_MASTER_BOT
|
835
|
-
if ADMIN_USERS.include?(from) #admin user
|
836
|
-
all = $1
|
837
|
-
message = $2
|
838
|
-
if all.nil?
|
839
|
-
@bots_created.each do |k, v|
|
840
|
-
respond message, k
|
841
|
-
end
|
842
|
-
respond "Bot channels have been notified", dest
|
843
|
-
else
|
844
|
-
myconv = client.web_client.users_conversations(exclude_archived: true, limit: 100, types: "im, public_channel").channels
|
845
|
-
myconv.each do |c|
|
846
|
-
respond message, c.id unless c.name == MASTER_CHANNEL
|
847
|
-
end
|
848
|
-
respond "Channels and users have been notified", dest
|
849
|
-
end
|
850
|
-
end
|
851
|
-
end
|
852
|
-
|
853
|
-
#helpmaster: ----------------------------------------------
|
854
|
-
#helpmaster: `create bot on CHANNEL_NAME`
|
855
|
-
#helpmaster: `create cloud bot on CHANNEL_NAME`
|
856
|
-
#helpmaster: creates a new bot on the channel specified
|
857
|
-
#helpmaster: it will work only if you are on Master channel
|
858
|
-
#helpmaster: the admins will be the master admins, the creator of the bot and the creator of the channel
|
859
|
-
#helpmaster: follow the instructions in case creating cloud bots
|
860
|
-
when /^create\s+(cloud\s+)?bot\s+on\s+<#C\w+\|(.+)>\s*/i, /^create\s+(cloud\s+)?bot\s+on\s+(.+)\s*/i
|
861
|
-
if ON_MASTER_BOT
|
862
|
-
cloud = !$1.nil?
|
863
|
-
channel = $2
|
864
|
-
|
865
|
-
get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
|
866
|
-
channel_id = nil
|
867
|
-
if @channels_name.key?(channel) #it is an id
|
868
|
-
channel_id = channel
|
869
|
-
channel = @channels_name[channel_id]
|
870
|
-
elsif @channels_id.key?(channel) #it is a channel name
|
871
|
-
channel_id = @channels_id[channel]
|
872
|
-
end
|
873
|
-
#todo: add pagination for case more than 1000 channels on the workspace
|
874
|
-
channels = client.web_client.conversations_list(
|
875
|
-
types: 'private_channel,public_channel',
|
876
|
-
limit: '1000',
|
877
|
-
exclude_archived: 'true').channels
|
878
|
-
channel_found = channels.detect { |c| c.name == channel }
|
879
|
-
members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil?
|
880
|
-
|
881
|
-
if channel_id.nil?
|
882
|
-
respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
|
883
|
-
elsif channel == MASTER_CHANNEL
|
884
|
-
respond "There is already a bot in this channel: #{channel}", dest
|
885
|
-
elsif @bots_created.keys.include?(channel_id)
|
886
|
-
respond "There is already a bot in this channel: #{channel}, kill it before", dest
|
887
|
-
elsif config[:nick_id] != channel_found.creator and !members.include?(config[:nick_id])
|
888
|
-
respond "You need to add first to the channel the smart bot user: #{config[:nick]}", dest
|
889
|
-
else
|
890
|
-
if channel_id != config[:channel]
|
891
|
-
begin
|
892
|
-
rules_file = "slack-smart-bot_rules_#{channel_id}_#{from.gsub(" ", "_")}.rb"
|
893
|
-
if defined?(RULES_FOLDER)
|
894
|
-
rules_file = RULES_FOLDER + rules_file
|
895
|
-
else
|
896
|
-
Dir.mkdir("rules") unless Dir.exist?("rules")
|
897
|
-
Dir.mkdir("rules/#{channel_id}") unless Dir.exist?("rules/#{channel_id}")
|
898
|
-
rules_file = "./rules/#{channel_id}/" + rules_file
|
899
|
-
end
|
900
|
-
default_rules = (__FILE__).gsub(/\.rb$/, "_rules.rb")
|
901
|
-
File.delete(rules_file) if File.exist?(rules_file)
|
902
|
-
FileUtils.copy_file(default_rules, rules_file) unless File.exist?(rules_file)
|
903
|
-
admin_users = Array.new()
|
904
|
-
creator_info = client.web_client.users_info(user: channel_found.creator)
|
905
|
-
admin_users = [from, creator_info.user.name] + MASTER_USERS
|
906
|
-
admin_users.uniq!
|
907
|
-
@logger.info "ruby #{$0} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on"
|
908
|
-
if cloud
|
909
|
-
respond "Copy the bot folder to your cloud location and run `ruby #{$0} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on&`", dest
|
910
|
-
else
|
911
|
-
t = Thread.new do
|
912
|
-
`ruby #{$0} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on`
|
913
|
-
end
|
914
|
-
end
|
915
|
-
@bots_created[channel_id] = {
|
916
|
-
creator_name: from,
|
917
|
-
channel_id: channel_id,
|
918
|
-
channel_name: @channels_name[channel_id],
|
919
|
-
status: :on,
|
920
|
-
created: Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18],
|
921
|
-
rules_file: rules_file,
|
922
|
-
admins: admin_users.join(","),
|
923
|
-
extended: [],
|
924
|
-
cloud: cloud,
|
925
|
-
thread: t,
|
926
|
-
}
|
927
|
-
respond "The bot has been created on channel: #{channel}. Rules file: #{File.basename rules_file}. Admins: #{admin_users.join(", ")}", dest
|
928
|
-
update_bots_file()
|
929
|
-
rescue Exception => stack
|
930
|
-
@logger.fatal stack
|
931
|
-
message = "Problem creating the bot on channel #{channel}. Error: <#{stack}>."
|
932
|
-
@logger.error message
|
933
|
-
respond message, dest
|
934
|
-
end
|
935
|
-
else
|
936
|
-
respond "There is already a bot in this channel: #{channel}, and it is the Master Channel!", dest
|
937
|
-
end
|
938
|
-
end
|
939
|
-
else
|
940
|
-
@logger.info MASTER_CHANNEL
|
941
|
-
@logger.info @channel_id.inspect
|
942
|
-
respond "Sorry I cannot create bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest
|
943
|
-
end
|
944
|
-
|
945
|
-
#helpmaster: ----------------------------------------------
|
946
|
-
#helpmaster: `kill bot on CHANNEL_NAME`
|
947
|
-
#helpmaster: kills the bot on the specified channel
|
948
|
-
#helpmaster: Only works if you are on Master channel and you created that bot or you are an admin user
|
949
|
-
#helpmaster:
|
950
|
-
when /^kill\sbot\son\s<#C\w+\|(.+)>\s*$/i, /^kill\sbot\son\s(.+)\s*$/i
|
951
|
-
if ON_MASTER_BOT
|
952
|
-
channel = $1
|
953
|
-
|
954
|
-
get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
|
955
|
-
channel_id = nil
|
956
|
-
if @channels_name.key?(channel) #it is an id
|
957
|
-
channel_id = channel
|
958
|
-
channel = @channels_name[channel_id]
|
959
|
-
elsif @channels_id.key?(channel) #it is a channel name
|
960
|
-
channel_id = @channels_id[channel]
|
961
|
-
end
|
962
|
-
if channel_id.nil?
|
963
|
-
respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
|
964
|
-
elsif @bots_created.keys.include?(channel_id)
|
965
|
-
if @bots_created[channel_id][:admins].split(",").include?(from)
|
966
|
-
if @bots_created[channel_id][:thread].kind_of?(Thread) and @bots_created[channel_id][:thread].alive?
|
967
|
-
@bots_created[channel_id][:thread].kill
|
968
|
-
end
|
969
|
-
@bots_created.delete(channel_id)
|
970
|
-
update_bots_file()
|
971
|
-
respond "Bot on channel: #{channel}, has been killed and deleted.", dest
|
972
|
-
send_msg_channel(channel, "Bot has been killed by #{from}")
|
973
|
-
else
|
974
|
-
respond "You need to be the creator or an admin of that bot channel", dest
|
975
|
-
end
|
976
|
-
else
|
977
|
-
respond "There is no bot in this channel: #{channel}", dest
|
978
|
-
end
|
979
|
-
else
|
980
|
-
respond "Sorry I cannot kill bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest
|
981
|
-
end
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
else
|
986
|
-
processed = false
|
987
|
-
end
|
988
|
-
else
|
989
|
-
processed = false
|
990
|
-
end
|
991
|
-
|
992
|
-
on_demand = false
|
993
|
-
if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or
|
994
|
-
command.match(/^()!(.+)/im) or
|
995
|
-
command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im)
|
996
|
-
command = $2
|
997
|
-
on_demand = true
|
998
|
-
end
|
999
|
-
|
1000
|
-
#only when :on and (listening or on demand or direct message)
|
1001
|
-
if @status == :on and
|
1002
|
-
(@questions.keys.include?(from) or
|
1003
|
-
(@listening.include?(from) and typem!=:on_extended) or
|
1004
|
-
typem == :on_dm or typem ==:on_pg or on_demand)
|
1005
|
-
processed2 = true
|
1006
|
-
|
1007
|
-
#help: ===================================
|
1008
|
-
#help:
|
1009
|
-
#help: *These commands will run only when the smart bot is listening to you or on demand or in a private conversation with the Smart Bot*. To run a command on demand:
|
1010
|
-
#help: `!THE_COMMAND`
|
1011
|
-
#help: `@NAME_OF_BOT THE_COMMAND`
|
1012
|
-
#help: `NAME_OF_BOT THE_COMMAND`
|
1013
|
-
#help:
|
1014
|
-
case command
|
1015
|
-
|
1016
|
-
when /^bot\s+rules$/i
|
1017
|
-
if typem == :on_extended or typem == :on_call #for the other cases above.
|
1018
|
-
help_message_rules = ''
|
1019
|
-
message = "-\n\n\n===================================\n*Rules from channel #{CHANNEL}*\n"
|
1020
|
-
if typem == :on_extended
|
1021
|
-
message += "To run the commands on this extended channel, add `!` before the command.\n"
|
1022
|
-
end
|
1023
|
-
help_message_rules = IO.readlines(rules_file).join
|
1024
|
-
message += help_message_rules.scan(/#\s*help\s*:(.*)/).join("\n")
|
1025
|
-
respond message, dest
|
1026
|
-
unless rules_file.empty?
|
1027
|
-
begin
|
1028
|
-
eval(File.new(rules_file).read) if File.exist?(rules_file)
|
1029
|
-
end
|
1030
|
-
end
|
1031
|
-
if defined?(git_project) and git_project.to_s!='' and help_message_rules != ''
|
1032
|
-
respond "Git project: #{git_project}", dest
|
1033
|
-
else
|
1034
|
-
def git_project() '' end
|
1035
|
-
def project_folder() '' end
|
1036
|
-
end
|
1037
|
-
end
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
#helpadmin: ----------------------------------------------
|
1042
|
-
#helpadmin: `extend rules to CHANNEL_NAME`
|
1043
|
-
#helpadmin: `use rules on CHANNEL_NAME`
|
1044
|
-
#helpadmin: It will allow to use the specific rules from this channel on the CHANNEL_NAME
|
1045
|
-
#helpadmin:
|
1046
|
-
when /^extend\s+rules\s+(to\s+)<#C\w+\|(.+)>/i, /^extend\s+rules\s+(to\s+)(.+)/i,
|
1047
|
-
/^use\s+rules\s+(on\s+)<#C\w+\|(.+)>/i, /^use\s+rules\s+(on\s+)(.+)/i
|
1048
|
-
unless typem == :on_extended
|
1049
|
-
if ON_MASTER_BOT
|
1050
|
-
respond "You cannot use the rules from Master Channel on any other channel.", dest
|
1051
|
-
elsif !ADMIN_USERS.include?(from) #not admin
|
1052
|
-
respond "Only admins can extend the rules. Admins on this channel: #{ADMIN_USERS}", dest
|
1053
|
-
else
|
1054
|
-
channel = $2
|
1055
|
-
#todo: add pagination for case more than 1000 channels on the workspace
|
1056
|
-
channels = client.web_client.conversations_list(
|
1057
|
-
types: 'private_channel,public_channel',
|
1058
|
-
limit: '1000',
|
1059
|
-
exclude_archived: 'true').channels
|
1060
|
-
|
1061
|
-
channel_found = channels.detect { |c| c.name == channel }
|
1062
|
-
members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil?
|
1063
|
-
get_bots_created()
|
1064
|
-
channels_in_use = []
|
1065
|
-
@bots_created.each do |k,v|
|
1066
|
-
if v.key?(:extended) and v[:extended].include?(channel)
|
1067
|
-
channels_in_use << v[:channel_name]
|
1068
|
-
end
|
1069
|
-
end
|
1070
|
-
|
1071
|
-
if channel_found.nil?
|
1072
|
-
respond "The channel you specified doesn't exist", dest
|
1073
|
-
elsif @bots_created.key?(@channels_id[channel])
|
1074
|
-
respond "There is a bot already running on that channel.", dest
|
1075
|
-
elsif @bots_created[@channel_id][:extended].include?(channel)
|
1076
|
-
respond "The rules are already extended to that channel.", dest
|
1077
|
-
elsif !members.include?(config[:nick_id])
|
1078
|
-
respond "You need to add first to the channel the smart bot user: #{config[:nick]}", dest
|
1079
|
-
elsif !members.include?(user.id)
|
1080
|
-
respond "You need to join that channel first", dest
|
1081
|
-
else
|
1082
|
-
channels_in_use.each do |channel_in_use|
|
1083
|
-
respond "The rules from channel <##{@channels_id[channel_in_use]}> are already in use on that channel", dest
|
1084
|
-
end
|
1085
|
-
@bots_created[@channel_id][:extended] = [] unless @bots_created[@channel_id].key?(:extended)
|
1086
|
-
@bots_created[@channel_id][:extended] << channel
|
1087
|
-
update_bots_file()
|
1088
|
-
respond "<@#{user.id}> extended the rules from #{CHANNEL} to be used on #{channel}.", @master_bot_id
|
1089
|
-
respond "Now the rules from <##{@channel_id}> are available on <##{@channels_id[channel]}>", dest
|
1090
|
-
respond "<@#{user.id}> extended the rules from <##{@channel_id}> to this channel so now you can talk to the Smart Bot on demand using those rules.", @channels_id[channel]
|
1091
|
-
respond "Use `!` before the command you want to run", @channels_id[channel]
|
1092
|
-
respond "To see the specific rules for this bot on this channel: `!bot rules`", @channels_id[channel]
|
1093
|
-
end
|
1094
|
-
end
|
1095
|
-
end
|
1096
|
-
|
1097
|
-
#helpadmin: ----------------------------------------------
|
1098
|
-
#helpadmin: `stop using rules on CHANNEL_NAME`
|
1099
|
-
#helpadmin: it will stop using the extended rules on the specified channel.
|
1100
|
-
#helpadmin:
|
1101
|
-
when /^stop using rules (on\s+)<#\w+\|(.+)>/i, /^stop using rules (on\s+)(.+)/i
|
1102
|
-
unless typem == :on_extended
|
1103
|
-
if !ADMIN_USERS.include?(from) #not admin
|
1104
|
-
respond "Only admins can extend or stop using the rules. Admins on this channel: #{ADMIN_USERS}", dest
|
1105
|
-
else
|
1106
|
-
channel = $2
|
1107
|
-
get_bots_created()
|
1108
|
-
if @bots_created[@channel_id][:extended].include?(channel)
|
1109
|
-
@bots_created[@channel_id][:extended].delete(channel)
|
1110
|
-
update_bots_file()
|
1111
|
-
respond "<@#{user.id}> removed the access to the rules of #{CHANNEL} from #{channel}.", @master_bot_id
|
1112
|
-
respond "The rules won't be accessible from <##{@channels_id[channel]}> from now on.", dest
|
1113
|
-
respond "<@#{user.id}> removed the access to the rules of <##{@channel_id}> from this channel.", @channels_id[channel]
|
1114
|
-
else
|
1115
|
-
respond "The rules were not accessible from #{@channels_id[channel]}", dest
|
1116
|
-
end
|
1117
|
-
end
|
1118
|
-
end
|
1119
|
-
|
1120
|
-
#help: ----------------------------------------------
|
1121
|
-
#help: `add shortcut NAME: COMMAND`
|
1122
|
-
#help: `add sc NAME: COMMAND`
|
1123
|
-
#help: `add shortcut for all NAME: COMMAND`
|
1124
|
-
#help: `add sc for all NAME: COMMAND`
|
1125
|
-
#help: `shortchut NAME: COMMAND`
|
1126
|
-
#help: `shortchut for all NAME: COMMAND`
|
1127
|
-
#help: It will add a shortcut that will execute the command we supply.
|
1128
|
-
#help: In case we supply 'for all' then the shorcut will be available for everybody
|
1129
|
-
#help: Example:
|
1130
|
-
#help: _add shortcut for all Spanish account: code require 'iso/iban'; 10.times {puts ISO::IBAN.random('ES')}_
|
1131
|
-
#help: Then to call this shortcut:
|
1132
|
-
#help: _sc spanish account_
|
1133
|
-
#help: _shortcut Spanish Account_
|
1134
|
-
#help: _Spanish Account_
|
1135
|
-
#help:
|
1136
|
-
when /^(add\s)?shortcut\s(for\sall)?\s*(.+)\s*:\s*(.+)/i, /^(add\s)sc\s(for\sall)?\s*(.+)\s*:\s*(.+)/i
|
1137
|
-
unless typem == :on_extended
|
1138
|
-
for_all = $2
|
1139
|
-
shortcut_name = $3.to_s.downcase
|
1140
|
-
command_to_run = $4
|
1141
|
-
@shortcuts[from] = Hash.new() unless @shortcuts.keys.include?(from)
|
1142
|
-
|
1143
|
-
if !ADMIN_USERS.include?(from) and @shortcuts[:all].include?(shortcut_name) and !@shortcuts[from].include?(shortcut_name)
|
1144
|
-
respond "Only the creator of the shortcut or an admin user can modify it", dest
|
1145
|
-
elsif !@shortcuts[from].include?(shortcut_name)
|
1146
|
-
#new shortcut
|
1147
|
-
@shortcuts[from][shortcut_name] = command_to_run
|
1148
|
-
@shortcuts[:all][shortcut_name] = command_to_run if for_all.to_s != ""
|
1149
|
-
update_shortcuts_file()
|
1150
|
-
respond "shortcut added", dest
|
1151
|
-
else
|
1152
|
-
|
1153
|
-
#are you sure? to avoid overwriting existing
|
1154
|
-
unless @questions.keys.include?(from)
|
1155
|
-
ask("The shortcut already exists, are you sure you want to overwrite it?", command, from, dest)
|
1156
|
-
else
|
1157
|
-
case @questions[from]
|
1158
|
-
when /^(yes|yep)/i
|
1159
|
-
@shortcuts[from][shortcut_name] = command_to_run
|
1160
|
-
@shortcuts[:all][shortcut_name] = command_to_run if for_all.to_s != ""
|
1161
|
-
update_shortcuts_file()
|
1162
|
-
respond "shortcut added", dest
|
1163
|
-
@questions.delete(from)
|
1164
|
-
when /^no/i
|
1165
|
-
respond "ok, I won't add it", dest
|
1166
|
-
@questions.delete(from)
|
1167
|
-
else
|
1168
|
-
respond "I don't understand, yes or no?", dest
|
1169
|
-
end
|
1170
|
-
end
|
1171
|
-
end
|
1172
|
-
end
|
1173
|
-
|
1174
|
-
#help: ----------------------------------------------
|
1175
|
-
#help: `delete shortcut NAME`
|
1176
|
-
#help: `delete sc NAME`
|
1177
|
-
#help: It will delete the shortcut with the supplied name
|
1178
|
-
#help:
|
1179
|
-
when /^delete\s+shortcut\s+(.+)/i, /^delete\s+sc\s+(.+)/i
|
1180
|
-
unless typem == :on_extended
|
1181
|
-
shortcut = $1.to_s.downcase
|
1182
|
-
deleted = false
|
1183
|
-
|
1184
|
-
if !ADMIN_USERS.include?(from) and @shortcuts[:all].include?(shortcut) and !@shortcuts[from].include?(shortcut)
|
1185
|
-
respond "Only the creator of the shortcut or an admin user can delete it", dest
|
1186
|
-
elsif (@shortcuts.keys.include?(from) and @shortcuts[from].keys.include?(shortcut)) or
|
1187
|
-
(ADMIN_USERS.include?(from) and @shortcuts[:all].include?(shortcut))
|
1188
|
-
#are you sure? to avoid deleting by mistake
|
1189
|
-
unless @questions.keys.include?(from)
|
1190
|
-
ask("are you sure you want to delete it?", command, from, dest)
|
1191
|
-
else
|
1192
|
-
case @questions[from]
|
1193
|
-
when /^(yes|yep)/i
|
1194
|
-
respond "shortcut deleted!", dest
|
1195
|
-
respond "#{shortcut}: #{@shortcuts[from][shortcut]}", dest
|
1196
|
-
@shortcuts[from].delete(shortcut)
|
1197
|
-
@shortcuts[:all].delete(shortcut)
|
1198
|
-
@questions.delete(from)
|
1199
|
-
update_shortcuts_file()
|
1200
|
-
when /^no/i
|
1201
|
-
respond "ok, I won't delete it", dest
|
1202
|
-
@questions.delete(from)
|
1203
|
-
else
|
1204
|
-
respond "I don't understand, yes or no?", dest
|
1205
|
-
end
|
1206
|
-
end
|
1207
|
-
else
|
1208
|
-
respond "shortcut not found", dest
|
1209
|
-
end
|
1210
|
-
end
|
1211
|
-
|
1212
|
-
#help: ----------------------------------------------
|
1213
|
-
#help: `see shortcuts`
|
1214
|
-
#help: `see sc`
|
1215
|
-
#help: It will display the shortcuts stored for the user and for :all
|
1216
|
-
#help:
|
1217
|
-
when /^see\sshortcuts/i, /^see\ssc/i
|
1218
|
-
unless typem == :on_extended
|
1219
|
-
msg = ""
|
1220
|
-
if @shortcuts[:all].keys.size > 0
|
1221
|
-
msg = "*Available shortcuts for all:*\n"
|
1222
|
-
@shortcuts[:all].each { |name, value|
|
1223
|
-
msg += " _#{name}: #{value}_\n"
|
1224
|
-
}
|
1225
|
-
respond msg, dest
|
1226
|
-
end
|
1227
|
-
|
1228
|
-
if @shortcuts.keys.include?(from) and @shortcuts[from].keys.size > 0
|
1229
|
-
new_hash = @shortcuts[from].dup
|
1230
|
-
@shortcuts[:all].keys.each { |k| new_hash.delete(k) }
|
1231
|
-
if new_hash.keys.size > 0
|
1232
|
-
msg = "*Available shortcuts for #{from}:*\n"
|
1233
|
-
new_hash.each { |name, value|
|
1234
|
-
msg += " _#{name}: #{value}_\n"
|
1235
|
-
}
|
1236
|
-
respond msg, dest
|
1237
|
-
end
|
1238
|
-
end
|
1239
|
-
respond "No shortcuts found", dest if msg == ""
|
1240
|
-
end
|
1241
|
-
|
1242
|
-
#help: ----------------------------------------------
|
1243
|
-
#help: `id channel CHANNEL_NAME`
|
1244
|
-
#help: shows the id of a channel name
|
1245
|
-
#help:
|
1246
|
-
when /^id\schannel\s<#C\w+\|(.+)>\s*/i, /^id channel (.+)/
|
1247
|
-
unless typem == :on_extended
|
1248
|
-
channel_name = $1
|
1249
|
-
get_channels_name_and_id()
|
1250
|
-
if @channels_id.keys.include?(channel_name)
|
1251
|
-
respond "the id of #{channel_name} is #{@channels_id[channel_name]}", dest
|
1252
|
-
else
|
1253
|
-
respond "channel: #{channel_name} not found", dest
|
1254
|
-
end
|
1255
|
-
end
|
1256
|
-
|
1257
|
-
#help: ----------------------------------------------
|
1258
|
-
#help: `ruby RUBY_CODE`
|
1259
|
-
#help: `code RUBY_CODE`
|
1260
|
-
#help: runs the code supplied and returns the output. Also you can send a Ruby file instead. Examples:
|
1261
|
-
#help: _code puts (34344/99)*(34+14)_
|
1262
|
-
#help: _ruby require 'json'; res=[]; 20.times {res<<rand(100)}; my_json={result: res}; puts my_json.to_json_
|
1263
|
-
#help:
|
1264
|
-
when /^\s*ruby\s(.+)/im, /^\s*code\s(.+)/im
|
1265
|
-
code = $1
|
1266
|
-
code.gsub!("\\n", "\n")
|
1267
|
-
code.gsub!("\\r", "\r")
|
1268
|
-
@logger.info code
|
1269
|
-
unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
|
1270
|
-
code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
|
1271
|
-
code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or
|
1272
|
-
code.include?("ENV") or code.match?(/=\s*IO/)
|
1273
|
-
unless rules_file.empty?
|
1274
|
-
begin
|
1275
|
-
eval(File.new(rules_file).read) if File.exist?(rules_file)
|
1276
|
-
end
|
1277
|
-
end
|
1278
|
-
|
1279
|
-
respond "Running", dest if code.size > 100
|
1280
|
-
|
1281
|
-
begin
|
1282
|
-
code.gsub!(/^\W*$/,'') #to remove special chars from slack when copy/pasting
|
1283
|
-
ruby = "ruby -e \"#{code.gsub('"', '\"')}\""
|
1284
|
-
if defined?(project_folder) and project_folder.to_s!='' and Dir.exist?(project_folder)
|
1285
|
-
ruby = ("cd #{project_folder} &&" + ruby)
|
1286
|
-
else
|
1287
|
-
def project_folder() '' end
|
1288
|
-
end
|
1289
|
-
stdout, stderr, status = Open3.capture3(ruby)
|
1290
|
-
if stderr == ""
|
1291
|
-
if stdout == ""
|
1292
|
-
respond "Nothing returned. Remember you need to use p or puts to print", dest
|
1293
|
-
else
|
1294
|
-
respond stdout, dest
|
1295
|
-
end
|
1296
|
-
else
|
1297
|
-
respond stderr, dest
|
1298
|
-
end
|
1299
|
-
rescue Exception => exc
|
1300
|
-
respond exc, dest
|
1301
|
-
end
|
1302
|
-
else
|
1303
|
-
respond "Sorry I cannot run this due security reasons", dest
|
1304
|
-
end
|
1305
|
-
|
1306
|
-
|
1307
|
-
else
|
1308
|
-
processed2 = false
|
1309
|
-
end #of case
|
1310
|
-
|
1311
|
-
processed = true if processed or processed2
|
1312
|
-
end
|
1313
|
-
|
1314
|
-
return processed
|
1315
|
-
end
|
1316
|
-
|
1317
|
-
def respond(msg, dest = nil)
|
1318
|
-
if dest.nil?
|
1319
|
-
client.message(channel: @channel_id, text: msg, as_user: true)
|
1320
|
-
elsif dest[0] == "C" or dest[0] == "G" # channel
|
1321
|
-
client.message(channel: dest, text: msg, as_user: true)
|
1322
|
-
elsif dest[0] == "D" # Direct message
|
1323
|
-
send_msg_user(dest, msg)
|
1324
|
-
else
|
1325
|
-
@logger.warn("method respond not treated correctly: msg:#{msg} dest:#{dest}")
|
1326
|
-
end
|
1327
|
-
end
|
1328
|
-
|
1329
|
-
#context: previous message
|
1330
|
-
#to: user that should answer
|
1331
|
-
def ask(question, context, to, dest = nil)
|
1332
|
-
if dest.nil?
|
1333
|
-
client.message(channel: @channel_id, text: "#{to}: #{question}", as_user: true)
|
1334
|
-
elsif dest[0] == "C" or dest[0] == "G" # channel
|
1335
|
-
client.message(channel: dest, text: "#{to}: #{question}", as_user: true)
|
1336
|
-
elsif dest[0] == "D" #private message
|
1337
|
-
send_msg_user(dest, "#{to}: #{question}")
|
1338
|
-
end
|
1339
|
-
@questions[to] = context
|
1340
|
-
end
|
1341
|
-
|
1342
|
-
# to: (String) Channel name or id
|
1343
|
-
# msg: (String) message to send
|
1344
|
-
def send_msg_channel(to, msg)
|
1345
|
-
unless msg == ""
|
1346
|
-
get_channels_name_and_id() unless @channels_name.key?(to) or @channels_id.key?(to)
|
1347
|
-
if @channels_name.key?(to) #it is an id
|
1348
|
-
channel_id = to
|
1349
|
-
elsif @channels_id.key?(to) #it is a channel name
|
1350
|
-
channel_id = @channels_id[to]
|
1351
|
-
else
|
1352
|
-
@logger.fatal "Channel: #{to} not found. Message: #{msg}"
|
1353
|
-
end
|
1354
|
-
client.message(channel: channel_id, text: msg, as_user: true)
|
1355
|
-
end
|
1356
|
-
end
|
1357
|
-
|
1358
|
-
#to send messages without listening for a response to users
|
1359
|
-
def send_msg_user(id_user, msg)
|
1360
|
-
unless msg == ""
|
1361
|
-
if id_user[0] == "D"
|
1362
|
-
client.message(channel: id_user, as_user: true, text: msg)
|
1363
|
-
else
|
1364
|
-
im = client.web_client.im_open(user: id_user)
|
1365
|
-
client.message(channel: im["channel"]["id"], as_user: true, text: msg)
|
1366
|
-
end
|
1367
|
-
end
|
1368
|
-
end
|
1369
|
-
|
1370
|
-
#to send a file to an user or channel
|
1371
|
-
#send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'message to be sent', 'text/plain', "text")
|
1372
|
-
#send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'message to be sent', 'image/jpeg', "jpg")
|
1373
|
-
def send_file(to, msg, file, title, format, type = "text")
|
1374
|
-
if to[0] == "U" #user
|
1375
|
-
im = client.web_client.im_open(user: to)
|
1376
|
-
channel = im["channel"]["id"]
|
1377
|
-
else
|
1378
|
-
channel = to
|
1379
|
-
end
|
1380
|
-
|
1381
|
-
client.web_client.files_upload(
|
1382
|
-
channels: channel,
|
1383
|
-
as_user: true,
|
1384
|
-
file: Faraday::UploadIO.new(file, format),
|
1385
|
-
title: title,
|
1386
|
-
filename: file,
|
1387
|
-
filetype: type,
|
1388
|
-
initial_comment: msg,
|
1389
|
-
)
|
1390
|
-
end
|
1391
|
-
|
1392
211
|
private :update_bots_file, :get_bots_created, :get_channels_name_and_id, :update_shortcuts_file
|
1393
212
|
end
|