slack-smart-bot 1.5.1 → 1.6.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -2
  3. data/lib/slack-smart-bot.rb +6 -1
  4. data/lib/slack/smart-bot/commands.rb +5 -0
  5. data/lib/slack/smart-bot/commands/general/bot_help.rb +44 -40
  6. data/lib/slack/smart-bot/commands/general/bot_status.rb +32 -28
  7. data/lib/slack/smart-bot/commands/general/bye_bot.rb +9 -1
  8. data/lib/slack/smart-bot/commands/general/hi_bot.rb +6 -1
  9. data/lib/slack/smart-bot/commands/general/use_rules.rb +33 -29
  10. data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +40 -35
  11. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +1 -0
  12. data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +32 -0
  13. data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +30 -25
  14. data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +43 -0
  15. data/lib/slack/smart-bot/commands/on_bot/repl.rb +202 -0
  16. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +33 -29
  17. data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +73 -0
  18. data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +24 -0
  19. data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +23 -18
  20. data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +32 -27
  21. data/lib/slack/smart-bot/commands/on_master/create_bot.rb +79 -74
  22. data/lib/slack/smart-bot/listen.rb +2 -0
  23. data/lib/slack/smart-bot/process.rb +61 -9
  24. data/lib/slack/smart-bot/process_first.rb +17 -3
  25. data/lib/slack/smart-bot/treat_message.rb +24 -3
  26. data/lib/slack/smart-bot/utils.rb +3 -0
  27. data/lib/slack/smart-bot/utils/get_help.rb +1 -1
  28. data/lib/slack/smart-bot/utils/get_repls.rb +11 -0
  29. data/lib/slack/smart-bot/utils/update_repls.rb +8 -0
  30. metadata +28 -19
@@ -0,0 +1,73 @@
1
+ class SlackSmartBot
2
+ # help: ----------------------------------------------
3
+ # help: `run repl SESSION_NAME`
4
+ # help: `run repl SESSION_NAME ENV_VAR=VALUE ENV_VAR=VALUE`
5
+ # help: `run live SESSION_NAME`
6
+ # help: `run irb SESSION_NAME`
7
+ # help:
8
+ # help: Will run the repl session specified and return the output.
9
+ # help: You can supply the Environmental Variables you need for the Session
10
+ # help: It will return only the values that were print out on the repl with puts, print, p or pp
11
+ # help: Example:
12
+ # help: _run repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'_
13
+ # help:
14
+ def run_repl(dest, user, session_name, env_vars, rules_file)
15
+ #todo: add tests
16
+ from = user.name
17
+ if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(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
20
+ save_stats(__method__)
21
+ Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl")
22
+ Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}")
23
+ if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.input")
24
+ if @repls.key?(session_name) and @repls[session_name][:type] == :private and
25
+ @repls[session_name][:creator_name]!=user.name and
26
+ !config.admins.include?(user.name)
27
+ respond "The REPL with session name: #{session_name} is private", dest
28
+ else
29
+ if @repls.key?(session_name) #not temp
30
+ @repls[session_name][:accessed] = Time.now.to_s
31
+ if @repls[session_name].creator_name == user.name
32
+ @repls[session_name][:runs_by_creator] += 1
33
+ else
34
+ @repls[session_name][:runs_by_others] += 1
35
+ end
36
+ update_repls()
37
+ end
38
+
39
+ content = env_vars.join("\n")
40
+ content += "\nrequire 'nice_http'\n"
41
+ unless rules_file.empty? # to get the project_folder
42
+ begin
43
+ eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
44
+ end
45
+ end
46
+ if File.exist?("#{project_folder}/.smart-bot-repl")
47
+ content += File.read("#{project_folder}/.smart-bot-repl")
48
+ content += "\n"
49
+ end
50
+ content += File.read("#{config.path}/repl/#{@channel_id}/#{session_name}.input").gsub(/^(quit|exit|bye)$/i,'')
51
+ Dir.mkdir("#{project_folder}/tmp") unless Dir.exist?("#{project_folder}/tmp")
52
+ Dir.mkdir("#{project_folder}/tmp/repl") unless Dir.exist?("#{project_folder}/tmp/repl")
53
+ File.write("#{project_folder}/tmp/repl/#{session_name}.rb", content, mode: "w+")
54
+ process_to_run = "ruby #{project_folder}/tmp/repl/#{session_name}.rb"
55
+ process_to_run = ("cd #{project_folder} && #{process_to_run}") if defined?(project_folder)
56
+ respond "Running REPL #{session_name}"
57
+ stdout, stderr, status = Open3.capture3(process_to_run)
58
+ if stderr == ""
59
+ if stdout == ""
60
+ respond "*#{session_name}*: Nothing returned."
61
+ else
62
+ respond "*#{session_name}*: #{stdout}"
63
+ end
64
+ else
65
+ respond "*#{session_name}*: #{stdout} #{stderr}"
66
+ end
67
+ end
68
+ else
69
+ respond "The REPL with session name: #{session_name} doesn't exist on this Smart Bot Channel", dest
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,24 @@
1
+ class SlackSmartBot
2
+ # help: ----------------------------------------------
3
+ # help: `see repls`
4
+ # help: `see irbs`
5
+ # help: It will display the repls
6
+ # help:
7
+ def see_repls(dest, user, typem)
8
+ #todo: add tests
9
+ save_stats(__method__)
10
+ from = user.name
11
+ if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(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
14
+ message = ""
15
+ @repls.sort.to_h.each do |session_name, repl|
16
+ if (repl.creator_name == user.name or repl.type == :public) or (config.admins.include?(user.name) and typem == :on_dm)
17
+ message += "(#{repl.type}) *#{session_name}*: #{repl.description} / created: #{repl.created} / accessed: #{repl.accessed} / creator: #{repl.creator} / runs: #{repl.runs_by_creator+repl.runs_by_others} / gets: #{repl.gets} \n"
18
+ end
19
+ end
20
+ message = "No repls created" if message == ''
21
+ respond message
22
+ end
23
+ end
24
+ end
@@ -4,30 +4,35 @@ class SlackSmartBot
4
4
  # help: `see sc`
5
5
  # help: It will display the shortcuts stored for the user and for :all
6
6
  # help:
7
- def see_shortcuts(dest, from, typem)
7
+ def see_shortcuts(dest, user, typem)
8
8
  save_stats(__method__)
9
- unless typem == :on_extended
10
- msg = ""
11
- if @shortcuts[:all].keys.size > 0
12
- msg = "*Available shortcuts for all:*\n"
13
- @shortcuts[:all].each { |name, value|
14
- msg += " _#{name}: #{value}_\n"
15
- }
16
- respond msg, dest
17
- end
18
-
19
- if @shortcuts.keys.include?(from) and @shortcuts[from].keys.size > 0
20
- new_hash = @shortcuts[from].dup
21
- @shortcuts[:all].keys.each { |k| new_hash.delete(k) }
22
- if new_hash.keys.size > 0
23
- msg = "*Available shortcuts for #{from}:*\n"
24
- new_hash.each { |name, value|
9
+ from = user.name
10
+ if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id)
11
+ respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
12
+ else
13
+ unless typem == :on_extended
14
+ msg = ""
15
+ if @shortcuts[:all].keys.size > 0
16
+ msg = "*Available shortcuts for all:*\n"
17
+ @shortcuts[:all].each { |name, value|
25
18
  msg += " _#{name}: #{value}_\n"
26
19
  }
27
20
  respond msg, dest
28
21
  end
22
+
23
+ if @shortcuts.keys.include?(from) and @shortcuts[from].keys.size > 0
24
+ new_hash = @shortcuts[from].dup
25
+ @shortcuts[:all].keys.each { |k| new_hash.delete(k) }
26
+ if new_hash.keys.size > 0
27
+ msg = "*Available shortcuts for #{from}:*\n"
28
+ new_hash.each { |name, value|
29
+ msg += " _#{name}: #{value}_\n"
30
+ }
31
+ respond msg, dest
32
+ end
33
+ end
34
+ respond "No shortcuts found", dest if msg == ""
29
35
  end
30
- respond "No shortcuts found", dest if msg == ""
31
36
  end
32
37
  end
33
38
  end
@@ -1,37 +1,42 @@
1
1
  class SlackSmartBot
2
- def bot_rules(dest, help_command, typem, rules_file, from)
2
+ def bot_rules(dest, help_command, typem, rules_file, user)
3
3
  save_stats(__method__)
4
- if typem == :on_extended or typem == :on_call #for the other cases above.
5
- help_filtered = get_help(rules_file, dest, from, true)
4
+ from = user.name
5
+ if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id)
6
+ respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
7
+ else
8
+ if typem == :on_extended or typem == :on_call #for the other cases above.
9
+ help_filtered = get_help(rules_file, dest, from, true)
6
10
 
7
- if help_command.to_s != ""
8
- help_found = false
9
- help_filtered.split(/^\s*-------*$/).each do |h|
10
- if h.match?(/[`_]#{help_command}/i)
11
- respond "*#{config.channel}*:#{h}", dest
12
- help_found = true
11
+ if help_command.to_s != ""
12
+ help_found = false
13
+ help_filtered.split(/^\s*-------*$/).each do |h|
14
+ if h.match?(/[`_]#{help_command}/i)
15
+ respond "*#{config.channel}*:#{h}", dest
16
+ help_found = true
17
+ end
13
18
  end
19
+ respond("*#{config.channel}*: I didn't find any command starting by `#{help_command}`", dest) unless help_found
20
+ else
21
+ message = "-\n\n\n===================================\n*Rules from channel #{config.channel}*\n"
22
+ if typem == :on_extended
23
+ message += "To run the commands on this extended channel, add `!`, `!!` or `^` before the command.\n"
24
+ end
25
+ message += help_filtered
26
+ respond message, dest
14
27
  end
15
- respond("*#{config.channel}*: I didn't find any command starting by `#{help_command}`", dest) unless help_found
16
- else
17
- message = "-\n\n\n===================================\n*Rules from channel #{config.channel}*\n"
18
- if typem == :on_extended
19
- message += "To run the commands on this extended channel, add `!`, `!!` or `^` before the command.\n"
20
- end
21
- message += help_filtered
22
- respond message, dest
23
- end
24
28
 
25
- unless rules_file.empty?
26
- begin
27
- eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
29
+ unless rules_file.empty?
30
+ begin
31
+ eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
32
+ end
33
+ end
34
+ if defined?(git_project) and git_project.to_s != "" and help_command.to_s == ""
35
+ respond "Git project: #{git_project}", dest
36
+ else
37
+ def git_project() "" end
38
+ def project_folder() "" end
28
39
  end
29
- end
30
- if defined?(git_project) and git_project.to_s != "" and help_command.to_s == ""
31
- respond "Git project: #{git_project}", dest
32
- else
33
- def git_project() "" end
34
- def project_folder() "" end
35
40
  end
36
41
  end
37
42
  end
@@ -7,87 +7,92 @@ class SlackSmartBot
7
7
  # helpmaster: the admins will be the master admins, the creator of the bot and the creator of the channel
8
8
  # helpmaster: follow the instructions in case creating cloud bots
9
9
  # helpmaster:
10
- def create_bot(dest, from, cloud, channel)
10
+ def create_bot(dest, user, cloud, channel)
11
11
  save_stats(__method__)
12
- if config.on_master_bot
13
- get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
14
- channel_id = nil
15
- if @channels_name.key?(channel) #it is an id
16
- channel_id = channel
17
- channel = @channels_name[channel_id]
18
- elsif @channels_id.key?(channel) #it is a channel name
19
- channel_id = @channels_id[channel]
20
- end
21
- #todo: add pagination for case more than 1000 channels on the workspace
22
- channels = client.web_client.conversations_list(
23
- types: "private_channel,public_channel",
24
- limit: "1000",
25
- exclude_archived: "true",
26
- ).channels
27
- channel_found = channels.detect { |c| c.name == channel }
28
- members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil?
12
+ from = user.name
13
+ if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(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
16
+ if config.on_master_bot
17
+ get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
18
+ channel_id = nil
19
+ if @channels_name.key?(channel) #it is an id
20
+ channel_id = channel
21
+ channel = @channels_name[channel_id]
22
+ elsif @channels_id.key?(channel) #it is a channel name
23
+ channel_id = @channels_id[channel]
24
+ end
25
+ #todo: add pagination for case more than 1000 channels on the workspace
26
+ channels = client.web_client.conversations_list(
27
+ types: "private_channel,public_channel",
28
+ limit: "1000",
29
+ exclude_archived: "true",
30
+ ).channels
31
+ channel_found = channels.detect { |c| c.name == channel }
32
+ members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil?
29
33
 
30
- if channel_id.nil?
31
- respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
32
- elsif channel == config.master_channel
33
- respond "There is already a bot in this channel: #{channel}", dest
34
- elsif @bots_created.keys.include?(channel_id)
35
- respond "There is already a bot in this channel: #{channel}, kill it before", dest
36
- elsif config[:nick_id] != channel_found.creator and !members.include?(config[:nick_id])
37
- respond "You need to add first to the channel the smart bot user: #{config[:nick]}", dest
38
- else
39
- if channel_id != config[:channel]
40
- begin
41
- rules_file = "slack-smart-bot_rules_#{channel_id}_#{from.gsub(" ", "_")}.rb"
42
- if defined?(RULES_FOLDER)
43
- rules_file = RULES_FOLDER + rules_file
44
- else
45
- Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
46
- Dir.mkdir("#{config.path}/rules/#{channel_id}") unless Dir.exist?("#{config.path}/rules/#{channel_id}")
47
- rules_file = "/rules/#{channel_id}/" + rules_file
48
- end
49
- default_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_rules.rb")
50
- File.delete(config.path + rules_file) if File.exist?(config.path + rules_file)
51
- FileUtils.copy_file(default_rules, config.path + rules_file) unless File.exist?(config.path + rules_file)
52
- admin_users = Array.new()
53
- creator_info = client.web_client.users_info(user: channel_found.creator)
54
- admin_users = [from, creator_info.user.name] + config.masters
55
- admin_users.uniq!
56
- @logger.info "ruby #{config.file_path} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on"
57
-
58
- if cloud
59
- respond "Copy the bot folder to your cloud location and run `ruby #{config.file} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on&`", dest
60
- else
61
- t = Thread.new do
62
- `BOT_SILENT=false ruby #{config.file_path} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on`
34
+ if channel_id.nil?
35
+ respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
36
+ elsif channel == config.master_channel
37
+ respond "There is already a bot in this channel: #{channel}", dest
38
+ elsif @bots_created.keys.include?(channel_id)
39
+ respond "There is already a bot in this channel: #{channel}, kill it before", dest
40
+ elsif config[:nick_id] != channel_found.creator and !members.include?(config[:nick_id])
41
+ respond "You need to add first to the channel the smart bot user: #{config[:nick]}", dest
42
+ else
43
+ if channel_id != config[:channel]
44
+ begin
45
+ rules_file = "slack-smart-bot_rules_#{channel_id}_#{from.gsub(" ", "_")}.rb"
46
+ if defined?(RULES_FOLDER)
47
+ rules_file = RULES_FOLDER + rules_file
48
+ else
49
+ Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
50
+ Dir.mkdir("#{config.path}/rules/#{channel_id}") unless Dir.exist?("#{config.path}/rules/#{channel_id}")
51
+ rules_file = "/rules/#{channel_id}/" + rules_file
52
+ end
53
+ default_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_rules.rb")
54
+ File.delete(config.path + rules_file) if File.exist?(config.path + rules_file)
55
+ FileUtils.copy_file(default_rules, config.path + rules_file) unless File.exist?(config.path + rules_file)
56
+ admin_users = Array.new()
57
+ creator_info = client.web_client.users_info(user: channel_found.creator)
58
+ admin_users = [from, creator_info.user.name] + config.masters
59
+ admin_users.uniq!
60
+ @logger.info "ruby #{config.file_path} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on"
61
+
62
+ if cloud
63
+ respond "Copy the bot folder to your cloud location and run `ruby #{config.file} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on&`", dest
64
+ else
65
+ t = Thread.new do
66
+ `BOT_SILENT=false ruby #{config.file_path} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on`
67
+ end
63
68
  end
69
+ @bots_created[channel_id] = {
70
+ creator_name: from,
71
+ channel_id: channel_id,
72
+ channel_name: @channels_name[channel_id],
73
+ status: :on,
74
+ created: Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18],
75
+ rules_file: rules_file,
76
+ admins: admin_users.join(","),
77
+ extended: [],
78
+ cloud: cloud,
79
+ thread: t,
80
+ }
81
+ respond "The bot has been created on channel: #{channel}. Rules file: #{File.basename rules_file}. Admins: #{admin_users.join(", ")}", dest
82
+ update_bots_file()
83
+ rescue Exception => stack
84
+ @logger.fatal stack
85
+ message = "Problem creating the bot on channel #{channel}. Error: <#{stack}>."
86
+ @logger.error message
87
+ respond message, dest
64
88
  end
65
- @bots_created[channel_id] = {
66
- creator_name: from,
67
- channel_id: channel_id,
68
- channel_name: @channels_name[channel_id],
69
- status: :on,
70
- created: Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18],
71
- rules_file: rules_file,
72
- admins: admin_users.join(","),
73
- extended: [],
74
- cloud: cloud,
75
- thread: t,
76
- }
77
- respond "The bot has been created on channel: #{channel}. Rules file: #{File.basename rules_file}. Admins: #{admin_users.join(", ")}", dest
78
- update_bots_file()
79
- rescue Exception => stack
80
- @logger.fatal stack
81
- message = "Problem creating the bot on channel #{channel}. Error: <#{stack}>."
82
- @logger.error message
83
- respond message, dest
89
+ else
90
+ respond "There is already a bot in this channel: #{channel}, and it is the Master Channel!", dest
84
91
  end
85
- else
86
- respond "There is already a bot in this channel: #{channel}, and it is the Master Channel!", dest
87
92
  end
93
+ else
94
+ respond "Sorry I cannot create bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest
88
95
  end
89
- else
90
- respond "Sorry I cannot create bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest
91
96
  end
92
97
  end
93
98
  end
@@ -2,6 +2,7 @@ class SlackSmartBot
2
2
  def listen_simulate
3
3
  @salutations = [config[:nick], "<@#{config[:nick_id]}>", "bot", "smart"]
4
4
  @pings = []
5
+ @last_activity_check = Time.now
5
6
  get_bots_created()
6
7
  @buffer_complete = [] unless defined?(@buffer_complete)
7
8
  b = File.read("#{config.path}/buffer_complete.log")
@@ -41,6 +42,7 @@ class SlackSmartBot
41
42
 
42
43
  def listen
43
44
  @pings = []
45
+ @last_activity_check = Time.now
44
46
  get_bots_created()
45
47
 
46
48
  client.on :message do |data|
@@ -1,6 +1,7 @@
1
1
  class SlackSmartBot
2
2
  def process(user, command, dest, dchannel, rules_file, typem, files, ts)
3
3
  from = user.name
4
+
4
5
  if user.profile.display_name.to_s.match?(/\A\s*\z/)
5
6
  user.profile.display_name = user.profile.real_name
6
7
  end
@@ -56,7 +57,7 @@ class SlackSmartBot
56
57
  when /^\s*pause\s(this\s)?bot$/i
57
58
  pause_bot(dest, from)
58
59
  when /^\s*bot\sstatus/i
59
- bot_status(dest, from)
60
+ bot_status(dest, user)
60
61
  when /\Anotify\s+<#(C\w+)\|.+>\s+(.+)\s*\z/im, /\Anotify\s+(all)?\s*(.+)\s*\z/im
61
62
  where = $1
62
63
  message = $2
@@ -64,7 +65,7 @@ class SlackSmartBot
64
65
  when /^\s*create\s+(cloud\s+)?bot\s+on\s+<#C\w+\|(.+)>\s*/i, /^create\s+(cloud\s+)?bot\s+on\s+(.+)\s*/i
65
66
  cloud = !$1.nil?
66
67
  channel = $2
67
- create_bot(dest, from, cloud, channel)
68
+ create_bot(dest, user, cloud, channel)
68
69
  when /^\s*kill\sbot\son\s<#C\w+\|(.+)>\s*$/i, /^kill\sbot\son\s(.+)\s*$/i
69
70
  channel = $1
70
71
  kill_bot_on_channel(dest, from, channel)
@@ -119,8 +120,13 @@ class SlackSmartBot
119
120
 
120
121
  # only when :on and (listening or on demand or direct message)
121
122
  if @status == :on and
122
- (@questions.keys.include?(from) or
123
- (@listening.include?(from) and typem != :on_extended) or
123
+ (@questions.key?(from) or
124
+ (@repl_sessions.key?(from) and dest==@repl_sessions[from][:dest] and
125
+ ((@repl_sessions[from][:on_thread] and Thread.current[:thread_ts] == @repl_sessions[from][:thread_ts]) or
126
+ (!@repl_sessions[from][:on_thread] and !Thread.current[:on_thread]))) or
127
+ (@listening.key?(from) and typem != :on_extended and
128
+ ((@listening[from].key?(dest) and !Thread.current[:on_thread]) or
129
+ (@listening[from].key?(Thread.current[:thread_ts]) and Thread.current[:on_thread] ) )) or
124
130
  typem == :on_dm or typem == :on_pg or on_demand)
125
131
  processed2 = true
126
132
 
@@ -129,17 +135,17 @@ class SlackSmartBot
129
135
  # bot rules for extended channels
130
136
  when /^bot\s+rules\s*(.+)?$/i
131
137
  help_command = $1
132
- bot_rules(dest, help_command, typem, rules_file, from)
138
+ bot_rules(dest, help_command, typem, rules_file, user)
133
139
  when /^\s*(add\s)?shortcut\s(for\sall)?\s*([^:]+)\s*:\s*(.+)/i, /^(add\s)sc\s(for\sall)?\s*([^:]+)\s*:\s*(.+)/i
134
140
  for_all = $2
135
141
  shortcut_name = $3.to_s.downcase
136
142
  command_to_run = $4
137
- add_shortcut(dest, from, typem, for_all, shortcut_name, command, command_to_run)
143
+ add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run)
138
144
  when /^\s*(delete|remove)\s+shortcut\s+(.+)/i, /^(delete|remove)\s+sc\s+(.+)/i
139
145
  shortcut = $2.to_s.downcase
140
- delete_shortcut(dest, from, shortcut, typem, command)
146
+ delete_shortcut(dest, user, shortcut, typem, command)
141
147
  when /^\s*see\sshortcuts/i, /^see\ssc/i
142
- see_shortcuts(dest, from, typem)
148
+ see_shortcuts(dest, user, typem)
143
149
 
144
150
  #kept to be backwards compatible
145
151
  when /^\s*id\schannel\s<#C\w+\|(.+)>\s*/i, /^id channel (.+)/
@@ -157,7 +163,53 @@ class SlackSmartBot
157
163
  code.gsub!("\\n", "\n")
158
164
  code.gsub!("\\r", "\r")
159
165
  @logger.info code
160
- ruby_code(dest, code, rules_file)
166
+ ruby_code(dest, user, code, rules_file)
167
+ when /^\s*(private\s+)?(repl|irb|live)\s*()()()$/i,
168
+ /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()()\s*$/i,
169
+ /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s*"(.+)"()\s*$/i,
170
+ /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s*"(.+)"\s+(.+)\s*$/i,
171
+ /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()\s+(.+)\s*$/i,
172
+ /^\s*(private\s+)?(repl|irb|live)()\s+()(.+)\s*$/i
173
+ if $1.to_s!=''
174
+ type = :private
175
+ else
176
+ type = :public
177
+ end
178
+ session_name = $3
179
+ description = $4
180
+ opts = " #{$5}"
181
+ env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i)
182
+ opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev|
183
+ env_vars << ev.gsub('=',"='") + "'"
184
+ end
185
+ env_vars.each_with_index do |ev, idx|
186
+ ev.gsub!("=","']=")
187
+ ev.lstrip!
188
+ env_vars[idx] = "ENV['#{ev}"
189
+ end
190
+ repl(dest, user, session_name, env_vars.flatten, rules_file, command, description, type)
191
+ when /^\s*get\s+(repl|irb|live)\s+([\w\-]+)\s*/i
192
+ session_name = $2
193
+ get_repl(dest, user, session_name)
194
+ when /^\s*run\s+(repl|irb|live)\s+([\w\-]+)()\s*$/i,
195
+ /^\s*run\s+(repl|irb|live)\s+([\w\-]+)\s+(.+)\s*$/i
196
+ session_name = $2
197
+ opts = " #{$3}"
198
+ env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i)
199
+ opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev|
200
+ env_vars << ev.gsub('=',"='") + "'"
201
+ end
202
+ env_vars.each_with_index do |ev, idx|
203
+ ev.gsub!("=","']=")
204
+ ev.lstrip!
205
+ env_vars[idx] = "ENV['#{ev}"
206
+ end
207
+ run_repl(dest, user, session_name, env_vars.flatten, rules_file)
208
+ when /^\s*(delete|remove)\s+(repl|irb|live)\s+([\w\-]+)\s*$/i
209
+ repl_name = $3.downcase
210
+ delete_repl(dest, user, repl_name)
211
+ when /^\s*see\s+(repls|repl|irb|irbs)\s*$/i
212
+ see_repls(dest, user, typem)
161
213
  else
162
214
  processed2 = false
163
215
  end #of case