slack-smart-bot 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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