slack-smart-bot 1.12.8 → 1.13.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +85 -12
  3. data/lib/slack/smart-bot/comm/respond.rb +1 -0
  4. data/lib/slack/smart-bot/comm/update.rb +13 -0
  5. data/lib/slack/smart-bot/comm.rb +1 -0
  6. data/lib/slack/smart-bot/commands/general/add_team.rb +1 -0
  7. data/lib/slack/smart-bot/commands/general/add_vacation.rb +5 -0
  8. data/lib/slack/smart-bot/commands/general/allow_access.rb +1 -1
  9. data/lib/slack/smart-bot/commands/general/delete_team.rb +1 -0
  10. data/lib/slack/smart-bot/commands/general/deny_access.rb +1 -1
  11. data/lib/slack/smart-bot/commands/general/public_holidays.rb +144 -0
  12. data/lib/slack/smart-bot/commands/general/see_announcements.rb +2 -2
  13. data/lib/slack/smart-bot/commands/general/see_memos_team.rb +202 -0
  14. data/lib/slack/smart-bot/commands/general/see_teams.rb +3 -175
  15. data/lib/slack/smart-bot/commands/general/see_vacations.rb +41 -21
  16. data/lib/slack/smart-bot/commands/general/set_public_holidays.rb +21 -0
  17. data/lib/slack/smart-bot/commands/general/update_team.rb +1 -0
  18. data/lib/slack/smart-bot/commands/general_bot_commands.rb +100 -8
  19. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +27 -3
  20. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +12 -8
  21. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +33 -4
  22. data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +22 -1
  23. data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +50 -4
  24. data/lib/slack/smart-bot/commands/on_bot/admin_master/update_message.rb +25 -0
  25. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +8 -6
  26. data/lib/slack/smart-bot/commands/on_bot/repl.rb +55 -15
  27. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +2 -1
  28. data/lib/slack/smart-bot/commands.rb +4 -0
  29. data/lib/slack/smart-bot/listen.rb +1 -1
  30. data/lib/slack/smart-bot/process.rb +36 -6
  31. data/lib/slack/smart-bot/process_first.rb +250 -188
  32. data/lib/slack/smart-bot/treat_message.rb +1 -1
  33. data/lib/slack/smart-bot/utils/build_help.rb +1 -1
  34. data/lib/slack/smart-bot/utils/create_routine_thread.rb +40 -4
  35. data/lib/slack/smart-bot/utils/decrypt.rb +15 -0
  36. data/lib/slack/smart-bot/utils/display_calendar.rb +86 -0
  37. data/lib/slack/smart-bot/utils/encrypt.rb +15 -0
  38. data/lib/slack/smart-bot/utils/encryption_get_key_iv.rb +29 -0
  39. data/lib/slack/smart-bot/utils/get_help.rb +1 -1
  40. data/lib/slack/smart-bot/utils/get_team_members.rb +39 -0
  41. data/lib/slack/smart-bot/utils/get_teams.rb +22 -16
  42. data/lib/slack/smart-bot/utils/get_vacations.rb +20 -15
  43. data/lib/slack/smart-bot/utils/save_stats.rb +2 -2
  44. data/lib/slack/smart-bot/utils/update_teams.rb +15 -9
  45. data/lib/slack/smart-bot/utils/update_vacations.rb +5 -3
  46. data/lib/slack/smart-bot/utils.rb +5 -0
  47. data/lib/slack-smart-bot.rb +9 -0
  48. data/lib/slack-smart-bot_general_commands.rb +33 -0
  49. data/lib/slack-smart-bot_general_rules.rb +2 -2
  50. data/whats_new.txt +15 -17
  51. metadata +27 -11
@@ -61,10 +61,12 @@ class SlackSmartBot
61
61
  /\A\s*stop\s+using\s+rules\s+(on\s+)(.+)\s*$/i
62
62
  channel = $2
63
63
  stop_using_rules_on(dest, user, from, channel, typem)
64
- when /\A\s*stop\s+using\s+(rules\s+from\s+)?<#\w+\|(.+)>/i,
64
+ when /\A\s*stop\s+using\s+rules\s*$()()/i,
65
+ /\A\s*stop\s+using\s+(rules\s+from\s+)?<#\w+\|(.+)>/i,
65
66
  /\A\s*stop\s+using\s+(rules\s+from\s+)?<#(\w+)\|>/i,
66
67
  /\A\s*stop\s+using\s+(rules\s+from\s+)?(.+)\s*$/i
67
68
  channel = $2
69
+ channel = @channel_id if channel.to_s == ''
68
70
  stop_using_rules(dest, channel, user, dchannel)
69
71
  when /\A\s*extend\s+rules\s+(to\s+)<#C\w+\|(.+)>/i, /\A\s*extend\s+rules\s+(to\s+)<#(\w+)\|>/i,
70
72
  /\A\s*extend\s+rules\s+(to\s+)(.+)/i,
@@ -106,6 +108,8 @@ class SlackSmartBot
106
108
  /\A\s*(add|create)\s+(silent\s+)?(bgroutine|routine)\s+([\w\.]+)\s+(every)\s+(\d+)\s*(days|hours|minutes|seconds|mins|min|secs|sec|d|h|m|s)\s*(\s<#(C\w+)\|.*>\s*)?(\s.+)?\s*\z/im,
107
109
  /\A\s*(add|create)\s+(silent\s+)?(bgroutine|routine)\s+([\w\.]+)\s+on\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday|weekend|weekday)s?\s+at\s+(\d+:\d+:?\d+?)\s*()(\s#(\w+)\s*)(\s.+)?\s*\z/im,
108
110
  /\A\s*(add|create)\s+(silent\s+)?(bgroutine|routine)\s+([\w\.]+)\s+on\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday|weekend|weekday)s?\s+at\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.*>\s*)?(\s.+)?\s*\z/im,
111
+ /\A\s*(add|create)\s+(silent\s+)?(bgroutine|routine)\s+([\w\.]+)\s+on\s+the\s+(\d+)[^\s]*\s+at\s+(\d+:\d+:?\d+?)\s*()(\s#(\w+)\s*)(\s.+)?\s*\z/im,
112
+ /\A\s*(add|create)\s+(silent\s+)?(bgroutine|routine)\s+([\w\.]+)\s+on\s+the\s+(\d+)[^\s]*\s+at\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.*>\s*)?(\s.+)?\s*\z/im,
109
113
  /\A\s*(add|create)\s+(silent\s+)?(bgroutine|routine)\s+([\w\.]+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s#(\w+)\s*)(\s.+)?\s*\z/im,
110
114
  /\A\s*(add|create)\s+(silent\s+)?(bgroutine|routine)\s+([\w\.]+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.*>\s*)?(\s.+)?\s*\z/im
111
115
  silent = $2.to_s!=''
@@ -145,9 +149,11 @@ class SlackSmartBot
145
149
  when /\A\s*start\s+routine\s+([\w\.]+)\s*$/i
146
150
  name = $1.downcase
147
151
  start_routine(dest, from, name)
148
- when /\A\s*see\s+(all\s+)?routines\s*$/i
152
+ when /\A\s*see\s+(all\s+)?routines\s*()$/i, /\A\s*see\s+(all\s+)?routines\s+(name|creator|status|next_run|last_run|command)\s+\/(.+)\/\s*$/i
149
153
  all = $1.to_s != ""
150
- see_routines(dest, from, user, all)
154
+ header = $2.to_s.downcase
155
+ regexp = $3.to_s
156
+ see_routines(dest, from, user, all, header, regexp)
151
157
  when /\A\s*get\s+bot\s+logs?\s*$/i
152
158
  get_bot_logs(dest, from, typem)
153
159
  when /\A\s*send\s+message\s+(on|to|in)\s+<(https?:[^:]+)>\s*:\s*(.+)\s*$/im,
@@ -158,25 +164,49 @@ class SlackSmartBot
158
164
  thread_ts = ''
159
165
  to_channel = ''
160
166
  to = []
167
+ stats_from = ''
168
+ stats_to = ''
169
+ stats_channel_filter = ''
170
+ stats_command_filter = ''
161
171
 
162
172
  opts.split(' ').each do |opt|
163
173
  if opt.match?(/\Ahttps:/i)
164
174
  to_channel, thread_ts = opt.scan(/\/archives\/(\w+)\/(\w\d+)/)[0]
165
175
  to << to_channel
166
176
  elsif opt.match(/<#([^>]+)\|.*>/) #channel
167
- to << $1
177
+ if stats_from == ''
178
+ to << $1
179
+ else
180
+ stats_channel_filter = $1
181
+ end
168
182
  elsif opt.match(/#([^\s]+)/) #channel
169
- to << $1
183
+ if stats_from == ''
184
+ to << $1
185
+ else
186
+ stats_channel_filter = $1
187
+ end
170
188
  elsif opt.match(/<@(\w+)>/)
171
189
  to << $1
190
+ elsif opt.match(/\d{4}[\/\-]\d\d[\/\-]\d\d/)
191
+ if stats_from == ''
192
+ stats_from = opt
193
+ else
194
+ stats_to = opt
195
+ end
196
+ elsif stats_to!=''
197
+ stats_command_filter = opt
172
198
  end
173
199
  end
174
200
 
175
201
  thread_ts.gsub!('.','')
176
- send_message(dest, from, typem, to, thread_ts, message)
202
+ send_message(dest, from, typem, to, thread_ts, stats_from, stats_to, stats_channel_filter, stats_command_filter, message)
177
203
  when /\A\s*delete\s+message\s+(http.+)\s*$/i
178
204
  url = $1
179
205
  delete_message(from, typem, url)
206
+ when /\A\s*update\s+message\s+(http[^\s]+)\s+(.+)\s*\z/mi
207
+ url = $1
208
+ text = Thread.current[:command_orig].scan(/\A\s*update\s+message\s+<?http[^\s]+\s+(.+)\s*\z/mi).join
209
+ update_message(from, typem, url, text)
180
210
  when /\A\s*react\s+(on|to|in)\s*([^\s]+)\s+([p\d\.]+)\s+(.+)\s*$/i,
181
211
  /\A\s*react\s+(on|to|in)\s*([^\s]+)\s+()(.+)\s*$/i
182
212
  to = $2
@@ -2,12 +2,66 @@ class SlackSmartBot
2
2
  def process_first(user, text, dest, dchannel, typem, files, ts, thread_ts, routine, routine_name, routine_type, command_orig)
3
3
  nick = user.name
4
4
  rules_file = ""
5
- text.gsub!(/^!!/,'^') # to treat it just as ^
5
+ if text.match(/\A\s*(stop|quit|exit|kill)\s+(iterator|iteration|loop)\s+(\d+)\s*\z/i)
6
+ save_stats :quit_loop, forced: true, data: {dest: dest, typem: typem, user: user, files: false, command: text, routine: routine}
7
+ num_iteration = $3.to_i
8
+ if config.admins.include?(user.name) or @loops.key?(user.name)
9
+ if config.admins.include?(user.name)
10
+ name_loop = ''
11
+ @loops.each do |k,v|
12
+ if v.include?(num_iteration)
13
+ name_loop = k
14
+ break
15
+ end
16
+ end
17
+ else
18
+ name_loop = user.name
19
+ end
20
+ if @loops.key?(name_loop) and @loops[name_loop].include?(num_iteration)
21
+ @loops[name_loop].delete(num_iteration)
22
+ respond "Loop #{num_iteration} stopped", dest, thread_ts: thread_ts
23
+ else
24
+ respond "You don't have any loop with id #{num_iteration}. Only the creator of the loop or an admin can stop the loop.", dest, thread_ts: thread_ts
25
+ end
26
+ else
27
+ respond "Only the creator of the loop or an admin can stop the loop.", dest, thread_ts: thread_ts
28
+ end
29
+ @logger.info "command: #{nick}> #{text}"
30
+ return :next #jal
31
+ end
32
+ if text.match(/\A\s*!*^?\s*(for\s*)?(\d+)\s+times\s+every\s+(\d+)\s*(m|minute|minutes|s|sc|second|seconds)\s+(.+)\s*\z/i)
33
+ save_stats :create_loop, forced: true, data: {dest: dest, typem: typem, user: user, files: false, command: text, routine: routine}
34
+ # min every 10s, max every 60m, max times 24
35
+ command_every = text.dup
36
+ text = $5
37
+ num_times = $2.to_i
38
+ type_every = $4.downcase
39
+ every_seconds = $3.to_i
40
+ command_every.gsub!(/^\s*!*^?\s*/, '')
41
+ every_seconds = (every_seconds * 60) if type_every[0] == "m"
42
+ if num_times > 24 or every_seconds < 10 or every_seconds > 3600
43
+ respond "You can't do that. Maximum times is 24, minimum every is 10 seconds, maximum every is 60 minutes.", dest, thread_ts: thread_ts
44
+ return :next #jal
45
+ end
46
+ @loops[user.name] ||= []
47
+ @num_loops ||= 0
48
+ @num_loops += 1
49
+ loop_id = @num_loops
50
+ @loops[user.name] << loop_id
51
+ respond "Loop #{loop_id} started. To stop the loop use: `#{['stop','quit','exit', 'kill'].sample} #{['iteration','iterator','loop'].sample} #{loop_id}`", dest, thread_ts: thread_ts
52
+ #todo: command_orig should be reasigned maybe to remove for N times every X seconds. Check.
53
+ else
54
+ command_every = ''
55
+ num_times = 1
56
+ every_seconds = 0
57
+ end
58
+
59
+ text.gsub!(/^!!/, "^") # to treat it just as ^
6
60
  shared = []
7
- if @shares.key?(@channels_name[dest]) and (ts.to_s!='' or config.simulate) and (user.id!=config.nick_id or (user.id == config.nick_id and !text.match?(/\A\*?Shares from channel/)))
61
+ if @shares.key?(@channels_name[dest]) and (ts.to_s != "" or config.simulate) and (user.id != config.nick_id or (user.id == config.nick_id and !text.match?(/\A\*?Shares from channel/)))
8
62
  @shares[@channels_name[dest]].each do |row|
9
- if row[:user_deleted]==''
10
- if ((row[:type] == 'text' and text.include?(row[:condition][1..-2])) or (row[:type]=='regexp' and text.match?(/#{row[:condition][1..-2]}/im))) and !shared.include?(row[:to_channel])
63
+ if row[:user_deleted] == ""
64
+ if ((row[:type] == "text" and text.include?(row[:condition][1..-2])) or (row[:type] == "regexp" and text.match?(/#{row[:condition][1..-2]}/im))) and !shared.include?(row[:to_channel])
11
65
  if config.simulate
12
66
  link = text
13
67
  else
@@ -41,7 +95,7 @@ class SlackSmartBot
41
95
  if @bots_created.key?(@rules_imported[user.name][user.name])
42
96
  rules_file = @bots_created[@rules_imported[user.name][user.name]][:rules_file]
43
97
  end
44
- elsif dest[0] == 'D' and (!@rules_imported.key?(user.name) or ( @rules_imported.key?(user.name) and !@rules_imported[user.name].key?(user.name)))
98
+ elsif dest[0] == "D" and (!@rules_imported.key?(user.name) or (@rules_imported.key?(user.name) and !@rules_imported[user.name].key?(user.name)))
45
99
  if File.exist?("#{config.path}/rules/general_rules.rb")
46
100
  rules_file = "/rules/general_rules.rb"
47
101
  end
@@ -98,18 +152,18 @@ class SlackSmartBot
98
152
 
99
153
  #only for shortcuts
100
154
  if text.match(/^@?(#{config[:nick]}):*\s+(.+)\s*/im) or
101
- text.match(/^()\^\s*(.+)\s*/im) or
102
- text.match(/^()!\s*(.+)\s*/im) or
103
- text.match(/^()<@#{config[:nick_id]}>\s+(.+)\s*/im)
155
+ text.match(/^()\^\s*(.+)\s*/im) or
156
+ text.match(/^()!\s*(.+)\s*/im) or
157
+ text.match(/^()<@#{config[:nick_id]}>\s+(.+)\s*/im)
104
158
  command2 = $2
105
159
  if text.match?(/^()\^\s*(.+)/im)
106
160
  add_double_excl = true
107
161
  addexcl = false
108
162
  if command2.match?(/^![^!]/) or command2.match?(/^\^/)
109
- command2[0]=''
163
+ command2[0] = ""
110
164
  elsif command2.match?(/^!!/)
111
- command2[0]=''
112
- command2[1]=''
165
+ command2[0] = ""
166
+ command2[1] = ""
113
167
  end
114
168
  else
115
169
  add_double_excl = false
@@ -118,14 +172,14 @@ class SlackSmartBot
118
172
  command = command2
119
173
  else
120
174
  addexcl = false
121
- if text.include?('$') #for shortcuts inside commands
175
+ if text.include?("$") #for shortcuts inside commands
122
176
  command = text.lstrip.rstrip
123
177
  else
124
178
  command = text.downcase.lstrip.rstrip
125
179
  end
126
180
  end
127
181
 
128
- if command.include?('$') #for adding shortcuts inside commands
182
+ if command.include?("$") #for adding shortcuts inside commands
129
183
  command.scan(/\$([^\$]+)/i).flatten.each do |sc|
130
184
  sc.strip!
131
185
  if @shortcuts.key?(nick) and @shortcuts[nick].keys.include?(sc)
@@ -155,10 +209,10 @@ class SlackSmartBot
155
209
  text = "^" + text if add_double_excl
156
210
  end
157
211
  if command.scan(/^(shortcut|sc)\s+([^:]+)\s*$/i).any? or
158
- (@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or
159
- (@shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)) or
160
- (@shortcuts_global.keys.include?(:all) and @shortcuts_global[:all].keys.include?(command)) or
161
- (@shortcuts_global.keys.include?(nick) and @shortcuts_global[nick].keys.include?(command))
212
+ (@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or
213
+ (@shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)) or
214
+ (@shortcuts_global.keys.include?(:all) and @shortcuts_global[:all].keys.include?(command)) or
215
+ (@shortcuts_global.keys.include?(nick) and @shortcuts_global[nick].keys.include?(command))
162
216
  command = $2.downcase unless $2.nil?
163
217
  if @shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)
164
218
  text = @shortcuts[nick][command].dup
@@ -178,209 +232,217 @@ class SlackSmartBot
178
232
 
179
233
  command = text
180
234
 
181
- begin
182
- t = Thread.new do
183
- begin
184
- processed = false
185
- processed_rules = false
235
+ num_times.times do |i|
236
+ command_thread = command.dup
237
+ begin
238
+ t = Thread.new do
239
+ begin
240
+ sleep every_seconds * i if every_seconds > 0
241
+ Thread.exit if command_every!='' and @loops.key?(user.name) and !@loops[user.name].include?(loop_id)
242
+ @logger.info "i: #{i}, num_times: #{num_times}, every_seconds: #{every_seconds}, command: #{command_thread}" if command_every!=''
243
+ processed = false
244
+ processed_rules = false
186
245
 
187
- Thread.current[:dest] = dest
188
- Thread.current[:user] = user
189
- Thread.current[:command] = command
190
- Thread.current[:rules_file] = rules_file
191
- Thread.current[:typem] = typem
192
- Thread.current[:files?] = !files.nil? && files.size>0
193
- Thread.current[:ts] = ts
194
- Thread.current[:thread_ts] = thread_ts
195
- Thread.current[:routine] = routine
196
- Thread.current[:routine_name] = routine_name
197
- Thread.current[:routine_type] = routine_type
198
- Thread.current[:dchannel] = dchannel
199
- Thread.current[:command_orig] = command_orig
200
- if thread_ts.to_s == ''
201
- Thread.current[:on_thread] = false
202
- Thread.current[:thread_ts] = Thread.current[:ts] # to create the thread if necessary
203
- else
204
- Thread.current[:on_thread] = true
205
- end
206
- if (dest[0] == "C") || (dest[0] == "G") and @rules_imported.key?(user.name) &&
207
- @rules_imported[user.name].key?(dchannel) && @bots_created.key?(@rules_imported[user.name][dchannel])
246
+ Thread.current[:dest] = dest
247
+ Thread.current[:user] = user
248
+ Thread.current[:command] = command_thread.dup
249
+ Thread.current[:rules_file] = rules_file
250
+ Thread.current[:typem] = typem
251
+ Thread.current[:files?] = !files.nil? && files.size > 0
252
+ Thread.current[:ts] = ts
253
+ Thread.current[:thread_ts] = thread_ts
254
+ Thread.current[:routine] = routine
255
+ Thread.current[:routine_name] = routine_name
256
+ Thread.current[:routine_type] = routine_type
257
+ Thread.current[:dchannel] = dchannel
258
+ Thread.current[:command_orig] = command_orig.dup
259
+ if thread_ts.to_s == ""
260
+ Thread.current[:on_thread] = false
261
+ Thread.current[:thread_ts] = Thread.current[:ts] # to create the thread if necessary
262
+ else
263
+ Thread.current[:on_thread] = true
264
+ end
265
+ if (dest[0] == "C") || (dest[0] == "G") and @rules_imported.key?(user.name) &&
266
+ @rules_imported[user.name].key?(dchannel) && @bots_created.key?(@rules_imported[user.name][dchannel])
208
267
  Thread.current[:using_channel] = @rules_imported[user.name][dchannel]
209
- elsif dest[0] == "D" && @rules_imported.key?(user.name) && @rules_imported[user.name].key?(user.name) and
210
- @bots_created.key?(@rules_imported[user.name][user.name])
268
+ elsif dest[0] == "D" && @rules_imported.key?(user.name) && @rules_imported[user.name].key?(user.name) and
269
+ @bots_created.key?(@rules_imported[user.name][user.name])
211
270
  Thread.current[:using_channel] = @rules_imported[user.name][user.name]
212
- else
213
- Thread.current[:using_channel] = ''
214
- end
215
- if (typem == :on_pub or typem == :on_pg) and (!command.match?(/\s*bot\s+stats\s*(.*)\s*$/i) or dest!=@channels_id[config.stats_channel])
216
- processed = false
217
- else
218
- processed = process(user, command, dest, dchannel, rules_file, typem, files, Thread.current[:thread_ts])
219
- end
220
- on_demand = false
221
- if command.match(/\A@?(#{config[:nick]}):*\s+(.+)/im) or
222
- command.match(/\A()!!(.+)/im) or
223
- command.match(/\A()\^(.+)/im) or
224
- command.match(/\A()!(.+)/im) or
225
- command.match(/\A()<@#{config[:nick_id]}>\s+(.+)/im)
226
- command2 = $2
227
- Thread.current[:command] = command2
228
- if command2.match?(/^()!!(.+)/im) or
229
- command.match?(/^()\^(.+)/im)
230
- Thread.current[:on_thread] = true
271
+ else
272
+ Thread.current[:using_channel] = ""
231
273
  end
232
- command = command2
233
- on_demand = true
234
- end
235
- unless config.on_maintenance or @status != :on
236
- if typem == :on_pub or typem == :on_pg or typem == :on_extended
237
- if command.match(/\A\s*(#{@salutations.join("|")})\s+(rules|help)\s*(.+)?$/i) or command.match(/\A(#{@salutations.join("|")}),? what can I do/i)
238
- $2.to_s.match?(/rules/i) ? specific = true : specific = false
239
- help_command = $3
240
- if typem == :on_extended and specific
241
- bot_rules(dest, help_command, typem, rules_file, user)
242
- else
243
- bot_help(user, user.name, dest, dchannel, specific, help_command, rules_file)
274
+ if (typem == :on_pub or typem == :on_pg) and (!command_thread.match?(/\s*bot\s+stats\s*(.*)\s*$/i) or dest != @channels_id[config.stats_channel])
275
+ processed = false
276
+ else
277
+ processed = process(user, command_thread, dest, dchannel, rules_file, typem, files, Thread.current[:thread_ts])
278
+ end
279
+ on_demand = false
280
+ if command_thread.match(/\A@?(#{config[:nick]}):*\s+(.+)/im) or
281
+ command_thread.match(/\A()!!(.+)/im) or
282
+ command_thread.match(/\A()\^(.+)/im) or
283
+ command_thread.match(/\A()!(.+)/im) or
284
+ command_thread.match(/\A()<@#{config[:nick_id]}>\s+(.+)/im)
285
+ command2 = $2
286
+ Thread.current[:command] = command2
287
+ if command2.match?(/^()!!(.+)/im) or
288
+ command_thread.match?(/^()\^(.+)/im)
289
+ Thread.current[:on_thread] = true
290
+ end
291
+ command_thread = command2
292
+ on_demand = true
293
+ end
294
+ unless config.on_maintenance or @status != :on
295
+ if typem == :on_pub or typem == :on_pg or typem == :on_extended
296
+ if command_thread.match(/\A\s*(#{@salutations.join("|")})\s+(rules|help)\s*(.+)?$/i) or command_thread.match(/\A(#{@salutations.join("|")}),? what can I do/i)
297
+ $2.to_s.match?(/rules/i) ? specific = true : specific = false
298
+ help_command = $3
299
+ if typem == :on_extended and specific
300
+ bot_rules(dest, help_command, typem, rules_file, user)
301
+ else
302
+ bot_help(user, user.name, dest, dchannel, specific, help_command, rules_file)
303
+ end
304
+ processed = true
244
305
  end
245
- processed = true
246
- end
306
+ end
307
+ processed = (processed || general_bot_commands(user, command_thread, dest, files))
308
+ processed = (processed || general_commands(user, command_thread, dest, files)) if defined?(general_commands)
309
+ @logger.info "command: #{nick}> #{command_thread}" if processed
247
310
  end
248
- processed = (processed || general_bot_commands(user, command, dest, files) )
249
- processed = (processed || general_commands(user, command, dest, files) ) if defined?(general_commands)
250
- @logger.info "command: #{nick}> #{command}" if processed
251
- end
252
311
 
253
- if !config.on_maintenance and !processed and typem != :on_pub and typem != :on_pg
254
- if @status == :on and
255
- (!answer.empty? or
256
- (@repl_sessions.key?(nick) and dest==@repl_sessions[nick][:dest] and
257
- ((@repl_sessions[nick][:on_thread] and thread_ts == @repl_sessions[nick][:thread_ts]) or
258
- (!@repl_sessions[nick][:on_thread] and !Thread.current[:on_thread] ))) or
259
- (@listening.key?(nick) and typem != :on_extended and
260
- ((@listening[nick].key?(dest) and !Thread.current[:on_thread]) or
261
- (@listening[nick].key?(thread_ts) and Thread.current[:on_thread] ) )) or
262
- dest[0] == "D" or on_demand)
263
- @logger.info "command: #{nick}> #{command}" unless processed
264
- #todo: verify this
312
+ if !config.on_maintenance and !processed and typem != :on_pub and typem != :on_pg
313
+ if @status == :on and
314
+ (!answer.empty? or
315
+ (@repl_sessions.key?(nick) and dest == @repl_sessions[nick][:dest] and
316
+ ((@repl_sessions[nick][:on_thread] and thread_ts == @repl_sessions[nick][:thread_ts]) or
317
+ (!@repl_sessions[nick][:on_thread] and !Thread.current[:on_thread]))) or
318
+ (@listening.key?(nick) and typem != :on_extended and
319
+ ((@listening[nick].key?(dest) and !Thread.current[:on_thread]) or
320
+ (@listening[nick].key?(thread_ts) and Thread.current[:on_thread]))) or
321
+ dest[0] == "D" or on_demand)
322
+ @logger.info "command: #{nick}> #{command_thread}" unless processed
323
+ #todo: verify this
265
324
 
266
- if dest[0] == "C" or dest[0] == "G" or (dest[0] == "D" and typem == :on_call)
267
- if typem != :on_call and @rules_imported.key?(user.name) and @rules_imported[user.name].key?(dchannel)
268
- if @bots_created.key?(@rules_imported[user.name][dchannel])
269
- if @bots_created[@rules_imported[user.name][dchannel]][:status] != :on
270
- respond "The bot on that channel is not :on", dest
271
- rules_file = ""
272
- end
273
- end
274
- end
275
- unless rules_file.empty?
276
- begin
277
- eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
278
- rescue Exception => stack
279
- @logger.fatal "ERROR ON RULES FILE: #{rules_file}"
280
- @logger.fatal stack
281
- end
282
- if defined?(rules)
283
- command[0] = "" if command[0] == "!"
284
- command.gsub!(/^@\w+:*\s*/, "")
285
- if method(:rules).parameters.size == 4
286
- processed_rules = rules(user, command, processed, dest)
287
- elsif method(:rules).parameters.size == 5
288
- processed_rules = rules(user, command, processed, dest, files)
289
- else
290
- processed_rules = rules(user, command, processed, dest, files, rules_file)
325
+ if dest[0] == "C" or dest[0] == "G" or (dest[0] == "D" and typem == :on_call)
326
+ if typem != :on_call and @rules_imported.key?(user.name) and @rules_imported[user.name].key?(dchannel)
327
+ if @bots_created.key?(@rules_imported[user.name][dchannel])
328
+ if @bots_created[@rules_imported[user.name][dchannel]][:status] != :on
329
+ respond "The bot on that channel is not :on", dest
330
+ rules_file = ""
331
+ end
291
332
  end
292
- else
293
- @logger.warn "It seems like rules method is not defined"
294
333
  end
295
- end
296
- elsif @rules_imported.key?(user.name) and @rules_imported[user.name].key?(user.name)
297
- if @bots_created.key?(@rules_imported[user.name][user.name])
298
- if @bots_created[@rules_imported[user.name][user.name]][:status] == :on
334
+ unless rules_file.empty?
299
335
  begin
300
- eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) and !['.','..'].include?(config.path + rules_file)
336
+ eval(File.new(config.path + rules_file).read) if File.exist?(config.path + rules_file)
301
337
  rescue Exception => stack
302
- @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
338
+ @logger.fatal "ERROR ON RULES FILE: #{rules_file}"
303
339
  @logger.fatal stack
304
340
  end
305
- else
306
- respond "The bot on <##{@rules_imported[user.name][user.name]}|#{@bots_created[@rules_imported[user.name][user.name]][:channel_name]}> is not :on", dest
307
- rules_file = ""
341
+ if defined?(rules)
342
+ command_thread[0] = "" if command_thread[0] == "!"
343
+ command_thread.gsub!(/^@\w+:*\s*/, "")
344
+ if method(:rules).parameters.size == 4
345
+ processed_rules = rules(user, command_thread, processed, dest)
346
+ elsif method(:rules).parameters.size == 5
347
+ processed_rules = rules(user, command_thread, processed, dest, files)
348
+ else
349
+ processed_rules = rules(user, command_thread, processed, dest, files, rules_file)
350
+ end
351
+ else
352
+ @logger.warn "It seems like rules method is not defined"
353
+ end
354
+ end
355
+ elsif @rules_imported.key?(user.name) and @rules_imported[user.name].key?(user.name)
356
+ if @bots_created.key?(@rules_imported[user.name][user.name])
357
+ if @bots_created[@rules_imported[user.name][user.name]][:status] == :on
358
+ begin
359
+ eval(File.new(config.path + rules_file).read) if File.exist?(config.path + rules_file) and ![".", ".."].include?(config.path + rules_file)
360
+ rescue Exception => stack
361
+ @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
362
+ @logger.fatal stack
363
+ end
364
+ else
365
+ respond "The bot on <##{@rules_imported[user.name][user.name]}|#{@bots_created[@rules_imported[user.name][user.name]][:channel_name]}> is not :on", dest
366
+ rules_file = ""
367
+ end
308
368
  end
309
- end
310
369
 
311
- unless rules_file.empty?
312
- if defined?(rules)
313
- command[0] = "" if command[0] == "!"
314
- command.gsub!(/^@\w+:*\s*/, "")
315
- if method(:rules).parameters.size == 4
316
- processed_rules = rules(user, command, processed, dest)
317
- elsif method(:rules).parameters.size == 5
318
- processed_rules = rules(user, command, processed, dest, files)
370
+ unless rules_file.empty?
371
+ if defined?(rules)
372
+ command_thread[0] = "" if command_thread[0] == "!"
373
+ command_thread.gsub!(/^@\w+:*\s*/, "")
374
+ if method(:rules).parameters.size == 4
375
+ processed_rules = rules(user, command_thread, processed, dest)
376
+ elsif method(:rules).parameters.size == 5
377
+ processed_rules = rules(user, command_thread, processed, dest, files)
378
+ else
379
+ processed_rules = rules(user, command_thread, processed, dest, files, rules_file)
380
+ end
319
381
  else
320
- processed_rules = rules(user, command, processed, dest, files, rules_file)
382
+ @logger.warn "It seems like rules method is not defined"
321
383
  end
322
- else
323
- @logger.warn "It seems like rules method is not defined"
324
384
  end
325
- end
326
- elsif dest[0] == 'D' and
327
- (!@rules_imported.key?(user.name) or ( @rules_imported.key?(user.name) and !@rules_imported[user.name].key?(user.name))) and
328
- rules_file.include?('general_rules.rb')
329
- begin
330
- eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) and !['.','..'].include?(config.path + rules_file)
331
- rescue Exception => stack
332
- @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
333
- @logger.fatal stack
334
- end
385
+ elsif dest[0] == "D" and
386
+ (!@rules_imported.key?(user.name) or (@rules_imported.key?(user.name) and !@rules_imported[user.name].key?(user.name))) and
387
+ rules_file.include?("general_rules.rb")
388
+ begin
389
+ eval(File.new(config.path + rules_file).read) if File.exist?(config.path + rules_file) and ![".", ".."].include?(config.path + rules_file)
390
+ rescue Exception => stack
391
+ @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
392
+ @logger.fatal stack
393
+ end
335
394
 
336
- if defined?(general_rules)
337
- command[0] = "" if command[0] == "!"
338
- command.gsub!(/^@\w+:*\s*/, "")
339
- #todo: check to change processed > processed_rules
340
- if method(:general_rules).parameters.size == 4
341
- processed = general_rules(user, command, processed, dest)
342
- elsif method(:general_rules).parameters.size == 5
343
- processed = general_rules(user, command, processed, dest, files)
395
+ if defined?(general_rules)
396
+ command_thread[0] = "" if command_thread[0] == "!"
397
+ command_thread.gsub!(/^@\w+:*\s*/, "")
398
+ #todo: check to change processed > processed_rules
399
+ if method(:general_rules).parameters.size == 4
400
+ processed = general_rules(user, command_thread, processed, dest)
401
+ elsif method(:general_rules).parameters.size == 5
402
+ processed = general_rules(user, command_thread, processed, dest, files)
403
+ else
404
+ processed = general_rules(user, command_thread, processed, dest, files, rules_file)
405
+ end
344
406
  else
345
- processed = general_rules(user, command, processed, dest, files, rules_file)
407
+ @logger.warn "It seems like general_rules method is not defined"
408
+ end
409
+ unless processed
410
+ dont_understand("")
346
411
  end
347
412
  else
348
- @logger.warn "It seems like general_rules method is not defined"
349
- end
350
- unless processed
351
- dont_understand('')
352
- end
353
- else
354
- @logger.info "it is a direct message with no rules file selected so no rules file executed."
355
- if command.match?(/^\s*bot\s+rules\s*(.*)$/i)
356
- 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
357
- end
358
- unless processed
359
- dont_understand('')
413
+ @logger.info "it is a direct message with no rules file selected so no rules file executed."
414
+ if command_thread.match?(/^\s*bot\s+rules\s*(.*)$/i)
415
+ 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
416
+ end
417
+ unless processed
418
+ dont_understand("")
419
+ end
360
420
  end
361
- end
362
421
 
363
- processed = (processed_rules || processed)
422
+ processed = (processed_rules || processed)
364
423
 
365
- if processed and @listening.key?(nick)
366
- if Thread.current[:on_thread] and @listening[nick].key?(Thread.current[:thread_ts])
367
- @listening[nick][Thread.current[:thread_ts]] = Time.now
368
- elsif !Thread.current[:on_thread] and @listening[nick].key?(dest)
369
- @listening[nick][dest] = Time.now
424
+ if processed and @listening.key?(nick)
425
+ if Thread.current[:on_thread] and @listening[nick].key?(Thread.current[:thread_ts])
426
+ @listening[nick][Thread.current[:thread_ts]] = Time.now
427
+ elsif !Thread.current[:on_thread] and @listening[nick].key?(dest)
428
+ @listening[nick][dest] = Time.now
429
+ end
370
430
  end
371
431
  end
372
432
  end
433
+
434
+ if processed and config.general_message != "" and !routine
435
+ respond eval("\"" + config.general_message + "\"")
436
+ end
437
+ respond "_*Loop #{loop_id}* (#{i+1}/#{num_times}) <@#{user.name}>: #{command_every}_" if command_every!='' and processed
438
+ @loops[user.name].delete(loop_id) if command_every!='' and !processed and @loops.key?(user.name) and @loops[user.name].include?(loop_id)
439
+ rescue Exception => stack
440
+ @logger.fatal stack
373
441
  end
374
-
375
- if processed and config.general_message != '' and !routine
376
- respond eval("\"" + config.general_message + "\"")
377
- end
378
- rescue Exception => stack
379
- @logger.fatal stack
380
442
  end
443
+ rescue => e
444
+ @logger.error "exception: #{e.inspect}"
381
445
  end
382
- rescue => e
383
- @logger.error "exception: #{e.inspect}"
384
446
  end
385
447
  end
386
448
  end
@@ -290,7 +290,7 @@ class SlackSmartBot
290
290
  end
291
291
 
292
292
  else
293
- @logger.warn "Pay attention there is no user on users with id #{data.user}" if user_info.nil?
293
+ @logger.warn "Pay attention there is no user on users with id #{data.user}" if user_info.nil? and data.user.to_s!=''
294
294
  if !config.on_master_bot and !dest.nil? and (data.channel == @master_bot_id or dest[0] == "D") and
295
295
  data.text.match?(/^\s*(!|!!|\^)?\s*bot\s+status\s*$/i) and @admin_users_id.include?(data.user)
296
296
  respond "ping from #{config.channel}", dest
@@ -17,7 +17,7 @@ class SlackSmartBot
17
17
  help_message[:admin][t.scan(/\/(\w+)$/).join.to_sym] = res[:admin]
18
18
  help_message[:normal][t.scan(/\/(\w+)$/).join.to_sym] = res[:normal]
19
19
  else
20
- lines = IO.readlines(t)
20
+ lines = IO.readlines(t, encoding: 'UTF-8')
21
21
  data = {master:{}, admin:{}, normal:{}}
22
22
  data.master = lines.join #normal user help
23
23
  data.admin = lines.reject {|l| l.match?(/^\s*#\s*help\s*master\s*:.+$/i)}.join #not master help