slack-smart-bot 1.8.2 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +18 -11
- data/lib/slack-smart-bot.rb +43 -44
- data/lib/slack-smart-bot_rules.rb +6 -6
- data/lib/slack/smart-bot/comm.rb +5 -1
- data/lib/slack/smart-bot/comm/ask.rb +12 -5
- data/lib/slack/smart-bot/comm/dont_understand.rb +1 -1
- data/lib/slack/smart-bot/comm/event_hello.rb +30 -0
- data/lib/slack/smart-bot/comm/get_channel_members.rb +8 -0
- data/lib/slack/smart-bot/comm/get_channels.rb +20 -0
- data/lib/slack/smart-bot/comm/get_user_info.rb +16 -0
- data/lib/slack/smart-bot/comm/react.rb +21 -8
- data/lib/slack/smart-bot/comm/respond.rb +10 -5
- data/lib/slack/smart-bot/comm/send_msg_channel.rb +2 -2
- data/lib/slack/smart-bot/comm/send_msg_user.rb +4 -4
- data/lib/slack/smart-bot/comm/unreact.rb +21 -8
- data/lib/slack/smart-bot/commands.rb +3 -1
- data/lib/slack/smart-bot/commands/general/bot_help.rb +16 -3
- data/lib/slack/smart-bot/commands/general/bot_stats.rb +313 -0
- data/lib/slack/smart-bot/commands/general/bot_status.rb +1 -1
- data/lib/slack/smart-bot/commands/general/bye_bot.rb +1 -1
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +1 -1
- data/lib/slack/smart-bot/commands/general/use_rules.rb +2 -6
- data/lib/slack/smart-bot/commands/general/whats_new.rb +19 -0
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +65 -33
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +3 -7
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +8 -2
- data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +1 -1
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +52 -21
- data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +5 -5
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +50 -18
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +34 -9
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +2 -3
- data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +1 -1
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +27 -9
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +14 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +3 -3
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +1 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +41 -0
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +4 -8
- data/lib/slack/smart-bot/listen.rb +6 -5
- data/lib/slack/smart-bot/process.rb +227 -188
- data/lib/slack/smart-bot/process_first.rb +104 -87
- data/lib/slack/smart-bot/treat_message.rb +98 -38
- data/lib/slack/smart-bot/utils.rb +2 -0
- data/lib/slack/smart-bot/utils/answer.rb +18 -0
- data/lib/slack/smart-bot/utils/answer_delete.rb +15 -0
- data/lib/slack/smart-bot/utils/build_help.rb +57 -5
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +11 -2
- data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +1 -7
- data/lib/slack/smart-bot/utils/get_help.rb +79 -17
- data/lib/slack/smart-bot/utils/save_stats.rb +21 -8
- data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +6 -0
- data/whats_new.txt +18 -0
- metadata +21 -12
- data/lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb +0 -195
@@ -14,7 +14,7 @@ class SlackSmartBot
|
|
14
14
|
gems_remote = `gem list slack-smart-bot --remote`
|
15
15
|
version_remote = gems_remote.to_s().scan(/slack-smart-bot \((\d+\.\d+\.\d+)/).join
|
16
16
|
version_message = ""
|
17
|
-
if version_remote
|
17
|
+
if Gem::Version.new(version_remote) > Gem::Version.new(VERSION)
|
18
18
|
version_message = " There is a new available version: #{version_remote}."
|
19
19
|
end
|
20
20
|
require "socket"
|
@@ -4,8 +4,8 @@ class SlackSmartBot
|
|
4
4
|
# help: `Bye Bot`
|
5
5
|
# help: `Bye Smart`
|
6
6
|
# help: `Bye NAME_OF_THE_BOT`
|
7
|
-
# help: Also apart of Bye you can use _Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu_
|
8
7
|
# help: Bot stops listening to you
|
8
|
+
# help: Also apart of Bye you can use _Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu_
|
9
9
|
# help:
|
10
10
|
def bye_bot(dest, from, display_name)
|
11
11
|
if @status == :on
|
@@ -5,9 +5,9 @@ class SlackSmartBot
|
|
5
5
|
# help: `Hi Smart`
|
6
6
|
# help: `Hello Bot` `Hola Bot` `Hallo Bot` `What's up Bot` `Hey Bot` `Hæ Bot`
|
7
7
|
# help: `Hello THE_NAME_OF_THE_BOT`
|
8
|
-
# help: Also apart of Hello you can use _Hallo, Hi, Hola, What's up, Hey, Hæ_
|
9
8
|
# help: Bot starts listening to you
|
10
9
|
# help: After that if you want to avoid a single message to be treated by the smart bot, start the message by -
|
10
|
+
# help: Also apart of Hello you can use _Hallo, Hi, Hola, What's up, Hey, Hæ_
|
11
11
|
# help:
|
12
12
|
def hi_bot(user, dest, dchannel, from, display_name)
|
13
13
|
if @status == :on
|
@@ -15,14 +15,10 @@ class SlackSmartBot
|
|
15
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
16
|
else
|
17
17
|
#todo: add pagination for case more than 1000 channels on the workspace
|
18
|
-
channels =
|
19
|
-
types: "private_channel,public_channel",
|
20
|
-
limit: "1000",
|
21
|
-
exclude_archived: "true",
|
22
|
-
).channels
|
18
|
+
channels = get_channels()
|
23
19
|
|
24
20
|
channel_found = channels.detect { |c| c.name == channel }
|
25
|
-
members =
|
21
|
+
members = get_channel_members(@channels_id[channel]) unless channel_found.nil?
|
26
22
|
|
27
23
|
if channel_found.nil?
|
28
24
|
respond "The channel you are trying to use doesn't exist", dest
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
|
3
|
+
# help: ----------------------------------------------
|
4
|
+
# help: `What's new`
|
5
|
+
# help: It will display the last user changes on Slack Smart Bot
|
6
|
+
# help:
|
7
|
+
def whats_new(user, dest, dchannel, from, display_name)
|
8
|
+
if @status == :on
|
9
|
+
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.read(whats_new_file)
|
12
|
+
whats_new.split(/^\-\-\-\-\-\-+$/).each do |msg|
|
13
|
+
respond msg
|
14
|
+
sleep 0.3
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -7,8 +7,10 @@ class SlackSmartBot
|
|
7
7
|
# help: `add sc for all NAME: COMMAND`
|
8
8
|
# help: `shortcut NAME: COMMAND`
|
9
9
|
# help: `shortcut for all NAME: COMMAND`
|
10
|
+
# help: `add global sc for all NAME: COMMAND`
|
10
11
|
# help: It will add a shortcut that will execute the command we supply.
|
11
12
|
# help: In case we supply 'for all' then the shorcut will be available for everybody
|
13
|
+
# help: If 'global' or 'generic' supplied and in Master channel then the shortcut will be available in all Bot channels.
|
12
14
|
# help: If you want to use a shortcut as a inline shortcut inside a command you can do it by adding a $ fex: _!run tests $cust1_
|
13
15
|
# help: Example:
|
14
16
|
# help: _add shortcut for all Spanish account: code require 'iso/iban'; 10.times {puts ISO::IBAN.random('ES')}_
|
@@ -17,7 +19,7 @@ class SlackSmartBot
|
|
17
19
|
# help: _shortcut Spanish Account_
|
18
20
|
# help: _Spanish Account_
|
19
21
|
# help:
|
20
|
-
def add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run)
|
22
|
+
def add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run, global)
|
21
23
|
save_stats(__method__)
|
22
24
|
unless typem == :on_extended
|
23
25
|
from = user.name
|
@@ -25,43 +27,73 @@ class SlackSmartBot
|
|
25
27
|
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
26
28
|
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
27
29
|
else
|
28
|
-
@shortcuts[from] = Hash.new() unless @shortcuts.keys.include?(from)
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
if global
|
32
|
+
if !config.on_master_bot or typem != :on_master
|
33
|
+
respond "It is only possible to add global shortcuts from Master channel"
|
34
|
+
else
|
35
|
+
@shortcuts_global[from] = Hash.new() unless @shortcuts_global.keys.include?(from)
|
36
|
+
found_other = false
|
37
|
+
if for_all.to_s != ""
|
38
|
+
@shortcuts_global.each { |sck, scv|
|
39
|
+
if sck != :all and sck != from and scv.key?(shortcut_name)
|
40
|
+
found_other = true
|
41
|
+
end
|
42
|
+
}
|
35
43
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
if @shortcuts_global[:all].include?(shortcut_name) or @shortcuts_global[from].include?(shortcut_name)
|
45
|
+
respond "Global shortcut name already in use. Please use another shortcut name."
|
46
|
+
elsif found_other
|
47
|
+
respond "You cannot create a global shortcut for all with the same name than other user is using."
|
48
|
+
elsif !@shortcuts_global[from].include?(shortcut_name)
|
49
|
+
#new shortcut
|
50
|
+
@shortcuts_global[from][shortcut_name] = command_to_run
|
51
|
+
@shortcuts_global[:all][shortcut_name] = command_to_run if for_all.to_s != ""
|
52
|
+
update_shortcuts_file()
|
53
|
+
respond "global shortcut added"
|
54
|
+
else
|
55
|
+
respond "Not possible to add the global shortcut" #todo: check if this is ever gonna be the case
|
56
|
+
end
|
57
|
+
end
|
48
58
|
else
|
49
|
-
|
50
|
-
|
51
|
-
|
59
|
+
@shortcuts[from] = Hash.new() unless @shortcuts.keys.include?(from)
|
60
|
+
|
61
|
+
found_other = false
|
62
|
+
if for_all.to_s != ""
|
63
|
+
@shortcuts.each { |sck, scv|
|
64
|
+
if sck != :all and sck != from and scv.key?(shortcut_name)
|
65
|
+
found_other = true
|
66
|
+
end
|
67
|
+
}
|
68
|
+
end
|
69
|
+
if !config.admins.include?(from) and @shortcuts[:all].include?(shortcut_name) and !@shortcuts[from].include?(shortcut_name)
|
70
|
+
respond "Only the creator of the shortcut can modify it", dest
|
71
|
+
elsif found_other
|
72
|
+
respond "You cannot create a shortcut for all with the same name than other user is using", dest
|
73
|
+
elsif !@shortcuts[from].include?(shortcut_name)
|
74
|
+
#new shortcut
|
75
|
+
@shortcuts[from][shortcut_name] = command_to_run
|
76
|
+
@shortcuts[:all][shortcut_name] = command_to_run if for_all.to_s != ""
|
77
|
+
update_shortcuts_file()
|
78
|
+
respond "shortcut added", dest
|
52
79
|
else
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
@shortcuts[:all][shortcut_name] = command_to_run if for_all.to_s != ""
|
57
|
-
update_shortcuts_file()
|
58
|
-
respond "shortcut added", dest
|
59
|
-
@questions.delete(from)
|
60
|
-
when /^no/i
|
61
|
-
respond "ok, I won't add it", dest
|
62
|
-
@questions.delete(from)
|
80
|
+
#are you sure? to avoid overwriting existing
|
81
|
+
if answer.empty?
|
82
|
+
ask("The shortcut already exists, are you sure you want to overwrite it?", command, from, dest)
|
63
83
|
else
|
64
|
-
|
84
|
+
case answer
|
85
|
+
when /^(yes|yep)/i
|
86
|
+
@shortcuts[from][shortcut_name] = command_to_run
|
87
|
+
@shortcuts[:all][shortcut_name] = command_to_run if for_all.to_s != ""
|
88
|
+
update_shortcuts_file()
|
89
|
+
respond "shortcut added", dest
|
90
|
+
answer_delete(from)
|
91
|
+
when /^no/i
|
92
|
+
respond "ok, I won't add it", dest
|
93
|
+
answer_delete(from)
|
94
|
+
else
|
95
|
+
ask "I don't understand, yes or no?", command, from, dest
|
96
|
+
end
|
65
97
|
end
|
66
98
|
end
|
67
99
|
end
|
@@ -14,15 +14,11 @@ class SlackSmartBot
|
|
14
14
|
respond "Only admins can extend the rules. Admins on this channel: #{config.admins}", dest
|
15
15
|
else
|
16
16
|
#todo: add pagination for case more than 1000 channels on the workspace
|
17
|
-
channels =
|
18
|
-
types: "private_channel,public_channel",
|
19
|
-
limit: "1000",
|
20
|
-
exclude_archived: "true",
|
21
|
-
).channels
|
17
|
+
channels = get_channels()
|
22
18
|
|
23
19
|
channel_found = channels.detect { |c| c.name == channel }
|
24
20
|
get_channels_name_and_id()
|
25
|
-
members =
|
21
|
+
members = get_channel_members(@channels_id[channel]) unless channel_found.nil?
|
26
22
|
get_bots_created()
|
27
23
|
channels_in_use = []
|
28
24
|
@bots_created.each do |k, v|
|
@@ -39,7 +35,7 @@ class SlackSmartBot
|
|
39
35
|
elsif !members.include?(user.id)
|
40
36
|
respond "You need to join that channel first", dest
|
41
37
|
elsif !members.include?(config[:nick_id])
|
42
|
-
respond "You need to add first to the channel the smart bot user:
|
38
|
+
respond "You need to add first to the channel the smart bot user: <@#{config[:nick_id]}>", dest
|
43
39
|
else
|
44
40
|
channels_in_use.each do |channel_in_use|
|
45
41
|
respond "The rules from channel <##{@channels_id[channel_in_use]}> are already in use on that channel", dest
|
@@ -13,6 +13,7 @@ class SlackSmartBot
|
|
13
13
|
respond "zZzzzzZzzzzZZZZZZzzzzzzzz", dest
|
14
14
|
@status = :paused
|
15
15
|
@bots_created[@channel_id][:status] = :paused
|
16
|
+
update_bots_file()
|
16
17
|
unless config.on_master_bot
|
17
18
|
send_msg_channel config.master_channel, "Changed status on #{config.channel} to :paused"
|
18
19
|
end
|
@@ -38,8 +38,14 @@ class SlackSmartBot
|
|
38
38
|
respond "Routines on channel *#{rout_ch.get_values(:channel_name).values.flatten.uniq[0]}*", dest
|
39
39
|
rout_ch.each do |k, v|
|
40
40
|
msg = []
|
41
|
-
|
42
|
-
|
41
|
+
if v[:dest][0] == 'D'
|
42
|
+
extram = " (*DM to #{v[:creator]}*)"
|
43
|
+
elsif v[:dest] != ch
|
44
|
+
extram = " (*publish on <##{v[:dest]}>*)"
|
45
|
+
else
|
46
|
+
extram = ''
|
47
|
+
end
|
48
|
+
msg << "*`#{k}`*#{extram}"
|
43
49
|
msg << "\tCreator: #{v[:creator]}"
|
44
50
|
msg << "\tStatus: #{v[:status]}"
|
45
51
|
msg << "\tEvery: #{v[:every]}" unless v[:every] == ""
|
@@ -12,6 +12,7 @@ class SlackSmartBot
|
|
12
12
|
respond "This bot is running and listening from now on. You can pause again: pause this bot", dest
|
13
13
|
@status = :on
|
14
14
|
@bots_created[@channel_id][:status] = :on
|
15
|
+
update_bots_file()
|
15
16
|
unless config.on_master_bot
|
16
17
|
send_msg_channel config.master_channel, "Changed status on #{config.channel} to :on"
|
17
18
|
end
|
@@ -3,7 +3,6 @@ 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
|
9
8
|
# help:
|
@@ -20,6 +19,7 @@ class SlackSmartBot
|
|
20
19
|
@repls.delete(session_name)
|
21
20
|
update_repls()
|
22
21
|
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")
|
22
|
+
File.delete("#{config.path}/repl/#{@channel_id}/#{session_name}.output") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.output")
|
23
23
|
File.delete("#{config.path}/repl/#{@channel_id}/#{session_name}.run") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
|
24
24
|
respond "REPL #{session_name} deleted"
|
25
25
|
else
|
@@ -2,10 +2,12 @@ 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.
|
6
8
|
# help:
|
7
9
|
|
8
|
-
def delete_shortcut(dest, user, shortcut, typem, command)
|
10
|
+
def delete_shortcut(dest, user, shortcut, typem, command, global)
|
9
11
|
save_stats(__method__)
|
10
12
|
unless typem == :on_extended
|
11
13
|
from = user.name
|
@@ -15,32 +17,61 @@ class SlackSmartBot
|
|
15
17
|
else
|
16
18
|
deleted = false
|
17
19
|
|
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)
|
20
|
+
if global
|
21
|
+
if !config.on_master_bot or typem != :on_master
|
22
|
+
respond "It is only possible to delete global shortcuts from Master channel"
|
25
23
|
else
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
if !config.admins.include?(from) and @shortcuts_global[:all].include?(shortcut) and
|
25
|
+
(!@shortcuts_global.key?(from) or !@shortcuts_global[from].include?(shortcut))
|
26
|
+
respond "Only the creator of the shortcut or an admin user can delete it"
|
27
|
+
elsif (@shortcuts_global.key?(from) and @shortcuts_global[from].keys.include?(shortcut)) or
|
28
|
+
(config.admins.include?(from) and @shortcuts_global[:all].include?(shortcut))
|
29
|
+
|
30
|
+
respond "global shortcut deleted!", dest
|
31
|
+
if @shortcuts_global.key?(from) and @shortcuts_global[from].key?(shortcut)
|
32
|
+
respond("#{shortcut}: #{@shortcuts_global[from][shortcut]}", dest)
|
33
|
+
elsif @shortcuts_global.key?(:all) and @shortcuts_global[:all].key?(shortcut)
|
34
|
+
respond("#{shortcut}: #{@shortcuts_global[:all][shortcut]}", dest)
|
35
|
+
end
|
36
|
+
@shortcuts_global[from].delete(shortcut) if @shortcuts_global.key?(from) and @shortcuts_global[from].key?(shortcut)
|
37
|
+
@shortcuts_global[:all].delete(shortcut) if @shortcuts_global.key?(:all) and @shortcuts_global[:all].key?(shortcut)
|
34
38
|
update_shortcuts_file()
|
35
|
-
when /^no/i
|
36
|
-
@questions.delete(from)
|
37
|
-
respond "ok, I won't delete it", dest
|
38
39
|
else
|
39
|
-
|
40
|
+
respond 'shortcut not found'
|
40
41
|
end
|
41
42
|
end
|
42
43
|
else
|
43
|
-
|
44
|
+
if !config.admins.include?(from) and @shortcuts[:all].include?(shortcut) and
|
45
|
+
(!@shortcuts.key?(from) or !@shortcuts[from].include?(shortcut))
|
46
|
+
respond "Only the creator of the shortcut or an admin user can delete it", dest
|
47
|
+
elsif (@shortcuts.keys.include?(from) and @shortcuts[from].keys.include?(shortcut)) or
|
48
|
+
(config.admins.include?(from) and @shortcuts[:all].include?(shortcut))
|
49
|
+
#are you sure? to avoid deleting by mistake
|
50
|
+
if answer.empty?
|
51
|
+
ask("are you sure you want to delete it?", command, from, dest)
|
52
|
+
else
|
53
|
+
case answer
|
54
|
+
when /^(yes|yep)/i
|
55
|
+
answer_delete(from)
|
56
|
+
respond "shortcut deleted!", dest
|
57
|
+
if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut)
|
58
|
+
respond("#{shortcut}: #{@shortcuts[from][shortcut]}", dest)
|
59
|
+
elsif @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut)
|
60
|
+
respond("#{shortcut}: #{@shortcuts[:all][shortcut]}", dest)
|
61
|
+
end
|
62
|
+
@shortcuts[from].delete(shortcut) if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut)
|
63
|
+
@shortcuts[:all].delete(shortcut) if @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut)
|
64
|
+
update_shortcuts_file()
|
65
|
+
when /^no/i
|
66
|
+
answer_delete(from)
|
67
|
+
respond "ok, I won't delete it", dest
|
68
|
+
else
|
69
|
+
ask("I don't understand, are you sure you want to delete it? (yes or no)", command, from, dest)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
else
|
73
|
+
respond "shortcut not found", dest
|
74
|
+
end
|
44
75
|
end
|
45
76
|
end
|
46
77
|
end
|
@@ -3,7 +3,6 @@ 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.
|
8
7
|
# help:
|
9
8
|
def get_repl(dest, user, session_name)
|
@@ -16,22 +15,23 @@ class SlackSmartBot
|
|
16
15
|
Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
|
17
16
|
Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}")
|
18
17
|
if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
|
19
|
-
if @repls.key?(session_name) and @repls[session_name][:type] == :private and
|
18
|
+
if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) and
|
20
19
|
@repls[session_name][:creator_name]!=user.name and
|
21
20
|
!config.admins.include?(user.name)
|
22
21
|
respond "The REPL with session name: #{session_name} is private", dest
|
23
22
|
else
|
23
|
+
content = "require 'nice_http'\n"
|
24
24
|
if @repls.key?(session_name)
|
25
25
|
@repls[session_name][:accessed] = Time.now.to_s
|
26
26
|
@repls[session_name][:gets] += 1
|
27
27
|
update_repls()
|
28
28
|
end
|
29
|
-
|
30
|
-
|
31
|
-
if File.exist?("#{project_folder}/.smart-bot-repl")
|
29
|
+
if !@repls.key?(session_name) or
|
30
|
+
(File.exist?("#{project_folder}/.smart-bot-repl") and @repls[session_name][:type] != :private_clean and @repls[session_name][:type] != :public_clean)
|
32
31
|
content += File.read("#{project_folder}/.smart-bot-repl")
|
33
32
|
content += "\n"
|
34
33
|
end
|
34
|
+
|
35
35
|
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
36
|
File.write("#{config.path}/repl/#{@channel_id}/#{session_name}.rb", content, mode: "w+")
|
37
37
|
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,15 +5,16 @@ 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.
|
@@ -78,7 +79,13 @@ class SlackSmartBot
|
|
78
79
|
}
|
79
80
|
update_repls()
|
80
81
|
end
|
81
|
-
|
82
|
+
react :running
|
83
|
+
if Thread.current[:ts].to_s == ''
|
84
|
+
@ts_react = Thread.current[:thread_ts]
|
85
|
+
else
|
86
|
+
@ts_react = Thread.current[:ts]
|
87
|
+
end
|
88
|
+
|
82
89
|
message = "Session name: *#{session_name}*
|
83
90
|
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
91
|
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 +103,19 @@ class SlackSmartBot
|
|
96
103
|
File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.output", "", mode: "a+")
|
97
104
|
File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.run", "", mode: "a+")
|
98
105
|
|
106
|
+
if type != :private_clean and type != :public_clean
|
107
|
+
pre_execute = '
|
108
|
+
if File.exist?(\"./.smart-bot-repl\")
|
109
|
+
begin
|
110
|
+
eval(File.read(\"./.smart-bot-repl\"), bindme' + serialt + ')
|
111
|
+
rescue Exception => resp_repl
|
112
|
+
end
|
113
|
+
end
|
114
|
+
'
|
115
|
+
else
|
116
|
+
pre_execute = ''
|
117
|
+
end
|
118
|
+
|
99
119
|
process_to_run = '
|
100
120
|
ruby -e "' + env_vars.join("\n") + '
|
101
121
|
require \"amazing_print\"
|
@@ -105,17 +125,12 @@ class SlackSmartBot
|
|
105
125
|
(obj.methods - Object.methods)
|
106
126
|
end
|
107
127
|
|
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
|
128
|
+
file_input_repl = File.open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.input\", \"r\")
|
129
|
+
' + pre_execute + '
|
115
130
|
while true do
|
116
131
|
sleep 0.2
|
117
132
|
code_to_run_repl = file_input_repl.read
|
118
|
-
if code_to_run_repl.to_s
|
133
|
+
if code_to_run_repl.to_s!=\"\"
|
119
134
|
add_to_run_repl = true
|
120
135
|
if code_to_run_repl.to_s.match?(/^quit$/i) or
|
121
136
|
code_to_run_repl.to_s.match?(/^exit$/i) or
|
@@ -134,16 +149,16 @@ class SlackSmartBot
|
|
134
149
|
end
|
135
150
|
if resp_repl.to_s != \"\"
|
136
151
|
if code_to_run_repl.match?(/^\s*p\s+/i)
|
137
|
-
open(\"' +
|
152
|
+
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
138
153
|
f.puts \"\`\`\`\n#{resp_repl.inspect}\n\`\`\`\"
|
139
154
|
}
|
140
155
|
else
|
141
|
-
open(\"' +
|
156
|
+
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
|
142
157
|
f.puts \"\`\`\`\n#{resp_repl.ai}\n\`\`\`\"
|
143
158
|
}
|
144
159
|
end
|
145
160
|
unless error or !add_to_run_repl
|
146
|
-
open(\"' +
|
161
|
+
open(\"' + File.expand_path(config.path) + '/repl/' + @channel_id + '/' + session_name + '.run\", \"a+\") {|f|
|
147
162
|
f.puts code_to_run_repl
|
148
163
|
}
|
149
164
|
end
|
@@ -152,7 +167,6 @@ class SlackSmartBot
|
|
152
167
|
end
|
153
168
|
end"
|
154
169
|
'
|
155
|
-
|
156
170
|
unless rules_file.empty? # to get the project_folder
|
157
171
|
begin
|
158
172
|
eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
|
@@ -160,12 +174,12 @@ class SlackSmartBot
|
|
160
174
|
end
|
161
175
|
started = Time.now
|
162
176
|
process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
|
163
|
-
|
177
|
+
|
164
178
|
stdin, stdout, stderr, wait_thr = Open3.popen3(process_to_run)
|
165
179
|
timeout = 30 * 60 # 30 minutes
|
166
180
|
|
167
181
|
file_output_repl = File.open("#{config.path}/repl/#{@channel_id}/#{session_name}.output", "r")
|
168
|
-
|
182
|
+
@repl_sessions[from][:pid] = wait_thr.pid
|
169
183
|
while (wait_thr.status == 'run' or wait_thr.status == 'sleep') and @repl_sessions.key?(from)
|
170
184
|
begin
|
171
185
|
if (Time.now-@repl_sessions[from][:finished]) > timeout
|
@@ -173,6 +187,14 @@ class SlackSmartBot
|
|
173
187
|
f.puts 'quit'
|
174
188
|
}
|
175
189
|
respond "REPL session finished: #{@repl_sessions[from][:name]}", dest
|
190
|
+
unreact :running, @ts_react
|
191
|
+
pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
192
|
+
pids.each do |pid|
|
193
|
+
begin
|
194
|
+
Process.kill("KILL", pid)
|
195
|
+
rescue
|
196
|
+
end
|
197
|
+
end
|
176
198
|
@repl_sessions.delete(from)
|
177
199
|
break
|
178
200
|
end
|
@@ -199,10 +221,12 @@ class SlackSmartBot
|
|
199
221
|
code.gsub!("\\r", "\r")
|
200
222
|
# Disabled for the moment since it is deleting lines with '}'
|
201
223
|
#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
|
224
|
+
if code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File.") or
|
203
225
|
code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
|
204
226
|
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/)
|
227
|
+
code.include?("ENV") or code.match?(/=\s*IO/) or code.include?("Dir.") or
|
228
|
+
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/)
|
206
230
|
respond "Sorry I cannot run this due security reasons", dest
|
207
231
|
else
|
208
232
|
@repl_sessions[from][:input]<<code
|
@@ -212,6 +236,14 @@ class SlackSmartBot
|
|
212
236
|
f.puts code
|
213
237
|
}
|
214
238
|
respond "REPL session finished: #{@repl_sessions[from][:name]}", dest
|
239
|
+
unreact :running, @ts_react
|
240
|
+
pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
241
|
+
pids.each do |pid|
|
242
|
+
begin
|
243
|
+
Process.kill("KILL", pid)
|
244
|
+
rescue
|
245
|
+
end
|
246
|
+
end
|
215
247
|
@repl_sessions.delete(from)
|
216
248
|
when /^\s*-/i
|
217
249
|
#ommit
|