slack-smart-bot 1.7.0 → 1.9.2

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -12
  3. data/lib/slack-smart-bot.rb +53 -43
  4. data/lib/slack-smart-bot_general_rules.rb +7 -4
  5. data/lib/slack-smart-bot_rules.rb +8 -6
  6. data/lib/slack/smart-bot/comm.rb +6 -1
  7. data/lib/slack/smart-bot/comm/ask.rb +12 -5
  8. data/lib/slack/smart-bot/comm/dont_understand.rb +1 -1
  9. data/lib/slack/smart-bot/comm/event_hello.rb +30 -0
  10. data/lib/slack/smart-bot/comm/get_channel_members.rb +8 -0
  11. data/lib/slack/smart-bot/comm/get_channels.rb +20 -0
  12. data/lib/slack/smart-bot/comm/get_user_info.rb +16 -0
  13. data/lib/slack/smart-bot/comm/react.rb +21 -8
  14. data/lib/slack/smart-bot/comm/respond.rb +38 -12
  15. data/lib/slack/smart-bot/comm/send_file.rb +1 -1
  16. data/lib/slack/smart-bot/comm/send_msg_channel.rb +2 -2
  17. data/lib/slack/smart-bot/comm/send_msg_user.rb +4 -4
  18. data/lib/slack/smart-bot/comm/unreact.rb +29 -0
  19. data/lib/slack/smart-bot/commands.rb +3 -1
  20. data/lib/slack/smart-bot/commands/general/bot_help.rb +16 -3
  21. data/lib/slack/smart-bot/commands/general/bot_stats.rb +313 -0
  22. data/lib/slack/smart-bot/commands/general/bot_status.rb +1 -1
  23. data/lib/slack/smart-bot/commands/general/bye_bot.rb +1 -1
  24. data/lib/slack/smart-bot/commands/general/hi_bot.rb +1 -1
  25. data/lib/slack/smart-bot/commands/general/use_rules.rb +6 -9
  26. data/lib/slack/smart-bot/commands/general/whats_new.rb +19 -0
  27. data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +65 -33
  28. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +42 -9
  29. data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +3 -7
  30. data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +1 -0
  31. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +9 -2
  32. data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +1 -0
  33. data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +1 -1
  34. data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +52 -21
  35. data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +5 -5
  36. data/lib/slack/smart-bot/commands/on_bot/repl.rb +50 -18
  37. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +34 -9
  38. data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +2 -3
  39. data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +1 -1
  40. data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +27 -9
  41. data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +14 -1
  42. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +3 -3
  43. data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +1 -1
  44. data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +41 -0
  45. data/lib/slack/smart-bot/commands/on_master/create_bot.rb +4 -8
  46. data/lib/slack/smart-bot/listen.rb +6 -5
  47. data/lib/slack/smart-bot/process.rb +230 -186
  48. data/lib/slack/smart-bot/process_first.rb +104 -87
  49. data/lib/slack/smart-bot/treat_message.rb +128 -52
  50. data/lib/slack/smart-bot/utils.rb +2 -0
  51. data/lib/slack/smart-bot/utils/answer.rb +18 -0
  52. data/lib/slack/smart-bot/utils/answer_delete.rb +15 -0
  53. data/lib/slack/smart-bot/utils/build_help.rb +57 -5
  54. data/lib/slack/smart-bot/utils/create_routine_thread.rb +48 -8
  55. data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +1 -7
  56. data/lib/slack/smart-bot/utils/get_help.rb +79 -17
  57. data/lib/slack/smart-bot/utils/save_stats.rb +21 -8
  58. data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +6 -0
  59. data/whats_new.txt +24 -0
  60. metadata +23 -13
  61. data/lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb +0 -135
@@ -1,5 +1,5 @@
1
1
  class SlackSmartBot
2
- def process_first(user, text, dest, dchannel, typem, files, ts, thread_ts)
2
+ def process_first(user, text, dest, dchannel, typem, files, ts, thread_ts, routine)
3
3
  nick = user.name
4
4
  rules_file = ""
5
5
  text.gsub!(/^!!/,'^') # to treat it just as ^
@@ -80,21 +80,21 @@ class SlackSmartBot
80
80
  text.match(/^()\^\s*(.+)\s*/im) or
81
81
  text.match(/^()!\s*(.+)\s*/im) or
82
82
  text.match(/^()<@#{config[:nick_id]}>\s+(.+)\s*/im)
83
- command2 = $2
84
- if text.match?(/^()\^\s*(.+)/im)
85
- add_double_excl = true
86
- addexcl = false
87
- if command2.match?(/^![^!]/) or command2.match?(/^\^/)
83
+ command2 = $2
84
+ if text.match?(/^()\^\s*(.+)/im)
85
+ add_double_excl = true
86
+ addexcl = false
87
+ if command2.match?(/^![^!]/) or command2.match?(/^\^/)
88
88
  command2[0]=''
89
- elsif command2.match?(/^!!/)
89
+ elsif command2.match?(/^!!/)
90
90
  command2[0]=''
91
91
  command2[1]=''
92
- end
93
- else
92
+ end
93
+ else
94
94
  add_double_excl = false
95
95
  addexcl = true
96
- end
97
- command = command2
96
+ end
97
+ command = command2
98
98
  else
99
99
  addexcl = false
100
100
  if text.include?('$') #for shortcuts inside commands
@@ -111,6 +111,10 @@ class SlackSmartBot
111
111
  command.gsub!("$#{sc}", @shortcuts[nick][sc])
112
112
  elsif @shortcuts.key?(:all) and @shortcuts[:all].keys.include?(sc)
113
113
  command.gsub!("$#{sc}", @shortcuts[:all][sc])
114
+ elsif @shortcuts_global.key?(nick) and @shortcuts_global[nick].keys.include?(sc)
115
+ command.gsub!("$#{sc}", @shortcuts_global[nick][sc])
116
+ elsif @shortcuts_global.key?(:all) and @shortcuts_global[:all].keys.include?(sc)
117
+ command.gsub!("$#{sc}", @shortcuts_global[:all][sc])
114
118
  end
115
119
  end
116
120
  command.scan(/\$([^\s]+)/i).flatten.each do |sc|
@@ -119,6 +123,10 @@ class SlackSmartBot
119
123
  command.gsub!("$#{sc}", @shortcuts[nick][sc])
120
124
  elsif @shortcuts.key?(:all) and @shortcuts[:all].keys.include?(sc)
121
125
  command.gsub!("$#{sc}", @shortcuts[:all][sc])
126
+ elsif @shortcuts_global.key?(nick) and @shortcuts_global[nick].keys.include?(sc)
127
+ command.gsub!("$#{sc}", @shortcuts_global[nick][sc])
128
+ elsif @shortcuts_global.key?(:all) and @shortcuts_global[:all].keys.include?(sc)
129
+ command.gsub!("$#{sc}", @shortcuts_global[:all][sc])
122
130
  end
123
131
  end
124
132
  text = command
@@ -126,13 +134,19 @@ class SlackSmartBot
126
134
  text = "^" + text if add_double_excl
127
135
  end
128
136
  if command.scan(/^(shortcut|sc)\s+([^:]+)\s*$/i).any? or
129
- (@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or
130
- (@shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command))
137
+ (@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or
138
+ (@shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)) or
139
+ (@shortcuts_global.keys.include?(:all) and @shortcuts_global[:all].keys.include?(command)) or
140
+ (@shortcuts_global.keys.include?(nick) and @shortcuts_global[nick].keys.include?(command))
131
141
  command = $2.downcase unless $2.nil?
132
142
  if @shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)
133
143
  text = @shortcuts[nick][command].dup
134
144
  elsif @shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)
135
145
  text = @shortcuts[:all][command].dup
146
+ elsif @shortcuts_global.keys.include?(nick) and @shortcuts_global[nick].keys.include?(command)
147
+ text = @shortcuts_global[nick][command].dup
148
+ elsif @shortcuts_global.keys.include?(:all) and @shortcuts_global[:all].keys.include?(command)
149
+ text = @shortcuts_global[:all][command].dup
136
150
  else
137
151
  respond "Shortcut not found", dest unless dest[0] == "C" and dchannel != dest #on extended channel
138
152
  return :next #jal
@@ -154,6 +168,7 @@ class SlackSmartBot
154
168
  Thread.current[:files?] = !files.nil? && files.size>0
155
169
  Thread.current[:ts] = ts
156
170
  Thread.current[:thread_ts] = thread_ts
171
+ Thread.current[:routine] = routine
157
172
  if thread_ts.to_s == ''
158
173
  Thread.current[:on_thread] = false
159
174
  Thread.current[:thread_ts] = Thread.current[:ts] # to create the thread if necessary
@@ -187,96 +202,98 @@ class SlackSmartBot
187
202
  command = command2
188
203
  on_demand = true
189
204
  end
190
- if @status == :on and
191
- (@questions.key?(nick) or
192
- (@repl_sessions.key?(nick) and dest==@repl_sessions[nick][:dest] and
193
- ((@repl_sessions[nick][:on_thread] and thread_ts == @repl_sessions[nick][:thread_ts]) or
194
- (!@repl_sessions[nick][:on_thread] and !Thread.current[:on_thread] ))) or
195
- (@listening.key?(nick) and typem != :on_extended and
196
- ((@listening[nick].key?(dest) and !Thread.current[:on_thread]) or
197
- (@listening[nick].key?(thread_ts) and Thread.current[:on_thread] ) )) or
198
- dest[0] == "D" or on_demand)
199
- @logger.info "command: #{nick}> #{command}" unless processed
200
- #todo: verify this
205
+ unless config.on_maintenance and processed
206
+ if @status == :on and
207
+ (!answer.empty? or
208
+ (@repl_sessions.key?(nick) and dest==@repl_sessions[nick][:dest] and
209
+ ((@repl_sessions[nick][:on_thread] and thread_ts == @repl_sessions[nick][:thread_ts]) or
210
+ (!@repl_sessions[nick][:on_thread] and !Thread.current[:on_thread] ))) or
211
+ (@listening.key?(nick) and typem != :on_extended and
212
+ ((@listening[nick].key?(dest) and !Thread.current[:on_thread]) or
213
+ (@listening[nick].key?(thread_ts) and Thread.current[:on_thread] ) )) or
214
+ dest[0] == "D" or on_demand)
215
+ @logger.info "command: #{nick}> #{command}" unless processed
216
+ #todo: verify this
201
217
 
202
- if dest[0] == "C" or dest[0] == "G" or (dest[0] == "D" and typem == :on_call)
203
- if typem != :on_call and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
204
- if @bots_created.key?(@rules_imported[user.id][dchannel])
205
- if @bots_created[@rules_imported[user.id][dchannel]][:status] != :on
206
- respond "The bot on that channel is not :on", dest
207
- rules_file = ""
218
+ if dest[0] == "C" or dest[0] == "G" or (dest[0] == "D" and typem == :on_call)
219
+ if typem != :on_call and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
220
+ if @bots_created.key?(@rules_imported[user.id][dchannel])
221
+ if @bots_created[@rules_imported[user.id][dchannel]][:status] != :on
222
+ respond "The bot on that channel is not :on", dest
223
+ rules_file = ""
224
+ end
208
225
  end
209
226
  end
210
- end
211
- unless rules_file.empty?
212
- begin
213
- eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
214
- rescue Exception => stack
215
- @logger.fatal "ERROR ON RULES FILE: #{rules_file}"
216
- @logger.fatal stack
217
- end
218
- if defined?(rules)
219
- command[0] = "" if command[0] == "!"
220
- command.gsub!(/^@\w+:*\s*/, "")
221
- if method(:rules).parameters.size == 4
222
- rules(user, command, processed, dest)
223
- elsif method(:rules).parameters.size == 5
224
- rules(user, command, processed, dest, files)
225
- else
226
- rules(user, command, processed, dest, files, rules_file)
227
- end
228
- else
229
- @logger.warn "It seems like rules method is not defined"
230
- end
231
- end
232
- elsif @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id)
233
- if @bots_created.key?(@rules_imported[user.id][user.id])
234
- if @bots_created[@rules_imported[user.id][user.id]][:status] == :on
227
+ unless rules_file.empty?
235
228
  begin
236
- eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) and !['.','..'].include?(config.path + rules_file)
229
+ eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
237
230
  rescue Exception => stack
238
- @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
231
+ @logger.fatal "ERROR ON RULES FILE: #{rules_file}"
239
232
  @logger.fatal stack
240
233
  end
241
- else
242
- respond "The bot on <##{@rules_imported[user.id][user.id]}|#{@bots_created[@rules_imported[user.id][user.id]][:channel_name]}> is not :on", dest
243
- rules_file = ""
234
+ if defined?(rules)
235
+ command[0] = "" if command[0] == "!"
236
+ command.gsub!(/^@\w+:*\s*/, "")
237
+ if method(:rules).parameters.size == 4
238
+ rules(user, command, processed, dest)
239
+ elsif method(:rules).parameters.size == 5
240
+ rules(user, command, processed, dest, files)
241
+ else
242
+ rules(user, command, processed, dest, files, rules_file)
243
+ end
244
+ else
245
+ @logger.warn "It seems like rules method is not defined"
246
+ end
247
+ end
248
+ elsif @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id)
249
+ if @bots_created.key?(@rules_imported[user.id][user.id])
250
+ if @bots_created[@rules_imported[user.id][user.id]][:status] == :on
251
+ begin
252
+ eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) and !['.','..'].include?(config.path + rules_file)
253
+ rescue Exception => stack
254
+ @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
255
+ @logger.fatal stack
256
+ end
257
+ else
258
+ respond "The bot on <##{@rules_imported[user.id][user.id]}|#{@bots_created[@rules_imported[user.id][user.id]][:channel_name]}> is not :on", dest
259
+ rules_file = ""
260
+ end
244
261
  end
245
- end
246
262
 
247
- unless rules_file.empty?
248
- if defined?(rules)
249
- command[0] = "" if command[0] == "!"
250
- command.gsub!(/^@\w+:*\s*/, "")
251
- if method(:rules).parameters.size == 4
252
- rules(user, command, processed, dest)
253
- elsif method(:rules).parameters.size == 5
254
- rules(user, command, processed, dest, files)
263
+ unless rules_file.empty?
264
+ if defined?(rules)
265
+ command[0] = "" if command[0] == "!"
266
+ command.gsub!(/^@\w+:*\s*/, "")
267
+ if method(:rules).parameters.size == 4
268
+ rules(user, command, processed, dest)
269
+ elsif method(:rules).parameters.size == 5
270
+ rules(user, command, processed, dest, files)
271
+ else
272
+ rules(user, command, processed, dest, files, rules_file)
273
+ end
255
274
  else
256
- rules(user, command, processed, dest, files, rules_file)
275
+ @logger.warn "It seems like rules method is not defined"
257
276
  end
258
- else
259
- @logger.warn "It seems like rules method is not defined"
277
+ end
278
+ else
279
+ @logger.info "it is a direct message with no rules file selected so no rules file executed."
280
+ if command.match?(/^\s*bot\s+rules\s*(.*)$/i)
281
+ respond "No rules running. You can use the command `use rules from CHANNEL` to specify the rules you want to use on this private conversation.\n`bot help` to see available commands.", dest
282
+ end
283
+ unless processed
284
+ dont_understand('')
260
285
  end
261
286
  end
262
- else
263
- @logger.info "it is a direct message with no rules file selected so no rules file executed."
264
- if command.match?(/^\s*bot\s+rules\s*$/i)
265
- respond "No rules running. You can use the command `use rules from CHANNEL` to specify the rules you want to use on this private conversation.\n`bot help` to see available commands.", dest
266
- end
267
- unless processed
268
- dont_understand('')
269
- end
270
- end
271
287
 
272
- if processed and @listening.key?(nick)
273
- if Thread.current[:on_thread] and @listening[nick].key?(Thread.current[:thread_ts])
274
- @listening[nick][Thread.current[:thread_ts]] = Time.now
275
- elsif !Thread.current[:on_thread] and @listening[nick].key?(dest)
276
- @listening[nick][dest] = Time.now
288
+ if processed and @listening.key?(nick)
289
+ if Thread.current[:on_thread] and @listening[nick].key?(Thread.current[:thread_ts])
290
+ @listening[nick][Thread.current[:thread_ts]] = Time.now
291
+ elsif !Thread.current[:on_thread] and @listening[nick].key?(dest)
292
+ @listening[nick][dest] = Time.now
293
+ end
277
294
  end
278
- end
279
295
 
296
+ end
280
297
  end
281
298
  rescue Exception => stack
282
299
  @logger.fatal stack
@@ -4,45 +4,57 @@ class SlackSmartBot
4
4
  begin
5
5
  unless data.text.to_s.match(/\A\s*\z/)
6
6
  #to remove italic, bold... from data.text since there is no method on slack api
7
- #only works when no @user or #channel mentioned
8
7
  if remove_blocks and !data.blocks.nil? and data.blocks.size > 0
8
+ data_text = ''
9
9
  data.blocks.each do |b|
10
10
  if b.type == 'rich_text'
11
11
  if b.elements.size > 0
12
12
  b.elements.each do |e|
13
- if e.type == 'rich_text_section'
14
- if e.elements.size > 0 and (e.elements.type.uniq - ['link', 'text']) == []
15
- data.text = ''
13
+ if e.type == 'rich_text_section' or e.type == 'rich_text_preformatted'
14
+ if e.elements.size > 0 and (e.elements.type.uniq - ['link', 'text', 'user', 'channel']) == []
15
+ data_text += '```' if e.type == 'rich_text_preformatted'
16
16
  e.elements.each do |el|
17
17
  if el.type == 'text'
18
- data.text += el.text
18
+ data_text += el.text
19
+ elsif el.type == 'user'
20
+ data_text += "<@#{el.user_id}>"
21
+ elsif el.type == 'channel'
22
+ tch = data.text.scan(/(<##{el.channel_id}\|[^\>]+>)/).join
23
+ data_text += tch
19
24
  else
20
- data.text += el.url
25
+ data_text += el.url
21
26
  end
22
27
  end
28
+ data_text += '```' if e.type == 'rich_text_preformatted'
23
29
  end
24
- break
25
30
  end
26
31
  end
27
32
  end
28
- break
29
33
  end
30
34
  end
35
+ data.text = data_text unless data_text == ''
31
36
  end
32
37
  data.text = CGI.unescapeHTML(data.text)
33
38
  data.text.gsub!("\u00A0", " ") #to change &nbsp; (asc char 160) into blank space
34
39
  end
40
+ data.text.gsub!('‘', "'")
35
41
  data.text.gsub!('’', "'")
36
- data.text.gsub!('“', '"')
37
- rescue
42
+ data.text.gsub!('“', '"')
43
+ data.text.gsub!('”', '"')
44
+ rescue Exception => exc
38
45
  @logger.warn "Impossible to unescape or clean format for data.text:#{data.text}"
46
+ @logger.warn exc.inspect
39
47
  end
48
+ data.routine = false unless data.key?(:routine)
49
+
40
50
  if config[:testing] and config.on_master_bot
41
51
  open("#{config.path}/buffer.log", "a") { |f|
42
- f.puts "|#{data.channel}|#{data.user}|#{data.text}"
52
+ f.puts "|#{data.channel}|#{data.user}|#{data.user_name}|#{data.text}"
43
53
  }
44
54
  end
45
- if data.channel[0] == "D" or data.channel[0] == "C" or data.channel[0] == "G" #Direct message or Channel or Private Channel
55
+ if data.key?(:dest) and data.dest.to_s!='' # for run routines and publish on different channels
56
+ dest = data.dest
57
+ elsif data.channel[0] == "D" or data.channel[0] == "C" or data.channel[0] == "G" #Direct message or Channel or Private Channel
46
58
  dest = data.channel
47
59
  else # not treated
48
60
  dest = nil
@@ -56,24 +68,42 @@ class SlackSmartBot
56
68
  @pings << $1
57
69
  end
58
70
  typem = :dont_treat
59
- if !dest.nil? and !data.text.nil? and !data.text.to_s.match?(/^\s*$/)
60
- if data.text.match(/^<@#{config[:nick_id]}>\s(on\s)?<#(\w+)\|([^>]+)>\s*:?\s*(.*)/im)
61
- channel_rules = $2
62
- channel_rules_name = $3
63
- # to be treated only on the bot of the requested channel
64
- if @channel_id == channel_rules
65
- data.text = $4
66
- typem = :on_call
71
+ if !dest.nil? and !data.text.nil? and !data.text.to_s.match?(/\A\s*\z/)
72
+ #todo: we need to add mixed channels: @smart-bot on private1 #bot1cm <#CXDDFRDDF|bot2cu>: echo A
73
+ if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?((<#\w+\|[^>]+>\s*)+)\s*:?\s*(.*)/im) or
74
+ data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?((#[a-zA-Z0-9]+\s*)+)\s*:?\s*(.*)/im) or
75
+ data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?(([a-zA-Z0-9]+\s*)+)\s*:\s*(.*)/im)
76
+ channels_rules = $2 #multiple channels @smart-bot on #channel1 #channel2 echo AAA
77
+ data_text = $4
78
+ channel_rules_name = ''
79
+ channel_rules = ''
80
+ channels_arr = channels_rules.scan(/<#(\w+)\|([^>]+)>/)
81
+ if channels_arr.size == 0
82
+ channels_arr = []
83
+ channels_rules.scan(/([^\s]+)/).each do |cn|
84
+ cna = cn.join.gsub('#','')
85
+ channels_arr << [@channels_id[cna], cna]
86
+ end
67
87
  end
68
- elsif dest == @master_bot_id
88
+ # to be treated only on the bots of the requested channels
89
+ channels_arr.each do |tcid, tcname|
90
+ if @channel_id == tcid
91
+ data.text = data_text
92
+ typem = :on_call
93
+ channel_rules = tcid
94
+ channel_rules_name = tcname
95
+ break
96
+ end
97
+ end
98
+ elsif data.channel == @master_bot_id
69
99
  if config.on_master_bot #only to be treated on master bot channel
70
100
  typem = :on_master
71
101
  end
72
- elsif @bots_created.key?(dest)
73
- if @channel_id == dest #only to be treated by the bot on the channel
102
+ elsif @bots_created.key?(data.channel)
103
+ if @channel_id == data.channel #only to be treated by the bot on the channel
74
104
  typem = :on_bot
75
105
  end
76
- elsif dest[0] == "D" #Direct message
106
+ elsif data.channel[0] == "D" #Direct message
77
107
  get_rules_imported()
78
108
  if @rules_imported.key?(data.user) && @rules_imported[data.user].key?(data.user) and
79
109
  @bots_created.key?(@rules_imported[data.user][data.user])
@@ -85,21 +115,21 @@ class SlackSmartBot
85
115
  #only to be treated by master bot
86
116
  typem = :on_dm
87
117
  end
88
- elsif dest[0] == "C" or dest[0] == "G"
118
+ elsif data.channel[0] == "C" or data.channel[0] == "G"
89
119
  #only to be treated on the channel of the bot. excluding running ruby
90
- if !config.on_master_bot and @bots_created.key?(@channel_id) and @bots_created[@channel_id][:extended].include?(@channels_name[dest]) and
120
+ if !config.on_master_bot and @bots_created.key?(@channel_id) and @bots_created[@channel_id][:extended].include?(@channels_name[data.channel]) and
91
121
  !data.text.match?(/^!?\s*(ruby|code)\s+/) and !data.text.match?(/^!?!?\s*(ruby|code)\s+/) and !data.text.match?(/^\^?\s*(ruby|code)\s+/)
92
122
  typem = :on_extended
93
123
  elsif config.on_master_bot and (data.text.match?(/^!?\s*(ruby|code)\s+/) or data.text.match?(/^!?!?\s*(ruby|code)\s+/) or data.text.match?(/^\^?\s*(ruby|code)\s+/) )
94
124
  #or in case of running ruby, the master bot
95
125
  @bots_created.each do |k, v|
96
- if v.key?(:extended) and v[:extended].include?(@channels_name[dest])
126
+ if v.key?(:extended) and v[:extended].include?(@channels_name[data.channel])
97
127
  typem = :on_extended
98
128
  break
99
129
  end
100
130
  end
101
131
  end
102
- if dest[0] == "G" and config.on_master_bot and typem != :on_extended #private group
132
+ if data.channel[0] == "G" and config.on_master_bot and typem != :on_extended #private group
103
133
  typem = :on_pg
104
134
  end
105
135
  end
@@ -116,18 +146,27 @@ class SlackSmartBot
116
146
  end
117
147
  begin
118
148
  #todo: when changed @questions user_id then move user_info inside the ifs to avoid calling it when not necessary
119
- user_info = client.web_client.users_info(user: data.user)
120
- if @questions.key?(user_info.user.name)
149
+ user_info = get_user_info(data.user)
150
+
151
+ #user_info.user.id = data.user #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
152
+ data.user = user_info.user.id #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
153
+ if data.thread_ts.nil?
154
+ qdest = dest
155
+ else
156
+ qdest = data.thread_ts
157
+ end
158
+ if !answer(user_info.user.name, qdest).empty?
121
159
  if data.text.match?(/^\s*(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i)
122
- @questions.delete(user_info.user.name)
160
+ answer_delete(user_info.user.name, qdest)
123
161
  command = data.text
124
162
  else
125
- command = @questions[user_info.user.name]
126
- @questions[user_info.user.name] = data.text
163
+ command = answer(user_info.user.name, qdest)
164
+ @answer[user_info.user.name][qdest] = data.text
165
+ @questions[user_info.user.name] = data.text # to be backwards compatible #todo remove it when 2.0
127
166
  end
128
- elsif @repl_sessions.key?(user_info.user.name) and dest==@repl_sessions[user_info.user.name][:dest] and
167
+ elsif @repl_sessions.key?(user_info.user.name) and data.channel==@repl_sessions[user_info.user.name][:dest] and
129
168
  ((@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts == @repl_sessions[user_info.user.name][:thread_ts]) or
130
- (!@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts.to_s == '' ))
169
+ (!@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts.to_s == '' ))
131
170
 
132
171
  if data.text.match(/^\s*```(.*)```\s*$/im)
133
172
  @repl_sessions[user_info.user.name][:command] = $1
@@ -140,16 +179,16 @@ class SlackSmartBot
140
179
  end
141
180
 
142
181
  #when added special characters on the message
143
- if command.match(/^\s*```(.*)```\s*$/im)
182
+ if command.match(/\A\s*```(.*)```\s*\z/im)
144
183
  command = $1
145
184
  elsif command.size >= 2 and
146
- ((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_"))
185
+ ((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_"))
147
186
  command = command[1..-2]
148
187
  end
149
188
 
150
189
  #ruby file attached
151
190
  if !data.files.nil? and data.files.size == 1 and
152
- (command.match?(/^(ruby|code)\s*$/) or (command.match?(/^\s*$/) and data.files[0].filetype == "ruby") or
191
+ (command.match?(/^(ruby|code)\s*$/) or (command.match?(/^\s*$/) and data.files[0].filetype == "ruby") or
153
192
  (typem == :on_call and data.files[0].filetype == "ruby"))
154
193
  res = Faraday.new("https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" }).get(data.files[0].url_private)
155
194
  command += " ruby" if command != "ruby"
@@ -160,47 +199,68 @@ class SlackSmartBot
160
199
  command = "!" + command unless command[0] == "!" or command.match?(/^\s*$/) or command[0] == "^"
161
200
 
162
201
  #todo: add pagination for case more than 1000 channels on the workspace
163
- channels = client.web_client.conversations_list(
164
- types: "private_channel,public_channel",
165
- limit: "1000",
166
- exclude_archived: "true",
167
- ).channels
202
+ channels = get_channels()
168
203
  channel_found = channels.detect { |c| c.name == channel_rules_name }
169
- members = client.web_client.conversations_members(channel: @channels_id[channel_rules_name]).members unless channel_found.nil?
204
+ members = get_channel_members(@channels_id[channel_rules_name]) unless channel_found.nil?
170
205
  if channel_found.nil?
171
206
  @logger.fatal "Not possible to find the channel #{channel_rules_name}"
172
207
  elsif channel_found.name == config.master_channel
173
- respond "You cannot use the rules from Master Channel on any other channel.", dest
208
+ respond "You cannot use the rules from Master Channel on any other channel.", data.channel
174
209
  elsif @status != :on
175
- respond "The bot in that channel is not :on", dest
210
+ respond "The bot in that channel is not :on", data.channel
176
211
  elsif data.user == channel_found.creator or members.include?(data.user)
177
- process_first(user_info.user, command, dest, channel_rules, typem, data.files, data.ts, data.thread_ts)
212
+ process_first(user_info.user, command, dest, channel_rules, typem, data.files, data.ts, data.thread_ts, data.routine)
178
213
  else
179
- respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", dest
214
+ respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", data.channel
180
215
  end
181
216
  elsif config.on_master_bot and typem == :on_extended and
182
217
  command.size > 0 and command[0] != "-"
183
218
  # to run ruby only from the master bot for the case more than one extended
184
- process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts)
219
+ process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts, data.routine)
185
220
  elsif !config.on_master_bot and @bots_created[@channel_id].key?(:extended) and
186
221
  @bots_created[@channel_id][:extended].include?(@channels_name[data.channel]) and
187
222
  command.size > 0 and command[0] != "-"
188
- process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts)
223
+ process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts, data.routine)
189
224
  elsif (dest[0] == "D" or @channel_id == data.channel or data.user == config[:nick_id]) and
190
225
  command.size > 0 and command[0] != "-"
191
- process_first(user_info.user, command, dest, data.channel, typem, data.files, data.ts, data.thread_ts)
226
+ process_first(user_info.user, command, dest, data.channel, typem, data.files, data.ts, data.thread_ts, data.routine)
192
227
  # if @botname on #channel_rules: do something
193
228
  end
194
229
  rescue Exception => stack
195
230
  @logger.fatal stack
196
231
  end
197
232
  else
198
- if !config.on_master_bot and !dest.nil? and (dest == @master_bot_id or dest[0] == "D") and
233
+ if !config.on_master_bot and !dest.nil? and (data.channel == @master_bot_id or dest[0] == "D") and
199
234
  data.text.match?(/^\s*bot\s+status\s*$/i) and @admin_users_id.include?(data.user)
200
235
  respond "ping from #{config.channel}", dest
201
236
  elsif !config.on_master_bot and !dest.nil? and data.user == config[:nick_id] and dest == @master_bot_id
202
237
  # to treat on other bots the status messages populated on master bot
203
238
  case data.text
239
+ when /From now on I'll be on maintenance status/i
240
+ sleep 2
241
+ if File.exist?("#{config.path}/config_tmp.status")
242
+ file_cts = IO.readlines("#{config.path}/config_tmp.status").join
243
+ unless file_cts.to_s() == ""
244
+ file_cts = eval(file_cts)
245
+ if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance)
246
+ config.on_maintenance = file_cts.on_maintenance
247
+ config.on_maintenance_message = file_cts.on_maintenance_message
248
+ end
249
+ end
250
+ end
251
+ when /From now on I won't be on maintenance/i
252
+ sleep 2
253
+ if File.exist?("#{config.path}/config_tmp.status")
254
+ file_cts = IO.readlines("#{config.path}/config_tmp.status").join
255
+ unless file_cts.to_s() == ""
256
+ file_cts = eval(file_cts)
257
+ if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance)
258
+ config.on_maintenance = file_cts.on_maintenance
259
+ config.on_maintenance_message = file_cts.on_maintenance_message
260
+ end
261
+ end
262
+ end
263
+
204
264
  when /^Bot has been (closed|killed) by/i
205
265
  sleep 2
206
266
  get_bots_created()
@@ -213,6 +273,22 @@ class SlackSmartBot
213
273
  when /removed the access to the rules of (.+) from (.+)\.$/i
214
274
  sleep 2
215
275
  get_bots_created()
276
+ when /global shortcut added/
277
+ sleep 2
278
+ if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb")
279
+ file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join
280
+ unless file_sc.to_s() == ""
281
+ @shortcuts_global = eval(file_sc)
282
+ end
283
+ end
284
+ when /global shortcut deleted/
285
+ sleep 2
286
+ if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb")
287
+ file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join
288
+ unless file_sc.to_s() == ""
289
+ @shortcuts_global = eval(file_sc)
290
+ end
291
+ end
216
292
  end
217
293
  end
218
294
  end