slack-smart-bot 1.9.1 → 1.11.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 (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