slack-smart-bot 1.12.8 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
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