slack-smart-bot 1.4.3 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -1
  3. data/lib/slack-smart-bot.rb +7 -0
  4. data/lib/slack-smart-bot_rules.rb +13 -2
  5. data/lib/slack/smart-bot/comm.rb +2 -1
  6. data/lib/slack/smart-bot/comm/ask.rb +10 -2
  7. data/lib/slack/smart-bot/comm/dont_understand.rb +1 -0
  8. data/lib/slack/smart-bot/comm/react.rb +16 -0
  9. data/lib/slack/smart-bot/comm/respond.rb +10 -2
  10. data/lib/slack/smart-bot/comm/send_file.rb +6 -0
  11. data/lib/slack/smart-bot/comm/send_msg_channel.rb +5 -1
  12. data/lib/slack/smart-bot/comm/send_msg_user.rb +10 -2
  13. data/lib/slack/smart-bot/commands.rb +2 -0
  14. data/lib/slack/smart-bot/commands/general/bot_help.rb +3 -3
  15. data/lib/slack/smart-bot/commands/general/bot_status.rb +1 -0
  16. data/lib/slack/smart-bot/commands/general/bye_bot.rb +1 -0
  17. data/lib/slack/smart-bot/commands/general/hi_bot.rb +1 -0
  18. data/lib/slack/smart-bot/commands/general/stop_using_rules.rb +1 -0
  19. data/lib/slack/smart-bot/commands/general/use_rules.rb +1 -0
  20. data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +1 -0
  21. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +1 -0
  22. data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +1 -0
  23. data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +1 -0
  24. data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +1 -0
  25. data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +1 -0
  26. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +1 -0
  27. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +1 -0
  28. data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +1 -0
  29. data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +1 -0
  30. data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +1 -0
  31. data/lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb +122 -0
  32. data/lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb +18 -0
  33. data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +1 -0
  34. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +2 -1
  35. data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +1 -0
  36. data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +3 -2
  37. data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +1 -0
  38. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +2 -1
  39. data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +1 -0
  40. data/lib/slack/smart-bot/commands/on_master/create_bot.rb +1 -0
  41. data/lib/slack/smart-bot/process.rb +29 -3
  42. data/lib/slack/smart-bot/process_first.rb +49 -12
  43. data/lib/slack/smart-bot/treat_message.rb +32 -9
  44. data/lib/slack/smart-bot/utils.rb +1 -0
  45. data/lib/slack/smart-bot/utils/get_help.rb +12 -6
  46. data/lib/slack/smart-bot/utils/save_stats.rb +32 -0
  47. metadata +8 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cb8cb53b73c745750923baa5dec85e97f3dafee2ece3861c76c1d95d77d8aa8
4
- data.tar.gz: 72104118233208a398a3da57745fc998ae78437f7063094e347a565b28d73890
3
+ metadata.gz: 7276a93ba8921b2fc6fe95b31d883210acdf5668959f997f4605f4069f4d1050
4
+ data.tar.gz: '0389132b491c8c7e0d7ee58057b8499a0b5210ccb0b940bb3426aa2a5e2e56b3'
5
5
  SHA512:
6
- metadata.gz: 492662c54354f6bfadb325fedad5510b2c3036398215c81a2d3a4605354f76aee3f0dc372311a3437b57a18fc51b78a5ee31ef9e81d3c87274ce19f77fd97614
7
- data.tar.gz: b9976a98998e14b271f43a3fc338be5ca59cd7b64e43a0bac846399c8a44ac943d2e9c993ede071bfe4714f6b04197389bde1257cf4a2f0edb33c4f6c7408cf3
6
+ metadata.gz: df45b098eb49a96e57d7c5fb64aca50f28bfc663b6c6f1122d98ef01f3064705b4fbd136273cd53db167bd8fa735b253354a3f1b310525eacf86cd78b59c4dbb
7
+ data.tar.gz: 2fe9fceb4f7bce3423371abd2185d91e1debe2a37155390838de5d4d0d900d96ffc5264fc613a6d7f75dc6e1bfebd160e422897ec301c93d3b1972aa8507e3c3
data/README.md CHANGED
@@ -106,6 +106,7 @@ def rules(user, command, processed, dest)
106
106
  # help:
107
107
  when /^echo\s(.+)/i
108
108
  respond $1
109
+ react :monkey_face
109
110
 
110
111
  # help: `go to sleep`
111
112
  # help: it will sleep the bot for 10 seconds
@@ -119,7 +120,9 @@ def rules(user, command, processed, dest)
119
120
  @questions.delete(from)
120
121
  respond "I'll be sleeping for 10 secs... just for you"
121
122
  respond "zZzzzzzZZZZZZzzzzzzz!"
123
+ react :sleeping
122
124
  sleep 10
125
+ react :sunny
123
126
  when /no/i, /nope/i, /cancel/i
124
127
  @questions.delete(from)
125
128
  respond "Thanks, I'm happy to be awake"
@@ -134,7 +137,7 @@ def rules(user, command, processed, dest)
134
137
  # help: It will run the process and report the results when done
135
138
  # help:
136
139
  when /^run something/i
137
- respond "Running"
140
+ react :runner
138
141
 
139
142
  process_to_run = "ruby -v"
140
143
  stdout, stderr, status = Open3.capture3(process_to_run)
@@ -171,6 +174,9 @@ To run a command on demand:
171
174
  **_`!THE_COMMAND`_**
172
175
  **_`@NAME_OF_BOT THE_COMMAND`_**
173
176
  **_`NAME_OF_BOT THE_COMMAND`_**
177
+ To run a command on demand and add the respond on a thread:
178
+ **_`^THE_COMMAND`_**
179
+ **_`!!THE_COMMAND`_**
174
180
 
175
181
  Examples run a command on demand:
176
182
  >**_Peter>_** `!ruby puts Time.now`
@@ -182,12 +188,18 @@ Examples run a command on demand:
182
188
  >**_Peter>_** `smart-bot see shortcuts`
183
189
  >**_Smart-Bot>_** `Available shortcuts for Peter:`
184
190
  >`Spanish account: ruby require 'iso/iban'; 10.times {puts ISO::IBAN.random('ES')}`
191
+ >**_Peter>_** `!!echo Example`
192
+ > **_Smart-Bot>_** `Example`
193
+ >**_Peter>_** `^echo Example`
194
+ > **_Smart-Bot>_** `Example`
185
195
 
186
196
  Also you can always call the Smart Bot from any channel, even from channels without a running Smart Bot. You can use the External Call on Demand: **_`@NAME_OF_BOT on #CHANNEL_NAME COMMAND`_**. In this case you will call the bot on #CHANNEL_NAME.
187
197
 
188
198
  Example:
189
199
  >**_Peter>_** `@smart-bot on #the_channel ruby puts Time.now`
190
200
  >**_Smart-Bot>_** `2019-10-23 12:43:42 +0000`
201
+ >**_Peter>_** `@smart-bot on #the_channel ^ruby puts Time.now`
202
+ >**_Smart-Bot>_** `2019-10-23 12:43:42 +0000`
191
203
 
192
204
 
193
205
 
@@ -232,6 +244,10 @@ To see the status of the bots, on the MASTER CHANNEL: **_`bot status`_**
232
244
 
233
245
  To close the Master Bot, run on MASTER CHANNEL: **_`exit bot`_**
234
246
 
247
+ If you are a Master Admin on a Direct Message with the Smart Bot you can call the **_`bot stats`_** and get use stats of the users. You need to set to <true> the `stats` settings when initializing the Smart Bot. Take a look at `bot help bot stats` for more info.
248
+
249
+ You can also get the bot logs of the bot channel you are using by calling `get bot logs`. You need to be a Master Admin user on a DM with the Smart Bot.
250
+
235
251
  #### Cloud Bots
236
252
  If you want to create a bot that will be running on a different machine: **_`create cloud bot on CHANNEL`_**. Even though the cloud bots are running on different machines, the management can be done through the MASTER CHANNEL. The new cloud bot will be managed by your Master Bot like the others, closing, pausing...
237
253
 
@@ -45,6 +45,8 @@ class SlackSmartBot
45
45
  end
46
46
  config[:testing] = false unless config.key?(:testing)
47
47
  config[:simulate] = false unless config.key?(:simulate)
48
+ config[:stats] = false unless config.key?(:stats)
49
+
48
50
  if config.path.to_s!='' and config.file.to_s==''
49
51
  config.file = File.basename($0)
50
52
  end
@@ -55,6 +57,10 @@ class SlackSmartBot
55
57
  config.file = File.basename(config.file_path)
56
58
  config.path = File.dirname(config.file_path)
57
59
  end
60
+ if config.stats
61
+ Dir.mkdir("#{config.path}/stats") unless Dir.exist?("#{config.path}/stats")
62
+ config.stats_path = "#{config.path}/stats/#{config.file.gsub(".rb", ".stats")}"
63
+ end
58
64
  Dir.mkdir("#{config.path}/logs") unless Dir.exist?("#{config.path}/logs")
59
65
  Dir.mkdir("#{config.path}/shortcuts") unless Dir.exist?("#{config.path}/shortcuts")
60
66
  Dir.mkdir("#{config.path}/routines") unless Dir.exist?("#{config.path}/routines")
@@ -101,6 +107,7 @@ class SlackSmartBot
101
107
 
102
108
 
103
109
  logfile = File.basename(config.rules_file.gsub("_rules_", "_logs_"), ".rb") + ".log"
110
+ config.log_file = logfile
104
111
  @logger = Logger.new("#{config.path}/logs/#{logfile}")
105
112
 
106
113
  config_log = config.dup
@@ -30,6 +30,9 @@ end
30
30
  # help: `!THE_COMMAND`
31
31
  # help: `@NAME_OF_BOT THE_COMMAND`
32
32
  # help: `NAME_OF_BOT THE_COMMAND`
33
+ # help: To run a command on demand and add the respond on a thread:
34
+ # help: `^THE_COMMAND`
35
+ # help: `!!THE_COMMAND`
33
36
  # help:
34
37
  def rules(user, command, processed, dest, files = [], rules_file = "")
35
38
  from = user.name
@@ -44,13 +47,16 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
44
47
  # help: Examples:
45
48
  # help: _echo I am the Smart Bot_
46
49
  when /^echo\s(.+)/i
50
+ save_stats :echo
47
51
  respond $1
52
+ react :monkey_face
48
53
 
49
54
  # help: ----------------------------------------------
50
55
  # help: `go to sleep`
51
56
  # help: it will sleep the bot for 5 seconds
52
57
  # help:
53
58
  when /^go\sto\ssleep/i
59
+ save_stats :to_to_sleep
54
60
  unless @questions.keys.include?(from)
55
61
  ask "do you want me to take a siesta?"
56
62
  else
@@ -59,7 +65,9 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
59
65
  @questions.delete(from)
60
66
  respond "I'll be sleeping for 5 secs... just for you"
61
67
  respond "zZzzzzzZZZZZZzzzzzzz!"
68
+ react :sleeping
62
69
  sleep 5
70
+ react :sunny
63
71
  when /no/i, /nope/i, /cancel/i
64
72
  @questions.delete(from)
65
73
  respond "Thanks, I'm happy to be awake"
@@ -74,7 +82,8 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
74
82
  # help: It will run the process and report the results when done
75
83
  # help:
76
84
  when /^run something/i
77
- respond "Running"
85
+ save_stats :run_something
86
+ react :runner
78
87
 
79
88
  process_to_run = "ruby -v"
80
89
  process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
@@ -88,7 +97,9 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
88
97
  else
89
98
  respond "#{display_name}: #{stdout} #{stderr}"
90
99
  end
91
-
100
+
101
+ # Emoticons you can use with `react` command https://www.webfx.com/tools/emoji-cheat-sheet/
102
+
92
103
  # Examples for respond and respond_direct
93
104
  # # send 'the message' to the channel or direct message where the command was written
94
105
  # respond "the message"
@@ -4,4 +4,5 @@ require_relative 'comm/respond_direct'
4
4
  require_relative 'comm/respond'
5
5
  require_relative 'comm/send_file'
6
6
  require_relative 'comm/send_msg_channel'
7
- require_relative 'comm/send_msg_user'
7
+ require_relative 'comm/send_msg_user'
8
+ require_relative 'comm/react'
@@ -19,7 +19,11 @@ class SlackSmartBot
19
19
  f.puts "|#{@channel_id}|#{config[:nick_id]}|#{message}~~~"
20
20
  }
21
21
  else
22
- client.message(channel: @channel_id, text: message, as_user: true)
22
+ if Thread.current[:on_thread]
23
+ client.message(channel: @channel_id, text: message, as_user: true, thread_ts: Thread.current[:thread_ts])
24
+ else
25
+ client.message(channel: @channel_id, text: message, as_user: true)
26
+ end
23
27
  end
24
28
  if config[:testing] and config.on_master_bot
25
29
  open("#{config.path}/buffer.log", "a") { |f|
@@ -32,7 +36,11 @@ class SlackSmartBot
32
36
  f.puts "|#{dest}|#{config[:nick_id]}|#{message}~~~"
33
37
  }
34
38
  else
35
- client.message(channel: dest, text: message, as_user: true)
39
+ if Thread.current[:on_thread]
40
+ client.message(channel: dest, text: message, as_user: true, thread_ts: Thread.current[:thread_ts])
41
+ else
42
+ client.message(channel: dest, text: message, as_user: true)
43
+ end
36
44
  end
37
45
  if config[:testing] and config.on_master_bot
38
46
  open("#{config.path}/buffer.log", "a") { |f|
@@ -1,6 +1,7 @@
1
1
  class SlackSmartBot
2
2
 
3
3
  def dont_understand(rules_file = nil, command = nil, user = nil, dest = nil, answer = ["what?", "huh?", "sorry?", "what do you mean?", "I don't understand"], channel_rules: config.channel, typem: nil)
4
+ save_stats(:dont_understand)
4
5
  command = Thread.current[:command] if command.nil?
5
6
  user = Thread.current[:user] if user.nil?
6
7
  dest = Thread.current[:dest] if dest.nil?
@@ -0,0 +1,16 @@
1
+ class SlackSmartBot
2
+ # list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/
3
+ # react(:thumbsup)
4
+ def react(emoji, parent=false)
5
+ if parent
6
+ ts = Thread.current[:thread_ts]
7
+ else
8
+ ts = Thread.current[:ts]
9
+ end
10
+ begin
11
+ client.web_client.reactions_add(channel: Thread.current[:dest], name: emoji, timestamp: ts)
12
+ rescue Exception => stack
13
+ @logger.warn stack
14
+ end
15
+ end
16
+ end
@@ -10,7 +10,11 @@ class SlackSmartBot
10
10
  f.puts "|#{@channel_id}|#{config[:nick_id]}|#{msg}~~~"
11
11
  }
12
12
  else
13
- client.message(channel: @channel_id, text: msg, as_user: true)
13
+ if Thread.current[:on_thread]
14
+ client.message(channel: @channel_id, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts])
15
+ else
16
+ client.message(channel: @channel_id, text: msg, as_user: true)
17
+ end
14
18
  end
15
19
  if config[:testing] and config.on_master_bot
16
20
  open("#{config.path}/buffer.log", "a") { |f|
@@ -23,7 +27,11 @@ class SlackSmartBot
23
27
  f.puts "|#{dest}|#{config[:nick_id]}|#{msg}~~~"
24
28
  }
25
29
  else
26
- client.message(channel: dest, text: msg, as_user: true)
30
+ if Thread.current[:on_thread]
31
+ client.message(channel: dest, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts])
32
+ else
33
+ client.message(channel: dest, text: msg, as_user: true)
34
+ end
27
35
  end
28
36
  if config[:testing] and config.on_master_bot
29
37
  open("#{config.path}/buffer.log", "a") { |f|
@@ -10,6 +10,11 @@ class SlackSmartBot
10
10
  else
11
11
  channel = to
12
12
  end
13
+ if Thread.current[:on_thread]
14
+ ts = Thread.current[:thread_ts]
15
+ else
16
+ ts = nil
17
+ end
13
18
 
14
19
  client.web_client.files_upload(
15
20
  channels: channel,
@@ -19,6 +24,7 @@ class SlackSmartBot
19
24
  filename: file,
20
25
  filetype: type,
21
26
  initial_comment: msg,
27
+ thread_ts: ts
22
28
  )
23
29
  end
24
30
 
@@ -17,7 +17,11 @@ class SlackSmartBot
17
17
  f.puts "|#{channel_id}|#{config[:nick_id]}|#{msg}~~~"
18
18
  }
19
19
  else
20
- client.message(channel: channel_id, text: msg, as_user: true)
20
+ if Thread.current[:on_thread]
21
+ client.message(channel: channel_id, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts])
22
+ else
23
+ client.message(channel: channel_id, text: msg, as_user: true)
24
+ end
21
25
  end
22
26
  if config[:testing] and config.on_master_bot
23
27
  open("#{config.path}/buffer.log", "a") { |f|
@@ -9,7 +9,11 @@ class SlackSmartBot
9
9
  f.puts "|#{id_user}|#{config[:nick_id]}|#{msg}~~~"
10
10
  }
11
11
  else
12
- client.message(channel: id_user, as_user: true, text: msg)
12
+ if Thread.current[:on_thread]
13
+ client.message(channel: id_user, as_user: true, text: msg, thread_ts: Thread.current[:thread_ts])
14
+ else
15
+ client.message(channel: id_user, as_user: true, text: msg)
16
+ end
13
17
  end
14
18
  if config[:testing] and config.on_master_bot
15
19
  open("#{config.path}/buffer.log", "a") { |f|
@@ -23,7 +27,11 @@ class SlackSmartBot
23
27
  f.puts "|#{im["channel"]["id"]}|#{config[:nick_id]}|#{msg}~~~"
24
28
  }
25
29
  else
26
- client.message(channel: im["channel"]["id"], as_user: true, text: msg)
30
+ if Thread.current[:on_thread]
31
+ client.message(channel: im["channel"]["id"], as_user: true, text: msg, thread_ts: Thread.current[:thread_ts])
32
+ else
33
+ client.message(channel: im["channel"]["id"], as_user: true, text: msg)
34
+ end
27
35
  end
28
36
  if config[:testing] and config.on_master_bot
29
37
  open("#{config.path}/buffer.log", "a") { |f|
@@ -23,3 +23,5 @@ require_relative "commands/on_bot/add_shortcut"
23
23
  require_relative "commands/on_bot/delete_shortcut"
24
24
  require_relative "commands/on_bot/see_shortcuts"
25
25
  require_relative "commands/on_extended/bot_rules"
26
+ require_relative "commands/on_bot/admin_master/get_bot_logs"
27
+ require_relative "commands/on_bot/admin_master/bot_stats"
@@ -11,7 +11,7 @@ class SlackSmartBot
11
11
  # help: `bot rules` will show only the specific rules for this channel.
12
12
  # help:
13
13
  def bot_help(user, from, dest, dchannel, specific, help_command, rules_file)
14
- help_message_rules = ""
14
+ save_stats(__method__)
15
15
  help_found = false
16
16
 
17
17
  message = ""
@@ -19,7 +19,7 @@ class SlackSmartBot
19
19
  help_message = get_help(rules_file, dest, from, specific)
20
20
 
21
21
  if help_command.to_s != ""
22
- help_message.split(/^\s*-------*$/).each do |h|
22
+ help_message.gsub(/====+/,'-'*30).split(/^\s*-------*$/).each do |h|
23
23
  if h.match?(/[`_]#{help_command}/i)
24
24
  respond h, dest
25
25
  help_found = true
@@ -52,7 +52,7 @@ class SlackSmartBot
52
52
  eval(File.new(config.path + rules_file).read) if File.exist?(config.path + rules_file)
53
53
  end
54
54
  end
55
- if defined?(git_project) && (git_project.to_s != "") && (help_message_rules != "") && (help_command.to_s == "")
55
+ if defined?(git_project) && (git_project.to_s != "") && (help_command.to_s == "")
56
56
  respond "Git project: #{git_project}", dest
57
57
  else
58
58
  def git_project
@@ -5,6 +5,7 @@ class SlackSmartBot
5
5
  # helpadmin: If on master channel and admin user also it will display info about bots created
6
6
  # helpadmin:
7
7
  def bot_status(dest, from)
8
+ save_stats(__method__)
8
9
  get_bots_created()
9
10
  gems_remote = `gem list slack-smart-bot --remote`
10
11
  version_remote = gems_remote.to_s().scan(/slack-smart-bot \((\d+\.\d+\.\d+)/).join
@@ -9,6 +9,7 @@ class SlackSmartBot
9
9
  # help:
10
10
  def bye_bot(dest, from, display_name)
11
11
  if @status == :on
12
+ save_stats(__method__)
12
13
  bye = ["Bye", "Bæ", "Good Bye", "Adiós", "Ciao", "Bless", "Bless bless", "Adeu"].sample
13
14
  respond "#{bye} #{display_name}", dest
14
15
  @listening.delete(from)
@@ -11,6 +11,7 @@ class SlackSmartBot
11
11
  # help:
12
12
  def hi_bot(user, dest, dchannel, from, display_name)
13
13
  if @status == :on
14
+ save_stats(__method__)
14
15
  greetings = ["Hello", "Hallo", "Hi", "Hola", "What's up", "Hey", "Hæ"].sample
15
16
  respond "#{greetings} #{display_name}", dest
16
17
  if Thread.current[:using_channel]!=''
@@ -4,6 +4,7 @@ class SlackSmartBot
4
4
  # help: it will stop using the rules from the specified channel.
5
5
  # help:
6
6
  def stop_using_rules(dest, channel, user, dchannel)
7
+ save_stats(__method__)
7
8
  if @channels_id.key?(channel)
8
9
  channel_id = @channels_id[channel]
9
10
  else
@@ -8,6 +8,7 @@ class SlackSmartBot
8
8
  # help: you need to be part of that channel to be able to use the rules.
9
9
  # help:
10
10
  def use_rules(dest, channel, user, dchannel)
11
+ save_stats(__method__)
11
12
  get_bots_created()
12
13
  #todo: add pagination for case more than 1000 channels on the workspace
13
14
  channels = client.web_client.conversations_list(
@@ -18,6 +18,7 @@ class SlackSmartBot
18
18
  # help: _Spanish Account_
19
19
  # help:
20
20
  def add_shortcut(dest, from, typem, for_all, shortcut_name, command, command_to_run)
21
+ save_stats(__method__)
21
22
  unless typem == :on_extended
22
23
  @shortcuts[from] = Hash.new() unless @shortcuts.keys.include?(from)
23
24
 
@@ -23,6 +23,7 @@ class SlackSmartBot
23
23
  # helpadmin: _create silent routine every 12 hours !Run customer tests_
24
24
  # helpadmin:
25
25
  def add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent)
26
+ save_stats(__method__)
26
27
  if files.nil? or files.size == 0 or (files.size > 0 and config.masters.include?(from))
27
28
  if config.admins.include?(from)
28
29
  if @routines.key?(@channel_id) && @routines[@channel_id].key?(name)
@@ -6,6 +6,7 @@ class SlackSmartBot
6
6
  # helpadmin: It will allow to use the specific rules from this channel on the CHANNEL_NAME
7
7
  # helpadmin:
8
8
  def extend_rules(dest, user, from, channel, typem)
9
+ save_stats(__method__)
9
10
  unless typem == :on_extended
10
11
  if config.on_master_bot
11
12
  respond "You cannot use the rules from Master Channel on any other channel.", dest
@@ -7,6 +7,7 @@ class SlackSmartBot
7
7
  # helpadmin: You can use this command only if you are an admin user
8
8
  # helpadmin:
9
9
  def pause_bot(dest, from)
10
+ save_stats(__method__)
10
11
  if config.admins.include?(from) #admin user
11
12
  respond "This bot is paused from now on. You can start it again: start this bot", dest
12
13
  respond "zZzzzzZzzzzZZZZZZzzzzzzzz", dest
@@ -8,6 +8,7 @@ class SlackSmartBot
8
8
  # helpadmin: _pause routine example_
9
9
  # helpadmin:
10
10
  def pause_routine(dest, from, name)
11
+ save_stats(__method__)
11
12
  if config.admins.include?(from) #admin user
12
13
  if !config.on_master_bot and dest[0] == "D"
13
14
  respond "It's only possible to pause routines from MASTER channel from a direct message with the bot.", dest
@@ -11,6 +11,7 @@ class SlackSmartBot
11
11
  # helpadmin: _kill routine example_
12
12
  # helpadmin:
13
13
  def remove_routine(dest, from, name)
14
+ save_stats(__method__)
14
15
  if config.admins.include?(from) #admin user
15
16
  if !config.on_master_bot and dest[0] == "D"
16
17
  respond "It's only possible to remove routines from MASTER channel from a direct message with the bot.", dest
@@ -11,6 +11,7 @@ class SlackSmartBot
11
11
  # helpadmin:
12
12
 
13
13
  def run_routine(dest, from, name)
14
+ save_stats(__method__)
14
15
  if config.admins.include?(from) #admin user
15
16
  if !config.on_master_bot and dest[0] == "D"
16
17
  respond "It's only possible to run routines from MASTER channel from a direct message with the bot.", dest
@@ -7,6 +7,7 @@ class SlackSmartBot
7
7
  # helpadmin: You can use this command only if you are an admin user
8
8
  # helpadmin:
9
9
  def see_routines(dest, from, user, all)
10
+ save_stats(__method__)
10
11
  if config.admins.include?(from) #admin user
11
12
  if all
12
13
  routines = {}
@@ -7,6 +7,7 @@ class SlackSmartBot
7
7
  # helpadmin: You can use this command only if you are an admin user
8
8
  # helpadmin:
9
9
  def start_bot(dest, from)
10
+ save_stats(__method__)
10
11
  if config.admins.include?(from) #admin user
11
12
  respond "This bot is running and listening from now on. You can pause again: pause this bot", dest
12
13
  @status = :on
@@ -10,6 +10,7 @@ class SlackSmartBot
10
10
  # helpadmin:
11
11
 
12
12
  def start_routine(dest, from, name)
13
+ save_stats(__method__)
13
14
  if config.admins.include?(from) #admin user
14
15
  if !config.on_master_bot and dest[0] == "D"
15
16
  respond "It's only possible to start routines from MASTER channel from a direct message with the bot.", dest
@@ -6,6 +6,7 @@ class SlackSmartBot
6
6
  # helpadmin:
7
7
 
8
8
  def stop_using_rules_on(dest, user, from, channel, typem)
9
+ save_stats(__method__)
9
10
  unless typem == :on_extended
10
11
  if !config.admins.include?(from) #not admin
11
12
  respond "Only admins can extend or stop using the rules. Admins on this channel: #{config.admins}", dest
@@ -0,0 +1,122 @@
1
+ class SlackSmartBot
2
+ # helpadmin: ----------------------------------------------
3
+ # helpadmin: `bot stats`
4
+ # helpadmin: `bot stats USER_NAME`
5
+ # helpadmin: `bot stats exclude masters`
6
+ # helpadmin: `bot stats from YYYY/MM/DD`
7
+ # helpadmin: `bot stats from YYYY/MM/DD to YYYY/MM/DD`
8
+ # helpadmin: `bot stats CHANNEL`
9
+ # helpadmin: `bot stats CHANNEL from YYYY/MM/DD`
10
+ # helpadmin: `bot stats CHANNEL from YYYY/MM/DD to YYYY/MM/DD`
11
+ # helpadmin: `bot stats USER_NAME from YYYY/MM/DD to YYYY/MM/DD`
12
+ # helpadmin: `bot stats CHANNEL USER_NAME from YYYY/MM/DD to YYYY/MM/DD`
13
+ # helpadmin: `bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD`
14
+ # helpadmin: `bot stats today`
15
+ # helpadmin: `bot stats exclude COMMAND_ID`
16
+ # helpadmin: To see the bot stats
17
+ # helpadmin: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot
18
+ # helpadmin: You need to set stats to true to generate the stats when running the bot instance.
19
+ # helpadmin: Examples:
20
+ # helpadmin: _bot stats #sales_
21
+ # helpadmin: _bot stats @peter.wind_
22
+ # helpadmin: _bot stats #sales from 2019/12/15 to 2019/12/31_
23
+ # helpadmin: _bot stats #sales today_
24
+ # helpadmin:
25
+ def bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command)
26
+ require 'csv'
27
+ if config.stats
28
+ message = []
29
+ else
30
+ message = ["You need to set stats to true to generate the stats when running the bot instance."]
31
+ end
32
+ save_stats(__method__)
33
+ if config.masters.include?(from_user) and typem==:on_dm #master admin user
34
+ if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
35
+ message<<'No stats'
36
+ else
37
+ from = "#{Time.now.strftime("%Y-%m")}-01" if from == ''
38
+ to = "#{Time.now.strftime("%Y-%m-%d")}" if to == ''
39
+ from_short = from
40
+ to_short = to
41
+ from_file = from[0..3] + '-' + from[5..6]
42
+ to_file = to[0..3] + '-' + to[5..6]
43
+ from+= " 00:00:00 +0000"
44
+ to+= " 23:59:59 +0000"
45
+ rows = []
46
+
47
+ Dir["#{config.stats_path}.*.log"].each do |file|
48
+ if file >= "#{config.stats_path}.#{from_file}.log" or file <= "#{config.stats_path}.#{to_file}.log"
49
+ CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
50
+ row[:date] = row[:date].to_s
51
+ if !exclude_masters or (exclude_masters and !config.masters.include?(row[:user_name]))
52
+ if user=='' or (user!='' and row[:user_id] == user)
53
+ if exclude_command == '' or (exclude_command!='' and row[:command]!=exclude_command)
54
+ if row[:bot_channel_id] == channel_id or channel_id == ''
55
+ if row[:date] >= from and row[:date] <= to
56
+ rows << row.to_h
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ total = rows.size
67
+ if exclude_masters
68
+ message << 'Excluding master admins'
69
+ end
70
+ if exclude_command != ''
71
+ message << "Excluding command #{exclude_command}"
72
+ end
73
+ if user!=''
74
+ message << "Showing only user <@#{user}>"
75
+ end
76
+ if channel_id == ''
77
+ message << "*Total calls*: #{total} from #{from_short} to #{to_short}"
78
+ else
79
+ message << "*Total calls <##{channel_id}>*: #{total} from #{from_short} to #{to_short}"
80
+ end
81
+ if total > 0
82
+
83
+ if channel_id == ''
84
+ message << "*Channels*"
85
+ channels = rows.bot_channel.uniq.sort
86
+ channels.each do |channel|
87
+ count = rows.count {|h| h.bot_channel==channel}
88
+ message << "\t#{channel}: #{count} (#{(count.to_f*100/total).round(2)}%)"
89
+ end
90
+ end
91
+ if user==''
92
+ message << "*Users*"
93
+ users = rows.user_name.uniq.sort
94
+ users.each do |user|
95
+ count = rows.count {|h| h.user_name==user}
96
+ message << "\t#{user}: #{count} (#{(count.to_f*100/total).round(2)}%)"
97
+ end
98
+ end
99
+
100
+ message << "*Commands*"
101
+ commands = rows.command.uniq.sort
102
+ commands.each do |command|
103
+ count = rows.count {|h| h.command==command}
104
+ message << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
105
+ end
106
+
107
+ message << "*Message type*"
108
+ types = rows.type_message.uniq.sort
109
+ types.each do |type|
110
+ count = rows.count {|h| h.type_message==type}
111
+ message << "\t#{type}: #{count} (#{(count.to_f*100/total).round(2)}%)"
112
+ end
113
+ message << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].type_message} #{rows[-1].user_name} #{rows[-1].command}"
114
+ end
115
+
116
+ end
117
+ else
118
+ message<<"Only Master admin users on a private conversation with the bot can see the bot stats."
119
+ end
120
+ respond "#{message.join("\n")}", dest
121
+ end
122
+ end
@@ -0,0 +1,18 @@
1
+ class SlackSmartBot
2
+
3
+ # helpadmin: ----------------------------------------------
4
+ # helpadmin: `get bot logs`
5
+ # helpadmin: To see the bot logs
6
+ # helpadmin: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot
7
+ # helpadmin:
8
+ def get_bot_logs(dest, from, typem)
9
+ save_stats(__method__)
10
+ if config.masters.include?(from) and typem==:on_dm #master admin user
11
+ respond 'Remember this data is private'
12
+ send_file(dest, "Logs for #{config.channel}", "#{config.path}/logs/#{config.log_file}", 'Remember this data is private', 'text/plain', "text")
13
+ else
14
+ respond "Only master admin users on a private conversation with the bot can get the bot logs.", dest
15
+ end
16
+ end
17
+ end
18
+
@@ -6,6 +6,7 @@ class SlackSmartBot
6
6
  # help:
7
7
 
8
8
  def delete_shortcut(dest, from, shortcut, typem, command)
9
+ save_stats(__method__)
9
10
  unless typem == :on_extended
10
11
  deleted = false
11
12
 
@@ -8,6 +8,7 @@ class SlackSmartBot
8
8
  # help:
9
9
 
10
10
  def ruby_code(dest, code, rules_file)
11
+ save_stats(__method__)
11
12
  unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
12
13
  code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
13
14
  code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or
@@ -36,7 +37,7 @@ class SlackSmartBot
36
37
  respond stdout, dest
37
38
  end
38
39
  else
39
- respond stderr, dest
40
+ respond "#{stderr}\n#{stdout}", dest
40
41
  end
41
42
  rescue Exception => exc
42
43
  respond exc, dest
@@ -5,6 +5,7 @@ class SlackSmartBot
5
5
  # help: It will display the shortcuts stored for the user and for :all
6
6
  # help:
7
7
  def see_shortcuts(dest, from, typem)
8
+ save_stats(__method__)
8
9
  unless typem == :on_extended
9
10
  msg = ""
10
11
  if @shortcuts[:all].keys.size > 0
@@ -1,5 +1,6 @@
1
1
  class SlackSmartBot
2
2
  def bot_rules(dest, help_command, typem, rules_file, from)
3
+ save_stats(__method__)
3
4
  if typem == :on_extended or typem == :on_call #for the other cases above.
4
5
  help_filtered = get_help(rules_file, dest, from, true)
5
6
 
@@ -15,7 +16,7 @@ class SlackSmartBot
15
16
  else
16
17
  message = "-\n\n\n===================================\n*Rules from channel #{config.channel}*\n"
17
18
  if typem == :on_extended
18
- message += "To run the commands on this extended channel, add `!` before the command.\n"
19
+ message += "To run the commands on this extended channel, add `!`, `!!` or `^` before the command.\n"
19
20
  end
20
21
  message += help_filtered
21
22
  respond message, dest
@@ -26,7 +27,7 @@ class SlackSmartBot
26
27
  eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file)
27
28
  end
28
29
  end
29
- if defined?(git_project) and git_project.to_s != "" and help_message_rules != "" and help_command.to_s == ""
30
+ if defined?(git_project) and git_project.to_s != "" and help_command.to_s == ""
30
31
  respond "Git project: #{git_project}", dest
31
32
  else
32
33
  def git_project() "" end
@@ -5,6 +5,7 @@ class SlackSmartBot
5
5
  # helpmaster: Only works if you are on Master channel and you created that bot or you are an admin user
6
6
  # helpmaster:
7
7
  def kill_bot_on_channel(dest, from, channel)
8
+ save_stats(__method__)
8
9
  if config.on_master_bot
9
10
  get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
10
11
  channel_id = nil
@@ -8,6 +8,7 @@ class SlackSmartBot
8
8
  # helpadmin: You can use this command only if you are an admin user and you are on the master channel
9
9
  # helpadmin:
10
10
  def exit_bot(command, from, dest, display_name)
11
+ save_stats(__method__)
11
12
  if config.on_master_bot
12
13
  if config.admins.include?(from) #admin user
13
14
  unless @questions.keys.include?(from)
@@ -24,7 +25,7 @@ class SlackSmartBot
24
25
  }
25
26
  update_bots_file()
26
27
  sleep 0.5
27
- if config.simulate #jal
28
+ if config.simulate
28
29
  @status = :off
29
30
  config.simulate = false
30
31
  Thread.exit
@@ -9,6 +9,7 @@ class SlackSmartBot
9
9
  # helpmaster: Only works if you are on Master channel and you are a master admin user
10
10
  # helpmaster:
11
11
  def notify_message(dest, from, where, message)
12
+ save_stats(__method__)
12
13
  if config.on_master_bot
13
14
  if config.admins.include?(from) #admin user
14
15
  if where.nil? #not all and not channel
@@ -8,6 +8,7 @@ class SlackSmartBot
8
8
  # helpmaster: follow the instructions in case creating cloud bots
9
9
  # helpmaster:
10
10
  def create_bot(dest, from, cloud, channel)
11
+ save_stats(__method__)
11
12
  if config.on_master_bot
12
13
  get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
13
14
  channel_id = nil
@@ -1,5 +1,5 @@
1
1
  class SlackSmartBot
2
- def process(user, command, dest, dchannel, rules_file, typem, files)
2
+ def process(user, command, dest, dchannel, rules_file, typem, files, ts)
3
3
  from = user.name
4
4
  if user.profile.display_name.to_s.match?(/\A\s*\z/)
5
5
  user.profile.display_name = user.profile.real_name
@@ -9,10 +9,18 @@ class SlackSmartBot
9
9
 
10
10
  on_demand = false
11
11
  if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or
12
+ command.match(/^()!!(.+)/im) or
13
+ command.match(/^()\^(.+)/im) or
12
14
  command.match(/^()!(.+)/im) or
13
15
  command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im)
14
- command = $2
15
- on_demand = true
16
+ command2 = $2
17
+ Thread.current[:command] = command2
18
+ if command2.match?(/^()!!(.+)/im) or
19
+ command.match?(/^()\^(.+)/im)
20
+ Thread.current[:on_thread] = true
21
+ end
22
+ command = command2
23
+ on_demand = true
16
24
  end
17
25
 
18
26
  #todo: check :on_pg in this case
@@ -84,6 +92,24 @@ class SlackSmartBot
84
92
  when /^\s*see\s+(all\s+)?routines\s*$/i
85
93
  all = $1.to_s != ""
86
94
  see_routines(dest, from, user, all)
95
+ when /^\s*get\s+bot\s+logs?\s*$/i
96
+ get_bot_logs(dest, from, typem)
97
+ when /^\s*bot\s+stats\s*(.*)\s*$/i
98
+ opts = $1.to_s
99
+ all_opts = opts.downcase.split(' ')
100
+ st_channel = opts.scan(/<#(\w+)\|.+>/).join
101
+ st_from = opts.scan(/from\s+(\d\d\d\d[\/\-\.]\d\d[\/\-\.]\d\d)/).join
102
+ st_from = st_from.gsub('.','-').gsub('/','-')
103
+ st_to = opts.scan(/to\s+(\d\d\d\d[\/\-\.]\d\d[\/\-\.]\d\d)/).join
104
+ st_to = st_to.gsub('.','-').gsub('/','-')
105
+ st_user = opts.scan(/<@([^>]+)>/).join
106
+ exclude_masters = opts.match?(/exclude\s+masters?/i)
107
+ if all_opts.include?('today')
108
+ st_from = st_to = "#{Time.now.strftime("%Y-%m-%d")}"
109
+ end
110
+ exclude_command = opts.scan(/exclude\s+([^\s]+)/i).join
111
+ exclude_command = '' if exclude_command == 'masters'
112
+ bot_stats(dest, from, typem, st_channel, st_from, st_to, st_user, exclude_masters, exclude_command)
87
113
  else
88
114
  processed = false
89
115
  end
@@ -1,7 +1,8 @@
1
1
  class SlackSmartBot
2
- def process_first(user, text, dest, dchannel, typem, files)
2
+ def process_first(user, text, dest, dchannel, typem, files, ts, thread_ts)
3
3
  nick = user.name
4
4
  rules_file = ""
5
+ text.gsub!(/^!!/,'^') # to treat it just as ^
5
6
  if typem == :on_call
6
7
  rules_file = config.rules_file
7
8
  elsif dest[0] == "C" or dest[0] == "G" # on a channel or private channel
@@ -30,7 +31,7 @@ class SlackSmartBot
30
31
  when /^Bot has been (closed|killed) by/i
31
32
  if config.channel == @channels_name[dchannel]
32
33
  @logger.info "#{nick}: #{text}"
33
- if config.simulate #jal
34
+ if config.simulate
34
35
  @status = :off
35
36
  config.simulate = false
36
37
  Thread.exit
@@ -76,13 +77,31 @@ class SlackSmartBot
76
77
 
77
78
  #only for shortcuts
78
79
  if text.match(/^@?(#{config[:nick]}):*\s+(.+)\s*/im) or
79
- text.match(/^()!\s*(.+)\s*/im) or
80
- text.match(/^()<@#{config[:nick_id]}>\s+(.+)\s*/im)
81
- command = $2
82
- addexcl = true
80
+ text.match(/^()\^\s*(.+)\s*/im) or
81
+ text.match(/^()!\s*(.+)\s*/im) or
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?(/^\^/)
88
+ command2[0]=''
89
+ elsif command2.match?(/^!!/)
90
+ command2[0]=''
91
+ command2[1]=''
92
+ end
93
+ else
94
+ add_double_excl = false
95
+ addexcl = true
96
+ end
97
+ command = command2
83
98
  else
84
99
  addexcl = false
85
- command = text.downcase.lstrip.rstrip
100
+ if text.include?('$') #for shortcuts inside commands
101
+ command = text.lstrip.rstrip
102
+ else
103
+ command = text.downcase.lstrip.rstrip
104
+ end
86
105
  end
87
106
 
88
107
  if command.include?('$') #for adding shortcuts inside commands
@@ -104,6 +123,7 @@ class SlackSmartBot
104
123
  end
105
124
  text = command
106
125
  text = "!" + text if addexcl and text[0] != "!"
126
+ text = "^" + text if add_double_excl
107
127
  end
108
128
  if command.scan(/^(shortcut|sc)\s+([^:]+)\s*$/i).any? or
109
129
  (@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or
@@ -118,6 +138,7 @@ class SlackSmartBot
118
138
  return :next #jal
119
139
  end
120
140
  text = "!" + text if addexcl and text[0] != "!"
141
+ text = "^" + text if add_double_excl
121
142
  end
122
143
 
123
144
  command = text
@@ -130,6 +151,15 @@ class SlackSmartBot
130
151
  Thread.current[:command] = command
131
152
  Thread.current[:rules_file] = rules_file
132
153
  Thread.current[:typem] = typem
154
+ Thread.current[:files?] = !files.nil? && files.size>0
155
+ Thread.current[:ts] = ts
156
+ Thread.current[:thread_ts] = thread_ts
157
+ if thread_ts.to_s == ''
158
+ Thread.current[:on_thread] = false
159
+ Thread.current[:thread_ts] = Thread.current[:ts] # to create the thread if necessary
160
+ else
161
+ Thread.current[:on_thread] = true
162
+ end
133
163
  if (dest[0] == "C") || (dest[0] == "G") and @rules_imported.key?(user.id) &&
134
164
  @rules_imported[user.id].key?(dchannel) && @bots_created.key?(@rules_imported[user.id][dchannel])
135
165
  Thread.current[:using_channel] = @rules_imported[user.id][dchannel]
@@ -140,14 +170,21 @@ class SlackSmartBot
140
170
  Thread.current[:using_channel] = ''
141
171
  end
142
172
 
143
- processed = process(user, command, dest, dchannel, rules_file, typem, files)
173
+ processed = process(user, command, dest, dchannel, rules_file, typem, files, Thread.current[:thread_ts])
144
174
  @logger.info "command: #{nick}> #{command}" if processed
145
175
  on_demand = false
146
176
  if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or
147
- command.match(/^()!(.+)/im) or
148
- command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im)
149
- command = $2
150
- Thread.current[:command] = command
177
+ command.match(/^()!!(.+)/im) or
178
+ command.match(/^()\^(.+)/im) or
179
+ command.match(/^()!(.+)/im) or
180
+ command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im)
181
+ command2 = $2
182
+ Thread.current[:command] = command2
183
+ if command2.match?(/^()!!(.+)/im) or
184
+ command.match?(/^()\^(.+)/im)
185
+ Thread.current[:on_thread] = true
186
+ end
187
+ command = command2
151
188
  on_demand = true
152
189
  end
153
190
  if @status == :on and
@@ -1,9 +1,31 @@
1
1
  class SlackSmartBot
2
2
  def treat_message(data)
3
3
  begin
4
- data.text = CGI.unescapeHTML(data.text) unless data.text.to_s.match(/\A\s*\z/)
4
+ unless data.text.to_s.match(/\A\s*\z/)
5
+ #to remove italic, bold... from data.text since there is no method on slack api
6
+ #only works when no @user or #channel mentioned
7
+ if !data.blocks.nil? and data.blocks.size > 0
8
+ data.blocks.each do |b|
9
+ if b.type == 'rich_text'
10
+ if b.elements.size > 0
11
+ b.elements.each do |e|
12
+ if e.type == 'rich_text_section'
13
+ if e.elements.size > 0 and e.elements.type.uniq == ['text']
14
+ data.text = e.elements.text.join
15
+ end
16
+ break
17
+ end
18
+ end
19
+ end
20
+ break
21
+ end
22
+ end
23
+ end
24
+ data.text = CGI.unescapeHTML(data.text)
25
+ data.text.gsub!("\u00A0", " ") #to change &nbsp; (asc char 160) into blank space
26
+ end
5
27
  rescue
6
- @logger.warn "Impossible to unescape the data.text:#{data.text}"
28
+ @logger.warn "Impossible to unescape or clean format for data.text:#{data.text}"
7
29
  end
8
30
  if config[:testing] and config.on_master_bot
9
31
  open("#{config.path}/buffer.log", "a") { |f|
@@ -56,9 +78,10 @@ class SlackSmartBot
56
78
  elsif dest[0] == "C" or dest[0] == "G"
57
79
  #only to be treated on the channel of the bot. excluding running ruby
58
80
  if !config.on_master_bot and @bots_created.key?(@channel_id) and @bots_created[@channel_id][:extended].include?(@channels_name[dest]) and
59
- !data.text.match?(/^!?\s*(ruby|code)\s+/)
81
+ !data.text.match?(/^!?\s*(ruby|code)\s+/) and !data.text.match?(/^!?!?\s*(ruby|code)\s+/) and !data.text.match?(/^\^?\s*(ruby|code)\s+/)
60
82
  typem = :on_extended
61
- elsif config.on_master_bot and data.text.match?(/^!?\s*(ruby|code)\s+/) #or in case of running ruby, the master bot
83
+ 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+/) )
84
+ #or in case of running ruby, the master bot
62
85
  @bots_created.each do |k, v|
63
86
  if v.key?(:extended) and v[:extended].include?(@channels_name[dest])
64
87
  typem = :on_extended
@@ -104,7 +127,7 @@ class SlackSmartBot
104
127
  end
105
128
 
106
129
  if typem == :on_call
107
- command = "!" + command unless command[0] == "!" or command.match?(/^\s*$/)
130
+ command = "!" + command unless command[0] == "!" or command.match?(/^\s*$/) or command[0] == "^"
108
131
 
109
132
  #todo: add pagination for case more than 1000 channels on the workspace
110
133
  channels = client.web_client.conversations_list(
@@ -121,21 +144,21 @@ class SlackSmartBot
121
144
  elsif @status != :on
122
145
  respond "The bot in that channel is not :on", dest
123
146
  elsif data.user == channel_found.creator or members.include?(data.user)
124
- process_first(user_info.user, command, dest, channel_rules, typem, data.files)
147
+ process_first(user_info.user, command, dest, channel_rules, typem, data.files, data.ts, data.thread_ts)
125
148
  else
126
149
  respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", dest
127
150
  end
128
151
  elsif config.on_master_bot and typem == :on_extended and
129
152
  command.size > 0 and command[0] != "-"
130
153
  # to run ruby only from the master bot for the case more than one extended
131
- process_first(user_info.user, command, dest, @channel_id, typem, data.files)
154
+ process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts)
132
155
  elsif !config.on_master_bot and @bots_created[@channel_id].key?(:extended) and
133
156
  @bots_created[@channel_id][:extended].include?(@channels_name[data.channel]) and
134
157
  command.size > 0 and command[0] != "-"
135
- process_first(user_info.user, command, dest, @channel_id, typem, data.files)
158
+ process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts)
136
159
  elsif (dest[0] == "D" or @channel_id == data.channel or data.user == config[:nick_id]) and
137
160
  command.size > 0 and command[0] != "-"
138
- process_first(user_info.user, command, dest, data.channel, typem, data.files)
161
+ process_first(user_info.user, command, dest, data.channel, typem, data.files, data.ts, data.thread_ts)
139
162
  # if @botname on #channel_rules: do something
140
163
  end
141
164
  rescue Exception => stack
@@ -10,3 +10,4 @@ require_relative 'utils/update_bots_file'
10
10
  require_relative 'utils/update_routines'
11
11
  require_relative 'utils/update_rules_imported'
12
12
  require_relative 'utils/update_shortcuts_file'
13
+ require_relative 'utils/save_stats'
@@ -4,7 +4,7 @@ class SlackSmartBot
4
4
  general: [:hi_bot, :bye_bot, :bot_help, :bot_status, :use_rules, :stop_using_rules],
5
5
  on_bot: [:ruby_code, :add_shortcut, :delete_shortcut, :see_shortcuts],
6
6
  on_bot_admin: [:extend_rules, :stop_using_rules_on, :start_bot, :pause_bot, :add_routine,
7
- :see_routines, :start_routine, :pause_routine, :remove_routine, :run_routine],
7
+ :see_routines, :start_routine, :pause_routine, :remove_routine, :run_routine]
8
8
  }
9
9
  # user_type: :admin, :user, :admin_master
10
10
  if config.masters.include?(from)
@@ -34,20 +34,23 @@ class SlackSmartBot
34
34
  if rules_file != ""
35
35
  help[:rules_file] = IO.readlines(config.path+rules_file).join.scan(/#\s*help\s*\w*:(.*)/i).join("\n")
36
36
  end
37
-
38
37
  help = remove_hash_keys(help, :admin_master) unless user_type == :admin_master
39
38
  help = remove_hash_keys(help, :admin) unless user_type == :admin or user_type == :admin_master
40
39
  help = remove_hash_keys(help, :on_master) unless channel_type == :master_bot
41
40
  help = remove_hash_keys(help, :on_extended) unless channel_type == :extended
42
41
  help = remove_hash_keys(help, :on_dm) unless channel_type == :direct
43
42
  txt = ""
43
+
44
44
  if channel_type == :bot or channel_type == :master_bot
45
45
  txt += "===================================
46
46
  For the Smart Bot start listening to you say *hi bot*
47
47
  To run a command on demand even when the Smart Bot is not listening to you:
48
48
  *!THE_COMMAND*
49
49
  *@NAME_OF_BOT THE_COMMAND*
50
- *NAME_OF_BOT THE_COMMAND*\n"
50
+ *NAME_OF_BOT THE_COMMAND*
51
+ To run a command on demand and add the respond on a thread:
52
+ *^THE_COMMAND*
53
+ *!!THE_COMMAND*\n"
51
54
  end
52
55
  if channel_type == :direct
53
56
  txt += "===================================
@@ -104,17 +107,20 @@ class SlackSmartBot
104
107
  end
105
108
  end
106
109
 
107
- if help.key?(:on_master) and help.on_master.key?(:admin_master)
110
+ if help.key?(:on_bot) and help.on_bot.key?(:admin_master) and help.on_bot.admin_master.size > 0
108
111
  txt += "===================================
109
112
  *Master Admin commands:*\n"
110
- help.on_master.admin_master.each do |k, v|
113
+ help.on_bot.admin_master.each do |k, v|
111
114
  txt += v if v.is_a?(String)
112
115
  end
113
116
  end
114
117
 
115
- if help.key?(:on_bot) and help.on_bot.key?(:admin_master) and help.on_bot.admin_master.size > 0
118
+ if help.key?(:on_master) and help.on_master.key?(:admin_master) and help.on_master.admin_master.size > 0
116
119
  txt += "===================================
117
120
  *Master Admin commands:*\n"
121
+ help.on_master.admin_master.each do |k, v|
122
+ txt += v if v.is_a?(String)
123
+ end
118
124
  end
119
125
 
120
126
  if help.key?(:rules_file)
@@ -0,0 +1,32 @@
1
+ class SlackSmartBot
2
+
3
+ def save_stats(method)
4
+ if config.stats
5
+ begin
6
+ require 'csv'
7
+ if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
8
+ CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", 'wb') do |csv|
9
+ csv << ['date','bot_channel', 'bot_channel_id', 'dest_channel', 'dest_channel_id', 'type_message', 'user_name', 'user_id', 'text', 'command', 'files']
10
+ end
11
+ end
12
+ dest = Thread.current[:dest]
13
+ typem = Thread.current[:typem]
14
+ user = Thread.current[:user]
15
+ files = Thread.current[:files?]
16
+ if method.to_s == 'ruby_code' and files
17
+ command_txt = 'ruby'
18
+ else
19
+ command_txt = Thread.current[:command]
20
+ end
21
+
22
+ CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "a+") do |csv|
23
+ csv << [Time.now, config.channel, @channel_id, @channels_name[dest], dest, typem, user.name, user.id, command_txt, method, files]
24
+ end
25
+ rescue Exception => exception
26
+ @logger.fatal "There was a problem on the stats"
27
+ @logger.fatal exception
28
+ end
29
+ end
30
+ end
31
+
32
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack-smart-bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.3
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mario Ruiz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-12 00:00:00.000000000 Z
11
+ date: 2020-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slack-ruby-client
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '0.14'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 0.14.4
22
+ version: 0.14.5
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '0.14'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 0.14.4
32
+ version: 0.14.5
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: nice_http
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -121,6 +121,7 @@ files:
121
121
  - lib/slack/smart-bot/comm.rb
122
122
  - lib/slack/smart-bot/comm/ask.rb
123
123
  - lib/slack/smart-bot/comm/dont_understand.rb
124
+ - lib/slack/smart-bot/comm/react.rb
124
125
  - lib/slack/smart-bot/comm/respond.rb
125
126
  - lib/slack/smart-bot/comm/respond_direct.rb
126
127
  - lib/slack/smart-bot/comm/send_file.rb
@@ -144,6 +145,8 @@ files:
144
145
  - lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb
145
146
  - lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb
146
147
  - lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb
148
+ - lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb
149
+ - lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb
147
150
  - lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb
148
151
  - lib/slack/smart-bot/commands/on_bot/ruby_code.rb
149
152
  - lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb
@@ -165,6 +168,7 @@ files:
165
168
  - lib/slack/smart-bot/utils/get_routines.rb
166
169
  - lib/slack/smart-bot/utils/get_rules_imported.rb
167
170
  - lib/slack/smart-bot/utils/remove_hash_keys.rb
171
+ - lib/slack/smart-bot/utils/save_stats.rb
168
172
  - lib/slack/smart-bot/utils/update_bots_file.rb
169
173
  - lib/slack/smart-bot/utils/update_routines.rb
170
174
  - lib/slack/smart-bot/utils/update_rules_imported.rb