slack-smart-bot 1.9.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +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
|