slack-smart-bot 1.8.2 → 1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -11
- data/lib/slack-smart-bot.rb +43 -44
- data/lib/slack-smart-bot_rules.rb +6 -6
- data/lib/slack/smart-bot/comm.rb +5 -1
- data/lib/slack/smart-bot/comm/ask.rb +12 -5
- data/lib/slack/smart-bot/comm/dont_understand.rb +1 -1
- data/lib/slack/smart-bot/comm/event_hello.rb +30 -0
- data/lib/slack/smart-bot/comm/get_channel_members.rb +8 -0
- data/lib/slack/smart-bot/comm/get_channels.rb +20 -0
- data/lib/slack/smart-bot/comm/get_user_info.rb +16 -0
- data/lib/slack/smart-bot/comm/react.rb +21 -8
- data/lib/slack/smart-bot/comm/respond.rb +10 -5
- data/lib/slack/smart-bot/comm/send_msg_channel.rb +2 -2
- data/lib/slack/smart-bot/comm/send_msg_user.rb +4 -4
- data/lib/slack/smart-bot/comm/unreact.rb +21 -8
- data/lib/slack/smart-bot/commands.rb +3 -1
- data/lib/slack/smart-bot/commands/general/bot_help.rb +16 -3
- data/lib/slack/smart-bot/commands/general/bot_stats.rb +313 -0
- data/lib/slack/smart-bot/commands/general/bot_status.rb +1 -1
- data/lib/slack/smart-bot/commands/general/bye_bot.rb +1 -1
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +1 -1
- data/lib/slack/smart-bot/commands/general/use_rules.rb +2 -6
- data/lib/slack/smart-bot/commands/general/whats_new.rb +19 -0
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +65 -33
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +3 -7
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +8 -2
- data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +1 -1
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +52 -21
- data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +5 -5
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +50 -18
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +34 -9
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +2 -3
- data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +1 -1
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +27 -9
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +14 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +3 -3
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +1 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +41 -0
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +4 -8
- data/lib/slack/smart-bot/listen.rb +6 -5
- data/lib/slack/smart-bot/process.rb +227 -188
- data/lib/slack/smart-bot/process_first.rb +104 -87
- data/lib/slack/smart-bot/treat_message.rb +98 -38
- data/lib/slack/smart-bot/utils.rb +2 -0
- data/lib/slack/smart-bot/utils/answer.rb +18 -0
- data/lib/slack/smart-bot/utils/answer_delete.rb +15 -0
- data/lib/slack/smart-bot/utils/build_help.rb +57 -5
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +11 -2
- data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +1 -7
- data/lib/slack/smart-bot/utils/get_help.rb +79 -17
- data/lib/slack/smart-bot/utils/save_stats.rb +21 -8
- data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +6 -0
- data/whats_new.txt +18 -0
- metadata +21 -12
- data/lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb +0 -195
@@ -13,39 +13,64 @@ class SlackSmartBot
|
|
13
13
|
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
14
14
|
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
15
15
|
else
|
16
|
-
unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
|
16
|
+
unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File.") or
|
17
17
|
code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
|
18
18
|
code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or
|
19
|
-
code.include?("ENV") or code.match?(/=\s*IO/)
|
19
|
+
code.include?("ENV") or code.match?(/=\s*IO/) or code.include?("Dir.") or code.match?(/=\s*IO/) or
|
20
|
+
code.match?(/=\s*File/) or code.match?(/=\s*Dir/) or code.match?(/<\s*File/) or code.match?(/<\s*Dir/) or
|
21
|
+
code.match?(/\w+:\s*File/) or code.match?(/\w+:\s*Dir/)
|
22
|
+
react :running
|
20
23
|
unless rules_file.empty?
|
21
24
|
begin
|
22
25
|
eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
26
|
-
respond "Running", dest if code.size >
|
29
|
+
respond "Running", dest if code.size > 200
|
27
30
|
|
28
31
|
begin
|
29
32
|
code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting
|
33
|
+
code.gsub!('$','\$') #to take $ as literal, fex: puts '$lolo' => puts '\$lolo'
|
30
34
|
ruby = "ruby -e \"#{code.gsub('"', '\"')}\""
|
31
35
|
if defined?(project_folder) and project_folder.to_s != "" and Dir.exist?(project_folder)
|
32
36
|
ruby = ("cd #{project_folder} &&" + ruby)
|
33
37
|
else
|
34
38
|
def project_folder() "" end
|
35
39
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
|
41
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(ruby)
|
42
|
+
timeout = timeoutt = 20
|
43
|
+
procstart = Time.now
|
44
|
+
while (wait_thr.status == 'run' or wait_thr.status == 'sleep') and timeout > 0
|
45
|
+
timeout -= 0.1
|
46
|
+
sleep 0.1
|
47
|
+
end
|
48
|
+
if timeout > 0
|
49
|
+
stdout = stdout.read
|
50
|
+
stderr = stderr.read
|
51
|
+
if stderr == ""
|
52
|
+
if stdout == ""
|
53
|
+
respond "Nothing returned. Remember you need to use p or puts to print", dest
|
54
|
+
else
|
55
|
+
respond stdout, dest
|
56
|
+
end
|
40
57
|
else
|
41
|
-
respond stdout, dest
|
58
|
+
respond "#{stderr}\n#{stdout}", dest
|
42
59
|
end
|
43
60
|
else
|
44
|
-
respond "#{
|
61
|
+
respond "The process didn't finish in #{timeoutt} secs so it was aborted. Timeout!"
|
62
|
+
pids = `pgrep -P #{wait_thr.pid}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
63
|
+
pids.each do |pid|
|
64
|
+
begin
|
65
|
+
Process.kill("KILL", pid)
|
66
|
+
rescue
|
67
|
+
end
|
68
|
+
end
|
45
69
|
end
|
46
70
|
rescue Exception => exc
|
47
71
|
respond exc, dest
|
48
72
|
end
|
73
|
+
unreact :running
|
49
74
|
else
|
50
75
|
respond "Sorry I cannot run this due security reasons", dest
|
51
76
|
end
|
@@ -4,7 +4,6 @@ class SlackSmartBot
|
|
4
4
|
# help: `run repl SESSION_NAME ENV_VAR=VALUE ENV_VAR=VALUE`
|
5
5
|
# help: `run live SESSION_NAME`
|
6
6
|
# help: `run irb SESSION_NAME`
|
7
|
-
# help:
|
8
7
|
# help: Will run the repl session specified and return the output.
|
9
8
|
# help: You can supply the Environmental Variables you need for the Session
|
10
9
|
# help: It will return only the values that were print out on the repl with puts, print, p or pp
|
@@ -22,7 +21,7 @@ class SlackSmartBot
|
|
22
21
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
23
22
|
Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}")
|
24
23
|
if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
|
25
|
-
if @repls.key?(session_name) and @repls[session_name][:type] == :private and
|
24
|
+
if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) and
|
26
25
|
@repls[session_name][:creator_name]!=user.name and
|
27
26
|
!config.admins.include?(user.name)
|
28
27
|
respond "The REPL with session name: #{session_name} is private", dest
|
@@ -44,7 +43,7 @@ class SlackSmartBot
|
|
44
43
|
eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
|
45
44
|
end
|
46
45
|
end
|
47
|
-
if File.exist?("#{project_folder}/.smart-bot-repl")
|
46
|
+
if File.exist?("#{project_folder}/.smart-bot-repl") and @repls[session_name][:type] != :private_clean and @repls[session_name][:type] != :public_clean
|
48
47
|
content += File.read("#{project_folder}/.smart-bot-repl")
|
49
48
|
content += "\n"
|
50
49
|
end
|
@@ -14,7 +14,7 @@ class SlackSmartBot
|
|
14
14
|
else
|
15
15
|
message = ""
|
16
16
|
@repls.sort.to_h.each do |session_name, repl|
|
17
|
-
if (repl.creator_name == user.name or repl.type == :public) or (config.admins.include?(user.name) and typem == :on_dm)
|
17
|
+
if (repl.creator_name == user.name or repl.type == :public or repl.type == :public_clean) or (config.admins.include?(user.name) and typem == :on_dm)
|
18
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
|
@@ -13,26 +13,44 @@ class SlackSmartBot
|
|
13
13
|
else
|
14
14
|
unless typem == :on_extended
|
15
15
|
msg = ""
|
16
|
-
if @shortcuts[:all].keys.size > 0
|
16
|
+
if @shortcuts[:all].keys.size > 0 or @shortcuts_global[:all].keys.size > 0
|
17
17
|
msg = "*Available shortcuts for all:*\n"
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
|
19
|
+
if @shortcuts[:all].keys.size > 0
|
20
|
+
@shortcuts[:all].each { |name, value|
|
21
|
+
msg += " _#{name}: #{value}_\n"
|
22
|
+
}
|
23
|
+
end
|
24
|
+
if @shortcuts_global[:all].keys.size > 0
|
25
|
+
@shortcuts_global[:all].each { |name, value|
|
26
|
+
msg += " _#{name} (global): #{value}_\n"
|
27
|
+
}
|
28
|
+
end
|
21
29
|
respond msg, dest
|
22
30
|
end
|
23
|
-
|
31
|
+
msg2 = ''
|
24
32
|
if @shortcuts.keys.include?(from) and @shortcuts[from].keys.size > 0
|
25
33
|
new_hash = @shortcuts[from].dup
|
26
34
|
@shortcuts[:all].keys.each { |k| new_hash.delete(k) }
|
27
35
|
if new_hash.keys.size > 0
|
28
|
-
|
36
|
+
msg2 = "*Available shortcuts for #{from}:*\n"
|
29
37
|
new_hash.each { |name, value|
|
30
|
-
|
38
|
+
msg2 += " _#{name}: #{value}_\n"
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
if @shortcuts_global.keys.include?(from) and @shortcuts_global[from].keys.size > 0
|
43
|
+
new_hash = @shortcuts_global[from].dup
|
44
|
+
@shortcuts_global[:all].keys.each { |k| new_hash.delete(k) }
|
45
|
+
if new_hash.keys.size > 0
|
46
|
+
msg2 = "*Available shortcuts for #{from}:*\n" if msg2 == ''
|
47
|
+
new_hash.each { |name, value|
|
48
|
+
msg2 += " _#{name} (global): #{value}_\n"
|
31
49
|
}
|
32
|
-
respond msg, dest
|
33
50
|
end
|
34
51
|
end
|
35
|
-
respond
|
52
|
+
respond msg2 unless msg2 == ''
|
53
|
+
respond "No shortcuts found" if (msg + msg2) == ""
|
36
54
|
end
|
37
55
|
end
|
38
56
|
end
|
@@ -7,7 +7,15 @@ class SlackSmartBot
|
|
7
7
|
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
8
8
|
else
|
9
9
|
if typem == :on_extended or typem == :on_call #for the other cases above.
|
10
|
-
|
10
|
+
|
11
|
+
if help_command.to_s != ''
|
12
|
+
help_command = '' if help_command.to_s.match?(/^\s*expanded\s*$/i) or help_command.to_s.match?(/^\s*extended\s*$/i)
|
13
|
+
expanded = true
|
14
|
+
else
|
15
|
+
expanded = false
|
16
|
+
end
|
17
|
+
|
18
|
+
help_filtered = get_help(rules_file, dest, from, true, expanded)
|
11
19
|
|
12
20
|
if help_command.to_s != ""
|
13
21
|
help_found = false
|
@@ -38,6 +46,11 @@ class SlackSmartBot
|
|
38
46
|
def git_project() "" end
|
39
47
|
def project_folder() "" end
|
40
48
|
end
|
49
|
+
unless expanded
|
50
|
+
message_not_expanded = "*If you want to see the expanded version of `bot rules`, please call `bot rules expanded`*\n"
|
51
|
+
message_not_expanded += "*Also to get specific expanded help for a specific command or rule call `bot rules COMMAND`*\n"
|
52
|
+
respond message_not_expanded
|
53
|
+
end
|
41
54
|
end
|
42
55
|
end
|
43
56
|
end
|
@@ -11,10 +11,10 @@ class SlackSmartBot
|
|
11
11
|
save_stats(__method__)
|
12
12
|
if config.on_master_bot
|
13
13
|
if config.admins.include?(from) #admin user
|
14
|
-
|
14
|
+
if answer.empty?
|
15
15
|
ask("are you sure?", command, from, dest)
|
16
16
|
else
|
17
|
-
case
|
17
|
+
case answer
|
18
18
|
when /yes/i, /yep/i, /sure/i
|
19
19
|
respond "Game over!", dest
|
20
20
|
respond "Ciao #{display_name}!", dest
|
@@ -33,7 +33,7 @@ class SlackSmartBot
|
|
33
33
|
exit!
|
34
34
|
end
|
35
35
|
when /no/i, /nope/i, /cancel/i
|
36
|
-
|
36
|
+
answer_delete(from)
|
37
37
|
respond "Thanks, I'm happy to be alive", dest
|
38
38
|
else
|
39
39
|
ask("I don't understand, are you sure do you want me to close? (yes or no)", command, from, dest)
|
@@ -18,7 +18,7 @@ class SlackSmartBot
|
|
18
18
|
end
|
19
19
|
respond "Bot channels have been notified", dest
|
20
20
|
elsif where == "all" #all
|
21
|
-
myconv =
|
21
|
+
myconv = get_channels(bot_is_in: true)
|
22
22
|
myconv.each do |c|
|
23
23
|
respond message, c.id unless c.name == config.master_channel
|
24
24
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
# helpmaster: ----------------------------------------------
|
3
|
+
# helpmaster: `set maintenance on`
|
4
|
+
# helpmaster: `set maintenance on MESSAGE`
|
5
|
+
# helpmaster: `set maintenance off`
|
6
|
+
# helpmaster: `turn maintenance on`
|
7
|
+
# helpmaster: `turn maintenance on MESSAGE`
|
8
|
+
# helpmaster: `turn maintenance off`
|
9
|
+
# helpmaster: The SmartBot will be on maintenance and responding with a generic message
|
10
|
+
# helpmaster: Only works if you are on Master channel and you are a master admin user
|
11
|
+
# helpmaster:
|
12
|
+
def set_maintenance(from, status, message)
|
13
|
+
save_stats(__method__)
|
14
|
+
if config.on_master_bot
|
15
|
+
if config.admins.include?(from) #admin user
|
16
|
+
if message == ''
|
17
|
+
config.on_maintenance_message = "Sorry I'm on maintenance so I cannot attend your request."
|
18
|
+
else
|
19
|
+
config.on_maintenance_message = message
|
20
|
+
end
|
21
|
+
|
22
|
+
if status == 'on'
|
23
|
+
config.on_maintenance = true
|
24
|
+
respond "From now on I'll be on maintenance status so I won't be responding accordingly."
|
25
|
+
else
|
26
|
+
config.on_maintenance = false
|
27
|
+
respond "From now on I won't be on maintenance. Everything is back to normal!"
|
28
|
+
end
|
29
|
+
|
30
|
+
file = File.open("#{config.path}/config_tmp.status", "w")
|
31
|
+
file.write config.inspect
|
32
|
+
file.close
|
33
|
+
|
34
|
+
else
|
35
|
+
respond 'Only master admins on master channel can use this command.'
|
36
|
+
end
|
37
|
+
else
|
38
|
+
respond 'Only master admins on master channel can use this command.'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -24,13 +24,9 @@ class SlackSmartBot
|
|
24
24
|
channel_id = @channels_id[channel]
|
25
25
|
end
|
26
26
|
#todo: add pagination for case more than 1000 channels on the workspace
|
27
|
-
channels =
|
28
|
-
types: "private_channel,public_channel",
|
29
|
-
limit: "1000",
|
30
|
-
exclude_archived: "true",
|
31
|
-
).channels
|
27
|
+
channels = get_channels()
|
32
28
|
channel_found = channels.detect { |c| c.name == channel }
|
33
|
-
members =
|
29
|
+
members = get_channel_members(@channels_id[channel]) unless channel_found.nil?
|
34
30
|
|
35
31
|
if channel_id.nil?
|
36
32
|
respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
|
@@ -39,7 +35,7 @@ class SlackSmartBot
|
|
39
35
|
elsif @bots_created.keys.include?(channel_id)
|
40
36
|
respond "There is already a bot in this channel: #{channel}, kill it before", dest
|
41
37
|
elsif config[:nick_id] != channel_found.creator and !members.include?(config[:nick_id])
|
42
|
-
respond "You need to add first to the channel the smart bot user:
|
38
|
+
respond "You need to add first to the channel the smart bot user: <@#{config[:nick_id]}>", dest
|
43
39
|
else
|
44
40
|
if channel_id != config[:channel]
|
45
41
|
begin
|
@@ -60,7 +56,7 @@ class SlackSmartBot
|
|
60
56
|
FileUtils.copy_file(default_rules, config.path + rules_file) unless File.exist?(config.path + rules_file)
|
61
57
|
FileUtils.copy_file(default_general_rules, config.path + general_rules_file) unless File.exist?(config.path + general_rules_file)
|
62
58
|
admin_users = Array.new()
|
63
|
-
creator_info =
|
59
|
+
creator_info = get_user_info(channel_found.creator)
|
64
60
|
admin_users = [from, creator_info.user.name] + config.masters
|
65
61
|
admin_users.uniq!
|
66
62
|
@logger.info "ruby #{config.file_path} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on"
|
@@ -6,7 +6,7 @@ class SlackSmartBot
|
|
6
6
|
get_bots_created()
|
7
7
|
@buffer_complete = [] unless defined?(@buffer_complete)
|
8
8
|
b = File.read("#{config.path}/buffer_complete.log")
|
9
|
-
result = b.scan(/^\|(\w+)\|(\w+)\|([^~]+)~~~/m)
|
9
|
+
result = b.scan(/^\|(\w+)\|(\w+)\|(\w+)\|([^~]+)~~~/m)
|
10
10
|
result.delete(nil)
|
11
11
|
new_messages = result[@buffer_complete.size..-1]
|
12
12
|
unless new_messages.nil? or new_messages.empty?
|
@@ -14,7 +14,8 @@ class SlackSmartBot
|
|
14
14
|
new_messages.each do |message|
|
15
15
|
channel = message[0].strip
|
16
16
|
user = message[1].strip
|
17
|
-
|
17
|
+
user_name = message[2].strip
|
18
|
+
command = message[3].to_s.strip
|
18
19
|
# take in consideration that on simulation we are treating all messages even those that are not populated on real cases like when the message is not populated to the specific bot connection when message is sent with the bot
|
19
20
|
@logger.info "treat message: #{message}" if config.testing
|
20
21
|
|
@@ -23,18 +24,18 @@ class SlackSmartBot
|
|
23
24
|
command.scan(/`([^`]+)`/).flatten.each do |cmd|
|
24
25
|
if cmd.to_s!=''
|
25
26
|
cmd = "^#{cmd}"
|
26
|
-
treat_message({channel: channel, user: user, text: cmd}, false)
|
27
|
+
treat_message({channel: channel, user: user, text: cmd, user_name: user_name}, false)
|
27
28
|
end
|
28
29
|
end
|
29
30
|
elsif command.match?(/^\s*\-!/)
|
30
31
|
command.scan(/`([^`]+)`/).flatten.each do |cmd|
|
31
32
|
if cmd.to_s!=''
|
32
33
|
cmd = "!#{cmd}"
|
33
|
-
treat_message({channel: channel, user: user, text: cmd}, false)
|
34
|
+
treat_message({channel: channel, user: user, text: cmd, user_name: user_name}, false)
|
34
35
|
end
|
35
36
|
end
|
36
37
|
else
|
37
|
-
treat_message({channel: channel, user: user, text: command})
|
38
|
+
treat_message({channel: channel, user: user, text: command, user_name: user_name})
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
class SlackSmartBot
|
2
2
|
def process(user, command, dest, dchannel, rules_file, typem, files, ts)
|
3
3
|
from = user.name
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
if config.simulate
|
5
|
+
display_name = user.profile.display_name
|
6
|
+
else
|
7
|
+
if user.profile.display_name.to_s.match?(/\A\s*\z/)
|
8
|
+
user.profile.display_name = user.profile.real_name
|
9
|
+
end
|
10
|
+
display_name = user.profile.display_name
|
7
11
|
end
|
8
|
-
|
12
|
+
|
9
13
|
processed = true
|
10
14
|
|
11
15
|
on_demand = false
|
@@ -23,205 +27,240 @@ class SlackSmartBot
|
|
23
27
|
command = command2
|
24
28
|
on_demand = true
|
25
29
|
end
|
30
|
+
if (on_demand or
|
31
|
+
(@listening.key?(from) and (@listening[from].key?(dest) or @listening[from].key?(Thread.current[:thread_ts])) )) and
|
32
|
+
config.on_maintenance and !command.match?(/\A(set|turn)\s+maintenance\s+off\s*\z/)
|
33
|
+
respond config.on_maintenance_message, dest
|
34
|
+
processed = true
|
35
|
+
end
|
26
36
|
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
if !config.on_maintenance or (config.on_maintenance and command.match?(/\A(set|turn)\s+maintenance\s+off\s*\z/))
|
38
|
+
#todo: check :on_pg in this case
|
39
|
+
if typem == :on_master or typem == :on_bot or typem == :on_pg or typem == :on_dm
|
40
|
+
|
41
|
+
case command
|
30
42
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
43
|
+
when /^\s*(Hello|Hallo|Hi|Hola|What's\sup|Hey|Hæ)\s+(#{@salutations.join("|")})\s*$/i
|
44
|
+
hi_bot(user, dest, dchannel, from, display_name)
|
45
|
+
when /^\s*what's\s+new\s*$/i
|
46
|
+
whats_new(user, dest, dchannel, from, display_name)
|
47
|
+
when /^\s*(Bye|Bæ|Good\s+Bye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s+(#{@salutations.join("|")})\s*$/i
|
48
|
+
bye_bot(dest, from, display_name)
|
49
|
+
when /^\s*bot\s+(rules|help)\s*(.+)?$/i, /^bot,? what can I do/i
|
50
|
+
$1.to_s.match?(/rules/i) ? specific = true : specific = false
|
51
|
+
help_command = $2
|
38
52
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
53
|
+
bot_help(user, from, dest, dchannel, specific, help_command, rules_file)
|
54
|
+
when /^\s*use\s+(rules\s+)?(from\s+)?<#C\w+\|(.+)>\s*$/i, /^use\s+(rules\s+)?(from\s+)?([^\s]+\s*$)/i
|
55
|
+
channel = $3
|
56
|
+
use_rules(dest, channel, user, dchannel)
|
57
|
+
when /^\s*stop\s+using\s+rules\s+(from\s+)<#\w+\|(.+)>/i, /^stop\s+using\s+rules\s+(from\s+)(.+)/i
|
58
|
+
channel = $2
|
59
|
+
stop_using_rules(dest, channel, user, dchannel)
|
60
|
+
when /^\s*extend\s+rules\s+(to\s+)<#C\w+\|(.+)>/i, /^extend\s+rules\s+(to\s+)(.+)/i,
|
61
|
+
/^\s*use\s+rules\s+(on\s+)<#C\w+\|(.+)>/i, /^use\s+rules\s+(on\s+)(.+)/i
|
62
|
+
channel = $2
|
63
|
+
extend_rules(dest, user, from, channel, typem)
|
64
|
+
when /^\s*stop\s+using\s+rules\s+(on\s+)<#\w+\|(.+)>/i, /^stop\s+using\s+rules\s+(on\s+)(.+)/i
|
65
|
+
channel = $2
|
66
|
+
stop_using_rules_on(dest, user, from, channel, typem)
|
67
|
+
when /^\s*exit\s+bot\s*$/i, /^quit\s+bot\s*$/i, /^close\s+bot\s*$/i
|
68
|
+
exit_bot(command, from, dest, display_name)
|
69
|
+
when /^\s*start\s+(this\s+)?bot$/i
|
70
|
+
start_bot(dest, from)
|
71
|
+
when /^\s*pause\s+(this\s+)?bot$/i
|
72
|
+
pause_bot(dest, from)
|
73
|
+
when /^\s*bot\s+status/i
|
74
|
+
bot_status(dest, user)
|
75
|
+
when /\Anotify\s+<#(C\w+)\|.+>\s+(.+)\s*\z/im, /\Anotify\s+(all)?\s*(.+)\s*\z/im
|
76
|
+
where = $1
|
77
|
+
message = $2
|
78
|
+
notify_message(dest, from, where, message)
|
79
|
+
when /^\s*create\s+(cloud\s+)?bot\s+on\s+<#C\w+\|(.+)>\s*/i, /^create\s+(cloud\s+)?bot\s+on\s+(.+)\s*/i
|
80
|
+
cloud = !$1.nil?
|
81
|
+
channel = $2
|
82
|
+
create_bot(dest, user, cloud, channel)
|
83
|
+
when /^\s*kill\s+bot\s+on\s+<#C\w+\|(.+)>\s*$/i, /^kill\s+bot\s+on\s+(.+)\s*$/i
|
84
|
+
channel = $1
|
85
|
+
kill_bot_on_channel(dest, from, channel)
|
86
|
+
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<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i,
|
87
|
+
/^\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<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i,
|
88
|
+
/^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i
|
89
|
+
silent = $2.to_s!=''
|
90
|
+
name = $3.downcase
|
91
|
+
type = $4
|
92
|
+
number_time = $5
|
93
|
+
period = $6
|
94
|
+
channel = $8
|
95
|
+
command_to_run = $9
|
96
|
+
add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent, channel)
|
97
|
+
when /^\s*(kill|delete|remove)\s+routine\s+(\w+)\s*$/i
|
98
|
+
name = $2.downcase
|
99
|
+
remove_routine(dest, from, name)
|
100
|
+
when /^\s*(run|execute)\s+routine\s+(\w+)\s*$/i
|
101
|
+
name = $2.downcase
|
102
|
+
run_routine(dest, from, name)
|
103
|
+
when /^\s*pause\s+routine\s+(\w+)\s*$/i
|
104
|
+
name = $1.downcase
|
105
|
+
pause_routine(dest, from, name)
|
106
|
+
when /^\s*start\s+routine\s+(\w+)\s*$/i
|
107
|
+
name = $1.downcase
|
108
|
+
start_routine(dest, from, name)
|
109
|
+
when /^\s*see\s+(all\s+)?routines\s*$/i
|
110
|
+
all = $1.to_s != ""
|
111
|
+
see_routines(dest, from, user, all)
|
112
|
+
when /^\s*get\s+bot\s+logs?\s*$/i
|
113
|
+
get_bot_logs(dest, from, typem)
|
114
|
+
when /^\s*bot\s+stats\s*(.*)\s*$/i
|
115
|
+
opts = $1.to_s
|
116
|
+
all_opts = opts.downcase.split(' ')
|
117
|
+
all_data = all_opts.include?('alldata')
|
118
|
+
st_channel = opts.scan(/<#(\w+)\|.+>/).join
|
119
|
+
st_from = opts.scan(/from\s+(\d\d\d\d[\/\-\.]\d\d[\/\-\.]\d\d)/).join
|
120
|
+
st_from = st_from.gsub('.','-').gsub('/','-')
|
121
|
+
st_to = opts.scan(/to\s+(\d\d\d\d[\/\-\.]\d\d[\/\-\.]\d\d)/).join
|
122
|
+
st_to = st_to.gsub('.','-').gsub('/','-')
|
123
|
+
st_user = opts.scan(/<@([^>]+)>/).join
|
124
|
+
st_command = opts.scan(/\s+command\s+(\w+)/i).join.downcase
|
125
|
+
st_command = opts.scan(/^command\s+(\w+)/i).join.downcase if st_command == ''
|
126
|
+
exclude_masters = all_opts.include?('exclude') && all_opts.include?('masters')
|
127
|
+
exclude_routines = all_opts.include?('exclude') && all_opts.include?('routines')
|
128
|
+
if exclude_masters
|
129
|
+
opts.gsub!(/\s+masters$/,'')
|
130
|
+
opts.gsub!(/\s+masters\s+/,'')
|
131
|
+
end
|
132
|
+
if exclude_routines
|
133
|
+
opts.gsub!(/\s+routines$/,'')
|
134
|
+
opts.gsub!(/\s+routines\s+/,'')
|
135
|
+
end
|
136
|
+
monthly = false
|
137
|
+
if all_opts.include?('today')
|
138
|
+
st_from = st_to = "#{Time.now.strftime("%Y-%m-%d")}"
|
139
|
+
elsif all_opts.include?('monthly')
|
140
|
+
monthly = true
|
141
|
+
end
|
142
|
+
exclude_command = opts.scan(/exclude\s+([^\s]+)/i).join
|
143
|
+
unless @master_admin_users_id.include?(user.id)
|
144
|
+
st_user = user.id
|
145
|
+
end
|
146
|
+
if (typem == :on_master or typem == :on_bot) and dest[0]!='D' #routine bot stats to be published on DM
|
147
|
+
st_channel = dchannel
|
148
|
+
end
|
149
|
+
bot_stats(dest, user, typem, st_channel, st_from, st_to, st_user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data)
|
150
|
+
when /\A(set|turn)\s+maintenance\s+(on|off)\s*()\z/im, /\A(set|turn)\s+maintenance\s+(on)\s*(.+)\s*\z/im
|
151
|
+
status = $2.downcase
|
152
|
+
message = $3.to_s
|
153
|
+
set_maintenance(from, status, message)
|
154
|
+
else
|
155
|
+
processed = false
|
115
156
|
end
|
116
|
-
exclude_command = opts.scan(/exclude\s+([^\s]+)/i).join
|
117
|
-
exclude_command = '' if exclude_command == 'masters'
|
118
|
-
bot_stats(dest, from, typem, st_channel, st_from, st_to, st_user, exclude_masters, exclude_command, monthly)
|
119
157
|
else
|
120
158
|
processed = false
|
121
159
|
end
|
122
|
-
else
|
123
|
-
processed = false
|
124
|
-
end
|
125
160
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
161
|
+
# only when :on and (listening or on demand or direct message)
|
162
|
+
if @status == :on and
|
163
|
+
(!answer.empty? or
|
164
|
+
(@repl_sessions.key?(from) and dest==@repl_sessions[from][:dest] and
|
165
|
+
((@repl_sessions[from][:on_thread] and Thread.current[:thread_ts] == @repl_sessions[from][:thread_ts]) or
|
166
|
+
(!@repl_sessions[from][:on_thread] and !Thread.current[:on_thread]))) or
|
167
|
+
(@listening.key?(from) and typem != :on_extended and
|
168
|
+
((@listening[from].key?(dest) and !Thread.current[:on_thread]) or
|
169
|
+
(@listening[from].key?(Thread.current[:thread_ts]) and Thread.current[:on_thread] ) )) or
|
170
|
+
typem == :on_dm or typem == :on_pg or on_demand)
|
171
|
+
processed2 = true
|
172
|
+
|
173
|
+
case command
|
137
174
|
|
138
|
-
|
175
|
+
# bot rules for extended channels
|
176
|
+
when /^bot\s+rules\s*(.+)?$/i
|
177
|
+
help_command = $1
|
178
|
+
bot_rules(dest, help_command, typem, rules_file, user)
|
179
|
+
when /^\s*(add\s+)?(global\s+|generic\s+)?shortcut\s+(for\sall)?\s*([^:]+)\s*:\s*(.+)/i,
|
180
|
+
/^(add\s+)(global\s+|generic\s+)?sc\s+(for\sall)?\s*([^:]+)\s*:\s*(.+)/i
|
181
|
+
for_all = $3
|
182
|
+
shortcut_name = $4.to_s.downcase
|
183
|
+
command_to_run = $5
|
184
|
+
global = $2.to_s != ''
|
185
|
+
add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run, global)
|
186
|
+
when /^\s*(delete|remove)\s+(global\s+|generic\s+)?shortcut\s+(.+)/i,
|
187
|
+
/^(delete|remove)\s+(global\s+|generic\s+)?sc\s+(.+)/i
|
188
|
+
shortcut = $3.to_s.downcase
|
189
|
+
global = $2.to_s != ''
|
139
190
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
bot_rules(dest, help_command, typem, rules_file, user)
|
144
|
-
when /^\s*(add\s)?shortcut\s(for\sall)?\s*([^:]+)\s*:\s*(.+)/i, /^(add\s)sc\s(for\sall)?\s*([^:]+)\s*:\s*(.+)/i
|
145
|
-
for_all = $2
|
146
|
-
shortcut_name = $3.to_s.downcase
|
147
|
-
command_to_run = $4
|
148
|
-
add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run)
|
149
|
-
when /^\s*(delete|remove)\s+shortcut\s+(.+)/i, /^(delete|remove)\s+sc\s+(.+)/i
|
150
|
-
shortcut = $2.to_s.downcase
|
151
|
-
delete_shortcut(dest, user, shortcut, typem, command)
|
152
|
-
when /^\s*see\sshortcuts/i, /^see\ssc/i
|
153
|
-
see_shortcuts(dest, user, typem)
|
191
|
+
delete_shortcut(dest, user, shortcut, typem, command, global)
|
192
|
+
when /^\s*see\s+shortcuts/i, /^see\ssc/i
|
193
|
+
see_shortcuts(dest, user, typem)
|
154
194
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
195
|
+
#kept to be backwards compatible
|
196
|
+
when /^\s*id\schannel\s<#C\w+\|(.+)>\s*/i, /^id channel (.+)/
|
197
|
+
unless typem == :on_extended
|
198
|
+
channel_name = $1
|
199
|
+
get_channels_name_and_id()
|
200
|
+
if @channels_id.keys.include?(channel_name)
|
201
|
+
respond "the id of #{channel_name} is #{@channels_id[channel_name]}", dest
|
202
|
+
else
|
203
|
+
respond "channel: #{channel_name} not found", dest
|
204
|
+
end
|
164
205
|
end
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
type =
|
206
|
+
when /^\s*ruby\s(.+)/im, /^\s*code\s(.+)/im
|
207
|
+
code = $1
|
208
|
+
code.gsub!("\\n", "\n")
|
209
|
+
code.gsub!("\\r", "\r")
|
210
|
+
@logger.info code
|
211
|
+
ruby_code(dest, user, code, rules_file)
|
212
|
+
when /^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s*()()()$/i,
|
213
|
+
/^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)()()\s*$/i,
|
214
|
+
/^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"()\s*$/i,
|
215
|
+
/^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"\s+(.+)\s*$/i,
|
216
|
+
/^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)()\s+(.+)\s*$/i,
|
217
|
+
/^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)()\s+()(.+)\s*$/i
|
218
|
+
opts_type = $1.to_s.downcase.split(' ')
|
219
|
+
opts_type.include?('private') ? type = :private : type = :public
|
220
|
+
type = "#{type}_clean".to_sym if opts_type.include?('clean')
|
221
|
+
|
222
|
+
session_name = $3
|
223
|
+
description = $4
|
224
|
+
opts = " #{$5}"
|
225
|
+
env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i)
|
226
|
+
opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev|
|
227
|
+
env_vars << ev.gsub('=',"='") + "'"
|
228
|
+
end
|
229
|
+
env_vars.each_with_index do |ev, idx|
|
230
|
+
ev.gsub!("=","']=")
|
231
|
+
ev.lstrip!
|
232
|
+
env_vars[idx] = "ENV['#{ev}"
|
233
|
+
end
|
234
|
+
repl(dest, user, session_name, env_vars.flatten, rules_file, command, description, type)
|
235
|
+
when /^\s*get\s+(repl|irb|live)\s+([\w\-]+)\s*/i
|
236
|
+
session_name = $2
|
237
|
+
get_repl(dest, user, session_name)
|
238
|
+
when /^\s*run\s+(repl|irb|live)\s+([\w\-]+)()\s*$/i,
|
239
|
+
/^\s*run\s+(repl|irb|live)\s+([\w\-]+)\s+(.+)\s*$/i
|
240
|
+
session_name = $2
|
241
|
+
opts = " #{$3}"
|
242
|
+
env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i)
|
243
|
+
opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev|
|
244
|
+
env_vars << ev.gsub('=',"='") + "'"
|
245
|
+
end
|
246
|
+
env_vars.each_with_index do |ev, idx|
|
247
|
+
ev.gsub!("=","']=")
|
248
|
+
ev.lstrip!
|
249
|
+
env_vars[idx] = "ENV['#{ev}"
|
250
|
+
end
|
251
|
+
run_repl(dest, user, session_name, env_vars.flatten, rules_file)
|
252
|
+
when /^\s*(delete|remove)\s+(repl|irb|live)\s+([\w\-]+)\s*$/i
|
253
|
+
repl_name = $3
|
254
|
+
delete_repl(dest, user, repl_name)
|
255
|
+
when /^\s*see\s+(repls|repl|irb|irbs)\s*$/i
|
256
|
+
see_repls(dest, user, typem)
|
180
257
|
else
|
181
|
-
|
182
|
-
end
|
183
|
-
session_name = $3
|
184
|
-
description = $4
|
185
|
-
opts = " #{$5}"
|
186
|
-
env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i)
|
187
|
-
opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev|
|
188
|
-
env_vars << ev.gsub('=',"='") + "'"
|
189
|
-
end
|
190
|
-
env_vars.each_with_index do |ev, idx|
|
191
|
-
ev.gsub!("=","']=")
|
192
|
-
ev.lstrip!
|
193
|
-
env_vars[idx] = "ENV['#{ev}"
|
194
|
-
end
|
195
|
-
repl(dest, user, session_name, env_vars.flatten, rules_file, command, description, type)
|
196
|
-
when /^\s*get\s+(repl|irb|live)\s+([\w\-]+)\s*/i
|
197
|
-
session_name = $2
|
198
|
-
get_repl(dest, user, session_name)
|
199
|
-
when /^\s*run\s+(repl|irb|live)\s+([\w\-]+)()\s*$/i,
|
200
|
-
/^\s*run\s+(repl|irb|live)\s+([\w\-]+)\s+(.+)\s*$/i
|
201
|
-
session_name = $2
|
202
|
-
opts = " #{$3}"
|
203
|
-
env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i)
|
204
|
-
opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev|
|
205
|
-
env_vars << ev.gsub('=',"='") + "'"
|
206
|
-
end
|
207
|
-
env_vars.each_with_index do |ev, idx|
|
208
|
-
ev.gsub!("=","']=")
|
209
|
-
ev.lstrip!
|
210
|
-
env_vars[idx] = "ENV['#{ev}"
|
211
|
-
end
|
212
|
-
run_repl(dest, user, session_name, env_vars.flatten, rules_file)
|
213
|
-
when /^\s*(delete|remove)\s+(repl|irb|live)\s+([\w\-]+)\s*$/i
|
214
|
-
repl_name = $3
|
215
|
-
delete_repl(dest, user, repl_name)
|
216
|
-
when /^\s*see\s+(repls|repl|irb|irbs)\s*$/i
|
217
|
-
see_repls(dest, user, typem)
|
218
|
-
else
|
219
|
-
processed2 = false
|
220
|
-
end #of case
|
258
|
+
processed2 = false
|
259
|
+
end #of case
|
221
260
|
|
222
|
-
|
261
|
+
processed = true if processed or processed2
|
262
|
+
end
|
223
263
|
end
|
224
|
-
|
225
264
|
return processed
|
226
265
|
end
|
227
266
|
end
|