slack-smart-bot 0.9.6 → 1.0.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +5 -1
  3. data/README.md +80 -175
  4. data/lib/slack-smart-bot.rb +95 -1276
  5. data/lib/slack-smart-bot_rules.rb +50 -69
  6. data/lib/slack/smart-bot/comm.rb +197 -0
  7. data/lib/slack/smart-bot/commands/general/bot_help.rb +74 -0
  8. data/lib/slack/smart-bot/commands/general/bot_status.rb +41 -0
  9. data/lib/slack/smart-bot/commands/general/bye_bot.rb +17 -0
  10. data/lib/slack/smart-bot/commands/general/hi_bot.rb +24 -0
  11. data/lib/slack/smart-bot/commands/general/stop_using_rules.rb +44 -0
  12. data/lib/slack/smart-bot/commands/general/use_rules.rb +48 -0
  13. data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +64 -0
  14. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +87 -0
  15. data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +63 -0
  16. data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +21 -0
  17. data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +26 -0
  18. data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +28 -0
  19. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +53 -0
  20. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +57 -0
  21. data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +20 -0
  22. data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +27 -0
  23. data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +30 -0
  24. data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +41 -0
  25. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +48 -0
  26. data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +32 -0
  27. data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +37 -0
  28. data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +38 -0
  29. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +42 -0
  30. data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +35 -0
  31. data/lib/slack/smart-bot/commands/on_master/create_bot.rb +94 -0
  32. data/lib/slack/smart-bot/listen.rb +36 -0
  33. data/lib/slack/smart-bot/process.rb +169 -0
  34. data/lib/slack/smart-bot/process_first.rb +201 -0
  35. data/lib/slack/smart-bot/treat_message.rb +139 -0
  36. data/lib/slack/smart-bot/utils.rb +299 -0
  37. metadata +71 -5
@@ -0,0 +1,28 @@
1
+ class SlackSmartBot
2
+
3
+ # helpadmin: ----------------------------------------------
4
+ # helpadmin: `kill routine NAME`
5
+ # helpadmin: `delete routine NAME`
6
+ # helpadmin: `remove routine NAME`
7
+ # helpadmin: It will kill and remove the specified routine
8
+ # helpadmin: You can use this command only if you are an admin user
9
+ # helpadmin: NAME: one word to identify the routine
10
+ # helpadmin: Examples:
11
+ # helpadmin: _kill routine example_
12
+ # helpadmin:
13
+ def remove_routine(dest, from, name)
14
+ if ADMIN_USERS.include?(from) #admin user
15
+ if !ON_MASTER_BOT and dest[0] == "D"
16
+ respond "It's only possible to remove routines from MASTER channel from a direct message with the bot.", dest
17
+ elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name)
18
+ @routines[@channel_id].delete(name)
19
+ update_routines()
20
+ respond "The routine *`#{name}`* has been removed.", dest
21
+ else
22
+ respond "There isn't a routine with that name: *`#{name}`*.\nCall `see routines` to see added routines", dest
23
+ end
24
+ else
25
+ respond "Only admin users can delete routines", dest
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,53 @@
1
+ class SlackSmartBot
2
+
3
+ # helpadmin: ----------------------------------------------
4
+ # helpadmin: `run routine NAME`
5
+ # helpadmin: `execute routine NAME`
6
+ # helpadmin: It will run the specified routine
7
+ # helpadmin: You can use this command only if you are an admin user
8
+ # helpadmin: NAME: one word to identify the routine
9
+ # helpadmin: Examples:
10
+ # helpadmin: _run routine example_
11
+ # helpadmin:
12
+
13
+ def run_routine(dest, from, name)
14
+ if ADMIN_USERS.include?(from) #admin user
15
+ if !ON_MASTER_BOT and dest[0] == "D"
16
+ respond "It's only possible to run routines from MASTER channel from a direct message with the bot.", dest
17
+ elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name)
18
+ if @routines[@channel_id][name][:file_path] != ""
19
+ if @routines[@channel_id][name][:file_path].match?(/\.rb$/i)
20
+ ruby = "ruby "
21
+ else
22
+ ruby = ""
23
+ end
24
+ process_to_run = "#{ruby}#{Dir.pwd}#{@routines[@channel_id][name][:file_path][1..-1]}"
25
+ process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
26
+
27
+ stdout, stderr, status = Open3.capture3(process_to_run)
28
+ if stderr == ""
29
+ unless stdout.match?(/\A\s*\z/)
30
+ respond "routine *`#{name}`*: #{stdout}", @routines[@channel_id][name][:dest]
31
+ end
32
+ else
33
+ respond "routine *`#{name}`*: #{stdout} #{stderr}", @routines[@channel_id][name][:dest]
34
+ end
35
+ else #command
36
+ respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest]
37
+ started = Time.now
38
+ treat_message({ channel: @routines[@channel_id][name][:dest],
39
+ user: @routines[@channel_id][name][:creator_id],
40
+ text: @routines[@channel_id][name][:command],
41
+ files: nil })
42
+ end
43
+ @routines[@channel_id][name][:last_elapsed] = (Time.now - started)
44
+ @routines[@channel_id][name][:last_run] = started.to_s
45
+ update_routines()
46
+ else
47
+ respond "There isn't a routine with that name: `#{name}`.\nCall `see routines` to see added routines", dest
48
+ end
49
+ else
50
+ respond "Only admin users can run routines", dest
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,57 @@
1
+ class SlackSmartBot
2
+ # helpadmin: ----------------------------------------------
3
+ # helpadmin: `see routines`
4
+ # helpadmin: `see all routines`
5
+ # helpadmin: It will show the routines of the channel
6
+ # helpadmin: In case of `all` and on the master channel, it will show all the routines from all channels
7
+ # helpadmin: You can use this command only if you are an admin user
8
+ # helpadmin:
9
+ def see_routines(dest, from, user, all)
10
+ if ADMIN_USERS.include?(from) #admin user
11
+ if all
12
+ routines = {}
13
+ if ON_MASTER_BOT
14
+ Dir["./routines/routines_*.rb"].each do |rout|
15
+ file_conf = IO.readlines(rout).join
16
+ unless file_conf.to_s() == ""
17
+ routines.merge!(eval(file_conf))
18
+ end
19
+ end
20
+ else
21
+ respond "To see all routines on all channels you need to run the command on the master channel.\nI'll display only the routines on this channel.", dest
22
+ routines = @routines.deep_copy
23
+ end
24
+ else
25
+ if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) and dest[0] == "D"
26
+ file_conf = IO.readlines("./routines/routines_#{@rules_imported[user.id][user.id]}").join
27
+ routines = eval(file_conf)
28
+ else
29
+ routines = @routines.deep_copy
30
+ end
31
+ end
32
+
33
+ if routines.get_values(:channel_name).size == 0
34
+ respond "There are no routines added.", dest
35
+ else
36
+ routines.each do |ch, rout_ch|
37
+ respond "Routines on channel *#{rout_ch.get_values(:channel_name).values.flatten.uniq[0]}*", dest
38
+ rout_ch.each do |k, v|
39
+ msg = []
40
+ ch != v[:dest] ? directm = " (*DM to #{v[:creator]}*)" : directm = ""
41
+ msg << "*`#{k}`*#{directm}"
42
+ msg << "\tCreator: #{v[:creator]}"
43
+ msg << "\tStatus: #{v[:status]}"
44
+ msg << "\tEvery: #{v[:every]}" unless v[:every] == ""
45
+ msg << "\tAt: #{v[:at]}" unless v[:at] == ""
46
+ msg << "\tNext Run: #{v[:next_run]}"
47
+ msg << "\tLast Run: #{v[:last_run]}"
48
+ msg << "\tTime consumed on last run: #{v[:last_elapsed]}"
49
+ respond msg.join("\n"), dest
50
+ end
51
+ end
52
+ end
53
+ else
54
+ respond "Only admin users can use this command", dest
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,20 @@
1
+ class SlackSmartBot
2
+
3
+ # helpadmin: ----------------------------------------------
4
+ # helpadmin: `start bot`
5
+ # helpadmin: `start this bot`
6
+ # helpadmin: the bot will start to listen
7
+ # helpadmin: You can use this command only if you are an admin user
8
+ # helpadmin:
9
+ def start_bot(dest, from)
10
+ if ADMIN_USERS.include?(from) #admin user
11
+ respond "This bot is running and listening from now on. You can pause again: pause this bot", dest
12
+ @status = :on
13
+ unless ON_MASTER_BOT
14
+ send_msg_channel MASTER_CHANNEL, "Changed status on #{CHANNEL} to :on"
15
+ end
16
+ else
17
+ respond "Only admin users can change my status", dest
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ class SlackSmartBot
2
+
3
+ # helpadmin: ----------------------------------------------
4
+ # helpadmin: `start routine NAME`
5
+ # helpadmin: It will start a paused routine
6
+ # helpadmin: You can use this command only if you are an admin user
7
+ # helpadmin: NAME: one word to identify the routine
8
+ # helpadmin: Examples:
9
+ # helpadmin: _start routine example_
10
+ # helpadmin:
11
+
12
+ def start_routine(dest, from, name)
13
+ if ADMIN_USERS.include?(from) #admin user
14
+ if !ON_MASTER_BOT and dest[0] == "D"
15
+ respond "It's only possible to start routines from MASTER channel from a direct message with the bot.", dest
16
+ elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name)
17
+ @routines[@channel_id][name][:status] = :on
18
+ update_routines()
19
+ respond "The routine *`#{name}`* has been started. The change will take effect in less than 30 secs.", dest
20
+ else
21
+ respond "There isn't a routine with that name: *`#{name}`*.\nCall `see routines` to see added routines", dest
22
+ end
23
+ else
24
+ respond "Only admin users can use this command", dest
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ class SlackSmartBot
2
+
3
+ # helpadmin: ----------------------------------------------
4
+ # helpadmin: `stop using rules on CHANNEL_NAME`
5
+ # helpadmin: it will stop using the extended rules on the specified channel.
6
+ # helpadmin:
7
+
8
+ def stop_using_rules_on(dest, user, from, channel, typem)
9
+ unless typem == :on_extended
10
+ if !ADMIN_USERS.include?(from) #not admin
11
+ respond "Only admins can extend or stop using the rules. Admins on this channel: #{ADMIN_USERS}", dest
12
+ else
13
+ get_bots_created()
14
+ if @bots_created[@channel_id][:extended].include?(channel)
15
+ @bots_created[@channel_id][:extended].delete(channel)
16
+ update_bots_file()
17
+ respond "<@#{user.id}> removed the access to the rules of #{CHANNEL} from #{channel}.", @master_bot_id
18
+ if @channels_id[channel][0] == "G"
19
+ respond "The rules won't be accessible from *#{channel}* from now on.", dest
20
+ else
21
+ respond "The rules won't be accessible from *<##{@channels_id[channel]}>* from now on.", dest
22
+ end
23
+ respond "<@#{user.id}> removed the access to the rules of <##{@channel_id}> from this channel.", @channels_id[channel]
24
+ else
25
+ respond "The rules were not accessible from *#{channel}*", dest
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ class SlackSmartBot
2
+ # help: ----------------------------------------------
3
+ # help: `delete shortcut NAME`
4
+ # help: `delete sc NAME`
5
+ # help: It will delete the shortcut with the supplied name
6
+ # help:
7
+
8
+ def delete_shortcut(dest, from, shortcut, typem, command)
9
+ unless typem == :on_extended
10
+ deleted = false
11
+
12
+ if !ADMIN_USERS.include?(from) and @shortcuts[:all].include?(shortcut) and !@shortcuts[from].include?(shortcut)
13
+ respond "Only the creator of the shortcut or an admin user can delete it", dest
14
+ elsif (@shortcuts.keys.include?(from) and @shortcuts[from].keys.include?(shortcut)) or
15
+ (ADMIN_USERS.include?(from) and @shortcuts[:all].include?(shortcut))
16
+ #are you sure? to avoid deleting by mistake
17
+ unless @questions.keys.include?(from)
18
+ ask("are you sure you want to delete it?", command, from, dest)
19
+ else
20
+ case @questions[from]
21
+ when /^(yes|yep)/i
22
+ @questions.delete(from)
23
+ respond "shortcut deleted!", dest
24
+ respond("#{shortcut}: #{@shortcuts[from][shortcut]}", dest) if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut)
25
+ respond("#{shortcut}: #{@shortcuts[:all][shortcut]}", dest) if @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut)
26
+ @shortcuts[from].delete(shortcut) if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut)
27
+ @shortcuts[:all].delete(shortcut) if @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut)
28
+ update_shortcuts_file()
29
+ when /^no/i
30
+ @questions.delete(from)
31
+ respond "ok, I won't delete it", dest
32
+ else
33
+ ask("I don't understand, are you sure you want to delete it? (yes or no)", command, from, dest)
34
+ end
35
+ end
36
+ else
37
+ respond "shortcut not found", dest
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,48 @@
1
+ class SlackSmartBot
2
+ # help: ----------------------------------------------
3
+ # help: `ruby RUBY_CODE`
4
+ # help: `code RUBY_CODE`
5
+ # help: runs the code supplied and returns the output. Also you can send a Ruby file instead. Examples:
6
+ # help: _code puts (34344/99)*(34+14)_
7
+ # help: _ruby require 'json'; res=[]; 20.times {res<<rand(100)}; my_json={result: res}; puts my_json.to_json_
8
+ # help:
9
+
10
+ def ruby_code(dest, code, rules_file)
11
+ unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
12
+ code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
13
+ code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or
14
+ code.include?("ENV") or code.match?(/=\s*IO/)
15
+ unless rules_file.empty?
16
+ begin
17
+ eval(File.new(rules_file).read) if File.exist?(rules_file)
18
+ end
19
+ end
20
+
21
+ respond "Running", dest if code.size > 100
22
+
23
+ begin
24
+ code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting
25
+ ruby = "ruby -e \"#{code.gsub('"', '\"')}\""
26
+ if defined?(project_folder) and project_folder.to_s != "" and Dir.exist?(project_folder)
27
+ ruby = ("cd #{project_folder} &&" + ruby)
28
+ else
29
+ def project_folder() "" end
30
+ end
31
+ stdout, stderr, status = Open3.capture3(ruby)
32
+ if stderr == ""
33
+ if stdout == ""
34
+ respond "Nothing returned. Remember you need to use p or puts to print", dest
35
+ else
36
+ respond stdout, dest
37
+ end
38
+ else
39
+ respond stderr, dest
40
+ end
41
+ rescue Exception => exc
42
+ respond exc, dest
43
+ end
44
+ else
45
+ respond "Sorry I cannot run this due security reasons", dest
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,32 @@
1
+ class SlackSmartBot
2
+ # help: ----------------------------------------------
3
+ # help: `see shortcuts`
4
+ # help: `see sc`
5
+ # help: It will display the shortcuts stored for the user and for :all
6
+ # help:
7
+ def see_shortcuts(dest, from, typem)
8
+ unless typem == :on_extended
9
+ msg = ""
10
+ if @shortcuts[:all].keys.size > 0
11
+ msg = "*Available shortcuts for all:*\n"
12
+ @shortcuts[:all].each { |name, value|
13
+ msg += " _#{name}: #{value}_\n"
14
+ }
15
+ respond msg, dest
16
+ end
17
+
18
+ if @shortcuts.keys.include?(from) and @shortcuts[from].keys.size > 0
19
+ new_hash = @shortcuts[from].dup
20
+ @shortcuts[:all].keys.each { |k| new_hash.delete(k) }
21
+ if new_hash.keys.size > 0
22
+ msg = "*Available shortcuts for #{from}:*\n"
23
+ new_hash.each { |name, value|
24
+ msg += " _#{name}: #{value}_\n"
25
+ }
26
+ respond msg, dest
27
+ end
28
+ end
29
+ respond "No shortcuts found", dest if msg == ""
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,37 @@
1
+ class SlackSmartBot
2
+ def bot_rules(dest, help_command, typem, rules_file, from)
3
+ if typem == :on_extended or typem == :on_call #for the other cases above.
4
+ help_filtered = get_help(rules_file, dest, from, true)
5
+
6
+ if help_command.to_s != ""
7
+ help_found = false
8
+ help_filtered.split(/^\s*-------*$/).each do |h|
9
+ if h.match?(/[`_]#{help_command}/i)
10
+ respond h, dest
11
+ help_found = true
12
+ end
13
+ end
14
+ respond("I didn't find any command starting by `#{help_command}`", dest) unless help_found
15
+ else
16
+ message = "-\n\n\n===================================\n*Rules from channel #{CHANNEL}*\n"
17
+ if typem == :on_extended
18
+ message += "To run the commands on this extended channel, add `!` before the command.\n"
19
+ end
20
+ message += help_filtered
21
+ respond message, dest
22
+ end
23
+
24
+ unless rules_file.empty?
25
+ begin
26
+ eval(File.new(rules_file).read) if File.exist?(rules_file)
27
+ end
28
+ end
29
+ if defined?(git_project) and git_project.to_s != "" and help_message_rules != "" and help_command.to_s == ""
30
+ respond "Git project: #{git_project}", dest
31
+ else
32
+ def git_project() "" end
33
+ def project_folder() "" end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ class SlackSmartBot
2
+ # helpmaster: ----------------------------------------------
3
+ # helpmaster: `kill bot on CHANNEL_NAME`
4
+ # helpmaster: kills the bot on the specified channel
5
+ # helpmaster: Only works if you are on Master channel and you created that bot or you are an admin user
6
+ # helpmaster:
7
+ def kill_bot_on_channel(dest, from, channel)
8
+ if ON_MASTER_BOT
9
+ get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
10
+ channel_id = nil
11
+ if @channels_name.key?(channel) #it is an id
12
+ channel_id = channel
13
+ channel = @channels_name[channel_id]
14
+ elsif @channels_id.key?(channel) #it is a channel name
15
+ channel_id = @channels_id[channel]
16
+ end
17
+ if channel_id.nil?
18
+ respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
19
+ elsif @bots_created.keys.include?(channel_id)
20
+ if @bots_created[channel_id][:admins].split(",").include?(from)
21
+ if @bots_created[channel_id][:thread].kind_of?(Thread) and @bots_created[channel_id][:thread].alive?
22
+ @bots_created[channel_id][:thread].kill
23
+ end
24
+ @bots_created.delete(channel_id)
25
+ update_bots_file()
26
+ respond "Bot on channel: #{channel}, has been killed and deleted.", dest
27
+ send_msg_channel(channel, "Bot has been killed by #{from}")
28
+ else
29
+ respond "You need to be the creator or an admin of that bot channel", dest
30
+ end
31
+ else
32
+ respond "There is no bot in this channel: #{channel}", dest
33
+ end
34
+ else
35
+ respond "Sorry I cannot kill bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ class SlackSmartBot
2
+
3
+ # helpadmin: ----------------------------------------------
4
+ # helpadmin: `exit bot`
5
+ # helpadmin: `quit bot`
6
+ # helpadmin: `close bot`
7
+ # helpadmin: The bot stops running and also stops all the bots created from this master channel
8
+ # helpadmin: You can use this command only if you are an admin user and you are on the master channel
9
+ # helpadmin:
10
+ def exit_bot(command, from, dest, display_name)
11
+ if ON_MASTER_BOT
12
+ if ADMIN_USERS.include?(from) #admin user
13
+ unless @questions.keys.include?(from)
14
+ ask("are you sure?", command, from, dest)
15
+ else
16
+ case @questions[from]
17
+ when /yes/i, /yep/i, /sure/i
18
+ respond "Game over!", dest
19
+ respond "Ciao #{display_name}!", dest
20
+ @bots_created.each { |key, value|
21
+ value[:thread] = ""
22
+ send_msg_channel(key, "Bot has been closed by #{from}")
23
+ sleep 0.5
24
+ }
25
+ update_bots_file()
26
+ sleep 0.5
27
+ exit!
28
+ when /no/i, /nope/i, /cancel/i
29
+ @questions.delete(from)
30
+ respond "Thanks, I'm happy to be alive", dest
31
+ else
32
+ ask("I don't understand, are you sure do you want me to close? (yes or no)", command, from, dest)
33
+ end
34
+ end
35
+ else
36
+ respond "Only admin users can kill me", dest
37
+ end
38
+ else
39
+ respond "To do this you need to be an admin user in the master channel: <##{@master_bot_id}>", dest
40
+ end
41
+ end
42
+ end