slack-smart-bot 1.9.1 → 1.11.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 +184 -16
- data/lib/slack/smart-bot/comm/ask.rb +55 -49
- data/lib/slack/smart-bot/comm/delete.rb +13 -0
- data/lib/slack/smart-bot/comm/dont_understand.rb +3 -3
- data/lib/slack/smart-bot/comm/event_hello.rb +8 -4
- data/lib/slack/smart-bot/comm/get_channel_members.rb +13 -4
- data/lib/slack/smart-bot/comm/get_channels.rb +31 -16
- data/lib/slack/smart-bot/comm/get_presence.rb +20 -0
- data/lib/slack/smart-bot/comm/get_user_info.rb +12 -8
- data/lib/slack/smart-bot/comm/get_users.rb +24 -0
- data/lib/slack/smart-bot/comm/react.rb +19 -2
- data/lib/slack/smart-bot/comm/respond.rb +224 -53
- 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 +59 -33
- data/lib/slack/smart-bot/comm/unreact.rb +22 -18
- data/lib/slack/smart-bot/comm.rb +4 -0
- data/lib/slack/smart-bot/commands/general/add_admin.rb +51 -0
- data/lib/slack/smart-bot/commands/general/add_announcement.rb +32 -0
- data/lib/slack/smart-bot/commands/general/add_team.rb +80 -0
- data/lib/slack/smart-bot/commands/general/allow_access.rb +67 -0
- data/lib/slack/smart-bot/commands/general/bot_help.rb +69 -33
- 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/delete_team.rb +34 -0
- data/lib/slack/smart-bot/commands/general/deny_access.rb +36 -0
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +16 -11
- data/lib/slack/smart-bot/commands/general/ping_team.rb +100 -0
- data/lib/slack/smart-bot/commands/general/poster.rb +116 -0
- data/lib/slack/smart-bot/commands/general/remove_admin.rb +58 -0
- data/lib/slack/smart-bot/commands/general/see_access.rb +24 -0
- data/lib/slack/smart-bot/commands/general/see_admins.rb +33 -0
- data/lib/slack/smart-bot/commands/general/see_announcements.rb +115 -0
- data/lib/slack/smart-bot/commands/general/see_command_ids.rb +29 -0
- data/lib/slack/smart-bot/commands/general/see_favorite_commands.rb +53 -0
- data/lib/slack/smart-bot/commands/general/see_shares.rb +41 -0
- data/lib/slack/smart-bot/commands/general/see_statuses.rb +91 -0
- data/lib/slack/smart-bot/commands/general/see_teams.rb +252 -0
- data/lib/slack/smart-bot/commands/general/share_messages.rb +58 -0
- data/lib/slack/smart-bot/commands/general/update_team.rb +109 -0
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +504 -0
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +4 -6
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +45 -14
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +4 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +6 -3
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +3 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +4 -4
- data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +8 -2
- data/lib/slack/smart-bot/commands/on_bot/admin/see_result_routine.rb +33 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +13 -10
- data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +6 -3
- data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +3 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +4 -1
- data/lib/slack/smart-bot/commands/on_bot/admin_master/delete_message.rb +25 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb +34 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +37 -0
- data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +4 -5
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +7 -8
- data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +400 -0
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/bot_status.rb +3 -4
- data/lib/slack/smart-bot/commands/on_bot/general/leaderboard.rb +201 -0
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/stop_using_rules.rb +12 -6
- data/lib/slack/smart-bot/commands/on_bot/general/suggest_command.rb +36 -0
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/use_rules.rb +13 -11
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/whats_new.rb +2 -1
- data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +4 -5
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +76 -21
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +3 -4
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +15 -7
- data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +5 -6
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +5 -6
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +45 -12
- data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +7 -3
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +4 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +3 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +33 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb +39 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +10 -1
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +28 -14
- data/lib/slack/smart-bot/commands/on_master/where_smartbot.rb +41 -0
- data/lib/slack/smart-bot/commands.rb +36 -5
- data/lib/slack/smart-bot/listen.rb +31 -33
- data/lib/slack/smart-bot/process.rb +234 -73
- data/lib/slack/smart-bot/process_first.rb +119 -38
- data/lib/slack/smart-bot/treat_message.rb +310 -237
- data/lib/slack/smart-bot/utils/build_help.rb +2 -2
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +81 -46
- data/lib/slack/smart-bot/utils/get_access_channels.rb +13 -0
- data/lib/slack/smart-bot/utils/get_admins_channels.rb +13 -0
- data/lib/slack/smart-bot/utils/get_bots_created.rb +28 -8
- data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +7 -2
- data/lib/slack/smart-bot/utils/get_command_ids.rb +84 -0
- data/lib/slack/smart-bot/utils/get_help.rb +79 -73
- data/lib/slack/smart-bot/utils/get_repls.rb +22 -2
- data/lib/slack/smart-bot/utils/get_routines.rb +22 -2
- data/lib/slack/smart-bot/utils/get_shares.rb +12 -0
- data/lib/slack/smart-bot/utils/get_teams.rb +22 -0
- data/lib/slack/smart-bot/utils/has_access.rb +28 -0
- data/lib/slack/smart-bot/utils/is_admin.rb +27 -0
- data/lib/slack/smart-bot/utils/save_stats.rb +46 -41
- data/lib/slack/smart-bot/utils/save_status.rb +67 -0
- data/lib/slack/smart-bot/utils/update_access_channels.rb +8 -0
- data/lib/slack/smart-bot/utils/update_admins_channels.rb +8 -0
- data/lib/slack/smart-bot/utils/update_bots_file.rb +28 -7
- data/lib/slack/smart-bot/utils/update_repls.rb +7 -4
- data/lib/slack/smart-bot/utils/update_routines.rb +9 -3
- data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +13 -6
- data/lib/slack/smart-bot/utils/update_teams.rb +16 -0
- data/lib/slack/smart-bot/utils.rb +11 -0
- data/lib/slack-smart-bot.rb +72 -12
- data/lib/slack-smart-bot_general_commands.rb +61 -0
- data/lib/slack-smart-bot_general_rules.rb +5 -2
- data/lib/slack-smart-bot_rules.rb +43 -17
- data/whats_new.txt +20 -15
- metadata +76 -9
- data/lib/slack/smart-bot/commands/general/bot_stats.rb +0 -313
@@ -0,0 +1,36 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
|
3
|
+
# help: ----------------------------------------------
|
4
|
+
# help: `suggest command`
|
5
|
+
# help: `random command`
|
6
|
+
# help: `command suggestion`
|
7
|
+
# help: `suggest rule`
|
8
|
+
# help: `random rule`
|
9
|
+
# help: `rule suggestion`
|
10
|
+
# help: it will display the help content for a random command.
|
11
|
+
# help: if used 'rule' then it will display a random rule.
|
12
|
+
# help: if used 'command' it will show any kind of command or rule.
|
13
|
+
# help: command_id: :suggest_command
|
14
|
+
# help:
|
15
|
+
def suggest_command(from, dest, dchannel, specific, rules_file)
|
16
|
+
save_stats(__method__)
|
17
|
+
dont_suggest = []
|
18
|
+
help_message = get_help(rules_file, dest, from, specific, true, descriptions: false, only_normal_user: true)
|
19
|
+
commands = help_message.gsub(/====+/,'-'*30).split(/^\s*-------*$/).flatten
|
20
|
+
commands.reject!{|c| c.match?(/These are specific commands for this bot on this/i) || c.match?(/\A\s*\z/)}
|
21
|
+
dont_suggest.each do |ds|
|
22
|
+
commands.reject!{|c| c.match?(/:#{ds}\s*$/i)}
|
23
|
+
end
|
24
|
+
@last_suggested_commands ||= []
|
25
|
+
@last_suggested_commands.shift if @last_suggested_commands.size >=5
|
26
|
+
command = ''
|
27
|
+
begin
|
28
|
+
command = commands.sample
|
29
|
+
end until !@last_suggested_commands.include?(command) or commands.size <= 5
|
30
|
+
@last_suggested_commands << command
|
31
|
+
command.gsub!(/^\s*command_id:\s+:\w+\s*$/,'')
|
32
|
+
message = "*Command suggestion*:\n#{command}"
|
33
|
+
respond message, dest, unfurl_links: false, unfurl_media: false
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -6,22 +6,23 @@ class SlackSmartBot
|
|
6
6
|
# help: `use CHANNEL`
|
7
7
|
# help: it will use the rules from the specified channel.
|
8
8
|
# help: you need to be part of that channel to be able to use the rules.
|
9
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#using-rules-from-other-channels|more info>
|
10
|
+
# help: command_id: :use_rules
|
9
11
|
# help:
|
10
12
|
def use_rules(dest, channel, user, dchannel)
|
11
13
|
save_stats(__method__)
|
12
14
|
get_bots_created()
|
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
|
15
|
+
if has_access?(__method__, user)
|
17
16
|
#todo: add pagination for case more than 1000 channels on the workspace
|
18
17
|
channels = get_channels()
|
19
|
-
|
18
|
+
channel.gsub!('#','') # for the case the channel name is in plain text including #
|
19
|
+
channel = @channels_name[channel] if @channels_name.key?(channel)
|
20
20
|
channel_found = channels.detect { |c| c.name == channel }
|
21
|
-
|
21
|
+
get_channels_name_and_id() unless @channels_id.key?(channel)
|
22
|
+
members = get_channel_members(@channels_id[channel]) unless channel_found.nil? or !@channels_id.key?(channel)
|
22
23
|
|
23
|
-
if channel_found.nil?
|
24
|
-
respond "The channel you are trying to use doesn't exist", dest
|
24
|
+
if channel_found.nil? or !@channels_id.key?(channel)
|
25
|
+
respond "The channel you are trying to use doesn't exist or cannot be found.", dest
|
25
26
|
elsif channel_found.name == config.master_channel
|
26
27
|
respond "You cannot use the rules from Master Channel on any other channel.", dest
|
27
28
|
elsif !@bots_created.key?(@channels_id[channel])
|
@@ -30,12 +31,13 @@ class SlackSmartBot
|
|
30
31
|
respond "The bot in that channel is not :on", dest
|
31
32
|
else
|
32
33
|
if user.id == channel_found.creator or members.include?(user.id)
|
33
|
-
@rules_imported[user.
|
34
|
+
@rules_imported[user.name] = {} unless @rules_imported.key?(user.name)
|
34
35
|
if dest[0] == "C" or dest[0] == "G" #todo: take in consideration bots that are not master
|
35
|
-
@rules_imported[user.
|
36
|
+
@rules_imported[user.name][dchannel] = channel_found.id
|
36
37
|
else
|
37
|
-
@rules_imported[user.
|
38
|
+
@rules_imported[user.name][user.name] = channel_found.id
|
38
39
|
end
|
40
|
+
sleep 0.5
|
39
41
|
update_rules_imported()
|
40
42
|
respond "I'm using now the rules from <##{channel_found.id}>", dest
|
41
43
|
|
@@ -3,11 +3,12 @@ class SlackSmartBot
|
|
3
3
|
# help: ----------------------------------------------
|
4
4
|
# help: `What's new`
|
5
5
|
# help: It will display the last user changes on Slack Smart Bot
|
6
|
+
# help: command_id: :whats_new
|
6
7
|
# help:
|
7
8
|
def whats_new(user, dest, dchannel, from, display_name)
|
8
9
|
if @status == :on
|
9
10
|
save_stats(__method__)
|
10
|
-
whats_new_file = (__FILE__).gsub(/lib\/slack\/smart-bot\/commands\/general\/whats_new\.rb$/, "whats_new.txt")
|
11
|
+
whats_new_file = (__FILE__).gsub(/lib\/slack\/smart-bot\/commands\/on_bot\/general\/whats_new\.rb$/, "whats_new.txt")
|
11
12
|
whats_new = File.read(whats_new_file)
|
12
13
|
whats_new.split(/^\-\-\-\-\-\-+$/).each do |msg|
|
13
14
|
respond msg
|
@@ -4,20 +4,19 @@ class SlackSmartBot
|
|
4
4
|
# help: `get irb SESSION_NAME`
|
5
5
|
# help: `get live SESSION_NAME`
|
6
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
|
+
# help: command_id: :get_repl
|
7
9
|
# help:
|
8
10
|
def get_repl(dest, user, session_name)
|
9
11
|
#todo: add tests
|
10
12
|
save_stats(__method__)
|
11
|
-
if
|
12
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
13
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
14
|
-
else
|
13
|
+
if has_access?(__method__, user)
|
15
14
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
16
15
|
Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}")
|
17
16
|
if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
|
18
17
|
if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) and
|
19
18
|
@repls[session_name][:creator_name]!=user.name and
|
20
|
-
!
|
19
|
+
!is_admin?(user.name)
|
21
20
|
respond "The REPL with session name: #{session_name} is private", dest
|
22
21
|
else
|
23
22
|
content = "require 'nice_http'\n"
|
@@ -17,9 +17,9 @@ class SlackSmartBot
|
|
17
17
|
# help: If 'clean' specified the repl won't pre execute the code written on the .smart-bot-repl file
|
18
18
|
# help: To avoid a message to be treated, start the message with '-'.
|
19
19
|
# help: Send _quit_, _bye_ or _exit_ to finish the session.
|
20
|
-
# help: Send puts, print, p or pp if you want to print out something when using
|
20
|
+
# help: Send puts, print, p or pp if you want to print out something when using _run repl_ later.
|
21
21
|
# help: After 30 minutes of no communication with the Smart Bot the session will be dismissed.
|
22
|
-
# 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.
|
23
23
|
# help: By default it will be automatically loaded the gems: string_pattern, nice_hash and nice_http
|
24
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
|
25
25
|
# help: If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
|
@@ -29,14 +29,13 @@ class SlackSmartBot
|
|
29
29
|
# help: _repl CreateCustomer: "It creates a random customer for testing" LOCATION=spain HOST='https://10.30.40.50:8887'_
|
30
30
|
# help: _repl delete_logs_
|
31
31
|
# help: _private repl random-ssn_
|
32
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
|
33
|
+
# help: command_id: :repl
|
32
34
|
# help:
|
33
35
|
def repl(dest, user, session_name, env_vars, rules_file, command, description, type)
|
34
36
|
#todo: add more tests
|
35
37
|
from = user.name
|
36
|
-
if
|
37
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
38
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
39
|
-
else
|
38
|
+
if has_access?(__method__, user)
|
40
39
|
if !@repl_sessions.key?(from)
|
41
40
|
save_stats(__method__)
|
42
41
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
@@ -80,11 +79,14 @@ class SlackSmartBot
|
|
80
79
|
update_repls()
|
81
80
|
end
|
82
81
|
react :running
|
82
|
+
@ts_react ||= {}
|
83
83
|
if Thread.current[:ts].to_s == ''
|
84
|
-
@ts_react = Thread.current[:thread_ts]
|
84
|
+
@ts_react[session_name] = Thread.current[:thread_ts]
|
85
85
|
else
|
86
|
-
@ts_react = Thread.current[:ts]
|
86
|
+
@ts_react[session_name] = Thread.current[:ts]
|
87
87
|
end
|
88
|
+
@ts_repl ||= {}
|
89
|
+
@ts_repl[session_name] = ''
|
88
90
|
|
89
91
|
message = "Session name: *#{session_name}*
|
90
92
|
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`.
|
@@ -117,14 +119,14 @@ class SlackSmartBot
|
|
117
119
|
end
|
118
120
|
|
119
121
|
process_to_run = '
|
120
|
-
|
122
|
+
' + env_vars.join("\n") + '
|
121
123
|
require \"amazing_print\"
|
122
124
|
bindme' + serialt + ' = binding
|
123
125
|
eval(\"require \'nice_http\'\" , bindme' + serialt + ')
|
124
126
|
def ls(obj)
|
125
127
|
(obj.methods - Object.methods)
|
126
128
|
end
|
127
|
-
|
129
|
+
file_run_path = \"' + + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.rb\"
|
128
130
|
file_input_repl = File.open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.input\", \"r\")
|
129
131
|
' + pre_execute + '
|
130
132
|
while true do
|
@@ -143,21 +145,43 @@ class SlackSmartBot
|
|
143
145
|
end
|
144
146
|
error = false
|
145
147
|
begin
|
146
|
-
|
148
|
+
begin
|
149
|
+
original_stdout = $stdout
|
150
|
+
$stdout = StringIO.new
|
151
|
+
resp_repl = eval(code_to_run_repl, bindme' + serialt + ')
|
152
|
+
stdout_repl = $stdout.string
|
153
|
+
ensure
|
154
|
+
$stdout = original_stdout
|
155
|
+
end
|
147
156
|
rescue Exception => resp_repl
|
148
157
|
error = true
|
149
158
|
end
|
150
|
-
if
|
159
|
+
if error
|
160
|
+
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
161
|
+
f.puts \"\`\`\`\n#{resp_repl.to_s.gsub(/^.+' + session_name + '\.rb:\d+:/,\"\")}\`\`\`\"
|
162
|
+
}
|
163
|
+
else
|
151
164
|
if code_to_run_repl.match?(/^\s*p\s+/i)
|
165
|
+
resp_repl = stdout_repl unless stdout_repl.to_s == \'\'
|
166
|
+
if stdout_repl.to_s == \'\'
|
167
|
+
resp_repl = resp_repl.inspect
|
168
|
+
else
|
169
|
+
resp_repl = stdout_repl
|
170
|
+
end
|
152
171
|
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
153
|
-
f.puts \"\`\`\`\n#{resp_repl
|
172
|
+
f.puts \"\`\`\`\n#{resp_repl}\`\`\`\"
|
154
173
|
}
|
155
174
|
else
|
175
|
+
if stdout_repl.to_s == \'\'
|
176
|
+
resp_repl = resp_repl.ai
|
177
|
+
else
|
178
|
+
resp_repl = stdout_repl
|
179
|
+
end
|
156
180
|
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
157
|
-
f.puts \"\`\`\`\n#{resp_repl
|
181
|
+
f.puts \"\`\`\`\n#{resp_repl}\`\`\`\"
|
158
182
|
}
|
159
183
|
end
|
160
|
-
unless
|
184
|
+
unless !add_to_run_repl
|
161
185
|
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.run\", \"a+\") {|f|
|
162
186
|
f.puts code_to_run_repl
|
163
187
|
}
|
@@ -165,16 +189,35 @@ class SlackSmartBot
|
|
165
189
|
end
|
166
190
|
end
|
167
191
|
end
|
168
|
-
end
|
192
|
+
end
|
169
193
|
'
|
170
194
|
unless rules_file.empty? # to get the project_folder
|
171
195
|
begin
|
172
196
|
eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
|
173
197
|
end
|
174
198
|
end
|
175
|
-
|
176
|
-
|
199
|
+
process_to_run.gsub!('\"','"')
|
200
|
+
file_run_path = "./tmp/repl/#{@channel_id}/#{session_name}.rb"
|
201
|
+
if defined?(project_folder)
|
202
|
+
Dir.mkdir("#{project_folder}/tmp/") unless Dir.exist?("#{project_folder}/tmp/")
|
203
|
+
Dir.mkdir("#{project_folder}/tmp/repl") unless Dir.exist?("#{project_folder}/tmp/repl")
|
204
|
+
Dir.mkdir("#{project_folder}/tmp/repl/#{@channel_id}/") unless Dir.exist?("#{project_folder}/tmp/repl/#{@channel_id}/")
|
205
|
+
file_run = File.open(file_run_path.gsub('./',"#{project_folder}/"), "w")
|
206
|
+
file_run.write process_to_run
|
207
|
+
file_run.close
|
208
|
+
else
|
209
|
+
Dir.mkdir("./tmp/") unless Dir.exist?("./tmp/")
|
210
|
+
Dir.mkdir("./tmp/repl") unless Dir.exist?("./tmp/repl")
|
211
|
+
Dir.mkdir("./tmp/repl/#{@channel_id}/") unless Dir.exist?("./tmp/repl/#{@channel_id}/")
|
212
|
+
file_run = File.open(file_run_path, "w")
|
213
|
+
file_run.write process_to_run
|
214
|
+
file_run.close
|
215
|
+
end
|
177
216
|
|
217
|
+
process_to_run = "ruby #{file_run_path}"
|
218
|
+
|
219
|
+
started = Time.now
|
220
|
+
process_to_run = ("cd #{project_folder} && " + process_to_run) if defined?(project_folder)
|
178
221
|
stdin, stdout, stderr, wait_thr = Open3.popen3(process_to_run)
|
179
222
|
timeout = 30 * 60 # 30 minutes
|
180
223
|
|
@@ -187,7 +230,7 @@ class SlackSmartBot
|
|
187
230
|
f.puts 'quit'
|
188
231
|
}
|
189
232
|
respond "REPL session finished: #{@repl_sessions[from][:name]}", dest
|
190
|
-
unreact :running, @ts_react
|
233
|
+
unreact :running, @ts_react[@repl_sessions[from].name]
|
191
234
|
pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
192
235
|
pids.each do |pid|
|
193
236
|
begin
|
@@ -201,6 +244,10 @@ class SlackSmartBot
|
|
201
244
|
sleep 0.2
|
202
245
|
resp_repl = file_output_repl.read
|
203
246
|
if resp_repl.to_s!=''
|
247
|
+
if @ts_repl[@repl_sessions[from].name].to_s != ''
|
248
|
+
unreact(:running, @ts_repl[@repl_sessions[from].name])
|
249
|
+
@ts_repl[@repl_sessions[from].name] = ''
|
250
|
+
end
|
204
251
|
if resp_repl.to_s.lines.count < 60 and resp_repl.to_s.size < 3500
|
205
252
|
respond resp_repl, dest
|
206
253
|
else
|
@@ -213,6 +260,8 @@ class SlackSmartBot
|
|
213
260
|
@logger.fatal excp
|
214
261
|
end
|
215
262
|
end
|
263
|
+
elsif @repl_sessions.key?(from) and @repl_sessions[from][:command].to_s == ''
|
264
|
+
respond 'You are already in a repl on this SmartBot. You need to quit that one before starting a new one.'
|
216
265
|
else
|
217
266
|
@repl_sessions[from][:finished] = Time.now
|
218
267
|
code = @repl_sessions[from][:command]
|
@@ -226,7 +275,9 @@ class SlackSmartBot
|
|
226
275
|
code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or
|
227
276
|
code.include?("ENV") or code.match?(/=\s*IO/) or code.include?("Dir.") or
|
228
277
|
code.match?(/=\s*File/) or code.match?(/=\s*Dir/) or code.match?(/<\s*File/) or code.match?(/<\s*Dir/) or
|
229
|
-
code.match?(/\w+:\s*File/) or code.match?(/\w+:\s*Dir/)
|
278
|
+
code.match?(/\w+:\s*File/) or code.match?(/\w+:\s*Dir/) or
|
279
|
+
code.match?(/=?\s*(require|load)(\(|\s)/i)
|
280
|
+
|
230
281
|
respond "Sorry I cannot run this due security reasons", dest
|
231
282
|
else
|
232
283
|
@repl_sessions[from][:input]<<code
|
@@ -236,7 +287,7 @@ class SlackSmartBot
|
|
236
287
|
f.puts code
|
237
288
|
}
|
238
289
|
respond "REPL session finished: #{@repl_sessions[from][:name]}", dest
|
239
|
-
unreact :running, @ts_react
|
290
|
+
unreact :running, @ts_react[@repl_sessions[from].name]
|
240
291
|
pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
241
292
|
pids.each do |pid|
|
242
293
|
begin
|
@@ -248,6 +299,10 @@ class SlackSmartBot
|
|
248
299
|
when /^\s*-/i
|
249
300
|
#ommit
|
250
301
|
else
|
302
|
+
if @ts_repl[@repl_sessions[from].name].to_s == ''
|
303
|
+
@ts_repl[@repl_sessions[from].name] = Thread.current[:ts]
|
304
|
+
react :running
|
305
|
+
end
|
251
306
|
open("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", 'a+') {|f|
|
252
307
|
f.puts code
|
253
308
|
}
|
@@ -5,14 +5,13 @@ 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>
|
9
|
+
# help: command_id: :ruby_code
|
8
10
|
# help:
|
9
11
|
|
10
12
|
def ruby_code(dest, user, code, rules_file)
|
11
13
|
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
|
14
|
+
if has_access?(__method__, user)
|
16
15
|
unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File.") or
|
17
16
|
code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
|
18
17
|
code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or
|
@@ -9,21 +9,20 @@ class SlackSmartBot
|
|
9
9
|
# help: It will return only the values that were print out on the repl with puts, print, p or pp
|
10
10
|
# help: Example:
|
11
11
|
# help: _run repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'_
|
12
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
|
13
|
+
# help: command_id: :run_repl
|
12
14
|
# help:
|
13
15
|
def run_repl(dest, user, session_name, env_vars, rules_file)
|
14
16
|
#todo: add tests
|
15
17
|
from = user.name
|
16
|
-
if
|
17
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
18
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
19
|
-
else
|
18
|
+
if has_access?(__method__, user)
|
20
19
|
save_stats(__method__)
|
21
20
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
22
21
|
Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}")
|
23
22
|
if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
|
24
23
|
if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) and
|
25
24
|
@repls[session_name][:creator_name]!=user.name and
|
26
|
-
!
|
25
|
+
!is_admin?(user.name)
|
27
26
|
respond "The REPL with session name: #{session_name} is private", dest
|
28
27
|
else
|
29
28
|
if @repls.key?(session_name) #not temp
|
@@ -43,7 +42,8 @@ class SlackSmartBot
|
|
43
42
|
eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
|
44
43
|
end
|
45
44
|
end
|
46
|
-
if File.exist?("#{project_folder}/.smart-bot-repl") and
|
45
|
+
if File.exist?("#{project_folder}/.smart-bot-repl") and
|
46
|
+
((@repls.key?(session_name) and @repls[session_name][:type] != :private_clean and @repls[session_name][:type] != :public_clean) or !@repls.key?(session_name))
|
47
47
|
content += File.read("#{project_folder}/.smart-bot-repl")
|
48
48
|
content += "\n"
|
49
49
|
end
|
@@ -60,7 +60,15 @@ class SlackSmartBot
|
|
60
60
|
respond "*#{session_name}*: Nothing returned."
|
61
61
|
else
|
62
62
|
if stdout.to_s.lines.count < 60 and stdout.to_s.size < 3500
|
63
|
-
|
63
|
+
output = ''
|
64
|
+
stdout.each_line do |line|
|
65
|
+
if line.match?(/^{.+}$/) or line.match?(/^\[.+\]$/)
|
66
|
+
output += "```\n#{line}```\n"
|
67
|
+
else
|
68
|
+
output +=line
|
69
|
+
end
|
70
|
+
end
|
71
|
+
respond "*#{session_name}*: #{output}"
|
64
72
|
else
|
65
73
|
send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: stdout)
|
66
74
|
end
|
@@ -2,19 +2,18 @@ class SlackSmartBot
|
|
2
2
|
# help: ----------------------------------------------
|
3
3
|
# help: `see repls`
|
4
4
|
# help: `see irbs`
|
5
|
-
# help:
|
5
|
+
# help: It will display the repls
|
6
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
|
7
|
+
# help: command_id: :see_repls
|
6
8
|
# help:
|
7
9
|
def see_repls(dest, user, typem)
|
8
10
|
#todo: add tests
|
9
11
|
save_stats(__method__)
|
10
12
|
from = user.name
|
11
|
-
if
|
12
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
13
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
14
|
-
else
|
13
|
+
if has_access?(__method__, user)
|
15
14
|
message = ""
|
16
15
|
@repls.sort.to_h.each do |session_name, repl|
|
17
|
-
if (repl.creator_name == user.name or repl.type == :public or repl.type == :public_clean) or (
|
16
|
+
if (repl.creator_name == user.name or repl.type == :public or repl.type == :public_clean) or (is_admin?(user.name) and typem == :on_dm)
|
18
17
|
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
18
|
end
|
20
19
|
end
|
@@ -3,14 +3,13 @@ class SlackSmartBot
|
|
3
3
|
# help: `see shortcuts`
|
4
4
|
# help: `see sc`
|
5
5
|
# help: It will display the shortcuts stored for the user and for :all
|
6
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#shortcuts|more info>
|
7
|
+
# help: command_id: :see_shortcuts
|
6
8
|
# help:
|
7
9
|
def see_shortcuts(dest, user, typem)
|
8
10
|
save_stats(__method__)
|
9
11
|
from = user.name
|
10
|
-
if
|
11
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
12
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
13
|
-
else
|
12
|
+
if has_access?(__method__, user)
|
14
13
|
unless typem == :on_extended
|
15
14
|
msg = ""
|
16
15
|
if @shortcuts[:all].keys.size > 0 or @shortcuts_global[:all].keys.size > 0
|
@@ -30,7 +29,7 @@ class SlackSmartBot
|
|
30
29
|
end
|
31
30
|
msg2 = ''
|
32
31
|
if @shortcuts.keys.include?(from) and @shortcuts[from].keys.size > 0
|
33
|
-
new_hash = @shortcuts[from].
|
32
|
+
new_hash = @shortcuts[from].deep_copy
|
34
33
|
@shortcuts[:all].keys.each { |k| new_hash.delete(k) }
|
35
34
|
if new_hash.keys.size > 0
|
36
35
|
msg2 = "*Available shortcuts for #{from}:*\n"
|
@@ -40,7 +39,7 @@ class SlackSmartBot
|
|
40
39
|
end
|
41
40
|
end
|
42
41
|
if @shortcuts_global.keys.include?(from) and @shortcuts_global[from].keys.size > 0
|
43
|
-
new_hash = @shortcuts_global[from].
|
42
|
+
new_hash = @shortcuts_global[from].deep_copy
|
44
43
|
@shortcuts_global[:all].keys.each { |k| new_hash.delete(k) }
|
45
44
|
if new_hash.keys.size > 0
|
46
45
|
msg2 = "*Available shortcuts for #{from}:*\n" if msg2 == ''
|
@@ -2,12 +2,9 @@ class SlackSmartBot
|
|
2
2
|
def bot_rules(dest, help_command, typem, rules_file, user)
|
3
3
|
save_stats(__method__)
|
4
4
|
from = user.name
|
5
|
-
if
|
6
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
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
|
-
else
|
5
|
+
if has_access?(__method__, user)
|
9
6
|
if typem == :on_extended or typem == :on_call #for the other cases above.
|
10
|
-
|
7
|
+
output = []
|
11
8
|
if help_command.to_s != ''
|
12
9
|
help_command = '' if help_command.to_s.match?(/^\s*expanded\s*$/i) or help_command.to_s.match?(/^\s*extended\s*$/i)
|
13
10
|
expanded = true
|
@@ -17,22 +14,47 @@ class SlackSmartBot
|
|
17
14
|
|
18
15
|
help_filtered = get_help(rules_file, dest, from, true, expanded)
|
19
16
|
|
17
|
+
commands = []
|
18
|
+
commands_search = []
|
20
19
|
if help_command.to_s != ""
|
21
20
|
help_found = false
|
22
21
|
help_filtered.split(/^\s*-------*$/).each do |h|
|
23
22
|
if h.match?(/[`_]#{help_command}/i)
|
24
|
-
|
23
|
+
output << "*#{config.channel}*:#{h}"
|
25
24
|
help_found = true
|
25
|
+
commands << h
|
26
|
+
elsif !h.match?(/\A\s*\*/) and !h.match?(/\A\s*=+/) #to avoid general messages for bot help *General rules...*
|
27
|
+
all_found = true
|
28
|
+
help_command.to_s.split(' ') do |hc|
|
29
|
+
unless hc.match?(/^\s*\z/)
|
30
|
+
if !h.match?(/#{hc}/i)
|
31
|
+
all_found = false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
commands_search << h if all_found
|
36
|
+
end
|
37
|
+
end
|
38
|
+
if commands.size < 10 and help_command.to_s!='' and commands_search.size > 0
|
39
|
+
commands_search.shuffle!
|
40
|
+
(10-commands.size).times do |n|
|
41
|
+
unless commands_search[n].nil?
|
42
|
+
output << commands_search[n]
|
43
|
+
help_found = true
|
44
|
+
end
|
26
45
|
end
|
27
46
|
end
|
28
|
-
|
47
|
+
unless help_found
|
48
|
+
output << "*#{config.channel}*: I didn't find any command with `#{help_command}`"
|
49
|
+
end
|
50
|
+
|
29
51
|
else
|
30
52
|
message = "-\n\n\n===================================\n*Rules from channel #{config.channel}*\n"
|
31
53
|
if typem == :on_extended
|
32
54
|
message += "To run the commands on this extended channel, add `!`, `!!` or `^` before the command.\n"
|
33
55
|
end
|
34
56
|
message += help_filtered
|
35
|
-
|
57
|
+
output << message
|
36
58
|
end
|
37
59
|
|
38
60
|
unless rules_file.empty?
|
@@ -41,16 +63,27 @@ class SlackSmartBot
|
|
41
63
|
end
|
42
64
|
end
|
43
65
|
if defined?(git_project) and git_project.to_s != "" and help_command.to_s == ""
|
44
|
-
|
66
|
+
output << "Git project: #{git_project}"
|
45
67
|
else
|
46
68
|
def git_project() "" end
|
47
69
|
def project_folder() "" end
|
48
70
|
end
|
49
71
|
unless expanded
|
50
|
-
message_not_expanded = "
|
51
|
-
message_not_expanded += "
|
52
|
-
|
72
|
+
message_not_expanded = "If you want to see the *expanded* version of *`bot rules`*, please call *`bot rules expanded`*\n"
|
73
|
+
message_not_expanded += "Also to get specific *expanded* help for a specific command or rule call *`bot rules COMMAND`*\n"
|
74
|
+
output << message_not_expanded
|
75
|
+
end
|
76
|
+
if output.join("\n").lines.count > 50 and dest[0]!='D'
|
77
|
+
dest = :on_thread
|
78
|
+
output.unshift('Since there are many lines returned the results are returned on a thread by default.')
|
79
|
+
end
|
80
|
+
output.each do |h|
|
81
|
+
msg = h.gsub(/^\s*command_id:\s+:\w+\s*$/,'')
|
82
|
+
unless msg.match?(/\A\s*\z/)
|
83
|
+
respond msg, dest, unfurl_links: false, unfurl_media: false
|
84
|
+
end
|
53
85
|
end
|
86
|
+
|
54
87
|
end
|
55
88
|
end
|
56
89
|
end
|
@@ -3,6 +3,8 @@ class SlackSmartBot
|
|
3
3
|
# helpmaster: `kill bot on CHANNEL_NAME`
|
4
4
|
# helpmaster: kills the bot on the specified channel
|
5
5
|
# helpmaster: Only works if you are on Master channel and you created that bot or you are an admin user
|
6
|
+
# helpmaster: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
|
7
|
+
# helpmaster: command_id: :kill_bot_on_channel
|
6
8
|
# helpmaster:
|
7
9
|
def kill_bot_on_channel(dest, from, channel)
|
8
10
|
save_stats(__method__)
|
@@ -18,14 +20,16 @@ class SlackSmartBot
|
|
18
20
|
if channel_id.nil?
|
19
21
|
respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
|
20
22
|
elsif @bots_created.keys.include?(channel_id)
|
21
|
-
|
23
|
+
@bots_created[channel_id] ||= {}
|
24
|
+
if @bots_created[channel_id][:admins].to_s.split(",").include?(from) # todo: consider adding is_admin?
|
22
25
|
if @bots_created[channel_id][:thread].kind_of?(Thread) and @bots_created[channel_id][:thread].alive?
|
23
26
|
@bots_created[channel_id][:thread].kill
|
24
27
|
end
|
25
28
|
@bots_created.delete(channel_id)
|
26
|
-
update_bots_file()
|
27
|
-
respond "Bot on channel: #{channel}, has been killed and deleted.", dest
|
28
29
|
send_msg_channel(channel, "Bot has been killed by #{from}")
|
30
|
+
respond "Bot on channel: #{channel}, has been killed and deleted.", dest
|
31
|
+
save_status :off, :killed, "The admin killed SmartBot on *##{@channels_name[channel_id]}*"
|
32
|
+
update_bots_file()
|
29
33
|
else
|
30
34
|
respond "You need to be the creator or an admin of that bot channel", dest
|
31
35
|
end
|
@@ -6,11 +6,13 @@ class SlackSmartBot
|
|
6
6
|
# helpadmin: `close bot`
|
7
7
|
# helpadmin: The bot stops running and also stops all the bots created from this master channel
|
8
8
|
# helpadmin: You can use this command only if you are an admin user and you are on the master channel
|
9
|
+
# helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
|
10
|
+
# helpadmin: command_id: :exit_bot
|
9
11
|
# helpadmin:
|
10
12
|
def exit_bot(command, from, dest, display_name)
|
11
13
|
save_stats(__method__)
|
12
14
|
if config.on_master_bot
|
13
|
-
if config.
|
15
|
+
if config.masters.include?(from) #admin user
|
14
16
|
if answer.empty?
|
15
17
|
ask("are you sure?", command, from, dest)
|
16
18
|
else
|
@@ -21,6 +23,7 @@ class SlackSmartBot
|
|
21
23
|
@bots_created.each { |key, value|
|
22
24
|
value[:thread] = ""
|
23
25
|
send_msg_channel(key, "Bot has been closed by #{from}")
|
26
|
+
save_status :off, :exited, "The admin closed SmartBot on *##{value.channel_name}*"
|
24
27
|
sleep 0.5
|
25
28
|
}
|
26
29
|
update_bots_file()
|
@@ -7,11 +7,13 @@ class SlackSmartBot
|
|
7
7
|
# helpmaster: It will send a notification message to all channels the bot joined and private conversations with the bot
|
8
8
|
# helpmaster: It will send a notification message to the specified channel and to its extended channels
|
9
9
|
# helpmaster: Only works if you are on Master channel and you are a master admin user
|
10
|
+
# helpmaster: <https://github.com/MarioRuiz/slack-smart-bot#sending-notifications|more info>
|
11
|
+
# helpmaster: command_id: :notify_message
|
10
12
|
# helpmaster:
|
11
13
|
def notify_message(dest, from, where, message)
|
12
14
|
save_stats(__method__)
|
13
15
|
if config.on_master_bot
|
14
|
-
if config.
|
16
|
+
if config.masters.include?(from) #admin user
|
15
17
|
if where.nil? #not all and not channel
|
16
18
|
@bots_created.each do |k, v|
|
17
19
|
respond message, k
|