slack-smart-bot 1.10.0 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +91 -21
  3. data/lib/slack/smart-bot/comm/delete.rb +13 -0
  4. data/lib/slack/smart-bot/comm/dont_understand.rb +2 -2
  5. data/lib/slack/smart-bot/comm/get_channel_members.rb +7 -3
  6. data/lib/slack/smart-bot/comm/get_presence.rb +20 -0
  7. data/lib/slack/smart-bot/comm/get_users.rb +1 -1
  8. data/lib/slack/smart-bot/comm/respond.rb +18 -13
  9. data/lib/slack/smart-bot/comm/send_msg_user.rb +12 -11
  10. data/lib/slack/smart-bot/comm.rb +2 -0
  11. data/lib/slack/smart-bot/commands/general/add_admin.rb +51 -0
  12. data/lib/slack/smart-bot/commands/general/add_announcement.rb +1 -1
  13. data/lib/slack/smart-bot/commands/general/add_team.rb +80 -0
  14. data/lib/slack/smart-bot/commands/general/allow_access.rb +67 -0
  15. data/lib/slack/smart-bot/commands/general/bot_help.rb +20 -11
  16. data/lib/slack/smart-bot/commands/general/delete_announcement.rb +1 -1
  17. data/lib/slack/smart-bot/commands/general/delete_share.rb +1 -1
  18. data/lib/slack/smart-bot/commands/general/delete_team.rb +34 -0
  19. data/lib/slack/smart-bot/commands/general/deny_access.rb +36 -0
  20. data/lib/slack/smart-bot/commands/general/ping_team.rb +100 -0
  21. data/lib/slack/smart-bot/commands/general/poster.rb +116 -0
  22. data/lib/slack/smart-bot/commands/general/remove_admin.rb +58 -0
  23. data/lib/slack/smart-bot/commands/general/see_access.rb +24 -0
  24. data/lib/slack/smart-bot/commands/general/see_admins.rb +33 -0
  25. data/lib/slack/smart-bot/commands/general/see_announcements.rb +6 -4
  26. data/lib/slack/smart-bot/commands/general/see_command_ids.rb +29 -0
  27. data/lib/slack/smart-bot/commands/general/see_favorite_commands.rb +3 -4
  28. data/lib/slack/smart-bot/commands/general/see_statuses.rb +34 -21
  29. data/lib/slack/smart-bot/commands/general/see_teams.rb +252 -0
  30. data/lib/slack/smart-bot/commands/general/share_messages.rb +1 -1
  31. data/lib/slack/smart-bot/commands/general/update_team.rb +109 -0
  32. data/lib/slack/smart-bot/commands/general_bot_commands.rb +271 -10
  33. data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +2 -1
  34. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +2 -1
  35. data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +2 -1
  36. data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +2 -1
  37. data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +2 -1
  38. data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +2 -1
  39. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +3 -2
  40. data/lib/slack/smart-bot/commands/on_bot/admin/see_result_routine.rb +2 -1
  41. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +10 -9
  42. data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +2 -1
  43. data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +2 -1
  44. data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +2 -1
  45. data/lib/slack/smart-bot/commands/on_bot/admin_master/delete_message.rb +25 -0
  46. data/lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb +1 -0
  47. data/lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb +3 -1
  48. data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +15 -2
  49. data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +2 -1
  50. data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +5 -4
  51. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +400 -0
  52. data/lib/slack/smart-bot/commands/{general → on_bot/general}/bot_status.rb +1 -0
  53. data/lib/slack/smart-bot/commands/{general → on_bot/general}/leaderboard.rb +1 -0
  54. data/lib/slack/smart-bot/commands/{general → on_bot/general}/stop_using_rules.rb +1 -0
  55. data/lib/slack/smart-bot/commands/{general → on_bot/general}/suggest_command.rb +6 -0
  56. data/lib/slack/smart-bot/commands/{general → on_bot/general}/use_rules.rb +1 -0
  57. data/lib/slack/smart-bot/commands/{general → on_bot/general}/whats_new.rb +2 -1
  58. data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +2 -1
  59. data/lib/slack/smart-bot/commands/on_bot/repl.rb +72 -15
  60. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +1 -0
  61. data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +11 -2
  62. data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +2 -1
  63. data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +3 -2
  64. data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +5 -4
  65. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +3 -2
  66. data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +2 -1
  67. data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +3 -2
  68. data/lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb +2 -1
  69. data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +2 -1
  70. data/lib/slack/smart-bot/commands/on_master/create_bot.rb +1 -0
  71. data/lib/slack/smart-bot/commands/on_master/where_smartbot.rb +41 -0
  72. data/lib/slack/smart-bot/commands.rb +22 -7
  73. data/lib/slack/smart-bot/listen.rb +30 -30
  74. data/lib/slack/smart-bot/process.rb +38 -18
  75. data/lib/slack/smart-bot/process_first.rb +2 -2
  76. data/lib/slack/smart-bot/treat_message.rb +13 -17
  77. data/lib/slack/smart-bot/utils/build_help.rb +1 -1
  78. data/lib/slack/smart-bot/utils/create_routine_thread.rb +1 -1
  79. data/lib/slack/smart-bot/utils/get_access_channels.rb +13 -0
  80. data/lib/slack/smart-bot/utils/get_admins_channels.rb +13 -0
  81. data/lib/slack/smart-bot/utils/get_bots_created.rb +27 -10
  82. data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +7 -2
  83. data/lib/slack/smart-bot/utils/get_command_ids.rb +84 -0
  84. data/lib/slack/smart-bot/utils/get_help.rb +34 -18
  85. data/lib/slack/smart-bot/utils/get_repls.rb +22 -2
  86. data/lib/slack/smart-bot/utils/get_routines.rb +22 -2
  87. data/lib/slack/smart-bot/utils/get_teams.rb +22 -0
  88. data/lib/slack/smart-bot/utils/has_access.rb +25 -9
  89. data/lib/slack/smart-bot/utils/is_admin.rb +27 -0
  90. data/lib/slack/smart-bot/utils/save_stats.rb +46 -43
  91. data/lib/slack/smart-bot/utils/save_status.rb +21 -6
  92. data/lib/slack/smart-bot/utils/update_access_channels.rb +8 -0
  93. data/lib/slack/smart-bot/utils/update_admins_channels.rb +8 -0
  94. data/lib/slack/smart-bot/utils/update_bots_file.rb +28 -7
  95. data/lib/slack/smart-bot/utils/update_repls.rb +7 -4
  96. data/lib/slack/smart-bot/utils/update_routines.rb +9 -3
  97. data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +13 -6
  98. data/lib/slack/smart-bot/utils/update_teams.rb +16 -0
  99. data/lib/slack/smart-bot/utils.rb +8 -0
  100. data/lib/slack-smart-bot.rb +28 -10
  101. data/lib/slack-smart-bot_general_commands.rb +16 -1
  102. data/whats_new.txt +16 -29
  103. metadata +64 -19
  104. data/lib/slack/smart-bot/commands/general/bot_stats.rb +0 -314
@@ -1,12 +1,28 @@
1
1
  class SlackSmartBot
2
- def has_access?(method, user=nil)
3
- user = Thread.current[:user] if user.nil?
4
- if config[:allow_access].key?(method) and !config[:allow_access][method].include?(user.name) and !config[:allow_access][method].include?(user.id) and
5
- (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][method].include?(user[:enterprise_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
- return false
2
+ def has_access?(method, user = nil)
3
+ user = Thread.current[:user] if user.nil?
4
+ if config[:allow_access].key?(method) and !config[:allow_access][method].include?(user.name) and !config[:allow_access][method].include?(user.id) and
5
+ (!user.key?(:enterprise_user) or (user.key?(:enterprise_user) and !config[:allow_access][method].include?(user[:enterprise_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
+ return false
8
+ else
9
+ if Thread.current[:typem] == :on_call
10
+ channel = Thread.current[:dchannel]
11
+ elsif Thread.current[:using_channel].to_s == ""
12
+ channel = Thread.current[:dest]
13
+ else
14
+ channel = Thread.current[:using_channel]
15
+ end
16
+ if !@access_channels.key?(channel) or !@access_channels[channel].key?(method.to_s) or @access_channels[channel][method.to_s].include?(user.name)
17
+ return true
18
+ else
19
+ if @admins_channels.key?(channel) and !@admins_channels[channel].empty?
20
+ respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{@admins_channels[channel].join(">, <@")}>"
8
21
  else
9
- return true
10
- end
22
+ respond "You don't have access to use this command, please contact an Admin to be able to use it."
23
+ end
24
+ return false
25
+ end
11
26
  end
12
- end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ class SlackSmartBot
2
+ def is_admin?(from=nil)
3
+ if from.nil?
4
+ user = Thread.current[:user]
5
+ from = user.name
6
+ end
7
+
8
+ if (Thread.current[:dchannel].to_s!='' and !@channels_creator.key?(Thread.current[:dchannel])) or
9
+ (Thread.current[:dest].to_s!='' and Thread.current[:dest][0]!='D' and !@channels_creator.key?(Thread.current[:dest])) or
10
+ (Thread.current[:using_channel].to_s!='' and !@channels_creator.key?(:using_channel))
11
+ get_channels_name_and_id()
12
+ end
13
+
14
+ if config.masters.include?(from) or
15
+ config.admins.include?(from) or
16
+ (Thread.current[:typem] == :on_call and @admins_channels.key?(Thread.current[:dchannel]) and @admins_channels[Thread.current[:dchannel]].include?(from)) or
17
+ (Thread.current[:using_channel].to_s == '' and @admins_channels.key?(Thread.current[:dest]) and @admins_channels[Thread.current[:dest]].include?(from)) or
18
+ (@admins_channels.key?(Thread.current[:using_channel]) and @admins_channels[Thread.current[:using_channel]].include?(from)) or
19
+ (Thread.current[:using_channel].to_s=='' and @channels_creator.key?(Thread.current[:dest]) and from == @channels_creator[Thread.current[:dest]]) or
20
+ (Thread.current[:typem] == :on_call and @channels_creator.key?(Thread.current[:dchannel]) and from == @channels_creator[Thread.current[:dchannel]]) or
21
+ (@channels_creator.key?(Thread.current[:using_channel]) and from == @channels_creator[Thread.current[:using_channel]])
22
+ return true
23
+ else
24
+ return false
25
+ end
26
+ end
27
+ end
@@ -1,47 +1,50 @@
1
1
  class SlackSmartBot
2
-
3
- def save_stats(method, data: {})
4
- if config.stats
5
- begin
6
- require 'csv'
7
- if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
8
- CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", 'wb') do |csv|
9
- csv << ['date','bot_channel', 'bot_channel_id', 'dest_channel', 'dest_channel_id', 'type_message', 'user_name', 'user_id', 'text', 'command', 'files']
10
- end
11
- end
12
- if data.empty?
13
- data = {
14
- dest: Thread.current[:dest],
15
- typem: Thread.current[:typem],
16
- user: Thread.current[:user],
17
- files: Thread.current[:files?],
18
- command: Thread.current[:command],
19
- routine: Thread.current[:routine]
20
- }
21
- end
22
- if method.to_s == 'ruby_code' and data.files
23
- command_txt = 'ruby'
24
- else
25
- command_txt = data.command
26
- end
27
- command_txt.gsub!(/```.+```/m,'```CODE```')
28
- command_txt = "#{command_txt[0..99]}..." if command_txt.size > 100
29
-
30
- if data.routine
31
- user_name = "routine/#{data.user.name}"
32
- user_id = "routine/#{data.user.id}"
33
- else
34
- user_name = data.user.name
35
- user_id = data.user.id
36
- end
37
- CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "a+") do |csv|
38
- csv << [Time.now, config.channel, @channel_id, @channels_name[data.dest], data.dest, data.typem, user_name, user_id, command_txt, method, data.files]
39
- end
40
- rescue Exception => exception
41
- @logger.fatal "There was a problem on the stats"
42
- @logger.fatal exception
2
+ def save_stats(method, data: {})
3
+ if has_access?(method, Thread.current[:user])
4
+ if config.stats
5
+ begin
6
+ require "csv"
7
+ if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
8
+ CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "wb") do |csv|
9
+ csv << ["date", "bot_channel", "bot_channel_id", "dest_channel", "dest_channel_id", "type_message", "user_name", "user_id", "text", "command", "files"]
43
10
  end
11
+ end
12
+ if data.empty?
13
+ data = {
14
+ dest: Thread.current[:dest],
15
+ typem: Thread.current[:typem],
16
+ user: Thread.current[:user],
17
+ files: Thread.current[:files?],
18
+ command: Thread.current[:command],
19
+ routine: Thread.current[:routine],
20
+ }
21
+ end
22
+ if method.to_s == "ruby_code" and data.files
23
+ command_txt = "ruby"
24
+ else
25
+ command_txt = data.command
26
+ end
27
+ command_txt.gsub!(/```.+```/m, "```CODE```")
28
+ command_txt = "#{command_txt[0..99]}..." if command_txt.size > 100
29
+
30
+ if data.routine
31
+ user_name = "routine/#{data.user.name}"
32
+ user_id = "routine/#{data.user.id}"
33
+ else
34
+ user_name = data.user.name
35
+ user_id = data.user.id
36
+ end
37
+ CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "a+") do |csv|
38
+ csv << [Time.now, config.channel, @channel_id, @channels_name[data.dest], data.dest, data.typem, user_name, user_id, command_txt, method, data.files]
39
+ end
40
+ rescue Exception => exception
41
+ @logger.fatal "There was a problem on the stats"
42
+ @logger.fatal exception
44
43
  end
44
+ end
45
+ else
46
+ sleep 0.2
47
+ Thread.exit
45
48
  end
46
-
47
- end
49
+ end
50
+ end
@@ -7,12 +7,23 @@ class SlackSmartBot
7
7
  CSV.open("#{config.path}/status/#{config.channel}_status.csv", "a+") do |csv|
8
8
  csv << [Time.now.strftime("%Y/%m/%d"), Time.now.strftime("%H:%M:%S"), status, status_id, message]
9
9
  end
10
+ if defined?(@channels_list) #wait until the 'client' started
11
+ channel_info = @channels_list.select { |c| c.id == @channel_id}[-1]
12
+ if channel_info.nil? or channel_info.is_private
13
+ channel_link = "##{config.channel}"
14
+ else
15
+ channel_link = "<##{@channel_id}|#{config.channel}>"
16
+ end
17
+ else
18
+ channel_link = "##{config.channel}"
19
+ end
20
+
10
21
  if status_id == :disconnected
11
22
  Thread.new do
12
23
  sleep 50
13
24
  @logger.info "check disconnection 50 scs later #{@last_notified_status_id}"
14
25
  unless @last_notified_status_id == :connected
15
- respond ":red_circle: The *SmartBot* on *<##{@channel_id}|#{config.channel}>* is down. An admin will take a look. <@#{config.admins.join(">, <@")}>", config.status_channel
26
+ respond ":red_circle: The *SmartBot* on *#{channel_link}* is down. An admin will take a look. <@#{config.admins.join(">, <@")}>", config.status_channel
16
27
  end
17
28
  end
18
29
  end
@@ -22,20 +33,24 @@ class SlackSmartBot
22
33
  if (Time.now-@last_status_change) > 20 or !defined?(@last_notified_status_id)
23
34
  if status_id == :connected
24
35
  if defined?(@last_notified_status_id)
25
- m = ":exclamation: :large_green_circle: The *SmartBot* on *<##{@channel_id}|#{config.channel}>* was not available for #{(Time.now-@last_status_change).round(0)} secs. *Now it is up and running again.*"
36
+ m = ":exclamation: :large_green_circle: The *SmartBot* on *#{channel_link}* was not available for #{(Time.now-@last_status_change).round(0)} secs. *Now it is up and running again.*"
26
37
  else
27
- m = ":large_green_circle: The *SmartBot* on *<##{@channel_id}|#{config.channel}>* is up and running again."
38
+ m = ":large_green_circle: The *SmartBot* on *#{channel_link}* is up and running again."
28
39
  end
29
40
  end
30
41
  end
31
42
  if status_id == :paused
32
- m = ":red_circle: #{message} *<##{@channel_id}|#{config.channel}>*"
43
+ m = ":red_circle: #{message} *#{channel_link}*"
33
44
  elsif status_id == :started
34
- m = ":large_green_circle: #{message} *<##{@channel_id}|#{config.channel}>*"
45
+ m = ":large_green_circle: #{message} *#{channel_link}*"
35
46
  elsif status_id == :killed or status_id == :exited
36
47
  m = ":red_circle: #{message}"
37
48
  elsif config.on_master_bot and status_id == :maintenance_on
38
- m = ":red_circle: The *SmartBot* is on maintenance so not possible to attend any request."
49
+ if message.to_s == "Sorry I'm on maintenance so I cannot attend your request."
50
+ m = ":red_circle: The *SmartBot* is on maintenance so not possible to attend any request."
51
+ else
52
+ m = ":red_circle: #{message}"
53
+ end
39
54
  elsif config.on_master_bot and status_id == :maintenance_off
40
55
  m = ":large_green_circle: The *SmartBot* is up and running again."
41
56
  end
@@ -0,0 +1,8 @@
1
+ class SlackSmartBot
2
+
3
+ def update_access_channels()
4
+ file = File.open("#{config.path}/rules/#{@channel_id}/access_channels.rb", "w")
5
+ file.write (@access_channels.inspect)
6
+ file.close
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class SlackSmartBot
2
+
3
+ def update_admins_channels()
4
+ file = File.open("#{config.path}/rules/#{@channel_id}/admins_channels.rb", "w")
5
+ file.write (@admins_channels.inspect)
6
+ file.close
7
+ end
8
+ end
@@ -1,11 +1,32 @@
1
1
  class SlackSmartBot
2
2
  def update_bots_file
3
- file = File.open(config.file_path.gsub(".rb", "_bots.rb"), "w")
4
- bots_created = @bots_created.dup
5
- bots_created.each { |k, v|
6
- v[:thread] = ""
7
- }
8
- file.write bots_created.inspect
9
- file.close
3
+ bots_file = config.file_path.gsub(".rb", "_bots.yaml")
4
+
5
+ if File.exist?(config.file_path.gsub(".rb", "_bots.rb")) #backwards compatible
6
+ file_conf = IO.readlines(config.file_path.gsub(".rb", "_bots.rb")).join
7
+ if file_conf.to_s() == ""
8
+ @bots_created = {}
9
+ else
10
+ @bots_created = eval(file_conf)
11
+ end
12
+ File.open(bots_file, 'w') {|file|
13
+ file.flock(File::LOCK_EX)
14
+ file.write(@bots_created.to_yaml)
15
+ file.flock(File::LOCK_UN)
16
+ }
17
+ File.delete(config.file_path.gsub(".rb", "_bots.rb"))
18
+ else
19
+ #not possible to use @bots_created.deep_copy since one of the fields contains a thread
20
+ bots_created = {}
21
+ @bots_created.each do |k,v|
22
+ bots_created[k] = v.dup
23
+ bots_created[k][:thread] = ''
24
+ end
25
+ File.open(bots_file, 'w') {|file|
26
+ file.flock(File::LOCK_EX)
27
+ file.write(bots_created.to_yaml)
28
+ file.flock(File::LOCK_UN)
29
+ }
30
+ end
10
31
  end
11
32
  end
@@ -1,8 +1,11 @@
1
1
  class SlackSmartBot
2
-
3
2
  def update_repls(channel = @channel_id)
4
- file = File.open("#{config.path}/repl/repls_#{channel}.rb", "w")
5
- file.write (@repls.inspect)
6
- file.close
3
+ require 'yaml'
4
+ repl_file = "#{config.path}/repl/repls_#{channel}.yaml"
5
+ File.open(repl_file, 'w') {|file|
6
+ file.flock(File::LOCK_EX)
7
+ file.write(@repls.to_yaml)
8
+ file.flock(File::LOCK_UN)
9
+ }
7
10
  end
8
11
  end
@@ -1,8 +1,11 @@
1
1
  class SlackSmartBot
2
2
 
3
3
  def update_routines(channel = @channel_id)
4
+
5
+ require 'yaml'
6
+ routines_file = "#{config.path}/routines/routines_#{channel}.yaml"
7
+
4
8
  routines = {}
5
- file = File.open("#{config.path}/routines/routines_#{channel}.rb", "w")
6
9
  @routines.each do |k,v|
7
10
  routines[k]={}
8
11
  v.each do |kk,vv|
@@ -10,7 +13,10 @@ class SlackSmartBot
10
13
  routines[k][kk][:thread]=""
11
14
  end
12
15
  end
13
- file.write (routines.inspect)
14
- file.close
16
+ File.open(routines_file, 'w') {|file|
17
+ file.flock(File::LOCK_EX)
18
+ file.write(routines.to_yaml)
19
+ file.flock(File::LOCK_UN)
20
+ }
15
21
  end
16
22
  end
@@ -1,13 +1,20 @@
1
1
  class SlackSmartBot
2
2
  def update_shortcuts_file
3
- file = File.open("#{config.path}/shortcuts/#{config.shortcuts_file}", "w")
4
- file.write @shortcuts.inspect
5
- file.close
3
+ require 'yaml'
4
+ sc_file = "#{config.path}/shortcuts/#{config.shortcuts_file}"
5
+ File.open(sc_file, 'w') {|file|
6
+ file.flock(File::LOCK_EX)
7
+ file.write(@shortcuts.to_yaml)
8
+ file.flock(File::LOCK_UN)
9
+ }
6
10
 
7
11
  if config.on_master_bot
8
- file = File.open("#{config.path}/shortcuts/shortcuts_global.rb", "w")
9
- file.write @shortcuts_global.inspect
10
- file.close
12
+ sc_file = "#{config.path}/shortcuts/shortcuts_global.yaml"
13
+ File.open(sc_file, 'w') {|file|
14
+ file.flock(File::LOCK_EX)
15
+ file.write(@shortcuts_global.to_yaml)
16
+ file.flock(File::LOCK_UN)
17
+ }
11
18
  end
12
19
  end
13
20
  end
@@ -0,0 +1,16 @@
1
+ class SlackSmartBot
2
+ def update_teams(team=nil)
3
+ require 'yaml'
4
+ unless team.nil?
5
+ get_teams()
6
+ @teams.merge!(team)
7
+ end
8
+ teams_file = config.file_path.gsub(".rb", "_teams.yaml")
9
+ File.open(teams_file, 'w') {|file|
10
+ file.flock(File::LOCK_EX)
11
+ file.write(@teams.to_yaml)
12
+ file.flock(File::LOCK_UN)
13
+ }
14
+ @datetime_teams_file = File.mtime(teams_file)
15
+ end
16
+ end
@@ -18,4 +18,12 @@ require_relative 'utils/answer'
18
18
  require_relative 'utils/answer_delete'
19
19
  require_relative 'utils/has_access'
20
20
  require_relative 'utils/save_status'
21
+ require_relative 'utils/get_admins_channels'
22
+ require_relative 'utils/update_admins_channels'
23
+ require_relative 'utils/is_admin'
24
+ require_relative 'utils/get_access_channels'
25
+ require_relative 'utils/update_access_channels'
26
+ require_relative 'utils/get_command_ids'
27
+ require_relative 'utils/get_teams'
28
+ require_relative 'utils/update_teams'
21
29
 
@@ -9,6 +9,7 @@ require "open3"
9
9
  require "nice_http"
10
10
  require "nice_hash"
11
11
  require 'cgi'
12
+ require 'yaml'
12
13
 
13
14
  require_relative "slack/smart-bot/comm"
14
15
  require_relative "slack/smart-bot/listen"
@@ -66,6 +67,7 @@ class SlackSmartBot
66
67
  Dir.mkdir("#{config.path}/routines") unless Dir.exist?("#{config.path}/routines")
67
68
  Dir.mkdir("#{config.path}/announcements") unless Dir.exist?("#{config.path}/announcements")
68
69
  Dir.mkdir("#{config.path}/shares") unless Dir.exist?("#{config.path}/shares")
70
+ Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
69
71
  File.delete("#{config.path}/config_tmp.status") if File.exist?("#{config.path}/config_tmp.status")
70
72
 
71
73
  config.masters = MASTER_USERS if config.masters.to_s=='' and defined?(MASTER_USERS)
@@ -77,7 +79,7 @@ class SlackSmartBot
77
79
  default_rules = (__FILE__).gsub(/\.rb$/, "_rules.rb")
78
80
  FileUtils.copy_file(default_rules, config.path + '/' + config.rules_file)
79
81
  end
80
- config.admins = config.masters unless config.admins.to_s!=''
82
+ config.admins = config.masters.dup unless config.admins.to_s!=''
81
83
  config.channel = config.master_channel unless config.channel.to_s!=''
82
84
  config.status_init = :on unless config.status_init.to_s!=''
83
85
  else
@@ -89,7 +91,7 @@ class SlackSmartBot
89
91
  config.rules_file[0]='' if config.rules_file[0]=='.'
90
92
  config.rules_file='/'+config.rules_file if config.rules_file[0]!='/'
91
93
 
92
- config.shortcuts_file = "slack-smart-bot_shortcuts_#{config.channel}.rb".gsub(" ", "_")
94
+ config.shortcuts_file = "slack-smart-bot_shortcuts_#{config.channel}.yaml".gsub(" ", "_")
93
95
  if config.channel == config.master_channel
94
96
  config.on_master_bot = true
95
97
  config.start_bots = true unless config.key?(:start_bots)
@@ -140,7 +142,7 @@ class SlackSmartBot
140
142
  else
141
143
  if config.logrtm
142
144
  logrtmname = "#{config.path}/logs/rtm_#{config.channel}.log"
143
- File.delete(logrtmname) if File.exists?(logrtmname)
145
+ File.delete(logrtmname) if File.exist?(logrtmname)
144
146
  @logrtm = Logger.new(logrtmname)
145
147
  self.client = Slack::RealTime::Client.new(start_method: :rtm_connect, logger: @logrtm)
146
148
  else
@@ -179,24 +181,34 @@ class SlackSmartBot
179
181
  @shares = Hash.new()
180
182
  @last_status_change = Time.now
181
183
 
182
-
183
- if File.exist?("#{config.path}/shortcuts/#{config.shortcuts_file}")
184
- file_sc = IO.readlines("#{config.path}/shortcuts/#{config.shortcuts_file}").join
185
- unless file_sc.to_s() == ""
186
- @shortcuts = eval(file_sc)
184
+ if File.exist?("#{config.path}/shortcuts/#{config.shortcuts_file}".gsub('.yaml','.rb')) #backwards compatible
185
+ file_conf = IO.readlines("#{config.path}/shortcuts/#{config.shortcuts_file}".gsub('.yaml','.rb')).join
186
+ if file_conf.to_s() == ""
187
+ @shortcuts = {}
188
+ else
189
+ @shortcuts = eval(file_conf)
187
190
  end
191
+ File.open("#{config.path}/shortcuts/#{config.shortcuts_file}", 'w') {|file| file.write(@shortcuts.to_yaml) }
192
+ File.delete("#{config.path}/shortcuts/#{config.shortcuts_file}".gsub('.yaml','.rb'))
193
+ elsif File.exist?("#{config.path}/shortcuts/#{config.shortcuts_file}")
194
+ @shortcuts = YAML.load(File.read("#{config.path}/shortcuts/#{config.shortcuts_file}"))
188
195
  end
189
- if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb")
196
+ if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb") #backwards compatible
190
197
  file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join
198
+ @shortcuts_global = {}
191
199
  unless file_sc.to_s() == ""
192
200
  @shortcuts_global = eval(file_sc)
193
201
  end
202
+ File.open("#{config.path}/shortcuts/shortcuts_global.yaml", 'w') {|file| file.write(@shortcuts_global.to_yaml) }
203
+ File.delete("#{config.path}/shortcuts/shortcuts_global.rb")
204
+ elsif File.exist?("#{config.path}/shortcuts/shortcuts_global.yaml")
205
+ @shortcuts_global = YAML.load(File.read("#{config.path}/shortcuts/shortcuts_global.yaml"))
194
206
  end
195
207
 
196
208
  get_routines()
197
209
  get_repls()
198
210
 
199
- if config.on_master_bot and File.exist?(config.file_path.gsub(".rb", "_bots.rb"))
211
+ if config.on_master_bot and (File.exist?(config.file_path.gsub(".rb", "_bots.rb")) or File.exist?(config.file_path.gsub('.rb', '_bots.yaml')))
200
212
  get_bots_created()
201
213
  if @bots_created.kind_of?(Hash) and config.start_bots
202
214
  @bots_created.each { |key, value|
@@ -270,13 +282,19 @@ class SlackSmartBot
270
282
  @datetime_general_commands = 0
271
283
  @channels_id = Hash.new()
272
284
  @channels_name = Hash.new()
285
+ @channels_creator = Hash.new()
286
+ @channels_list = Hash.new()
273
287
  get_channels_name_and_id()
274
288
  @channel_id = @channels_id[config.channel].dup
275
289
  @master_bot_id = @channels_id[config.master_channel].dup
276
290
 
291
+ Dir.mkdir("#{config.path}/rules/#{@channel_id}") unless Dir.exist?("#{config.path}/rules/#{@channel_id}/")
292
+
277
293
  get_routines()
278
294
  get_repls()
279
295
  get_shares()
296
+ get_admins_channels()
297
+ get_access_channels()
280
298
 
281
299
  if @routines.key?(@channel_id)
282
300
  @routines[@channel_id].each do |k, v|
@@ -21,7 +21,7 @@ def general_commands(user, command, dest, files = [])
21
21
 
22
22
 
23
23
  # this is a hidden command that it is not listed when calling bot help
24
- when /\A\s*(that's\s+)?(thanks|thank\s+you|I\s+love\s+you|nice|cool)\s+(#{@salutations.join("|")})\s*!*\s*$/i
24
+ when /\s*(that's\s+)?(thanks|thank\s+you|I\s+love\s+you|nice|cool)\s+(#{@salutations.join("|")})\s*!*\s*$/i
25
25
  save_stats :thanks
26
26
  reactions = [:heart, :heart_eyes, :blush, :relaxed, :simple_smile, :smiley, :two_hearts, :heartbeat, :green_heart ]
27
27
  reactions.sample(rand(3)+1).each {|rt| react rt }
@@ -30,6 +30,21 @@ def general_commands(user, command, dest, files = [])
30
30
  'Það var ekkert', 'De nada', 'No hay de qué', 'De rien', 'Bitte', 'Prego', 'मेरा सौभाग्य है', '不客氣', 'Παρακαλώ']
31
31
  respond "#{responses.sample}#{'!'*rand(4)}"
32
32
 
33
+ # this is a hidden command that it is not listed when calling bot help
34
+ when /\s*.*happy\s+birthday.*(<@\w+>)\s*.*$/i, /\s*.*(<@\w+>).*happy\s+birthday\s*.*$/i
35
+ unless Thread.current[:on_thread]
36
+ save_stats :happy_birthday
37
+ happy_user = $1
38
+ reactions = [:tada, :cake, :birthday]
39
+ sleep 30
40
+ reactions.sample(rand(3)+1).each {|rt| react rt }
41
+ sleep (rand(10)+5)*60 # so SmartBot is not the first one
42
+ responses = ['Happy birthday', "Very happy birthday", "Happy happy happy birthday", "Have a fabulous birthday", 'May all your wishes come true',
43
+ 'Many happy returns of the day', 'I wish you a wonderful birthday', 'Have a great one', 'I hope you have a fantastic day and a fantastic year to come',
44
+ 'To your happiness', "Don't count the candles. Enjoy the party", 'May your day be as awesome as you are', 'The best things in life are yet to come']
45
+ respond "#{happy_user} #{responses.sample}#{'!'*rand(4)}", :on_thread
46
+ end
47
+
33
48
  else
34
49
  return false
35
50
  end
data/whats_new.txt CHANGED
@@ -1,36 +1,23 @@
1
- *Version 1.10.0* Released 2021-Sep-17
1
+ *Version 1.11.0* Released 2022-May-09
2
2
 
3
3
  *For General users*
4
- - When on a private conversation with the SmartBot (DM) and not using any channels rule on the conversation, the general_rules will be available.
5
- - On DM with the SmartBot if you want to use a rule from a specific channel you can use also: `#CHANNEL RULE` or `on #CHANNEL RULE`. For example: `#sales get report for India`
6
- - Now when using general commands, the SmartBot will be responding on any channel where is a member, even though is not listening to you. For example: `clear screen`
7
- - Added command `suggest command` that will return the help content for a random command.
8
- - New command `leaderboard` returns useful information about the use of the SmartBot.
9
- - `add COLOR announcement MESSAGE`, `add EMOJI announcement MESSAGE` command stores the message on the announcement list labeled with the color/emoji specified, white by default. Aliases for announcement: statement, declaration, message. Related: `see announcements`, `delete announcement id`
10
- - `hi bot` and `bye bot` can be called from any channel where the SmartBot is a member.
11
- - Added general command `see statuses`, `who is on vacation?`, `who is not on vacation?`
12
- - New general command `see favorite commands`. It will display the favorite commands in that channel.
13
- - Now when running the `ruby` command it can be supplied a code block.
14
- - New general command `share messages /REGEXP/ on #CHANNEL`, `share messages "TEXT" on #CHANNEL`, `see shares', `delete share ID`. It will automatically share new messages published that meet the specified criteria.
4
+ - `run repl` displays results as code in case a value on stdout is returned as Hash or Array (<https://github.com/MarioRuiz/slack-smart-bot/issues/41|#41>).
5
+ - `repl` command displays results when using iterators and printing results (<https://github.com/MarioRuiz/slack-smart-bot/issues/35|#35>).
6
+ - `see command ids` will return the command ids. (<https://github.com/MarioRuiz/slack-smart-bot/issues/43|#43>)
7
+ - `poster MESSAGE`, `poster :EMOTICON_TEXT: MESSAGE`, `poster :EMOTICON_TEXT: :EMOTICON_BACKGROUND: MESSAGE`, `poster MINUTESm MESSAGE` It will create a poster with the message supplied. By default will be autodeleted 1 minute later. (<https://github.com/MarioRuiz/slack-smart-bot/issues/34|#34>)
8
+ - `who is available?` show members of the channel that are on line and not on a meeting or vacation or sick. (<https://github.com/MarioRuiz/slack-smart-bot/issues/52|#52>)
9
+ - You can add, update, see, ping, contact, and delete teams. When calling `see TEAM_NAME team` the availability of the members will be displayed. Call `bot help teams` for more info. (<https://github.com/MarioRuiz/slack-smart-bot/issues/53|#53>)
10
+ - repl improvements (<https://github.com/MarioRuiz/slack-smart-bot/issues/54|#54>)
11
+ - new Master command `where is smartbot?` will return the channels where the SmartBot is a member. (<https://github.com/MarioRuiz/slack-smart-bot/issues/56|#56>)
15
12
 
16
13
  *For Admin users*
17
- - respond_thread method will send the respond creating a thread if necessary. It can be used also `respond 'msg', :on_thread`
18
- - `respond 'msg', :direct` will send a direct message to the person that is executing the rule.
19
- - You can add general commands that will be responding on any channel where the Smart Bot is a member even though is not 'listening to you'. Add them to '/rules/general_commands.rb
20
- - when using `respond` you can supply two options: unfurl_links and unfurl_media. By default is a boolean: true
21
- - added option 'weekdays' and 'weekends' for `create routine` command, for example: `add silent routine suggestions on weekdays at 09:00 suggest command`
22
- - Added a new config for the SmartBot to log all RTM communication, admits `true` or `false`, by default `false`: `logrtm`
23
- - Use the command `send message to` and `react to` to impersonate the SmartBot. Only accessible for Master Admins on a DM with the SmartBot.
24
- - New command to see the result of the last run of a routine: `see result routine NAME`
25
- - Now it is possible to create *bgroutine* then the results of the routine run won't be published.
26
- - To display a general message after every command use: `set general message MESSAGE`. Use `set general message off` to stop displaying it.
27
- - When adding a general message is possible to use interpolation
28
- - If you are a master admin and you are on master channel then you can call `publish announcements` that will publish the announcements on all channels. The messages stored on a DM won't be published. This is very convenient to be called from a *Routine* for example every weekday at 09:00.
29
- - Now it is possible to send blocks `respond blocks: my_blocks`. More info about blocks: https://api.slack.com/block-kit
30
- - When using bgroutines if we want to avoid a file to be sent:
31
- send_file(dest, 'description', "file_path", 'desc', 'text/plain', "text") unless Thread.current[:routine_type] == 'bgroutine'
32
- - SmartBot will notify about SmartBot status changes if defined the status_channel in config file and the channel exists. By default: smartbot-status
14
+ - When calling `respond` it can be supplied the argument `return_message: true` to get access to the posted message. `msg = respond('my message', return_message: true)` (<https://github.com/MarioRuiz/slack-smart-bot/issues/31|#31>)
15
+ - New command `delete message URL` will delete the SmartBot message supplied. Only for Master Admins (<https://github.com/MarioRuiz/slack-smart-bot/issues/32|#32>).
16
+ - `send message` accept also the url of the message to respond on a thread. Only for Master Admins (<https://github.com/MarioRuiz/slack-smart-bot/issues/39|#39>).
17
+ - `react to` accept also the url of the message. Only for Master Admins (<https://github.com/MarioRuiz/slack-smart-bot/issues/40|#40>).
18
+ - You can add, remove and list admins of any channel by using: `add admin @user`, `remove admin @user` and `see admins`. You need to be the creator of the channel, a Master admin or an admin (<https://github.com/MarioRuiz/slack-smart-bot/issues/42|#42>).
19
+ - `see access COMMAND_ID`, `allow access COMMAND_ID`, `allow access COMMAND_ID @user1 @user99` and `deny access COMMAND_ID`: Allows us to decide which commands are accessible on every channel. (<https://github.com/MarioRuiz/slack-smart-bot/issues/44|#44>).
33
20
 
34
21
  ------------------------------
35
22
 
36
- *Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/dd23939f93ee95aca3c04d33cd1ce197d6efbd37/whats_new.txt|1.9.0>
23
+ *Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/dd23939f93ee95aca3c04d33cd1ce197d6efbd37/whats_new.txt|1.10.0>