slack-smart-bot 1.7.0 → 1.9.1

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 +52 -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 +11 -6
  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 +2 -6
  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 +33 -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 +227 -186
  48. data/lib/slack/smart-bot/process_first.rb +104 -87
  49. data/lib/slack/smart-bot/treat_message.rb +116 -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 +18 -0
  60. metadata +22 -12
  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,32 @@ 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
+ #if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?<#(\w+)\|([^>]+)>\s*:?\s*(.*)/im)
73
+ if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?((<#\w+\|[^>]+>\s*)+)\s*:?\s*(.*)/im)
74
+ channels_rules = $2 #multiple channels @smart-bot on #channel1 #channel2 echo AAA
75
+ data_text = $4
76
+ channel_rules_name = ''
77
+ channel_rules = ''
78
+ # to be treated only on the bots of the requested channels
79
+ channels_rules.scan(/<#(\w+)\|([^>]+)>/).each do |tcid, tcname|
80
+ if @channel_id == tcid
81
+ data.text = data_text
82
+ typem = :on_call
83
+ channel_rules = tcid
84
+ channel_rules_name = tcname
85
+ break
86
+ end
67
87
  end
68
- elsif dest == @master_bot_id
88
+ elsif data.channel == @master_bot_id
69
89
  if config.on_master_bot #only to be treated on master bot channel
70
90
  typem = :on_master
71
91
  end
72
- elsif @bots_created.key?(dest)
73
- if @channel_id == dest #only to be treated by the bot on the channel
92
+ elsif @bots_created.key?(data.channel)
93
+ if @channel_id == data.channel #only to be treated by the bot on the channel
74
94
  typem = :on_bot
75
95
  end
76
- elsif dest[0] == "D" #Direct message
96
+ elsif data.channel[0] == "D" #Direct message
77
97
  get_rules_imported()
78
98
  if @rules_imported.key?(data.user) && @rules_imported[data.user].key?(data.user) and
79
99
  @bots_created.key?(@rules_imported[data.user][data.user])
@@ -85,21 +105,21 @@ class SlackSmartBot
85
105
  #only to be treated by master bot
86
106
  typem = :on_dm
87
107
  end
88
- elsif dest[0] == "C" or dest[0] == "G"
108
+ elsif data.channel[0] == "C" or data.channel[0] == "G"
89
109
  #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
110
+ if !config.on_master_bot and @bots_created.key?(@channel_id) and @bots_created[@channel_id][:extended].include?(@channels_name[data.channel]) and
91
111
  !data.text.match?(/^!?\s*(ruby|code)\s+/) and !data.text.match?(/^!?!?\s*(ruby|code)\s+/) and !data.text.match?(/^\^?\s*(ruby|code)\s+/)
92
112
  typem = :on_extended
93
113
  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
114
  #or in case of running ruby, the master bot
95
115
  @bots_created.each do |k, v|
96
- if v.key?(:extended) and v[:extended].include?(@channels_name[dest])
116
+ if v.key?(:extended) and v[:extended].include?(@channels_name[data.channel])
97
117
  typem = :on_extended
98
118
  break
99
119
  end
100
120
  end
101
121
  end
102
- if dest[0] == "G" and config.on_master_bot and typem != :on_extended #private group
122
+ if data.channel[0] == "G" and config.on_master_bot and typem != :on_extended #private group
103
123
  typem = :on_pg
104
124
  end
105
125
  end
@@ -116,18 +136,27 @@ class SlackSmartBot
116
136
  end
117
137
  begin
118
138
  #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)
139
+ user_info = get_user_info(data.user)
140
+
141
+ #user_info.user.id = data.user #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
142
+ data.user = user_info.user.id #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
143
+ if data.thread_ts.nil?
144
+ qdest = dest
145
+ else
146
+ qdest = data.thread_ts
147
+ end
148
+ if !answer(user_info.user.name, qdest).empty?
121
149
  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)
150
+ answer_delete(user_info.user.name, qdest)
123
151
  command = data.text
124
152
  else
125
- command = @questions[user_info.user.name]
126
- @questions[user_info.user.name] = data.text
153
+ command = answer(user_info.user.name, qdest)
154
+ @answer[user_info.user.name][qdest] = data.text
155
+ @questions[user_info.user.name] = data.text # to be backwards compatible #todo remove it when 2.0
127
156
  end
128
- elsif @repl_sessions.key?(user_info.user.name) and dest==@repl_sessions[user_info.user.name][:dest] and
157
+ elsif @repl_sessions.key?(user_info.user.name) and data.channel==@repl_sessions[user_info.user.name][:dest] and
129
158
  ((@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 == '' ))
159
+ (!@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts.to_s == '' ))
131
160
 
132
161
  if data.text.match(/^\s*```(.*)```\s*$/im)
133
162
  @repl_sessions[user_info.user.name][:command] = $1
@@ -140,16 +169,16 @@ class SlackSmartBot
140
169
  end
141
170
 
142
171
  #when added special characters on the message
143
- if command.match(/^\s*```(.*)```\s*$/im)
172
+ if command.match(/\A\s*```(.*)```\s*\z/im)
144
173
  command = $1
145
174
  elsif command.size >= 2 and
146
- ((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_"))
175
+ ((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_"))
147
176
  command = command[1..-2]
148
177
  end
149
178
 
150
179
  #ruby file attached
151
180
  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
181
+ (command.match?(/^(ruby|code)\s*$/) or (command.match?(/^\s*$/) and data.files[0].filetype == "ruby") or
153
182
  (typem == :on_call and data.files[0].filetype == "ruby"))
154
183
  res = Faraday.new("https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" }).get(data.files[0].url_private)
155
184
  command += " ruby" if command != "ruby"
@@ -160,47 +189,66 @@ class SlackSmartBot
160
189
  command = "!" + command unless command[0] == "!" or command.match?(/^\s*$/) or command[0] == "^"
161
190
 
162
191
  #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
192
+ channels = get_channels()
168
193
  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?
194
+ members = get_channel_members(@channels_id[channel_rules_name]) unless channel_found.nil?
170
195
  if channel_found.nil?
171
196
  @logger.fatal "Not possible to find the channel #{channel_rules_name}"
172
197
  elsif channel_found.name == config.master_channel
173
- respond "You cannot use the rules from Master Channel on any other channel.", dest
198
+ respond "You cannot use the rules from Master Channel on any other channel.", data.channel
174
199
  elsif @status != :on
175
- respond "The bot in that channel is not :on", dest
200
+ respond "The bot in that channel is not :on", data.channel
176
201
  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)
202
+ process_first(user_info.user, command, dest, channel_rules, typem, data.files, data.ts, data.thread_ts, data.routine)
178
203
  else
179
- respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", dest
204
+ respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", data.channel
180
205
  end
181
206
  elsif config.on_master_bot and typem == :on_extended and
182
207
  command.size > 0 and command[0] != "-"
183
208
  # 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)
209
+ process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts, data.routine)
185
210
  elsif !config.on_master_bot and @bots_created[@channel_id].key?(:extended) and
186
211
  @bots_created[@channel_id][:extended].include?(@channels_name[data.channel]) and
187
212
  command.size > 0 and command[0] != "-"
188
- process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts)
213
+ process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts, data.routine)
189
214
  elsif (dest[0] == "D" or @channel_id == data.channel or data.user == config[:nick_id]) and
190
215
  command.size > 0 and command[0] != "-"
191
- process_first(user_info.user, command, dest, data.channel, typem, data.files, data.ts, data.thread_ts)
216
+ process_first(user_info.user, command, dest, data.channel, typem, data.files, data.ts, data.thread_ts, data.routine)
192
217
  # if @botname on #channel_rules: do something
193
218
  end
194
219
  rescue Exception => stack
195
220
  @logger.fatal stack
196
221
  end
197
222
  else
198
- if !config.on_master_bot and !dest.nil? and (dest == @master_bot_id or dest[0] == "D") and
223
+ if !config.on_master_bot and !dest.nil? and (data.channel == @master_bot_id or dest[0] == "D") and
199
224
  data.text.match?(/^\s*bot\s+status\s*$/i) and @admin_users_id.include?(data.user)
200
225
  respond "ping from #{config.channel}", dest
201
226
  elsif !config.on_master_bot and !dest.nil? and data.user == config[:nick_id] and dest == @master_bot_id
202
227
  # to treat on other bots the status messages populated on master bot
203
228
  case data.text
229
+ when /From now on I'll be on maintenance status/i
230
+ sleep 2
231
+ if File.exist?("#{config.path}/config_tmp.status")
232
+ file_cts = IO.readlines("#{config.path}/config_tmp.status").join
233
+ unless file_cts.to_s() == ""
234
+ file_cts = eval(file_cts)
235
+ if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance)
236
+ config.on_maintenance = file_cts.on_maintenance
237
+ end
238
+ end
239
+ end
240
+ when /From now on I won't be on maintenance/i
241
+ sleep 2
242
+ if File.exist?("#{config.path}/config_tmp.status")
243
+ file_cts = IO.readlines("#{config.path}/config_tmp.status").join
244
+ unless file_cts.to_s() == ""
245
+ file_cts = eval(file_cts)
246
+ if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance)
247
+ config.on_maintenance = file_cts.on_maintenance
248
+ end
249
+ end
250
+ end
251
+
204
252
  when /^Bot has been (closed|killed) by/i
205
253
  sleep 2
206
254
  get_bots_created()
@@ -213,6 +261,22 @@ class SlackSmartBot
213
261
  when /removed the access to the rules of (.+) from (.+)\.$/i
214
262
  sleep 2
215
263
  get_bots_created()
264
+ when /global shortcut added/
265
+ sleep 2
266
+ if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb")
267
+ file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join
268
+ unless file_sc.to_s() == ""
269
+ @shortcuts_global = eval(file_sc)
270
+ end
271
+ end
272
+ when /global shortcut deleted/
273
+ sleep 2
274
+ if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb")
275
+ file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join
276
+ unless file_sc.to_s() == ""
277
+ @shortcuts_global = eval(file_sc)
278
+ end
279
+ end
216
280
  end
217
281
  end
218
282
  end