slack-smart-bot 1.9.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +184 -16
  3. data/lib/slack/smart-bot/comm/ask.rb +55 -49
  4. data/lib/slack/smart-bot/comm/delete.rb +13 -0
  5. data/lib/slack/smart-bot/comm/dont_understand.rb +3 -3
  6. data/lib/slack/smart-bot/comm/event_hello.rb +8 -4
  7. data/lib/slack/smart-bot/comm/get_channel_members.rb +13 -4
  8. data/lib/slack/smart-bot/comm/get_channels.rb +31 -16
  9. data/lib/slack/smart-bot/comm/get_presence.rb +20 -0
  10. data/lib/slack/smart-bot/comm/get_user_info.rb +12 -8
  11. data/lib/slack/smart-bot/comm/get_users.rb +24 -0
  12. data/lib/slack/smart-bot/comm/react.rb +19 -2
  13. data/lib/slack/smart-bot/comm/respond.rb +224 -53
  14. data/lib/slack/smart-bot/comm/respond_direct.rb +2 -3
  15. data/lib/slack/smart-bot/comm/respond_thread.rb +5 -0
  16. data/lib/slack/smart-bot/comm/send_file.rb +38 -34
  17. data/lib/slack/smart-bot/comm/send_msg_channel.rb +27 -22
  18. data/lib/slack/smart-bot/comm/send_msg_user.rb +59 -33
  19. data/lib/slack/smart-bot/comm/unreact.rb +22 -18
  20. data/lib/slack/smart-bot/comm.rb +4 -0
  21. data/lib/slack/smart-bot/commands/general/add_admin.rb +51 -0
  22. data/lib/slack/smart-bot/commands/general/add_announcement.rb +32 -0
  23. data/lib/slack/smart-bot/commands/general/add_team.rb +80 -0
  24. data/lib/slack/smart-bot/commands/general/allow_access.rb +67 -0
  25. data/lib/slack/smart-bot/commands/general/bot_help.rb +69 -33
  26. data/lib/slack/smart-bot/commands/general/bye_bot.rb +0 -7
  27. data/lib/slack/smart-bot/commands/general/delete_announcement.rb +34 -0
  28. data/lib/slack/smart-bot/commands/general/delete_share.rb +34 -0
  29. data/lib/slack/smart-bot/commands/general/delete_team.rb +34 -0
  30. data/lib/slack/smart-bot/commands/general/deny_access.rb +36 -0
  31. data/lib/slack/smart-bot/commands/general/hi_bot.rb +16 -11
  32. data/lib/slack/smart-bot/commands/general/ping_team.rb +100 -0
  33. data/lib/slack/smart-bot/commands/general/poster.rb +116 -0
  34. data/lib/slack/smart-bot/commands/general/remove_admin.rb +58 -0
  35. data/lib/slack/smart-bot/commands/general/see_access.rb +24 -0
  36. data/lib/slack/smart-bot/commands/general/see_admins.rb +33 -0
  37. data/lib/slack/smart-bot/commands/general/see_announcements.rb +115 -0
  38. data/lib/slack/smart-bot/commands/general/see_command_ids.rb +29 -0
  39. data/lib/slack/smart-bot/commands/general/see_favorite_commands.rb +53 -0
  40. data/lib/slack/smart-bot/commands/general/see_shares.rb +41 -0
  41. data/lib/slack/smart-bot/commands/general/see_statuses.rb +91 -0
  42. data/lib/slack/smart-bot/commands/general/see_teams.rb +252 -0
  43. data/lib/slack/smart-bot/commands/general/share_messages.rb +58 -0
  44. data/lib/slack/smart-bot/commands/general/update_team.rb +109 -0
  45. data/lib/slack/smart-bot/commands/general_bot_commands.rb +504 -0
  46. data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +4 -6
  47. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +45 -14
  48. data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +4 -1
  49. data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +6 -3
  50. data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +3 -1
  51. data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +4 -4
  52. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +8 -2
  53. data/lib/slack/smart-bot/commands/on_bot/admin/see_result_routine.rb +33 -0
  54. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +13 -10
  55. data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +6 -3
  56. data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +3 -1
  57. data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +4 -1
  58. data/lib/slack/smart-bot/commands/on_bot/admin_master/delete_message.rb +25 -0
  59. data/lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb +1 -0
  60. data/lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb +34 -0
  61. data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +37 -0
  62. data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +4 -5
  63. data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +7 -8
  64. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +400 -0
  65. data/lib/slack/smart-bot/commands/{general → on_bot/general}/bot_status.rb +3 -4
  66. data/lib/slack/smart-bot/commands/on_bot/general/leaderboard.rb +201 -0
  67. data/lib/slack/smart-bot/commands/{general → on_bot/general}/stop_using_rules.rb +12 -6
  68. data/lib/slack/smart-bot/commands/on_bot/general/suggest_command.rb +36 -0
  69. data/lib/slack/smart-bot/commands/{general → on_bot/general}/use_rules.rb +13 -11
  70. data/lib/slack/smart-bot/commands/{general → on_bot/general}/whats_new.rb +2 -1
  71. data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +4 -5
  72. data/lib/slack/smart-bot/commands/on_bot/repl.rb +76 -21
  73. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +3 -4
  74. data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +15 -7
  75. data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +5 -6
  76. data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +5 -6
  77. data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +45 -12
  78. data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +7 -3
  79. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +4 -1
  80. data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +3 -1
  81. data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +33 -0
  82. data/lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb +39 -0
  83. data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +10 -1
  84. data/lib/slack/smart-bot/commands/on_master/create_bot.rb +28 -14
  85. data/lib/slack/smart-bot/commands/on_master/where_smartbot.rb +41 -0
  86. data/lib/slack/smart-bot/commands.rb +36 -5
  87. data/lib/slack/smart-bot/listen.rb +31 -33
  88. data/lib/slack/smart-bot/process.rb +234 -73
  89. data/lib/slack/smart-bot/process_first.rb +119 -38
  90. data/lib/slack/smart-bot/treat_message.rb +310 -237
  91. data/lib/slack/smart-bot/utils/build_help.rb +2 -2
  92. data/lib/slack/smart-bot/utils/create_routine_thread.rb +81 -46
  93. data/lib/slack/smart-bot/utils/get_access_channels.rb +13 -0
  94. data/lib/slack/smart-bot/utils/get_admins_channels.rb +13 -0
  95. data/lib/slack/smart-bot/utils/get_bots_created.rb +28 -8
  96. data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +7 -2
  97. data/lib/slack/smart-bot/utils/get_command_ids.rb +84 -0
  98. data/lib/slack/smart-bot/utils/get_help.rb +79 -73
  99. data/lib/slack/smart-bot/utils/get_repls.rb +22 -2
  100. data/lib/slack/smart-bot/utils/get_routines.rb +22 -2
  101. data/lib/slack/smart-bot/utils/get_shares.rb +12 -0
  102. data/lib/slack/smart-bot/utils/get_teams.rb +22 -0
  103. data/lib/slack/smart-bot/utils/has_access.rb +28 -0
  104. data/lib/slack/smart-bot/utils/is_admin.rb +27 -0
  105. data/lib/slack/smart-bot/utils/save_stats.rb +46 -41
  106. data/lib/slack/smart-bot/utils/save_status.rb +67 -0
  107. data/lib/slack/smart-bot/utils/update_access_channels.rb +8 -0
  108. data/lib/slack/smart-bot/utils/update_admins_channels.rb +8 -0
  109. data/lib/slack/smart-bot/utils/update_bots_file.rb +28 -7
  110. data/lib/slack/smart-bot/utils/update_repls.rb +7 -4
  111. data/lib/slack/smart-bot/utils/update_routines.rb +9 -3
  112. data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +13 -6
  113. data/lib/slack/smart-bot/utils/update_teams.rb +16 -0
  114. data/lib/slack/smart-bot/utils.rb +11 -0
  115. data/lib/slack-smart-bot.rb +72 -12
  116. data/lib/slack-smart-bot_general_commands.rb +61 -0
  117. data/lib/slack-smart-bot_general_rules.rb +5 -2
  118. data/lib/slack-smart-bot_rules.rb +43 -17
  119. data/whats_new.txt +20 -15
  120. metadata +76 -9
  121. data/lib/slack/smart-bot/commands/general/bot_stats.rb +0 -313
@@ -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"
@@ -43,6 +44,9 @@ class SlackSmartBot
43
44
  config[:allow_access] = Hash.new unless config.key?(:allow_access)
44
45
  config[:on_maintenance] = false unless config.key?(:on_maintenance)
45
46
  config[:on_maintenance_message] = "Sorry I'm on maintenance so I cannot attend your request." unless config.key?(:on_maintenance_message)
47
+ config[:general_message] = "" unless config.key?(:general_message)
48
+ config[:logrtm] = false unless config.key?(:logrtm)
49
+ config[:status_channel] = 'smartbot-status' unless config.key?(:status_channel)
46
50
 
47
51
  if config.path.to_s!='' and config.file.to_s==''
48
52
  config.file = File.basename($0)
@@ -61,6 +65,10 @@ class SlackSmartBot
61
65
  Dir.mkdir("#{config.path}/logs") unless Dir.exist?("#{config.path}/logs")
62
66
  Dir.mkdir("#{config.path}/shortcuts") unless Dir.exist?("#{config.path}/shortcuts")
63
67
  Dir.mkdir("#{config.path}/routines") unless Dir.exist?("#{config.path}/routines")
68
+ Dir.mkdir("#{config.path}/announcements") unless Dir.exist?("#{config.path}/announcements")
69
+ Dir.mkdir("#{config.path}/shares") unless Dir.exist?("#{config.path}/shares")
70
+ Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
71
+ File.delete("#{config.path}/config_tmp.status") if File.exist?("#{config.path}/config_tmp.status")
64
72
 
65
73
  config.masters = MASTER_USERS if config.masters.to_s=='' and defined?(MASTER_USERS)
66
74
  config.master_channel = MASTER_CHANNEL if config.master_channel.to_s=='' and defined?(MASTER_CHANNEL)
@@ -71,7 +79,7 @@ class SlackSmartBot
71
79
  default_rules = (__FILE__).gsub(/\.rb$/, "_rules.rb")
72
80
  FileUtils.copy_file(default_rules, config.path + '/' + config.rules_file)
73
81
  end
74
- config.admins = config.masters unless config.admins.to_s!=''
82
+ config.admins = config.masters.dup unless config.admins.to_s!=''
75
83
  config.channel = config.master_channel unless config.channel.to_s!=''
76
84
  config.status_init = :on unless config.status_init.to_s!=''
77
85
  else
@@ -83,7 +91,7 @@ class SlackSmartBot
83
91
  config.rules_file[0]='' if config.rules_file[0]=='.'
84
92
  config.rules_file='/'+config.rules_file if config.rules_file[0]!='/'
85
93
 
86
- config.shortcuts_file = "slack-smart-bot_shortcuts_#{config.channel}.rb".gsub(" ", "_")
94
+ config.shortcuts_file = "slack-smart-bot_shortcuts_#{config.channel}.yaml".gsub(" ", "_")
87
95
  if config.channel == config.master_channel
88
96
  config.on_master_bot = true
89
97
  config.start_bots = true unless config.key?(:start_bots)
@@ -116,6 +124,7 @@ class SlackSmartBot
116
124
  File.new("#{config.path}/buffer_complete.log", "w") if config[:simulate] and config.on_master_bot
117
125
 
118
126
  self.config = config
127
+ save_status :off, :initializing, "Initializing bot: #{config_log.inspect}"
119
128
 
120
129
  unless config.simulate and config.key?(:client)
121
130
  Slack.configure do |conf|
@@ -127,10 +136,18 @@ class SlackSmartBot
127
136
  while restarts < 200 and !created
128
137
  begin
129
138
  @logger.info "Connecting #{config_log.inspect}"
139
+ save_status :off, :connecting, "Connecting #{config_log.inspect}"
130
140
  if config.simulate and config.key?(:client)
131
141
  self.client = config.client
132
142
  else
133
- self.client = Slack::RealTime::Client.new(start_method: :rtm_connect)
143
+ if config.logrtm
144
+ logrtmname = "#{config.path}/logs/rtm_#{config.channel}.log"
145
+ File.delete(logrtmname) if File.exist?(logrtmname)
146
+ @logrtm = Logger.new(logrtmname)
147
+ self.client = Slack::RealTime::Client.new(start_method: :rtm_connect, logger: @logrtm)
148
+ else
149
+ self.client = Slack::RealTime::Client.new(start_method: :rtm_connect)
150
+ end
134
151
  end
135
152
  created = true
136
153
  rescue Exception => e
@@ -140,6 +157,8 @@ class SlackSmartBot
140
157
  @logger.fatal "Rescued on creation: #{e.inspect}"
141
158
  @logger.info "Waiting 60 seconds to retry. restarts: #{restarts}"
142
159
  puts "#{Time.now}: Not able to create client. Waiting 60 seconds to retry: #{config_log.inspect}"
160
+ save_status :off, :waiting, "Not able to create client. Waiting 60 seconds to retry: #{config_log.inspect}"
161
+
143
162
  sleep 60
144
163
  else
145
164
  exit!
@@ -157,32 +176,54 @@ class SlackSmartBot
157
176
  @rules_imported = Hash.new()
158
177
  @routines = Hash.new()
159
178
  @repls = Hash.new()
179
+ @users = Hash.new()
180
+ @announcements = Hash.new()
181
+ @shares = Hash.new()
182
+ @last_status_change = Time.now
160
183
 
161
- if File.exist?("#{config.path}/shortcuts/#{config.shortcuts_file}")
162
- file_sc = IO.readlines("#{config.path}/shortcuts/#{config.shortcuts_file}").join
163
- unless file_sc.to_s() == ""
164
- @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)
165
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}"))
166
195
  end
167
- if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb")
196
+ if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb") #backwards compatible
168
197
  file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join
198
+ @shortcuts_global = {}
169
199
  unless file_sc.to_s() == ""
170
200
  @shortcuts_global = eval(file_sc)
171
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"))
172
206
  end
173
207
 
174
208
  get_routines()
175
209
  get_repls()
176
210
 
177
- 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')))
178
212
  get_bots_created()
179
213
  if @bots_created.kind_of?(Hash) and config.start_bots
180
214
  @bots_created.each { |key, value|
181
215
  if !value.key?(:cloud) or (value.key?(:cloud) and value[:cloud] == false)
182
- @logger.info "ruby #{config.file_path} \"#{value[:channel_name]}\" \"#{value[:admins]}\" \"#{value[:rules_file]}\" #{value[:status].to_sym}"
216
+ if value.key?(:silent) and value.silent!=config.silent
217
+ silent = value.silent
218
+ else
219
+ silent = config.silent
220
+ end
221
+ @logger.info "BOT_SILENT=#{silent} ruby #{config.file_path} \"#{value[:channel_name]}\" \"#{value[:admins]}\" \"#{value[:rules_file]}\" #{value[:status].to_sym}"
183
222
  puts "Starting #{value[:channel_name]} Smart Bot"
223
+ save_status :off, :starting, "Starting #{value[:channel_name]} Smart Bot"
224
+
184
225
  t = Thread.new do
185
- `ruby #{config.file_path} \"#{value[:channel_name]}\" \"#{value[:admins]}\" \"#{value[:rules_file]}\" #{value[:status].to_sym}`
226
+ `BOT_SILENT=#{silent} ruby #{config.file_path} \"#{value[:channel_name]}\" \"#{value[:admins]}\" \"#{value[:rules_file]}\" #{value[:status].to_sym}`
186
227
  end
187
228
  value[:thread] = t
188
229
  sleep value[:admins].size
@@ -190,6 +231,12 @@ class SlackSmartBot
190
231
  }
191
232
  end
192
233
  end
234
+ general_rules_file = "/rules/general_rules.rb"
235
+ general_commands_file = "/rules/general_commands.rb"
236
+ default_general_rules = (__FILE__).gsub(/\/slack-smart-bot\.rb$/, "/slack-smart-bot_general_rules.rb")
237
+ default_general_commands = (__FILE__).gsub(/\/slack-smart-bot\.rb$/, "/slack-smart-bot_general_commands.rb")
238
+ FileUtils.copy_file(default_general_rules, config.path + general_rules_file) unless File.exist?(config.path + general_rules_file)
239
+ FileUtils.copy_file(default_general_commands, config.path + general_commands_file) unless File.exist?(config.path + general_commands_file)
193
240
 
194
241
  get_rules_imported()
195
242
 
@@ -212,9 +259,11 @@ class SlackSmartBot
212
259
  end
213
260
  rescue Slack::Web::Api::Errors::TooManyRequestsError
214
261
  @logger.fatal "TooManyRequestsError"
262
+ save_status :off, :TooManyRequestsError, "TooManyRequestsError please re run the bot and be sure of executing first: killall ruby"
215
263
  abort("TooManyRequestsError please re run the bot and be sure of executing first: killall ruby")
216
264
  rescue Exception => stack
217
265
  pp stack if config.testing
266
+ save_status :off, :wrong_admin_user, "The admin user specified on settings: #{config.admins.join(", ")}, doesn't exist on Slack. Execution aborted"
218
267
  abort("The admin user specified on settings: #{config.admins.join(", ")}, doesn't exist on Slack. Execution aborted")
219
268
  end
220
269
 
@@ -230,14 +279,23 @@ class SlackSmartBot
230
279
  @questions = Hash.new()
231
280
  @answer = Hash.new()
232
281
  @repl_sessions = Hash.new()
282
+ @datetime_general_commands = 0
233
283
  @channels_id = Hash.new()
234
284
  @channels_name = Hash.new()
285
+ @channels_creator = Hash.new()
286
+ @channels_list = Hash.new()
235
287
  get_channels_name_and_id()
236
288
  @channel_id = @channels_id[config.channel].dup
237
289
  @master_bot_id = @channels_id[config.master_channel].dup
238
290
 
291
+ Dir.mkdir("#{config.path}/rules/#{@channel_id}") unless Dir.exist?("#{config.path}/rules/#{@channel_id}/")
292
+
239
293
  get_routines()
240
294
  get_repls()
295
+ get_shares()
296
+ get_admins_channels()
297
+ get_access_channels()
298
+
241
299
  if @routines.key?(@channel_id)
242
300
  @routines[@channel_id].each do |k, v|
243
301
  @routines[@channel_id][k][:running] = false
@@ -249,7 +307,7 @@ class SlackSmartBot
249
307
  @routines.each do |ch, rout|
250
308
  rout.each do |k, v|
251
309
  if !v[:running] and v[:channel_name] == config.channel
252
- create_routine_thread(k)
310
+ create_routine_thread(k, v)
253
311
  end
254
312
  end
255
313
  end
@@ -258,12 +316,14 @@ class SlackSmartBot
258
316
  m = "Connection closing, exiting. #{Time.now}"
259
317
  @logger.info m
260
318
  @logger.info _data
319
+ #save_status :off, :closing, "Connection closing, exiting." #todo: don't notify for the moment, remove when checked
261
320
  end
262
321
 
263
322
  client.on :closed do |_data|
264
323
  m = "Connection has been disconnected. #{Time.now}"
265
324
  @logger.info m
266
325
  @logger.info _data
326
+ save_status :off, :disconnected, "Connection has been disconnected."
267
327
  end
268
328
  end
269
329
  self
@@ -0,0 +1,61 @@
1
+ # add here the general commands you will be using in any channel where The SmartBot is part of. Not necessary to use ! or ^, it will answer directly.
2
+ def general_commands(user, command, dest, files = [])
3
+
4
+ begin
5
+ case command
6
+
7
+ # help: ----------------------------------------------
8
+ # help: `cls`
9
+ # help: `clear`
10
+ # help: `clear screen`
11
+ # help: `NUMBER cls`
12
+ # help: It will send a big empty message.
13
+ # help: NUMBER (optional): number of lines. Default 100. Max 200.
14
+ # help: command_id: :cls
15
+ # help:
16
+ when /\A\s*(\d*)\s*(clear|cls|clear\s+screen)\s*\z/i
17
+ save_stats :cls
18
+ $1.to_s == '' ? lines = 100 : lines = $1.to_i
19
+ lines = 200 if lines > 200
20
+ respond (">#{"\n"*lines}<")
21
+
22
+
23
+ # this is a hidden command that it is not listed when calling bot help
24
+ when /\s*(that's\s+)?(thanks|thank\s+you|I\s+love\s+you|nice|cool)\s+(#{@salutations.join("|")})\s*!*\s*$/i
25
+ save_stats :thanks
26
+ reactions = [:heart, :heart_eyes, :blush, :relaxed, :simple_smile, :smiley, :two_hearts, :heartbeat, :green_heart ]
27
+ reactions.sample(rand(3)+1).each {|rt| react rt }
28
+ responses = ['Thank YOU', "You're welcome", "You're very welcome", 'No problem', 'No worries', "Don't mention it", 'My pleasure',
29
+ 'Anytime', 'It was the least I could do', 'Glad to help', 'Sure', 'Pleasure', 'The pleasure is mine', 'It was nothing', 'Much obliged', "I'm happy to help",
30
+ 'Það var ekkert', 'De nada', 'No hay de qué', 'De rien', 'Bitte', 'Prego', 'मेरा सौभाग्य है', '不客氣', 'Παρακαλώ']
31
+ respond "#{responses.sample}#{'!'*rand(4)}"
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
+
48
+ else
49
+ return false
50
+ end
51
+ return true
52
+ rescue => exception
53
+ if defined?(@logger)
54
+ @logger.fatal exception
55
+ respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>"
56
+ else
57
+ puts exception
58
+ end
59
+ return false
60
+ end
61
+ end
@@ -13,7 +13,9 @@ def general_rules(user, command, processed, dest, files = [], rules_file = "")
13
13
  # help: Examples:
14
14
  # help: _echo I am the Smart Bot_
15
15
  # help: _100 echo :heart:_
16
- when /^(\d*)\s*echo\s(.+)/i
16
+ # help: command_id: :echo
17
+ # help:
18
+ when /\A\s*(\d*)\s*echo\s(.+)/i
17
19
  save_stats :echo
18
20
  $1.to_s == '' ? times = 1 : times = $1.to_i
19
21
  respond ($2*times).to_s
@@ -25,9 +27,10 @@ def general_rules(user, command, processed, dest, files = [], rules_file = "")
25
27
  rescue => exception
26
28
  if defined?(@logger)
27
29
  @logger.fatal exception
28
- respond "Unexpected error!! Please contact an admin to solve it: <@#{ADMIN_USERS.join(">, <@")}>"
30
+ respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>"
29
31
  else
30
32
  puts exception
31
33
  end
34
+ return false
32
35
  end
33
36
  end
@@ -40,15 +40,18 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
40
40
 
41
41
  load "#{config.path}/rules/general_rules.rb"
42
42
 
43
- unless general_rules(user, command, processed, dest, files, rules_file)
43
+ if general_rules(user, command, processed, dest, files, rules_file)
44
+ return true
45
+ else
44
46
  begin
45
47
  case command
46
48
 
47
49
  # help: ----------------------------------------------
48
50
  # help: `go to sleep`
49
51
  # help: it will sleep the bot for 5 seconds
52
+ # help: command_id: :go_to_sleep
50
53
  # help:
51
- when /^go\sto\ssleep/i
54
+ when /\A\s*go\sto\ssleep/i
52
55
  save_stats :go_to_sleep
53
56
  if answer.empty?
54
57
  ask "do you want me to take a siesta?"
@@ -74,32 +77,41 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
74
77
  # help: ----------------------------------------------
75
78
  # help: `run something`
76
79
  # help: It will run the process and report the results when done
80
+ # help: command_id: :run_something
77
81
  # help:
78
- when /^run something/i
82
+ when /\Arun something/i
79
83
  save_stats :run_something
80
- react :runner
84
+ if has_access?(:run_something, user)
85
+ react :runner
81
86
 
82
- process_to_run = "ruby -v"
83
- process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
84
- stdout, stderr, status = Open3.capture3(process_to_run)
85
- unreact :runner
86
- if stderr == ""
87
- if stdout == ""
88
- respond "#{display_name}: Nothing returned."
87
+ process_to_run = "ruby -v"
88
+ process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
89
+ stdout, stderr, status = Open3.capture3(process_to_run)
90
+ unreact :runner
91
+ if stderr == ""
92
+ if stdout == ""
93
+ respond "#{display_name}: Nothing returned."
94
+ else
95
+ respond "#{display_name}: #{stdout}"
96
+ end
89
97
  else
90
- respond "#{display_name}: #{stdout}"
98
+ respond "#{display_name}: #{stdout} #{stderr}"
91
99
  end
92
- else
93
- respond "#{display_name}: #{stdout} #{stderr}"
94
100
  end
95
101
 
96
102
  # Emoticons you can use with `react` command https://www.webfx.com/tools/emoji-cheat-sheet/
97
103
 
98
- # Examples for respond and respond_direct
104
+ # Examples for respond, respond_thread and respond_direct
99
105
  # # send 'the message' to the channel or direct message where the command was written
100
106
  # respond "the message"
101
107
  # # send 'the message' privately as a direct message to the user that sent the command
102
108
  # respond_direct "the message"
109
+ # # same thing can be done:
110
+ # respond "the message", :direct
111
+ # # send 'the message' opening a thread
112
+ # respond_thread "the message"
113
+ # # same thing can be done:
114
+ # respond 'the message', :on_thread
103
115
  # # send 'the message' to a specific channel name
104
116
  # respond "the message", 'my_channel'
105
117
  # # send 'the message' to a specific channel id
@@ -109,6 +121,19 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
109
121
  # # send 'the message' to a specific user id as direct message
110
122
  # respond "the message", 'US3344D3'
111
123
 
124
+ # Example sending blocks https://api.slack.com/block-kit
125
+ # my_blocks = [
126
+ # { type: "context",
127
+ # elements:
128
+ # [
129
+ # { type: "plain_text", :text=>"\tInfo: " },
130
+ # { type: "image", image_url: "https://avatars.slack-edge.com/2021-03-23/182815_e54abb1dd_24.jpg", alt_text: "mario" },
131
+ # { type: "mrkdwn", text: " *Mario Ruiz* (marior) " }
132
+ # ]
133
+ # }
134
+ # ]
135
+ # respond blocks: my_blocks
136
+
112
137
  # Example downloading a file from slack
113
138
  # if !files.nil? and files.size == 1 and files[0].filetype == 'yaml'
114
139
  # require 'nice_http'
@@ -120,16 +145,17 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
120
145
  # send_file(to, msg, filepath, title, format, type = "text")
121
146
  # send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'title', 'text/plain', "text")
122
147
  # send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'title', 'image/jpeg', "jpg")
123
-
124
-
125
148
  else
126
149
  unless processed
127
150
  dont_understand()
128
151
  end
152
+ return false
129
153
  end
154
+ return true
130
155
  rescue => exception
131
156
  @logger.fatal exception
132
157
  respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>"
158
+ return false
133
159
  end
134
160
  end
135
161
  end
data/whats_new.txt CHANGED
@@ -1,18 +1,23 @@
1
- *Version 1.9.1* Released 2021-Mar-18
1
+ *Version 1.11.0* Released 2022-May-09
2
2
 
3
3
  *For General users*
4
- - Added command `what's new` that will show this.
5
- - `bot stats` will return detailed statistics using the SmartBot. If you call it from a DM with the SmartBot you will see all stats for all Bot channels.
6
- - Possible to create 'global' shortcuts that will be available on any SmartBot Channel.
7
- - Added option to start a `repl` without pre-executing '.smart-bot-repl' source code in case exists. Just add `clean` before the `repl` command. For example: `clean repl Example`
8
- - When using `Ruby` command in case the process doesn't finish in 20 seconds will be aborted.
9
- - When creating rules/commands and asking a question now you can use 'answer' instead of '@questions'. Take a look at README.md for an example.
10
- - Using external calls, it is possible to send to more than one bot channel the same rule: `@smart-bot on #channel1 #channel2 #channel3 echo Lala`
11
- - `bot help` and `bot rules` return by default a short version of the commands. Call `bot help expanded` or `bot rules expanded` to get a full desciption of the commands.
12
- - It is possible to exclude routines from results when using `bot stats`
13
- ------------------------------
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>)
12
+
14
13
  *For Admin users*
15
- - `Bot stats` now shows the top 10 users and attaches the full list of users and commands.
16
- - Bot Stats. Now the routines are displayed as routine/USER
17
- - When creating routines now it is possible to publish in a different channel: `add routine run_tests at 17:05 #thechannel !run api tests`
18
- - `Turn maintenance on/off` command available
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>).
20
+
21
+ ------------------------------
22
+
23
+ *Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/dd23939f93ee95aca3c04d33cd1ce197d6efbd37/whats_new.txt|1.10.0>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack-smart-bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.1
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mario Ruiz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-18 00:00:00.000000000 Z
11
+ date: 2022-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slack-ruby-client
@@ -58,6 +58,26 @@ dependencies:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '1'
61
+ - !ruby/object:Gem::Dependency
62
+ name: string_pattern
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2'
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 2.2.3
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '2'
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 2.2.3
61
81
  - !ruby/object:Gem::Dependency
62
82
  name: async-websocket
63
83
  requirement: !ruby/object:Gem::Requirement
@@ -125,31 +145,53 @@ files:
125
145
  - LICENSE
126
146
  - README.md
127
147
  - lib/slack-smart-bot.rb
148
+ - lib/slack-smart-bot_general_commands.rb
128
149
  - lib/slack-smart-bot_general_rules.rb
129
150
  - lib/slack-smart-bot_rules.rb
130
151
  - lib/slack/smart-bot/comm.rb
131
152
  - lib/slack/smart-bot/comm/ask.rb
153
+ - lib/slack/smart-bot/comm/delete.rb
132
154
  - lib/slack/smart-bot/comm/dont_understand.rb
133
155
  - lib/slack/smart-bot/comm/event_hello.rb
134
156
  - lib/slack/smart-bot/comm/get_channel_members.rb
135
157
  - lib/slack/smart-bot/comm/get_channels.rb
158
+ - lib/slack/smart-bot/comm/get_presence.rb
136
159
  - lib/slack/smart-bot/comm/get_user_info.rb
160
+ - lib/slack/smart-bot/comm/get_users.rb
137
161
  - lib/slack/smart-bot/comm/react.rb
138
162
  - lib/slack/smart-bot/comm/respond.rb
139
163
  - lib/slack/smart-bot/comm/respond_direct.rb
164
+ - lib/slack/smart-bot/comm/respond_thread.rb
140
165
  - lib/slack/smart-bot/comm/send_file.rb
141
166
  - lib/slack/smart-bot/comm/send_msg_channel.rb
142
167
  - lib/slack/smart-bot/comm/send_msg_user.rb
143
168
  - lib/slack/smart-bot/comm/unreact.rb
144
169
  - lib/slack/smart-bot/commands.rb
170
+ - lib/slack/smart-bot/commands/general/add_admin.rb
171
+ - lib/slack/smart-bot/commands/general/add_announcement.rb
172
+ - lib/slack/smart-bot/commands/general/add_team.rb
173
+ - lib/slack/smart-bot/commands/general/allow_access.rb
145
174
  - lib/slack/smart-bot/commands/general/bot_help.rb
146
- - lib/slack/smart-bot/commands/general/bot_stats.rb
147
- - lib/slack/smart-bot/commands/general/bot_status.rb
148
175
  - lib/slack/smart-bot/commands/general/bye_bot.rb
176
+ - lib/slack/smart-bot/commands/general/delete_announcement.rb
177
+ - lib/slack/smart-bot/commands/general/delete_share.rb
178
+ - lib/slack/smart-bot/commands/general/delete_team.rb
179
+ - lib/slack/smart-bot/commands/general/deny_access.rb
149
180
  - lib/slack/smart-bot/commands/general/hi_bot.rb
150
- - lib/slack/smart-bot/commands/general/stop_using_rules.rb
151
- - lib/slack/smart-bot/commands/general/use_rules.rb
152
- - lib/slack/smart-bot/commands/general/whats_new.rb
181
+ - lib/slack/smart-bot/commands/general/ping_team.rb
182
+ - lib/slack/smart-bot/commands/general/poster.rb
183
+ - lib/slack/smart-bot/commands/general/remove_admin.rb
184
+ - lib/slack/smart-bot/commands/general/see_access.rb
185
+ - lib/slack/smart-bot/commands/general/see_admins.rb
186
+ - lib/slack/smart-bot/commands/general/see_announcements.rb
187
+ - lib/slack/smart-bot/commands/general/see_command_ids.rb
188
+ - lib/slack/smart-bot/commands/general/see_favorite_commands.rb
189
+ - lib/slack/smart-bot/commands/general/see_shares.rb
190
+ - lib/slack/smart-bot/commands/general/see_statuses.rb
191
+ - lib/slack/smart-bot/commands/general/see_teams.rb
192
+ - lib/slack/smart-bot/commands/general/share_messages.rb
193
+ - lib/slack/smart-bot/commands/general/update_team.rb
194
+ - lib/slack/smart-bot/commands/general_bot_commands.rb
153
195
  - lib/slack/smart-bot/commands/on_bot/add_shortcut.rb
154
196
  - lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb
155
197
  - lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb
@@ -157,13 +199,24 @@ files:
157
199
  - lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb
158
200
  - lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb
159
201
  - lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb
202
+ - lib/slack/smart-bot/commands/on_bot/admin/see_result_routine.rb
160
203
  - lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb
161
204
  - lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb
162
205
  - lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb
163
206
  - lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb
207
+ - lib/slack/smart-bot/commands/on_bot/admin_master/delete_message.rb
164
208
  - lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb
209
+ - lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb
210
+ - lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb
165
211
  - lib/slack/smart-bot/commands/on_bot/delete_repl.rb
166
212
  - lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb
213
+ - lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb
214
+ - lib/slack/smart-bot/commands/on_bot/general/bot_status.rb
215
+ - lib/slack/smart-bot/commands/on_bot/general/leaderboard.rb
216
+ - lib/slack/smart-bot/commands/on_bot/general/stop_using_rules.rb
217
+ - lib/slack/smart-bot/commands/on_bot/general/suggest_command.rb
218
+ - lib/slack/smart-bot/commands/on_bot/general/use_rules.rb
219
+ - lib/slack/smart-bot/commands/on_bot/general/whats_new.rb
167
220
  - lib/slack/smart-bot/commands/on_bot/get_repl.rb
168
221
  - lib/slack/smart-bot/commands/on_bot/repl.rb
169
222
  - lib/slack/smart-bot/commands/on_bot/ruby_code.rb
@@ -174,8 +227,11 @@ files:
174
227
  - lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb
175
228
  - lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb
176
229
  - lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb
230
+ - lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb
231
+ - lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb
177
232
  - lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb
178
233
  - lib/slack/smart-bot/commands/on_master/create_bot.rb
234
+ - lib/slack/smart-bot/commands/on_master/where_smartbot.rb
179
235
  - lib/slack/smart-bot/listen.rb
180
236
  - lib/slack/smart-bot/process.rb
181
237
  - lib/slack/smart-bot/process_first.rb
@@ -185,19 +241,30 @@ files:
185
241
  - lib/slack/smart-bot/utils/answer_delete.rb
186
242
  - lib/slack/smart-bot/utils/build_help.rb
187
243
  - lib/slack/smart-bot/utils/create_routine_thread.rb
244
+ - lib/slack/smart-bot/utils/get_access_channels.rb
245
+ - lib/slack/smart-bot/utils/get_admins_channels.rb
188
246
  - lib/slack/smart-bot/utils/get_bots_created.rb
189
247
  - lib/slack/smart-bot/utils/get_channels_name_and_id.rb
248
+ - lib/slack/smart-bot/utils/get_command_ids.rb
190
249
  - lib/slack/smart-bot/utils/get_help.rb
191
250
  - lib/slack/smart-bot/utils/get_repls.rb
192
251
  - lib/slack/smart-bot/utils/get_routines.rb
193
252
  - lib/slack/smart-bot/utils/get_rules_imported.rb
253
+ - lib/slack/smart-bot/utils/get_shares.rb
254
+ - lib/slack/smart-bot/utils/get_teams.rb
255
+ - lib/slack/smart-bot/utils/has_access.rb
256
+ - lib/slack/smart-bot/utils/is_admin.rb
194
257
  - lib/slack/smart-bot/utils/remove_hash_keys.rb
195
258
  - lib/slack/smart-bot/utils/save_stats.rb
259
+ - lib/slack/smart-bot/utils/save_status.rb
260
+ - lib/slack/smart-bot/utils/update_access_channels.rb
261
+ - lib/slack/smart-bot/utils/update_admins_channels.rb
196
262
  - lib/slack/smart-bot/utils/update_bots_file.rb
197
263
  - lib/slack/smart-bot/utils/update_repls.rb
198
264
  - lib/slack/smart-bot/utils/update_routines.rb
199
265
  - lib/slack/smart-bot/utils/update_rules_imported.rb
200
266
  - lib/slack/smart-bot/utils/update_shortcuts_file.rb
267
+ - lib/slack/smart-bot/utils/update_teams.rb
201
268
  - whats_new.txt
202
269
  homepage: https://github.com/MarioRuiz/slack-smart-bot
203
270
  licenses:
@@ -211,14 +278,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
211
278
  requirements:
212
279
  - - ">="
213
280
  - !ruby/object:Gem::Version
214
- version: '2.5'
281
+ version: '2.6'
215
282
  required_rubygems_version: !ruby/object:Gem::Requirement
216
283
  requirements:
217
284
  - - ">="
218
285
  - !ruby/object:Gem::Version
219
286
  version: '0'
220
287
  requirements: []
221
- rubygems_version: 3.2.3
288
+ rubygems_version: 3.2.15
222
289
  signing_key:
223
290
  specification_version: 4
224
291
  summary: Create a Slack bot that is smart and so easy to expand, create new bots on