slack-smart-bot 1.8.1 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +127 -21
- data/lib/slack/smart-bot/comm/ask.rb +55 -42
- data/lib/slack/smart-bot/comm/dont_understand.rb +2 -2
- data/lib/slack/smart-bot/comm/event_hello.rb +34 -0
- data/lib/slack/smart-bot/comm/get_channel_members.rb +13 -0
- data/lib/slack/smart-bot/comm/get_channels.rb +35 -0
- data/lib/slack/smart-bot/comm/get_user_info.rb +20 -0
- data/lib/slack/smart-bot/comm/get_users.rb +24 -0
- data/lib/slack/smart-bot/comm/react.rb +38 -8
- data/lib/slack/smart-bot/comm/respond.rb +219 -48
- data/lib/slack/smart-bot/comm/respond_direct.rb +2 -3
- data/lib/slack/smart-bot/comm/respond_thread.rb +5 -0
- data/lib/slack/smart-bot/comm/send_file.rb +38 -34
- data/lib/slack/smart-bot/comm/send_msg_channel.rb +27 -22
- data/lib/slack/smart-bot/comm/send_msg_user.rb +58 -33
- data/lib/slack/smart-bot/comm/unreact.rb +24 -7
- data/lib/slack/smart-bot/comm.rb +7 -1
- data/lib/slack/smart-bot/commands/general/add_announcement.rb +32 -0
- data/lib/slack/smart-bot/commands/general/bot_help.rb +68 -28
- data/lib/slack/smart-bot/commands/general/bot_stats.rb +314 -0
- data/lib/slack/smart-bot/commands/general/bot_status.rb +3 -5
- data/lib/slack/smart-bot/commands/general/bye_bot.rb +0 -7
- data/lib/slack/smart-bot/commands/general/delete_announcement.rb +34 -0
- data/lib/slack/smart-bot/commands/general/delete_share.rb +34 -0
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +16 -11
- data/lib/slack/smart-bot/commands/general/leaderboard.rb +200 -0
- data/lib/slack/smart-bot/commands/general/see_announcements.rb +113 -0
- data/lib/slack/smart-bot/commands/general/see_favorite_commands.rb +54 -0
- data/lib/slack/smart-bot/commands/general/see_shares.rb +41 -0
- data/lib/slack/smart-bot/commands/general/see_statuses.rb +78 -0
- data/lib/slack/smart-bot/commands/general/share_messages.rb +58 -0
- data/lib/slack/smart-bot/commands/general/stop_using_rules.rb +11 -6
- data/lib/slack/smart-bot/commands/general/suggest_command.rb +30 -0
- data/lib/slack/smart-bot/commands/general/use_rules.rb +13 -16
- data/lib/slack/smart-bot/commands/general/whats_new.rb +19 -0
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +243 -0
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +67 -38
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +49 -14
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +5 -7
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +4 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +2 -3
- data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +6 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/see_result_routine.rb +32 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +12 -4
- data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +4 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +2 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb +32 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +24 -0
- data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +3 -5
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +54 -25
- data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +7 -9
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +55 -25
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +36 -13
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +5 -7
- data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +4 -6
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +29 -13
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +55 -9
- data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +4 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +5 -3
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +2 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +32 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb +38 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +49 -0
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +30 -21
- data/lib/slack/smart-bot/commands.rb +19 -1
- data/lib/slack/smart-bot/listen.rb +7 -8
- data/lib/slack/smart-bot/process.rb +373 -192
- data/lib/slack/smart-bot/process_first.rb +202 -104
- data/lib/slack/smart-bot/treat_message.rb +325 -186
- 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 +83 -30
- data/lib/slack/smart-bot/utils/get_bots_created.rb +4 -1
- data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +1 -7
- data/lib/slack/smart-bot/utils/get_help.rb +87 -35
- data/lib/slack/smart-bot/utils/get_shares.rb +12 -0
- data/lib/slack/smart-bot/utils/has_access.rb +12 -0
- data/lib/slack/smart-bot/utils/save_stats.rb +23 -8
- data/lib/slack/smart-bot/utils/save_status.rb +52 -0
- data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +6 -0
- data/lib/slack/smart-bot/utils.rb +5 -0
- data/lib/slack-smart-bot.rb +88 -47
- data/lib/slack-smart-bot_general_commands.rb +46 -0
- data/lib/slack-smart-bot_general_rules.rb +5 -2
- data/lib/slack-smart-bot_rules.rb +49 -23
- data/whats_new.txt +36 -0
- metadata +44 -13
- data/lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb +0 -195
@@ -7,6 +7,7 @@ class SlackSmartBot
|
|
7
7
|
# helpadmin: NAME: one word to identify the routine
|
8
8
|
# helpadmin: Examples:
|
9
9
|
# helpadmin: _start routine example_
|
10
|
+
# helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#routines|more info>
|
10
11
|
# helpadmin:
|
11
12
|
|
12
13
|
def start_routine(dest, from, name)
|
@@ -3,6 +3,7 @@ class SlackSmartBot
|
|
3
3
|
# helpadmin: ----------------------------------------------
|
4
4
|
# helpadmin: `stop using rules on CHANNEL_NAME`
|
5
5
|
# helpadmin: it will stop using the extended rules on the specified channel.
|
6
|
+
# helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#extending-rules-to-other-channels|more info>
|
6
7
|
# helpadmin:
|
7
8
|
|
8
9
|
def stop_using_rules_on(dest, user, from, channel, typem)
|
@@ -12,6 +13,7 @@ class SlackSmartBot
|
|
12
13
|
respond "Only admins can extend or stop using the rules. Admins on this channel: #{config.admins}", dest
|
13
14
|
else
|
14
15
|
get_bots_created()
|
16
|
+
channel = @channels_name[channel] if @channels_name.key?(channel)
|
15
17
|
if @bots_created[@channel_id][:extended].include?(channel)
|
16
18
|
@bots_created[@channel_id][:extended].delete(channel)
|
17
19
|
update_bots_file()
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
|
3
|
+
# helpadmin: ----------------------------------------------
|
4
|
+
# helpadmin: `react to #CHANNEL_NAME THREAD_ID EMOJIS`
|
5
|
+
# helpadmin: It will send the specified reactions as SmartBot
|
6
|
+
# 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
|
7
|
+
# helpadmin: Examples:
|
8
|
+
# helpadmin: _react to #sales 1622550707.012100 :thumbsup:_
|
9
|
+
# helpadmin: _react to #sales p1622550707012100 :thumbsup:_
|
10
|
+
# helpadmin: _react to #sales p1622550707012100 :thumbsup: :heavy_check_mark: :bathtub:_
|
11
|
+
# helpadmin:
|
12
|
+
def react_to(dest, from, typem, to, thread_ts, emojis)
|
13
|
+
save_stats(__method__)
|
14
|
+
if config.masters.include?(from) and typem==:on_dm #master admin user
|
15
|
+
succs = []
|
16
|
+
emojis.split(' ').each do |emoji|
|
17
|
+
succs << (react emoji, thread_ts, to)
|
18
|
+
end
|
19
|
+
succs.uniq!
|
20
|
+
if succs.size == 1 and succs[0] == true
|
21
|
+
react :heavy_check_mark
|
22
|
+
elsif succs.size == 2
|
23
|
+
react :exclamation
|
24
|
+
else
|
25
|
+
react :x
|
26
|
+
end
|
27
|
+
else
|
28
|
+
respond "Only master admin users on a `pr`ivate conversation with the SmartBot can send reactions as SmartBot.", dest
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
|
3
|
+
# helpadmin: ----------------------------------------------
|
4
|
+
# helpadmin: `send message to @USER_NAME : MESSAGE`
|
5
|
+
# helpadmin: `send message to #CHANNEL_NAME : MESSAGE`
|
6
|
+
# helpadmin: `send message to #CHANNEL_NAME THREAD_ID : MESSAGE`
|
7
|
+
# helpadmin: It will send the specified message as SmartBot
|
8
|
+
# 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
|
9
|
+
# helpadmin:
|
10
|
+
def send_message(dest, from, typem, to, thread_ts, message)
|
11
|
+
save_stats(__method__)
|
12
|
+
if config.masters.include?(from) and typem==:on_dm #master admin user
|
13
|
+
succ = (respond message, to, thread_ts: thread_ts, web_client: true)
|
14
|
+
if succ
|
15
|
+
react :heavy_check_mark
|
16
|
+
else
|
17
|
+
react :x
|
18
|
+
end
|
19
|
+
else
|
20
|
+
respond "Only master admin users on a private conversation with the SmartBot can send messages as SmartBot.", dest
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -3,23 +3,21 @@ class SlackSmartBot
|
|
3
3
|
# help: `delete repl SESSION_NAME`
|
4
4
|
# help: `delete irb SESSION_NAME`
|
5
5
|
# help: `remove repl SESSION_NAME`
|
6
|
-
# help:
|
7
6
|
# help: Will delete the specified REPL
|
8
7
|
# help: Only the creator of the REPL or an admin can delete REPLs
|
8
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
|
9
9
|
# help:
|
10
10
|
def delete_repl(dest, user, session_name)
|
11
11
|
#todo: add tests
|
12
12
|
save_stats(__method__)
|
13
|
-
if
|
14
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
15
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
16
|
-
else
|
13
|
+
if has_access?(__method__, user)
|
17
14
|
if @repls.key?(session_name)
|
18
15
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
19
16
|
if config.admins.include?(user.name) or @repls[session_name].creator_name == user.name
|
20
17
|
@repls.delete(session_name)
|
21
18
|
update_repls()
|
22
19
|
File.rename("#{config.path}/repl/#{@channel_id}/#{session_name}.input", "#{config.path}/repl/#{@channel_id}/#{session_name}_#{Time.now.strftime("%Y%m%d%H%M%S%N")}.deleted")
|
20
|
+
File.delete("#{config.path}/repl/#{@channel_id}/#{session_name}.output") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.output")
|
23
21
|
File.delete("#{config.path}/repl/#{@channel_id}/#{session_name}.run") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
|
24
22
|
respond "REPL #{session_name} deleted"
|
25
23
|
else
|
@@ -2,45 +2,74 @@ class SlackSmartBot
|
|
2
2
|
# help: ----------------------------------------------
|
3
3
|
# help: `delete shortcut NAME`
|
4
4
|
# help: `delete sc NAME`
|
5
|
+
# help: `delete global sc NAME`
|
5
6
|
# help: It will delete the shortcut with the supplied name
|
7
|
+
# help: 'global' or 'generic' can only be used on Master channel.
|
8
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#shortcuts|more info>
|
6
9
|
# help:
|
7
10
|
|
8
|
-
def delete_shortcut(dest, user, shortcut, typem, command)
|
11
|
+
def delete_shortcut(dest, user, shortcut, typem, command, global)
|
9
12
|
save_stats(__method__)
|
10
13
|
unless typem == :on_extended
|
11
14
|
from = user.name
|
12
|
-
if
|
13
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
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
|
-
else
|
15
|
+
if has_access?(__method__, user)
|
16
16
|
deleted = false
|
17
17
|
|
18
|
-
if
|
19
|
-
|
20
|
-
|
21
|
-
(config.admins.include?(from) and @shortcuts[:all].include?(shortcut))
|
22
|
-
#are you sure? to avoid deleting by mistake
|
23
|
-
unless @questions.keys.include?(from)
|
24
|
-
ask("are you sure you want to delete it?", command, from, dest)
|
18
|
+
if global
|
19
|
+
if !config.on_master_bot or typem != :on_master
|
20
|
+
respond "It is only possible to delete global shortcuts from Master channel"
|
25
21
|
else
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
22
|
+
if !config.admins.include?(from) and @shortcuts_global[:all].include?(shortcut) and
|
23
|
+
(!@shortcuts_global.key?(from) or !@shortcuts_global[from].include?(shortcut))
|
24
|
+
respond "Only the creator of the shortcut or an admin user can delete it"
|
25
|
+
elsif (@shortcuts_global.key?(from) and @shortcuts_global[from].keys.include?(shortcut)) or
|
26
|
+
(config.admins.include?(from) and @shortcuts_global[:all].include?(shortcut))
|
27
|
+
|
28
|
+
respond "global shortcut deleted!", dest
|
29
|
+
if @shortcuts_global.key?(from) and @shortcuts_global[from].key?(shortcut)
|
30
|
+
respond("#{shortcut}: #{@shortcuts_global[from][shortcut]}", dest)
|
31
|
+
elsif @shortcuts_global.key?(:all) and @shortcuts_global[:all].key?(shortcut)
|
32
|
+
respond("#{shortcut}: #{@shortcuts_global[:all][shortcut]}", dest)
|
33
|
+
end
|
34
|
+
@shortcuts_global[from].delete(shortcut) if @shortcuts_global.key?(from) and @shortcuts_global[from].key?(shortcut)
|
35
|
+
@shortcuts_global[:all].delete(shortcut) if @shortcuts_global.key?(:all) and @shortcuts_global[:all].key?(shortcut)
|
34
36
|
update_shortcuts_file()
|
35
|
-
when /^no/i
|
36
|
-
@questions.delete(from)
|
37
|
-
respond "ok, I won't delete it", dest
|
38
37
|
else
|
39
|
-
|
38
|
+
respond 'shortcut not found'
|
40
39
|
end
|
41
40
|
end
|
42
41
|
else
|
43
|
-
|
42
|
+
if !config.admins.include?(from) and @shortcuts[:all].include?(shortcut) and
|
43
|
+
(!@shortcuts.key?(from) or !@shortcuts[from].include?(shortcut))
|
44
|
+
respond "Only the creator of the shortcut or an admin user can delete it", dest
|
45
|
+
elsif (@shortcuts.keys.include?(from) and @shortcuts[from].keys.include?(shortcut)) or
|
46
|
+
(config.admins.include?(from) and @shortcuts[:all].include?(shortcut))
|
47
|
+
#are you sure? to avoid deleting by mistake
|
48
|
+
if answer.empty?
|
49
|
+
ask("are you sure you want to delete it?", command, from, dest)
|
50
|
+
else
|
51
|
+
case answer
|
52
|
+
when /^(yes|yep)/i
|
53
|
+
answer_delete(from)
|
54
|
+
respond "shortcut deleted!", dest
|
55
|
+
if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut)
|
56
|
+
respond("#{shortcut}: #{@shortcuts[from][shortcut]}", dest)
|
57
|
+
elsif @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut)
|
58
|
+
respond("#{shortcut}: #{@shortcuts[:all][shortcut]}", dest)
|
59
|
+
end
|
60
|
+
@shortcuts[from].delete(shortcut) if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut)
|
61
|
+
@shortcuts[:all].delete(shortcut) if @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut)
|
62
|
+
update_shortcuts_file()
|
63
|
+
when /^no/i
|
64
|
+
answer_delete(from)
|
65
|
+
respond "ok, I won't delete it", dest
|
66
|
+
else
|
67
|
+
ask("I don't understand, are you sure you want to delete it? (yes or no)", command, from, dest)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
else
|
71
|
+
respond "shortcut not found", dest
|
72
|
+
end
|
44
73
|
end
|
45
74
|
end
|
46
75
|
end
|
@@ -3,35 +3,33 @@ class SlackSmartBot
|
|
3
3
|
# help: `get repl SESSION_NAME`
|
4
4
|
# help: `get irb SESSION_NAME`
|
5
5
|
# help: `get live SESSION_NAME`
|
6
|
-
# help:
|
7
6
|
# help: Will get the Ruby commands sent on that SESSION_NAME.
|
7
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
|
8
8
|
# help:
|
9
9
|
def get_repl(dest, user, session_name)
|
10
10
|
#todo: add tests
|
11
11
|
save_stats(__method__)
|
12
|
-
if
|
13
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
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
|
-
else
|
12
|
+
if has_access?(__method__, user)
|
16
13
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
17
14
|
Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}")
|
18
15
|
if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
|
19
|
-
if @repls.key?(session_name) and @repls[session_name][:type] == :private and
|
16
|
+
if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) and
|
20
17
|
@repls[session_name][:creator_name]!=user.name and
|
21
18
|
!config.admins.include?(user.name)
|
22
19
|
respond "The REPL with session name: #{session_name} is private", dest
|
23
20
|
else
|
21
|
+
content = "require 'nice_http'\n"
|
24
22
|
if @repls.key?(session_name)
|
25
23
|
@repls[session_name][:accessed] = Time.now.to_s
|
26
24
|
@repls[session_name][:gets] += 1
|
27
25
|
update_repls()
|
28
26
|
end
|
29
|
-
|
30
|
-
|
31
|
-
if File.exist?("#{project_folder}/.smart-bot-repl")
|
27
|
+
if !@repls.key?(session_name) or
|
28
|
+
(File.exist?("#{project_folder}/.smart-bot-repl") and @repls[session_name][:type] != :private_clean and @repls[session_name][:type] != :public_clean)
|
32
29
|
content += File.read("#{project_folder}/.smart-bot-repl")
|
33
30
|
content += "\n"
|
34
31
|
end
|
32
|
+
|
35
33
|
content += File.read("#{config.path}/repl/#{@channel_id}/#{session_name}.run").gsub(/^(quit|exit|bye)$/i,'') #todo: remove this gsub it will never contain it
|
36
34
|
File.write("#{config.path}/repl/#{@channel_id}/#{session_name}.rb", content, mode: "w+")
|
37
35
|
send_file(dest, "REPL #{session_name} on #{config.channel}", "#{config.path}/repl/#{@channel_id}/#{session_name}.rb", " REPL #{session_name} on #{config.channel}", 'text/plain', "ruby")
|
@@ -5,20 +5,21 @@ class SlackSmartBot
|
|
5
5
|
# help: `irb`
|
6
6
|
# help: `repl SESSION_NAME`
|
7
7
|
# help: `private repl SESSION_NAME`
|
8
|
+
# help: `clean repl SESSION_NAME`
|
8
9
|
# help: `repl ENV_VAR=VALUE`
|
9
10
|
# help: `repl SESSION_NAME ENV_VAR=VALUE ENV_VAR='VALUE'`
|
10
11
|
# help: `repl SESSION_NAME: "DESCRIPTION"`
|
11
12
|
# help: `repl SESSION_NAME: "DESCRIPTION" ENV_VAR=VALUE ENV_VAR='VALUE'`
|
12
|
-
# help:
|
13
13
|
# help: Will run all we write as a ruby command and will keep the session values.
|
14
14
|
# help: SESSION_NAME only admits from a to Z, numbers, - and _
|
15
15
|
# help: If no SESSION_NAME supplied it will be treated as a temporary REPL
|
16
16
|
# help: If 'private' specified the repl will be accessible only by you and it will be displayed only to you when `see repls`
|
17
|
+
# help: If 'clean' specified the repl won't pre execute the code written on the .smart-bot-repl file
|
17
18
|
# help: To avoid a message to be treated, start the message with '-'.
|
18
19
|
# help: Send _quit_, _bye_ or _exit_ to finish the session.
|
19
20
|
# help: Send puts, print, p or pp if you want to print out something when using `run repl` later.
|
20
21
|
# help: After 30 minutes of no communication with the Smart Bot the session will be dismissed.
|
21
|
-
# help: If you declare on your rules file a method called
|
22
|
+
# help: If you declare on your rules file a method called 'project_folder' returning the path for the project folder, the code will be executed from that folder.
|
22
23
|
# help: By default it will be automatically loaded the gems: string_pattern, nice_hash and nice_http
|
23
24
|
# help: To pre-execute some ruby when starting the session add the code to .smart-bot-repl file on the project root folder defined on project_folder
|
24
25
|
# help: If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
|
@@ -28,14 +29,12 @@ class SlackSmartBot
|
|
28
29
|
# help: _repl CreateCustomer: "It creates a random customer for testing" LOCATION=spain HOST='https://10.30.40.50:8887'_
|
29
30
|
# help: _repl delete_logs_
|
30
31
|
# help: _private repl random-ssn_
|
32
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
|
31
33
|
# help:
|
32
34
|
def repl(dest, user, session_name, env_vars, rules_file, command, description, type)
|
33
35
|
#todo: add more tests
|
34
36
|
from = user.name
|
35
|
-
if
|
36
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
37
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
38
|
-
else
|
37
|
+
if has_access?(__method__, user)
|
39
38
|
if !@repl_sessions.key?(from)
|
40
39
|
save_stats(__method__)
|
41
40
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
@@ -78,7 +77,13 @@ class SlackSmartBot
|
|
78
77
|
}
|
79
78
|
update_repls()
|
80
79
|
end
|
81
|
-
|
80
|
+
react :running
|
81
|
+
if Thread.current[:ts].to_s == ''
|
82
|
+
@ts_react = Thread.current[:thread_ts]
|
83
|
+
else
|
84
|
+
@ts_react = Thread.current[:ts]
|
85
|
+
end
|
86
|
+
|
82
87
|
message = "Session name: *#{session_name}*
|
83
88
|
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
89
|
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`.
|
@@ -96,6 +101,19 @@ class SlackSmartBot
|
|
96
101
|
File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.output", "", mode: "a+")
|
97
102
|
File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.run", "", mode: "a+")
|
98
103
|
|
104
|
+
if type != :private_clean and type != :public_clean
|
105
|
+
pre_execute = '
|
106
|
+
if File.exist?(\"./.smart-bot-repl\")
|
107
|
+
begin
|
108
|
+
eval(File.read(\"./.smart-bot-repl\"), bindme' + serialt + ')
|
109
|
+
rescue Exception => resp_repl
|
110
|
+
end
|
111
|
+
end
|
112
|
+
'
|
113
|
+
else
|
114
|
+
pre_execute = ''
|
115
|
+
end
|
116
|
+
|
99
117
|
process_to_run = '
|
100
118
|
ruby -e "' + env_vars.join("\n") + '
|
101
119
|
require \"amazing_print\"
|
@@ -105,17 +123,12 @@ class SlackSmartBot
|
|
105
123
|
(obj.methods - Object.methods)
|
106
124
|
end
|
107
125
|
|
108
|
-
file_input_repl = File.open(\"' +
|
109
|
-
|
110
|
-
begin
|
111
|
-
eval(File.read(\"./.smart-bot-repl\"), bindme' + serialt + ')
|
112
|
-
rescue Exception => resp_repl
|
113
|
-
end
|
114
|
-
end
|
126
|
+
file_input_repl = File.open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.input\", \"r\")
|
127
|
+
' + pre_execute + '
|
115
128
|
while true do
|
116
129
|
sleep 0.2
|
117
130
|
code_to_run_repl = file_input_repl.read
|
118
|
-
if code_to_run_repl.to_s
|
131
|
+
if code_to_run_repl.to_s!=\"\"
|
119
132
|
add_to_run_repl = true
|
120
133
|
if code_to_run_repl.to_s.match?(/^quit$/i) or
|
121
134
|
code_to_run_repl.to_s.match?(/^exit$/i) or
|
@@ -132,18 +145,18 @@ class SlackSmartBot
|
|
132
145
|
rescue Exception => resp_repl
|
133
146
|
error = true
|
134
147
|
end
|
135
|
-
|
148
|
+
unless error
|
136
149
|
if code_to_run_repl.match?(/^\s*p\s+/i)
|
137
|
-
open(\"' +
|
150
|
+
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
138
151
|
f.puts \"\`\`\`\n#{resp_repl.inspect}\n\`\`\`\"
|
139
152
|
}
|
140
153
|
else
|
141
|
-
open(\"' +
|
154
|
+
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
142
155
|
f.puts \"\`\`\`\n#{resp_repl.ai}\n\`\`\`\"
|
143
156
|
}
|
144
157
|
end
|
145
|
-
unless
|
146
|
-
open(\"' +
|
158
|
+
unless !add_to_run_repl
|
159
|
+
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.run\", \"a+\") {|f|
|
147
160
|
f.puts code_to_run_repl
|
148
161
|
}
|
149
162
|
end
|
@@ -152,7 +165,6 @@ class SlackSmartBot
|
|
152
165
|
end
|
153
166
|
end"
|
154
167
|
'
|
155
|
-
|
156
168
|
unless rules_file.empty? # to get the project_folder
|
157
169
|
begin
|
158
170
|
eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
|
@@ -160,12 +172,12 @@ class SlackSmartBot
|
|
160
172
|
end
|
161
173
|
started = Time.now
|
162
174
|
process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
|
163
|
-
|
175
|
+
|
164
176
|
stdin, stdout, stderr, wait_thr = Open3.popen3(process_to_run)
|
165
177
|
timeout = 30 * 60 # 30 minutes
|
166
178
|
|
167
179
|
file_output_repl = File.open("#{config.path}/repl/#{@channel_id}/#{session_name}.output", "r")
|
168
|
-
|
180
|
+
@repl_sessions[from][:pid] = wait_thr.pid
|
169
181
|
while (wait_thr.status == 'run' or wait_thr.status == 'sleep') and @repl_sessions.key?(from)
|
170
182
|
begin
|
171
183
|
if (Time.now-@repl_sessions[from][:finished]) > timeout
|
@@ -173,6 +185,14 @@ class SlackSmartBot
|
|
173
185
|
f.puts 'quit'
|
174
186
|
}
|
175
187
|
respond "REPL session finished: #{@repl_sessions[from][:name]}", dest
|
188
|
+
unreact :running, @ts_react
|
189
|
+
pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
190
|
+
pids.each do |pid|
|
191
|
+
begin
|
192
|
+
Process.kill("KILL", pid)
|
193
|
+
rescue
|
194
|
+
end
|
195
|
+
end
|
176
196
|
@repl_sessions.delete(from)
|
177
197
|
break
|
178
198
|
end
|
@@ -199,10 +219,12 @@ class SlackSmartBot
|
|
199
219
|
code.gsub!("\\r", "\r")
|
200
220
|
# Disabled for the moment since it is deleting lines with '}'
|
201
221
|
#code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting.
|
202
|
-
if code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
|
222
|
+
if code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File.") or
|
203
223
|
code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
|
204
224
|
code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or
|
205
|
-
code.include?("ENV") or code.match?(/=\s*IO/)
|
225
|
+
code.include?("ENV") or code.match?(/=\s*IO/) or code.include?("Dir.") or
|
226
|
+
code.match?(/=\s*File/) or code.match?(/=\s*Dir/) or code.match?(/<\s*File/) or code.match?(/<\s*Dir/) or
|
227
|
+
code.match?(/\w+:\s*File/) or code.match?(/\w+:\s*Dir/)
|
206
228
|
respond "Sorry I cannot run this due security reasons", dest
|
207
229
|
else
|
208
230
|
@repl_sessions[from][:input]<<code
|
@@ -212,6 +234,14 @@ class SlackSmartBot
|
|
212
234
|
f.puts code
|
213
235
|
}
|
214
236
|
respond "REPL session finished: #{@repl_sessions[from][:name]}", dest
|
237
|
+
unreact :running, @ts_react
|
238
|
+
pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
239
|
+
pids.each do |pid|
|
240
|
+
begin
|
241
|
+
Process.kill("KILL", pid)
|
242
|
+
rescue
|
243
|
+
end
|
244
|
+
end
|
215
245
|
@repl_sessions.delete(from)
|
216
246
|
when /^\s*-/i
|
217
247
|
#ommit
|
@@ -5,47 +5,70 @@ class SlackSmartBot
|
|
5
5
|
# help: runs the code supplied and returns the output. Also you can send a Ruby file instead. Examples:
|
6
6
|
# help: _code puts (34344/99)*(34+14)_
|
7
7
|
# help: _ruby require 'json'; res=[]; 20.times {res<<rand(100)}; my_json={result: res}; puts my_json.to_json_
|
8
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#running-ruby-code-on-a-conversation|more info>
|
8
9
|
# help:
|
9
10
|
|
10
11
|
def ruby_code(dest, user, code, rules_file)
|
11
12
|
save_stats(__method__)
|
12
|
-
if
|
13
|
-
|
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
|
-
else
|
16
|
-
unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
|
13
|
+
if has_access?(__method__, user)
|
14
|
+
unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File.") or
|
17
15
|
code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
|
18
16
|
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/)
|
17
|
+
code.include?("ENV") or code.match?(/=\s*IO/) or code.include?("Dir.") or code.match?(/=\s*IO/) or
|
18
|
+
code.match?(/=\s*File/) or code.match?(/=\s*Dir/) or code.match?(/<\s*File/) or code.match?(/<\s*Dir/) or
|
19
|
+
code.match?(/\w+:\s*File/) or code.match?(/\w+:\s*Dir/)
|
20
|
+
react :running
|
20
21
|
unless rules_file.empty?
|
21
22
|
begin
|
22
23
|
eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
|
-
respond "Running", dest if code.size >
|
27
|
+
respond "Running", dest if code.size > 200
|
27
28
|
|
28
29
|
begin
|
29
30
|
code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting
|
31
|
+
code.gsub!('$','\$') #to take $ as literal, fex: puts '$lolo' => puts '\$lolo'
|
30
32
|
ruby = "ruby -e \"#{code.gsub('"', '\"')}\""
|
31
33
|
if defined?(project_folder) and project_folder.to_s != "" and Dir.exist?(project_folder)
|
32
34
|
ruby = ("cd #{project_folder} &&" + ruby)
|
33
35
|
else
|
34
36
|
def project_folder() "" end
|
35
37
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
|
39
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(ruby)
|
40
|
+
timeout = timeoutt = 20
|
41
|
+
procstart = Time.now
|
42
|
+
while (wait_thr.status == 'run' or wait_thr.status == 'sleep') and timeout > 0
|
43
|
+
timeout -= 0.1
|
44
|
+
sleep 0.1
|
45
|
+
end
|
46
|
+
if timeout > 0
|
47
|
+
stdout = stdout.read
|
48
|
+
stderr = stderr.read
|
49
|
+
if stderr == ""
|
50
|
+
if stdout == ""
|
51
|
+
respond "Nothing returned. Remember you need to use p or puts to print", dest
|
52
|
+
else
|
53
|
+
respond stdout, dest
|
54
|
+
end
|
40
55
|
else
|
41
|
-
respond stdout, dest
|
56
|
+
respond "#{stderr}\n#{stdout}", dest
|
42
57
|
end
|
43
58
|
else
|
44
|
-
respond "#{
|
59
|
+
respond "The process didn't finish in #{timeoutt} secs so it was aborted. Timeout!"
|
60
|
+
pids = `pgrep -P #{wait_thr.pid}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
61
|
+
pids.each do |pid|
|
62
|
+
begin
|
63
|
+
Process.kill("KILL", pid)
|
64
|
+
rescue
|
65
|
+
end
|
66
|
+
end
|
45
67
|
end
|
46
68
|
rescue Exception => exc
|
47
69
|
respond exc, dest
|
48
70
|
end
|
71
|
+
unreact :running
|
49
72
|
else
|
50
73
|
respond "Sorry I cannot run this due security reasons", dest
|
51
74
|
end
|