slack-smart-bot 1.6.6 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +8 -1
- data/lib/slack-smart-bot.rb +13 -8
- data/lib/slack-smart-bot_general_rules.rb +33 -0
- data/lib/slack-smart-bot_rules.rb +80 -84
- data/lib/slack/smart-bot/comm.rb +2 -1
- data/lib/slack/smart-bot/comm/react.rb +1 -1
- data/lib/slack/smart-bot/comm/respond.rb +1 -1
- data/lib/slack/smart-bot/comm/send_file.rb +28 -12
- data/lib/slack/smart-bot/comm/unreact.rb +16 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +24 -5
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +1 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb +88 -15
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +19 -32
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +12 -3
- data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +1 -1
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +5 -0
- data/lib/slack/smart-bot/process.rb +9 -5
- data/lib/slack/smart-bot/treat_message.rb +8 -12
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +25 -3
- data/lib/slack/smart-bot/utils/get_help.rb +5 -1
- metadata +14 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 19ab121009af799ef4d1338e6b274c3212aa3fb9eed9098ab32b4d445e620a14
|
|
4
|
+
data.tar.gz: d9d16f6eb8de9fe372865e56f4f4e22ae2b10acdd55918f2d17a38a25f7111d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d94f2a3b0f5f26c1ece8f9d9241b89e26714e6565104a1591c2f0ab0bac0bb9273d2e64e5a988fde4c18cdea0e89a8bcb98d5ee1f36ab22756b30d2b3cf61fff
|
|
7
|
+
data.tar.gz: 2dadb23423038f6141e0f8fdf540b15ec5da160058eb7d286e7fee9b6b7672c58d348f33221848b472997a42818283ea76cb67748ad1d2437784ac0a61f41b3d
|
data/README.md
CHANGED
|
@@ -124,6 +124,7 @@ def rules(user, command, processed, dest)
|
|
|
124
124
|
respond "zZzzzzzZZZZZZzzzzzzz!"
|
|
125
125
|
react :sleeping
|
|
126
126
|
sleep 10
|
|
127
|
+
unreact :sleeping
|
|
127
128
|
react :sunny
|
|
128
129
|
when /no/i, /nope/i, /cancel/i
|
|
129
130
|
@questions.delete(from)
|
|
@@ -152,6 +153,8 @@ def rules(user, command, processed, dest)
|
|
|
152
153
|
else
|
|
153
154
|
respond "#{user.name}: #{stdout} #{stderr}"
|
|
154
155
|
end
|
|
156
|
+
|
|
157
|
+
unreact :runner
|
|
155
158
|
|
|
156
159
|
else
|
|
157
160
|
unless processed
|
|
@@ -159,8 +162,11 @@ def rules(user, command, processed, dest)
|
|
|
159
162
|
end
|
|
160
163
|
end
|
|
161
164
|
end
|
|
162
|
-
|
|
163
165
|
```
|
|
166
|
+
|
|
167
|
+
Also you can add general rules that will be available on all Smart Bot channels to `./rules/general_rules.rb`
|
|
168
|
+
|
|
169
|
+
|
|
164
170
|
### How to access the Smart Bot
|
|
165
171
|
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.
|
|
166
172
|
|
|
@@ -388,6 +394,7 @@ Examples:
|
|
|
388
394
|
>**_`add routine run_tests every 3h !run tests on customers`_**
|
|
389
395
|
>**_`add routine clean_db at 17:05 !clean customers temp db`_**
|
|
390
396
|
>**_`add silent routine clean_db at 17:05 !clean customers temp db`_**
|
|
397
|
+
>**_`add routine clean_custdb on Mondays at 05:00 !clean customers db`_**
|
|
391
398
|
|
|
392
399
|
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.
|
|
393
400
|
|
data/lib/slack-smart-bot.rb
CHANGED
|
@@ -36,13 +36,7 @@ class SlackSmartBot
|
|
|
36
36
|
else
|
|
37
37
|
config[:path] = '.'
|
|
38
38
|
end
|
|
39
|
-
|
|
40
|
-
config[:silent] = true
|
|
41
|
-
elsif ENV['BOT_SILENT'].to_s == 'false'
|
|
42
|
-
config[:silent] = false
|
|
43
|
-
else
|
|
44
|
-
config[:silent] = false unless config.key?(:silent)
|
|
45
|
-
end
|
|
39
|
+
config[:silent] = false unless config.key?(:silent)
|
|
46
40
|
config[:testing] = false unless config.key?(:testing)
|
|
47
41
|
config[:simulate] = false unless config.key?(:simulate)
|
|
48
42
|
config[:stats] = false unless config.key?(:stats)
|
|
@@ -183,10 +177,20 @@ class SlackSmartBot
|
|
|
183
177
|
get_rules_imported()
|
|
184
178
|
|
|
185
179
|
begin
|
|
180
|
+
#todo: take in consideration the case that the value supplied on config.masters and config.admins are the ids and not the user names
|
|
186
181
|
@admin_users_id = []
|
|
182
|
+
@master_admin_users_id = []
|
|
187
183
|
config.admins.each do |au|
|
|
188
184
|
user_info = client.web_client.users_info(user: "@#{au}")
|
|
189
185
|
@admin_users_id << user_info.user.id
|
|
186
|
+
if config.masters.include?(au)
|
|
187
|
+
@master_admin_users_id << user_info.user.id
|
|
188
|
+
end
|
|
189
|
+
sleep 1
|
|
190
|
+
end
|
|
191
|
+
(config.masters-config.admins).each do |au|
|
|
192
|
+
user_info = client.web_client.users_info(user: "@#{au}")
|
|
193
|
+
@master_admin_users_id << user_info.user.id
|
|
190
194
|
sleep 1
|
|
191
195
|
end
|
|
192
196
|
rescue Slack::Web::Api::Errors::TooManyRequestsError
|
|
@@ -210,7 +214,8 @@ class SlackSmartBot
|
|
|
210
214
|
if version_remote != VERSION
|
|
211
215
|
version_message = ". There is a new available version: #{version_remote}."
|
|
212
216
|
end
|
|
213
|
-
|
|
217
|
+
if !config[:silent] or ENV['BOT_SILENT'].to_s == 'false'
|
|
218
|
+
ENV['BOT_SILENT'] = 'true' if config[:silent] == 'true' and ENV['BOT_SILENT'].to_s != 'true'
|
|
214
219
|
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."
|
|
215
220
|
end
|
|
216
221
|
@routines.each do |ch, rout|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# add here the general rules you will be using in all Smart Bots
|
|
2
|
+
def general_rules(user, command, processed, dest, files = [], rules_file = "")
|
|
3
|
+
from = user.name
|
|
4
|
+
display_name = user.profile.display_name
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
case command
|
|
8
|
+
|
|
9
|
+
# help: ----------------------------------------------
|
|
10
|
+
# help: `echo SOMETHING`
|
|
11
|
+
# help: `INTEGER echo SOMETHING`
|
|
12
|
+
# help: repeats SOMETHING. If INTEGER supplied then that number of times.
|
|
13
|
+
# help: Examples:
|
|
14
|
+
# help: _echo I am the Smart Bot_
|
|
15
|
+
# help: _100 echo :heart:_
|
|
16
|
+
when /^(\d*)\s*echo\s(.+)/i
|
|
17
|
+
save_stats :echo
|
|
18
|
+
$1.to_s == '' ? times = 1 : times = $1.to_i
|
|
19
|
+
respond ($2*times).to_s
|
|
20
|
+
|
|
21
|
+
else
|
|
22
|
+
return false
|
|
23
|
+
end
|
|
24
|
+
return true
|
|
25
|
+
rescue => exception
|
|
26
|
+
if defined?(@logger)
|
|
27
|
+
@logger.fatal exception
|
|
28
|
+
respond "Unexpected error!! Please contact an admin to solve it: <@#{ADMIN_USERS.join(">, <@")}>"
|
|
29
|
+
else
|
|
30
|
+
puts exception
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -38,102 +38,98 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
|
|
|
38
38
|
from = user.name
|
|
39
39
|
display_name = user.profile.display_name
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
load "#{config.path}/rules/general_rules.rb"
|
|
42
|
+
|
|
43
|
+
unless general_rules(user, command, processed, dest, files, rules_file)
|
|
44
|
+
begin
|
|
45
|
+
case command
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
react :monkey_face
|
|
53
|
-
|
|
54
|
-
# help: ----------------------------------------------
|
|
55
|
-
# help: `go to sleep`
|
|
56
|
-
# help: it will sleep the bot for 5 seconds
|
|
57
|
-
# help:
|
|
58
|
-
when /^go\sto\ssleep/i
|
|
59
|
-
save_stats :to_to_sleep
|
|
60
|
-
unless @questions.keys.include?(from)
|
|
61
|
-
ask "do you want me to take a siesta?"
|
|
62
|
-
else
|
|
63
|
-
case @questions[from]
|
|
64
|
-
when /yes/i, /yep/i, /sure/i
|
|
65
|
-
@questions.delete(from)
|
|
66
|
-
respond "I'll be sleeping for 5 secs... just for you"
|
|
67
|
-
respond "zZzzzzzZZZZZZzzzzzzz!"
|
|
68
|
-
react :sleeping
|
|
69
|
-
sleep 5
|
|
70
|
-
react :sunny
|
|
71
|
-
when /no/i, /nope/i, /cancel/i
|
|
72
|
-
@questions.delete(from)
|
|
73
|
-
respond "Thanks, I'm happy to be awake"
|
|
47
|
+
# help: ----------------------------------------------
|
|
48
|
+
# help: `go to sleep`
|
|
49
|
+
# help: it will sleep the bot for 5 seconds
|
|
50
|
+
# help:
|
|
51
|
+
when /^go\sto\ssleep/i
|
|
52
|
+
save_stats :go_to_sleep
|
|
53
|
+
unless @questions.keys.include?(from)
|
|
54
|
+
ask "do you want me to take a siesta?"
|
|
74
55
|
else
|
|
75
|
-
|
|
76
|
-
|
|
56
|
+
case @questions[from]
|
|
57
|
+
when /yes/i, /yep/i, /sure/i
|
|
58
|
+
@questions.delete(from)
|
|
59
|
+
respond "I'll be sleeping for 5 secs... just for you"
|
|
60
|
+
respond "zZzzzzzZZZZZZzzzzzzz!"
|
|
61
|
+
react :sleeping
|
|
62
|
+
sleep 5
|
|
63
|
+
unreact :sleeping
|
|
64
|
+
react :sunny
|
|
65
|
+
when /no/i, /nope/i, /cancel/i
|
|
66
|
+
@questions.delete(from)
|
|
67
|
+
respond "Thanks, I'm happy to be awake"
|
|
68
|
+
else
|
|
69
|
+
respond "I don't understand"
|
|
70
|
+
ask "are you sure do you want me to sleep? (yes or no)"
|
|
71
|
+
end
|
|
77
72
|
end
|
|
78
|
-
end
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
74
|
+
# help: ----------------------------------------------
|
|
75
|
+
# help: `run something`
|
|
76
|
+
# help: It will run the process and report the results when done
|
|
77
|
+
# help:
|
|
78
|
+
when /^run something/i
|
|
79
|
+
save_stats :run_something
|
|
80
|
+
react :runner
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if
|
|
93
|
-
|
|
82
|
+
process_to_run = "ruby -v"
|
|
83
|
+
process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
|
|
84
|
+
stdout, stderr, status = Open3.capture3(process_to_run)
|
|
85
|
+
unreact :runner
|
|
86
|
+
if stderr == ""
|
|
87
|
+
if stdout == ""
|
|
88
|
+
respond "#{display_name}: Nothing returned."
|
|
89
|
+
else
|
|
90
|
+
respond "#{display_name}: #{stdout}"
|
|
91
|
+
end
|
|
94
92
|
else
|
|
95
|
-
respond "#{display_name}: #{stdout}"
|
|
93
|
+
respond "#{display_name}: #{stdout} #{stderr}"
|
|
96
94
|
end
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# respond "the message", '@theuser'
|
|
114
|
-
# # send 'the message' to a specific user id as direct message
|
|
115
|
-
# respond "the message", 'US3344D3'
|
|
95
|
+
|
|
96
|
+
# Emoticons you can use with `react` command https://www.webfx.com/tools/emoji-cheat-sheet/
|
|
97
|
+
|
|
98
|
+
# Examples for respond and respond_direct
|
|
99
|
+
# # send 'the message' to the channel or direct message where the command was written
|
|
100
|
+
# respond "the message"
|
|
101
|
+
# # send 'the message' privately as a direct message to the user that sent the command
|
|
102
|
+
# respond_direct "the message"
|
|
103
|
+
# # send 'the message' to a specific channel name
|
|
104
|
+
# respond "the message", 'my_channel'
|
|
105
|
+
# # send 'the message' to a specific channel id
|
|
106
|
+
# respond "the message", 'CSU34D33'
|
|
107
|
+
# # send 'the message' to a specific user as direct message
|
|
108
|
+
# respond "the message", '@theuser'
|
|
109
|
+
# # send 'the message' to a specific user id as direct message
|
|
110
|
+
# respond "the message", 'US3344D3'
|
|
116
111
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
112
|
+
# Example downloading a file from slack
|
|
113
|
+
# if !files.nil? and files.size == 1 and files[0].filetype == 'yaml'
|
|
114
|
+
# require 'nice_http'
|
|
115
|
+
# http = NiceHttp.new(host: "https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" })
|
|
116
|
+
# http.get(files[0].url_private_download, save_data: './tmp/')
|
|
117
|
+
# end
|
|
123
118
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
119
|
+
# Examples sending a file to slack:
|
|
120
|
+
# send_file(to, msg, filepath, title, format, type = "text")
|
|
121
|
+
# send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'title', 'text/plain', "text")
|
|
122
|
+
# send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'title', 'image/jpeg', "jpg")
|
|
128
123
|
|
|
129
124
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
125
|
+
else
|
|
126
|
+
unless processed
|
|
127
|
+
dont_understand()
|
|
128
|
+
end
|
|
133
129
|
end
|
|
130
|
+
rescue => exception
|
|
131
|
+
@logger.fatal exception
|
|
132
|
+
respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>"
|
|
134
133
|
end
|
|
135
|
-
rescue => exception
|
|
136
|
-
@logger.fatal exception
|
|
137
|
-
respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>"
|
|
138
134
|
end
|
|
139
135
|
end
|
data/lib/slack/smart-bot/comm.rb
CHANGED
|
@@ -2,7 +2,7 @@ class SlackSmartBot
|
|
|
2
2
|
# list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/
|
|
3
3
|
# react(:thumbsup)
|
|
4
4
|
def react(emoji, parent=false)
|
|
5
|
-
if parent
|
|
5
|
+
if parent or Thread.current[:ts].to_s == ''
|
|
6
6
|
ts = Thread.current[:thread_ts]
|
|
7
7
|
else
|
|
8
8
|
ts = Thread.current[:ts]
|
|
@@ -38,7 +38,7 @@ class SlackSmartBot
|
|
|
38
38
|
f.puts "|#{dest}|#{config[:nick_id]}|#{msg}"
|
|
39
39
|
}
|
|
40
40
|
end
|
|
41
|
-
elsif dest[0] == "D" or dest[0] == "U" # Direct message
|
|
41
|
+
elsif dest[0] == "D" or dest[0] == "U" or dest[0] == "W" # Direct message
|
|
42
42
|
send_msg_user(dest, msg)
|
|
43
43
|
elsif dest[0] == "@"
|
|
44
44
|
begin
|
|
@@ -3,9 +3,12 @@ class SlackSmartBot
|
|
|
3
3
|
#to send a file to an user or channel
|
|
4
4
|
#send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'message to be sent', 'text/plain', "text")
|
|
5
5
|
#send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'message to be sent', 'image/jpeg', "jpg")
|
|
6
|
-
|
|
6
|
+
#send_file(dest, 'the message', "", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied")
|
|
7
|
+
#send_file(dest, 'the message', "myfile.rb", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied")
|
|
8
|
+
def send_file(to, msg, file, title, format, type = "text", content: '')
|
|
7
9
|
unless config[:simulate]
|
|
8
|
-
if
|
|
10
|
+
file = 'myfile' if file.to_s == '' and content!=''
|
|
11
|
+
if to[0] == "U" or to[0] == "W" #user
|
|
9
12
|
im = client.web_client.im_open(user: to)
|
|
10
13
|
channel = im["channel"]["id"]
|
|
11
14
|
else
|
|
@@ -18,16 +21,29 @@ class SlackSmartBot
|
|
|
18
21
|
ts = nil
|
|
19
22
|
end
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
if content.to_s == ''
|
|
25
|
+
client.web_client.files_upload(
|
|
26
|
+
channels: channel,
|
|
27
|
+
as_user: true,
|
|
28
|
+
file: Faraday::UploadIO.new(file, format),
|
|
29
|
+
title: title,
|
|
30
|
+
filename: file,
|
|
31
|
+
filetype: type,
|
|
32
|
+
initial_comment: msg,
|
|
33
|
+
thread_ts: ts
|
|
34
|
+
)
|
|
35
|
+
else
|
|
36
|
+
client.web_client.files_upload(
|
|
37
|
+
channels: channel,
|
|
38
|
+
as_user: true,
|
|
39
|
+
content: content,
|
|
40
|
+
title: title,
|
|
41
|
+
filename: file,
|
|
42
|
+
filetype: type,
|
|
43
|
+
initial_comment: msg,
|
|
44
|
+
thread_ts: ts
|
|
45
|
+
)
|
|
46
|
+
end
|
|
31
47
|
end
|
|
32
48
|
end
|
|
33
49
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class SlackSmartBot
|
|
2
|
+
# list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/
|
|
3
|
+
# unreact(:thumbsup)
|
|
4
|
+
def unreact(emoji, parent=false)
|
|
5
|
+
if parent
|
|
6
|
+
ts = Thread.current[:thread_ts]
|
|
7
|
+
else
|
|
8
|
+
ts = Thread.current[:ts]
|
|
9
|
+
end
|
|
10
|
+
begin
|
|
11
|
+
client.web_client.reactions_remove(channel: Thread.current[:dest], name: emoji, timestamp: ts)
|
|
12
|
+
rescue Exception => stack
|
|
13
|
+
@logger.warn stack
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -5,6 +5,7 @@ class SlackSmartBot
|
|
|
5
5
|
# helpadmin: `add silent routine NAME every NUMBER PERIOD`
|
|
6
6
|
# helpadmin: `create routine NAME every NUMBER PERIOD`
|
|
7
7
|
# helpadmin: `add routine NAME at TIME COMMAND`
|
|
8
|
+
# helpadmin: `add routine NAME on DAYWEEK at TIME COMMAND`
|
|
8
9
|
# helpadmin: `add routine NAME at TIME`
|
|
9
10
|
# helpadmin: `add silent routine NAME at TIME`
|
|
10
11
|
# helpadmin: `create routine NAME at TIME`
|
|
@@ -15,12 +16,14 @@ class SlackSmartBot
|
|
|
15
16
|
# helpadmin: NUMBER: Integer
|
|
16
17
|
# helpadmin: PERIOD: days, d, hours, h, minutes, mins, min, m, seconds, secs, sec, s
|
|
17
18
|
# helpadmin: TIME: time at format HH:MM:SS
|
|
19
|
+
# helpadmin: DAYWEEK: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. And their plurals.
|
|
18
20
|
# helpadmin: COMMAND: any valid smart bot command or rule
|
|
19
21
|
# helpadmin: Examples:
|
|
20
22
|
# helpadmin: _add routine example every 30s ruby puts 'a'_
|
|
21
23
|
# helpadmin: _add routine example every 3 days ruby puts 'a'_
|
|
22
24
|
# helpadmin: _add routine example at 17:05 ruby puts 'a'_
|
|
23
25
|
# helpadmin: _create silent routine every 12 hours !Run customer tests_
|
|
26
|
+
# helpadmin: _add routine example on Mondays at 05:00 !run customer tests_
|
|
24
27
|
# helpadmin:
|
|
25
28
|
def add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent)
|
|
26
29
|
save_stats(__method__)
|
|
@@ -30,13 +33,14 @@ class SlackSmartBot
|
|
|
30
33
|
respond "I'm sorry but there is already a routine with that name.\nCall `see routines` to see added routines", dest
|
|
31
34
|
else
|
|
32
35
|
number_time += ":00" if number_time.split(":").size == 2
|
|
33
|
-
if (type
|
|
36
|
+
if (type != "every") && !number_time.match?(/^[01][0-9]:[0-5][0-9]:[0-5][0-9]$/) &&
|
|
34
37
|
!number_time.match?(/^2[0-3]:[0-5][0-9]:[0-5][0-9]$/)
|
|
35
38
|
respond "Wrong time specified: *#{number_time}*"
|
|
36
39
|
else
|
|
37
40
|
file_path = ""
|
|
38
41
|
every = ""
|
|
39
42
|
at = ""
|
|
43
|
+
dayweek = ''
|
|
40
44
|
next_run = Time.now
|
|
41
45
|
case period.downcase
|
|
42
46
|
when "days", "d"
|
|
@@ -52,16 +56,31 @@ class SlackSmartBot
|
|
|
52
56
|
every = "#{number_time} seconds"
|
|
53
57
|
every_in_seconds = number_time.to_i
|
|
54
58
|
else # time
|
|
59
|
+
if type != 'at'
|
|
60
|
+
dayweek = type.downcase
|
|
61
|
+
days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday']
|
|
62
|
+
incr = days.index(dayweek) - Time.now.wday
|
|
63
|
+
if incr < 0
|
|
64
|
+
incr = (7+incr)*24*60*60
|
|
65
|
+
else
|
|
66
|
+
incr = incr * 24 * 60 * 60
|
|
67
|
+
end
|
|
68
|
+
days = incr/(24*60*60)
|
|
69
|
+
every_in_seconds = 7 * 24 * 60 * 60 # one week
|
|
70
|
+
else
|
|
71
|
+
days = 0
|
|
72
|
+
every_in_seconds = 24 * 60 * 60 # one day
|
|
73
|
+
end
|
|
74
|
+
|
|
55
75
|
at = number_time
|
|
56
|
-
if next_run.strftime("%H:%M:%S") < number_time
|
|
76
|
+
if next_run.strftime("%H:%M:%S") < number_time and days == 0
|
|
57
77
|
nt = number_time.split(":")
|
|
58
78
|
next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2])
|
|
59
79
|
else
|
|
60
|
-
next_run += (24 * 60 * 60) # one more
|
|
80
|
+
next_run += ((24 * 60 * 60) * days) # one or more days
|
|
61
81
|
nt = number_time.split(":")
|
|
62
82
|
next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2])
|
|
63
83
|
end
|
|
64
|
-
every_in_seconds = 24 * 60 * 60
|
|
65
84
|
end
|
|
66
85
|
Dir.mkdir("#{config.path}/routines/#{@channel_id}") unless Dir.exist?("#{config.path}/routines/#{@channel_id}")
|
|
67
86
|
|
|
@@ -78,7 +97,7 @@ class SlackSmartBot
|
|
|
78
97
|
|
|
79
98
|
@routines[@channel_id] = {} unless @routines.key?(@channel_id)
|
|
80
99
|
@routines[@channel_id][name] = { channel_name: config.channel, creator: from, creator_id: user.id, status: :on,
|
|
81
|
-
every: every, every_in_seconds: every_in_seconds, at: at, file_path: file_path,
|
|
100
|
+
every: every, every_in_seconds: every_in_seconds, at: at, dayweek: dayweek, file_path: file_path,
|
|
82
101
|
command: command_to_run.to_s.strip, silent: silent,
|
|
83
102
|
next_run: next_run.to_s, dest: dest, last_run: "", last_elapsed: "",
|
|
84
103
|
running: false }
|
|
@@ -54,7 +54,7 @@ class SlackSmartBot
|
|
|
54
54
|
respond "Now the rules from <##{@channel_id}> are available on *<##{@channels_id[channel]}>*", dest
|
|
55
55
|
end
|
|
56
56
|
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]
|
|
57
|
-
respond "Use `!` before the command you want to run", @channels_id[channel]
|
|
57
|
+
respond "Use `!` or `^` or `!!` before the command you want to run", @channels_id[channel]
|
|
58
58
|
respond "To see the specific rules for this bot on this channel: `!bot rules` or `!bot rules COMMAND`", @channels_id[channel]
|
|
59
59
|
end
|
|
60
60
|
end
|
|
@@ -44,6 +44,7 @@ class SlackSmartBot
|
|
|
44
44
|
msg << "\tStatus: #{v[:status]}"
|
|
45
45
|
msg << "\tEvery: #{v[:every]}" unless v[:every] == ""
|
|
46
46
|
msg << "\tAt: #{v[:at]}" unless v[:at] == ""
|
|
47
|
+
msg << "\tOn: #{v[:dayweek]}" unless !v.key?(:dayweek) or v[:dayweek].to_s == ""
|
|
47
48
|
msg << "\tNext Run: #{v[:next_run]}"
|
|
48
49
|
msg << "\tLast Run: #{v[:last_run]}"
|
|
49
50
|
msg << "\tTime consumed on last run: #{v[:last_elapsed]}" unless v[:command] !=''
|
|
@@ -13,6 +13,7 @@ class SlackSmartBot
|
|
|
13
13
|
# helpadmin: `bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD`
|
|
14
14
|
# helpadmin: `bot stats today`
|
|
15
15
|
# helpadmin: `bot stats exclude COMMAND_ID`
|
|
16
|
+
# helpadmin: `bot stats monthly`
|
|
16
17
|
# helpadmin: To see the bot stats
|
|
17
18
|
# helpadmin: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot
|
|
18
19
|
# helpadmin: You need to set stats to true to generate the stats when running the bot instance.
|
|
@@ -21,8 +22,9 @@ class SlackSmartBot
|
|
|
21
22
|
# helpadmin: _bot stats @peter.wind_
|
|
22
23
|
# helpadmin: _bot stats #sales from 2019/12/15 to 2019/12/31_
|
|
23
24
|
# helpadmin: _bot stats #sales today_
|
|
25
|
+
# helpadmin: _bot stats #sales from 2020-01-01 monthly_
|
|
24
26
|
# helpadmin:
|
|
25
|
-
def bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command)
|
|
27
|
+
def bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command, monthly)
|
|
26
28
|
require 'csv'
|
|
27
29
|
if config.stats
|
|
28
30
|
message = []
|
|
@@ -30,7 +32,7 @@ class SlackSmartBot
|
|
|
30
32
|
message = ["You need to set stats to true to generate the stats when running the bot instance."]
|
|
31
33
|
end
|
|
32
34
|
save_stats(__method__)
|
|
33
|
-
if config.masters.include?(from_user) and typem==:on_dm #master admin user
|
|
35
|
+
if (config.masters.include?(from_user) or @master_admin_users_id.include?(from_user)) and typem==:on_dm #master admin user
|
|
34
36
|
if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
|
|
35
37
|
message<<'No stats'
|
|
36
38
|
else
|
|
@@ -43,17 +45,71 @@ class SlackSmartBot
|
|
|
43
45
|
from+= " 00:00:00 +0000"
|
|
44
46
|
to+= " 23:59:59 +0000"
|
|
45
47
|
rows = []
|
|
46
|
-
|
|
48
|
+
rows_month = {}
|
|
49
|
+
users_month = {}
|
|
50
|
+
commands_month = {}
|
|
51
|
+
users_id_name = {}
|
|
52
|
+
users_name_id = {}
|
|
53
|
+
|
|
54
|
+
# to translate global and enterprise users since sometimes was returning different names/ids
|
|
55
|
+
Dir["#{config.stats_path}.*.log"].sort.each do |file|
|
|
56
|
+
if file >= "#{config.stats_path}.#{from_file}.log" or file <= "#{config.stats_path}.#{to_file}.log"
|
|
57
|
+
CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
|
|
58
|
+
unless users_id_name.key?(row[:user_id])
|
|
59
|
+
users_id_name[row[:user_id]] = row[:user_name]
|
|
60
|
+
end
|
|
61
|
+
unless users_name_id.key?(row[:user_name])
|
|
62
|
+
users_name_id[row[:user_name]] = row[:user_id]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if user!=''
|
|
70
|
+
user_info = client.web_client.users_info(user: user)
|
|
71
|
+
if users_id_name.key?(user_info.user.id)
|
|
72
|
+
user_name = users_id_name[user_info.user.id]
|
|
73
|
+
else
|
|
74
|
+
user_name = user_info.user.name
|
|
75
|
+
end
|
|
76
|
+
if users_name_id.key?(user_info.user.name)
|
|
77
|
+
user_id = users_name_id[user_info.user.name]
|
|
78
|
+
else
|
|
79
|
+
user_id = user_info.user.id
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
master_admins = config.masters.dup
|
|
83
|
+
config.masters.each do |u|
|
|
84
|
+
if users_id_name.key?(u)
|
|
85
|
+
master_admins << users_id_name[u]
|
|
86
|
+
elsif users_name_id.key?(u)
|
|
87
|
+
master_admins << users_name_id[u]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
47
91
|
Dir["#{config.stats_path}.*.log"].sort.each do |file|
|
|
48
92
|
if file >= "#{config.stats_path}.#{from_file}.log" or file <= "#{config.stats_path}.#{to_file}.log"
|
|
49
93
|
CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
|
|
50
94
|
row[:date] = row[:date].to_s
|
|
51
|
-
|
|
52
|
-
|
|
95
|
+
row[:user_name] = users_id_name[row[:user_id]]
|
|
96
|
+
row[:user_id] = users_name_id[row[:user_name]]
|
|
97
|
+
if !exclude_masters or (exclude_masters and !master_admins.include?(row[:user_name]) and
|
|
98
|
+
!master_admins.include?(row[:user_id]) and
|
|
99
|
+
!@master_admin_users_id.include?(row[:user_id]))
|
|
100
|
+
if user=='' or (user!='' and row[:user_name] == user_name) or (user!='' and row[:user_id] == user_id)
|
|
53
101
|
if exclude_command == '' or (exclude_command!='' and row[:command]!=exclude_command)
|
|
54
102
|
if row[:bot_channel_id] == channel_id or channel_id == ''
|
|
55
103
|
if row[:date] >= from and row[:date] <= to
|
|
56
104
|
rows << row.to_h
|
|
105
|
+
if monthly
|
|
106
|
+
rows_month[row[:date][0..6]] = 0 unless rows_month.key?(row[:date][0..6])
|
|
107
|
+
users_month[row[:date][0..6]] = [] unless users_month.key?(row[:date][0..6])
|
|
108
|
+
commands_month[row[:date][0..6]] = [] unless commands_month.key?(row[:date][0..6])
|
|
109
|
+
rows_month[row[:date][0..6]] += 1
|
|
110
|
+
users_month[row[:date][0..6]] << row[:user_id]
|
|
111
|
+
commands_month[row[:date][0..6]] << row[:command]
|
|
112
|
+
end
|
|
57
113
|
end
|
|
58
114
|
end
|
|
59
115
|
end
|
|
@@ -62,7 +118,6 @@ class SlackSmartBot
|
|
|
62
118
|
end
|
|
63
119
|
end
|
|
64
120
|
end
|
|
65
|
-
|
|
66
121
|
total = rows.size
|
|
67
122
|
if exclude_masters
|
|
68
123
|
message << 'Excluding master admins'
|
|
@@ -79,7 +134,22 @@ class SlackSmartBot
|
|
|
79
134
|
message << "*Total calls <##{channel_id}>*: #{total} from #{from_short} to #{to_short}"
|
|
80
135
|
end
|
|
81
136
|
if total > 0
|
|
82
|
-
|
|
137
|
+
if monthly
|
|
138
|
+
message << '*Totals by month / commands / users (%new)*'
|
|
139
|
+
all_users = []
|
|
140
|
+
new_users = []
|
|
141
|
+
rows_month.each do |k,v|
|
|
142
|
+
if all_users.empty?
|
|
143
|
+
message_new_users = ''
|
|
144
|
+
else
|
|
145
|
+
new_users = (users_month[k]-all_users).uniq
|
|
146
|
+
message_new_users = "(#{new_users.size*100/users_month[k].uniq.size}%)"
|
|
147
|
+
end
|
|
148
|
+
all_users += users_month[k]
|
|
149
|
+
message << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{message_new_users}"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
83
153
|
if channel_id == ''
|
|
84
154
|
message << "*Channels*"
|
|
85
155
|
channels = rows.bot_channel.uniq.sort
|
|
@@ -89,21 +159,25 @@ class SlackSmartBot
|
|
|
89
159
|
end
|
|
90
160
|
end
|
|
91
161
|
if user==''
|
|
92
|
-
|
|
93
|
-
|
|
162
|
+
users = rows.user_id.uniq.sort
|
|
163
|
+
message << "*Users* - #{users.size}"
|
|
164
|
+
count_user = {}
|
|
94
165
|
users.each do |user|
|
|
95
|
-
count = rows.count {|h| h.
|
|
96
|
-
|
|
166
|
+
count = rows.count {|h| h.user_id==user}
|
|
167
|
+
count_user[user] = count
|
|
168
|
+
end
|
|
169
|
+
count_user.sort_by {|k,v| -v}.each do |user, count|
|
|
170
|
+
message << "\t#{users_id_name[user]}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
|
97
171
|
end
|
|
98
172
|
end
|
|
99
|
-
|
|
100
|
-
message << "*Commands*"
|
|
173
|
+
|
|
101
174
|
commands = rows.command.uniq.sort
|
|
175
|
+
message << "*Commands* - #{commands.size}"
|
|
102
176
|
commands.each do |command|
|
|
103
177
|
count = rows.count {|h| h.command==command}
|
|
104
178
|
message << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
|
105
179
|
end
|
|
106
|
-
|
|
180
|
+
|
|
107
181
|
message << "*Message type*"
|
|
108
182
|
types = rows.type_message.uniq.sort
|
|
109
183
|
types.each do |type|
|
|
@@ -112,7 +186,6 @@ class SlackSmartBot
|
|
|
112
186
|
end
|
|
113
187
|
message << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].type_message} #{rows[-1].user_name} #{rows[-1].command}"
|
|
114
188
|
end
|
|
115
|
-
|
|
116
189
|
end
|
|
117
190
|
else
|
|
118
191
|
message<<"Only Master admin users on a private conversation with the bot can see the bot stats."
|
|
@@ -82,6 +82,7 @@ class SlackSmartBot
|
|
|
82
82
|
message = "Session name: *#{session_name}*
|
|
83
83
|
From now on I will execute all you write as a Ruby command and I will keep the session open until you send `quit` or `bye` or `exit`.
|
|
84
84
|
I will respond with the result so it is not necessary you send `print`, `puts`, `p` or `pp` unless you want it as the output when calling `run repl`.
|
|
85
|
+
Use `p` to print a message raw, exacly like it is returned.
|
|
85
86
|
If you want to avoid a message to be treated by me, start the message with '-'.
|
|
86
87
|
After 30 minutes of no communication with the Smart Bot the session will be dismissed.
|
|
87
88
|
If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
|
|
@@ -100,34 +101,8 @@ class SlackSmartBot
|
|
|
100
101
|
require \"amazing_print\"
|
|
101
102
|
bindme' + serialt + ' = binding
|
|
102
103
|
eval(\"require \'nice_http\'\" , bindme' + serialt + ')
|
|
103
|
-
def repl_params(met)
|
|
104
|
-
res = []
|
|
105
|
-
met.parameters.each do |par|
|
|
106
|
-
if par[0]==:req
|
|
107
|
-
res << par[1].to_s
|
|
108
|
-
elsif par[0]==:keyreq
|
|
109
|
-
res << par[1].to_s + \":\"
|
|
110
|
-
elsif par[0]==:key
|
|
111
|
-
res << \"?\"+par[1].to_s + \":\"
|
|
112
|
-
elsif par[0]==:opt
|
|
113
|
-
res << \"?\"+par[1].to_s
|
|
114
|
-
elsif par[0]==:rest
|
|
115
|
-
res << \"*\"+par[1].to_s
|
|
116
|
-
elsif par[0]==:keyrest
|
|
117
|
-
res << \"**\"+par[1].to_s
|
|
118
|
-
else
|
|
119
|
-
res << par[1].to_s
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
\"(#{res.join(\", \")})\"
|
|
123
|
-
end
|
|
124
104
|
def ls(obj)
|
|
125
|
-
|
|
126
|
-
res = []
|
|
127
|
-
mets.each do |met|
|
|
128
|
-
res << \"#{met}#{repl_params(obj.method(met))}\"
|
|
129
|
-
end
|
|
130
|
-
res.sort
|
|
105
|
+
(obj.methods - Object.methods)
|
|
131
106
|
end
|
|
132
107
|
|
|
133
108
|
file_input_repl = File.open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.input\", \"r\")
|
|
@@ -158,9 +133,15 @@ class SlackSmartBot
|
|
|
158
133
|
error = true
|
|
159
134
|
end
|
|
160
135
|
if resp_repl.to_s != \"\"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
136
|
+
if code_to_run_repl.match?(/^\s*p\s+/i)
|
|
137
|
+
open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
|
138
|
+
f.puts \"\`\`\`\n#{resp_repl.inspect}\n\`\`\`\"
|
|
139
|
+
}
|
|
140
|
+
else
|
|
141
|
+
open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
|
142
|
+
f.puts \"\`\`\`\n#{resp_repl.ai}\n\`\`\`\"
|
|
143
|
+
}
|
|
144
|
+
end
|
|
164
145
|
unless error or !add_to_run_repl
|
|
165
146
|
open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.run\", \"a+\") {|f|
|
|
166
147
|
f.puts code_to_run_repl
|
|
@@ -198,7 +179,13 @@ class SlackSmartBot
|
|
|
198
179
|
sleep 0.2
|
|
199
180
|
resp_repl = file_output_repl.read
|
|
200
181
|
if resp_repl.to_s!=''
|
|
201
|
-
|
|
182
|
+
if resp_repl.to_s.lines.count < 60 and resp_repl.to_s.size < 3500
|
|
183
|
+
respond resp_repl, dest
|
|
184
|
+
else
|
|
185
|
+
resp_repl.gsub!(/^\s*```/,'')
|
|
186
|
+
resp_repl.gsub!(/```\s*$/,'')
|
|
187
|
+
send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: resp_repl)
|
|
188
|
+
end
|
|
202
189
|
end
|
|
203
190
|
rescue Exception => excp
|
|
204
191
|
@logger.fatal excp
|
|
@@ -210,7 +197,7 @@ class SlackSmartBot
|
|
|
210
197
|
@repl_sessions[from][:command] = ''
|
|
211
198
|
code.gsub!("\\n", "\n")
|
|
212
199
|
code.gsub!("\\r", "\r")
|
|
213
|
-
# Disabled for the moment
|
|
200
|
+
# Disabled for the moment since it is deleting lines with '}'
|
|
214
201
|
#code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting.
|
|
215
202
|
if code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
|
|
216
203
|
code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
|
|
@@ -52,7 +52,7 @@ class SlackSmartBot
|
|
|
52
52
|
Dir.mkdir("#{project_folder}/tmp") unless Dir.exist?("#{project_folder}/tmp")
|
|
53
53
|
Dir.mkdir("#{project_folder}/tmp/repl") unless Dir.exist?("#{project_folder}/tmp/repl")
|
|
54
54
|
File.write("#{project_folder}/tmp/repl/#{session_name}.rb", content, mode: "w+")
|
|
55
|
-
process_to_run = "ruby
|
|
55
|
+
process_to_run = "ruby ./tmp/repl/#{session_name}.rb"
|
|
56
56
|
process_to_run = ("cd #{project_folder} && #{process_to_run}") if defined?(project_folder)
|
|
57
57
|
respond "Running REPL #{session_name}"
|
|
58
58
|
stdout, stderr, status = Open3.capture3(process_to_run)
|
|
@@ -60,10 +60,19 @@ class SlackSmartBot
|
|
|
60
60
|
if stdout == ""
|
|
61
61
|
respond "*#{session_name}*: Nothing returned."
|
|
62
62
|
else
|
|
63
|
-
|
|
63
|
+
if stdout.to_s.lines.count < 60 and stdout.to_s.size < 3500
|
|
64
|
+
respond "*#{session_name}*: #{stdout}"
|
|
65
|
+
else
|
|
66
|
+
send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: stdout)
|
|
67
|
+
end
|
|
64
68
|
end
|
|
65
69
|
else
|
|
66
|
-
|
|
70
|
+
if (stdout.to_s+stderr.to_s).lines.count < 60
|
|
71
|
+
respond "*#{session_name}*: #{stdout} #{stderr}"
|
|
72
|
+
else
|
|
73
|
+
send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: (stdout.to_s+stderr.to_s))
|
|
74
|
+
end
|
|
75
|
+
|
|
67
76
|
end
|
|
68
77
|
end
|
|
69
78
|
else
|
|
@@ -15,7 +15,7 @@ class SlackSmartBot
|
|
|
15
15
|
message = ""
|
|
16
16
|
@repls.sort.to_h.each do |session_name, repl|
|
|
17
17
|
if (repl.creator_name == user.name or repl.type == :public) or (config.admins.include?(user.name) and typem == :on_dm)
|
|
18
|
-
message += "(#{repl.type}) *#{session_name}*: #{repl.description} / created: #{repl.created} / accessed: #{repl.accessed} / creator: #{repl.
|
|
18
|
+
message += "(#{repl.type}) *#{session_name}*: #{repl.description} / created: #{repl.created} / accessed: #{repl.accessed} / creator: #{repl.creator_name} / runs: #{repl.runs_by_creator+repl.runs_by_others} / gets: #{repl.gets} \n"
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
message = "No repls created" if message == ''
|
|
@@ -46,14 +46,19 @@ class SlackSmartBot
|
|
|
46
46
|
rules_file = "slack-smart-bot_rules_#{channel_id}_#{from.gsub(" ", "_")}.rb"
|
|
47
47
|
if defined?(RULES_FOLDER)
|
|
48
48
|
rules_file = RULES_FOLDER + rules_file
|
|
49
|
+
general_rules_file = RULES_FOLDER + 'general_rules.rb'
|
|
49
50
|
else
|
|
50
51
|
Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
|
|
51
52
|
Dir.mkdir("#{config.path}/rules/#{channel_id}") unless Dir.exist?("#{config.path}/rules/#{channel_id}")
|
|
52
53
|
rules_file = "/rules/#{channel_id}/" + rules_file
|
|
54
|
+
general_rules_file = "/rules/general_rules.rb"
|
|
53
55
|
end
|
|
54
56
|
default_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_rules.rb")
|
|
57
|
+
default_general_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_general_rules.rb")
|
|
58
|
+
|
|
55
59
|
File.delete(config.path + rules_file) if File.exist?(config.path + rules_file)
|
|
56
60
|
FileUtils.copy_file(default_rules, config.path + rules_file) unless File.exist?(config.path + rules_file)
|
|
61
|
+
FileUtils.copy_file(default_general_rules, config.path + general_rules_file) unless File.exist?(config.path + general_rules_file)
|
|
57
62
|
admin_users = Array.new()
|
|
58
63
|
creator_info = client.web_client.users_info(user: channel_found.creator)
|
|
59
64
|
admin_users = [from, creator_info.user.name] + config.masters
|
|
@@ -70,7 +70,8 @@ class SlackSmartBot
|
|
|
70
70
|
channel = $1
|
|
71
71
|
kill_bot_on_channel(dest, from, channel)
|
|
72
72
|
when /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(every)\s+(\d+)\s*(days|hours|minutes|seconds|mins|min|secs|sec|d|h|m|s)\s*(\s.+)?\s*$/i,
|
|
73
|
-
|
|
73
|
+
/^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+on\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)s?\s+at\s+(\d+:\d+:?\d+?)\s*()(\s.+)?\s*$/i,
|
|
74
|
+
/^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s.+)?\s*$/i
|
|
74
75
|
silent = $2.to_s!=''
|
|
75
76
|
name = $3.downcase
|
|
76
77
|
type = $4
|
|
@@ -105,12 +106,15 @@ class SlackSmartBot
|
|
|
105
106
|
st_to = st_to.gsub('.','-').gsub('/','-')
|
|
106
107
|
st_user = opts.scan(/<@([^>]+)>/).join
|
|
107
108
|
exclude_masters = opts.match?(/exclude\s+masters?/i)
|
|
109
|
+
monthly = false
|
|
108
110
|
if all_opts.include?('today')
|
|
109
111
|
st_from = st_to = "#{Time.now.strftime("%Y-%m-%d")}"
|
|
112
|
+
elsif all_opts.include?('monthly')
|
|
113
|
+
monthly = true
|
|
110
114
|
end
|
|
111
115
|
exclude_command = opts.scan(/exclude\s+([^\s]+)/i).join
|
|
112
116
|
exclude_command = '' if exclude_command == 'masters'
|
|
113
|
-
bot_stats(dest, from, typem, st_channel, st_from, st_to, st_user, exclude_masters, exclude_command)
|
|
117
|
+
bot_stats(dest, from, typem, st_channel, st_from, st_to, st_user, exclude_masters, exclude_command, monthly)
|
|
114
118
|
else
|
|
115
119
|
processed = false
|
|
116
120
|
end
|
|
@@ -166,11 +170,11 @@ class SlackSmartBot
|
|
|
166
170
|
ruby_code(dest, user, code, rules_file)
|
|
167
171
|
when /^\s*(private\s+)?(repl|irb|live)\s*()()()$/i,
|
|
168
172
|
/^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()()\s*$/i,
|
|
169
|
-
/^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s
|
|
170
|
-
/^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s
|
|
173
|
+
/^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"()\s*$/i,
|
|
174
|
+
/^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"\s+(.+)\s*$/i,
|
|
171
175
|
/^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()\s+(.+)\s*$/i,
|
|
172
176
|
/^\s*(private\s+)?(repl|irb|live)()\s+()(.+)\s*$/i
|
|
173
|
-
|
|
177
|
+
if $1.to_s!=''
|
|
174
178
|
type = :private
|
|
175
179
|
else
|
|
176
180
|
type = :public
|
|
@@ -32,6 +32,8 @@ class SlackSmartBot
|
|
|
32
32
|
data.text = CGI.unescapeHTML(data.text)
|
|
33
33
|
data.text.gsub!("\u00A0", " ") #to change (asc char 160) into blank space
|
|
34
34
|
end
|
|
35
|
+
data.text.gsub!('’', "'")
|
|
36
|
+
data.text.gsub!('“', '"')
|
|
35
37
|
rescue
|
|
36
38
|
@logger.warn "Impossible to unescape or clean format for data.text:#{data.text}"
|
|
37
39
|
end
|
|
@@ -115,6 +117,8 @@ class SlackSmartBot
|
|
|
115
117
|
begin
|
|
116
118
|
#todo: when changed @questions user_id then move user_info inside the ifs to avoid calling it when not necessary
|
|
117
119
|
user_info = client.web_client.users_info(user: data.user)
|
|
120
|
+
#user_info.user.id = data.user #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
|
|
121
|
+
data.user = user_info.user.id #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
|
|
118
122
|
if @questions.key?(user_info.user.name)
|
|
119
123
|
if data.text.match?(/^\s*(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i)
|
|
120
124
|
@questions.delete(user_info.user.name)
|
|
@@ -127,12 +131,8 @@ class SlackSmartBot
|
|
|
127
131
|
((@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts == @repl_sessions[user_info.user.name][:thread_ts]) or
|
|
128
132
|
(!@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts.to_s == '' ))
|
|
129
133
|
|
|
130
|
-
if data.text.
|
|
131
|
-
|
|
132
|
-
@repl_sessions[user_info.user.name][:command] = ""
|
|
133
|
-
else
|
|
134
|
-
@repl_sessions[user_info.user.name][:command] = data.text[3..-4]
|
|
135
|
-
end
|
|
134
|
+
if data.text.match(/^\s*```(.*)```\s*$/im)
|
|
135
|
+
@repl_sessions[user_info.user.name][:command] = $1
|
|
136
136
|
else
|
|
137
137
|
@repl_sessions[user_info.user.name][:command] = data.text
|
|
138
138
|
end
|
|
@@ -142,12 +142,8 @@ class SlackSmartBot
|
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
#when added special characters on the message
|
|
145
|
-
if command.
|
|
146
|
-
|
|
147
|
-
command = ''
|
|
148
|
-
else
|
|
149
|
-
command = command[3..-4]
|
|
150
|
-
end
|
|
145
|
+
if command.match(/^\s*```(.*)```\s*$/im)
|
|
146
|
+
command = $1
|
|
151
147
|
elsif command.size >= 2 and
|
|
152
148
|
((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_"))
|
|
153
149
|
command = command[1..-2]
|
|
@@ -13,7 +13,6 @@ class SlackSmartBot
|
|
|
13
13
|
ruby = ""
|
|
14
14
|
end
|
|
15
15
|
@routines[@channel_id][name][:silent] = false if !@routines[@channel_id][name].key?(:silent)
|
|
16
|
-
|
|
17
16
|
if @routines[@channel_id][name][:at] == "" or
|
|
18
17
|
(@routines[@channel_id][name][:at] != "" and @routines[@channel_id][name][:running] and
|
|
19
18
|
@routines[@channel_id][name][:next_run] != "" and Time.now.to_s >= @routines[@channel_id][name][:next_run])
|
|
@@ -55,11 +54,34 @@ class SlackSmartBot
|
|
|
55
54
|
require "time"
|
|
56
55
|
every_in_seconds = Time.parse(@routines[@channel_id][name][:next_run]) - Time.now
|
|
57
56
|
elsif @routines[@channel_id][name][:at] != "" #coming from start after pause for 'at'
|
|
58
|
-
if
|
|
57
|
+
if @routines[@channel_id][name].key?(:dayweek) and @routines[@channel_id][name][:dayweek].to_s!=''
|
|
58
|
+
day = @routines[@channel_id][name][:dayweek]
|
|
59
|
+
days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday']
|
|
60
|
+
incr = days.index(day) - Time.now.wday
|
|
61
|
+
if incr < 0
|
|
62
|
+
incr = (7+incr)*24*60*60
|
|
63
|
+
else
|
|
64
|
+
incr = incr * 24 * 60 * 60
|
|
65
|
+
end
|
|
66
|
+
days = incr/(24*60*60)
|
|
67
|
+
weekly = true
|
|
68
|
+
else
|
|
69
|
+
days = 0
|
|
70
|
+
weekly = false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at] and days == 0
|
|
59
74
|
nt = @routines[@channel_id][name][:at].split(":")
|
|
60
75
|
next_run = Time.new(started.year, started.month, started.day, nt[0], nt[1], nt[2])
|
|
61
76
|
else
|
|
62
|
-
|
|
77
|
+
if days == 0 and started.strftime("%H:%M:%S") >= @routines[@channel_id][name][:at]
|
|
78
|
+
if weekly
|
|
79
|
+
days = 7
|
|
80
|
+
else
|
|
81
|
+
days = 1
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
next_run = started + (days * 24 * 60 * 60) # one more day/week
|
|
63
85
|
nt = @routines[@channel_id][name][:at].split(":")
|
|
64
86
|
next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2])
|
|
65
87
|
end
|
|
@@ -32,7 +32,11 @@ class SlackSmartBot
|
|
|
32
32
|
help = @help_messages.deep_copy
|
|
33
33
|
end
|
|
34
34
|
if rules_file != ""
|
|
35
|
-
help[:rules_file] =
|
|
35
|
+
help[:rules_file] = ''
|
|
36
|
+
help[:rules_file] += IO.readlines(config.path+rules_file).join.scan(/#\s*help\s*\w*:(.*)/i).join("\n") + "\n"
|
|
37
|
+
if File.exist?(config.path+'/rules/general_rules.rb')
|
|
38
|
+
help[:rules_file] += IO.readlines(config.path+'/rules/general_rules.rb').join.scan(/#\s*help\s*\w*:(.*)/i).join("\n")
|
|
39
|
+
end
|
|
36
40
|
end
|
|
37
41
|
help = remove_hash_keys(help, :admin_master) unless user_type == :admin_master
|
|
38
42
|
help = remove_hash_keys(help, :admin) unless user_type == :admin or user_type == :admin_master
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: slack-smart-bot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mario Ruiz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-10-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: slack-ruby-client
|
|
@@ -16,20 +16,20 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0.
|
|
19
|
+
version: '0.15'
|
|
20
20
|
- - ">="
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: 0.
|
|
22
|
+
version: 0.15.1
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
26
|
requirements:
|
|
27
27
|
- - "~>"
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: '0.
|
|
29
|
+
version: '0.15'
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.15.1
|
|
33
33
|
- !ruby/object:Gem::Dependency
|
|
34
34
|
name: nice_http
|
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -79,6 +79,9 @@ dependencies:
|
|
|
79
79
|
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
81
|
version: '1'
|
|
82
|
+
- - ">="
|
|
83
|
+
- !ruby/object:Gem::Version
|
|
84
|
+
version: 1.2.1
|
|
82
85
|
type: :runtime
|
|
83
86
|
prerelease: false
|
|
84
87
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -86,6 +89,9 @@ dependencies:
|
|
|
86
89
|
- - "~>"
|
|
87
90
|
- !ruby/object:Gem::Version
|
|
88
91
|
version: '1'
|
|
92
|
+
- - ">="
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: 1.2.1
|
|
89
95
|
- !ruby/object:Gem::Dependency
|
|
90
96
|
name: rspec
|
|
91
97
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -119,6 +125,7 @@ files:
|
|
|
119
125
|
- LICENSE
|
|
120
126
|
- README.md
|
|
121
127
|
- lib/slack-smart-bot.rb
|
|
128
|
+
- lib/slack-smart-bot_general_rules.rb
|
|
122
129
|
- lib/slack-smart-bot_rules.rb
|
|
123
130
|
- lib/slack/smart-bot/comm.rb
|
|
124
131
|
- lib/slack/smart-bot/comm/ask.rb
|
|
@@ -129,6 +136,7 @@ files:
|
|
|
129
136
|
- lib/slack/smart-bot/comm/send_file.rb
|
|
130
137
|
- lib/slack/smart-bot/comm/send_msg_channel.rb
|
|
131
138
|
- lib/slack/smart-bot/comm/send_msg_user.rb
|
|
139
|
+
- lib/slack/smart-bot/comm/unreact.rb
|
|
132
140
|
- lib/slack/smart-bot/commands.rb
|
|
133
141
|
- lib/slack/smart-bot/commands/general/bot_help.rb
|
|
134
142
|
- lib/slack/smart-bot/commands/general/bot_status.rb
|