slack-smart-bot 1.12.7 → 1.12.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb203b37854fdefed6f4c6243e4a77d11f1d196460f2e8e00741eec221b8f2aa
4
- data.tar.gz: 7735d64e95fbd4704585034ed0709866f4514426ffaf706f2b55d09596e1ff8f
3
+ metadata.gz: ce7ad9b141fa627afb25ac3a20fcf6e6b9d452105866620681c5430c691023be
4
+ data.tar.gz: 40cb7e645794af392d687afa6a4a839d9e7d9f1113a6fc90862cd6da3a0dedce
5
5
  SHA512:
6
- metadata.gz: 0673dd7b7018db1af520e76f70b45e75de865f17d1fd78aaa8d1c06e6b90551288e25cf10e5718bc71b09299e2715ad12fa969dd91d3421ffa9cad341256ac1c
7
- data.tar.gz: 45ef02e00f2d74c1e14a672a3a3b6bde255aa38e2a521d30cf3b29b80e657c32ae9d7f8edb742aa156cf5627cf3741c6fd620bdb92035eaf93679aa7011c9ee9
6
+ metadata.gz: af7a0da5cf90b055fe4dc48c781823e1941f0ceb8b2747d60dcd43ef44ceb2e380cd8a15ddc016ee7201b9e26e93ab8991db07bb2bea99bdfb69d751ed8fc7cb
7
+ data.tar.gz: 67cf9020b2894fab2fcb8c8082cc94e63d1e5e52eabc91dc8544b1f050fc948127f564687fd339f04f1f98a1fa8a2fdaa246f65e31ac93b06a18a10bef028596
@@ -1,501 +1,551 @@
1
1
  class SlackSmartBot
2
- # help: ----------------------------------------------
3
- # help: `bot stats`
4
- # helpmaster: `bot stats USER_NAME`
5
- # help: `bot stats exclude masters`
6
- # help: `bot stats exclude routines`
7
- # help: `bot stats from YYYY/MM/DD`
8
- # help: `bot stats from YYYY/MM/DD to YYYY/MM/DD`
9
- # help: `bot stats CHANNEL`
10
- # help: `bot stats CHANNEL from YYYY/MM/DD`
11
- # help: `bot stats CHANNEL from YYYY/MM/DD to YYYY/MM/DD`
12
- # help: `bot stats command COMMAND`
13
- # helpmaster: `bot stats USER_NAME from YYYY/MM/DD to YYYY/MM/DD`
14
- # helpmaster: `bot stats CHANNEL USER_NAME from YYYY/MM/DD to YYYY/MM/DD`
15
- # help: `bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD`
16
- # help: `bot stats members #CHANNEL`
17
- # help: `bot stats exclude members #CHANNEL`
18
- # help: `bot stats today`
19
- # help: `bot stats yesterday`
20
- # help: `bot stats last month`
21
- # help: `bot stats this month`
22
- # help: `bot stats last week`
23
- # help: `bot stats this week`
24
- # help: `bot stats exclude COMMAND_ID`
25
- # help: `bot stats monthly`
26
- # help: `bot stats alldata`
27
- # help: To see the bot stats
28
- # helpmaster: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot, or you are on the Smartbot-stats channel
29
- # helpmaster: You need to set stats to true to generate the stats when running the bot instance.
30
- # help: members #CHANNEL will return stats for only members of the channel supplied
31
- # help: exclude members #CHANNEL will return stats for only members that are not members of the channel supplied
32
- # help: If alldata option supplied then it will be attached files including all data and not only the top 10.
33
- # help: Examples:
34
- # help: _bot stats #sales_
35
- # helpmaster: _bot stats @peter.wind_
36
- # help: _bot stats #sales from 2019/12/15 to 2019/12/31_
37
- # help: _bot stats #sales today_
38
- # help: _bot stats #sales from 2020-01-01 monthly_
39
- # help: _bot stats exclude routines masters from 2021/01/01 monthly_
40
- # help: _bot stats members #development from 2022/01/01 to 2022/01/31_
41
- # help: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
42
- # help: command_id: :bot_stats
43
- # help:
44
- def bot_stats(dest, from_user, typem, channel_id, from, to, user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data, members_channel, exclude_members_channel)
45
- require 'csv'
46
- if config.stats
47
- message = []
48
- else
49
- message = ["You need to set stats to true to generate the stats when running the bot instance."]
2
+ # help: ----------------------------------------------
3
+ # help: `bot stats`
4
+ # helpmaster: `bot stats USER_NAME`
5
+ # help: `bot stats exclude masters`
6
+ # help: `bot stats exclude routines`
7
+ # help: `bot stats from YYYY/MM/DD`
8
+ # help: `bot stats from YYYY/MM/DD to YYYY/MM/DD`
9
+ # help: `bot stats CHANNEL`
10
+ # help: `bot stats CHANNEL from YYYY/MM/DD`
11
+ # help: `bot stats CHANNEL from YYYY/MM/DD to YYYY/MM/DD`
12
+ # help: `bot stats command COMMAND`
13
+ # helpmaster: `bot stats USER_NAME from YYYY/MM/DD to YYYY/MM/DD`
14
+ # helpmaster: `bot stats CHANNEL USER_NAME from YYYY/MM/DD to YYYY/MM/DD`
15
+ # help: `bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD`
16
+ # help: `bot stats HEADER /REGEXP/`
17
+ # help: `bot stats members #CHANNEL`
18
+ # help: `bot stats exclude members #CHANNEL`
19
+ # help: `bot stats today`
20
+ # help: `bot stats yesterday`
21
+ # help: `bot stats last month`
22
+ # help: `bot stats this month`
23
+ # help: `bot stats last week`
24
+ # help: `bot stats this week`
25
+ # help: `bot stats exclude COMMAND_ID`
26
+ # help: `bot stats monthly`
27
+ # help: `bot stats alldata`
28
+ # help: To see the bot stats
29
+ # helpmaster: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot, or you are on the Smartbot-stats channel
30
+ # helpmaster: You need to set stats to true to generate the stats when running the bot instance.
31
+ # help: members #CHANNEL will return stats for only members of the channel supplied
32
+ # help: exclude members #CHANNEL will return stats for only members that are not members of the channel supplied
33
+ # help: HEADER /REGEXP/ will return stats for only the rows that match the regexp on the stats header supplied
34
+ # help: If alldata option supplied then it will be attached files including all data and not only the top 10.
35
+ # help: Examples:
36
+ # help: _bot stats #sales_
37
+ # helpmaster: _bot stats @peter.wind_
38
+ # help: _bot stats #sales from 2019/12/15 to 2019/12/31_
39
+ # help: _bot stats #sales today_
40
+ # help: _bot stats #sales from 2020-01-01 monthly_
41
+ # help: _bot stats exclude routines masters from 2021/01/01 monthly_
42
+ # help: _bot stats members #development from 2022/01/01 to 2022/01/31_\
43
+ # help: _bot stats type_message /(on_pub|on_pg)/_
44
+ # help: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
45
+ # help: command_id: :bot_stats
46
+ # help:
47
+ def bot_stats(dest, from_user, typem, channel_id, from, to, user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data, members_channel, exclude_members_channel, header, regexp)
48
+ require "csv"
49
+ if config.stats
50
+ message = []
51
+ else
52
+ message = ["You need to set stats to true to generate the stats when running the bot instance."]
53
+ end
54
+ save_stats(__method__)
55
+ react :runner
56
+ get_channels_name_and_id() unless @channels_name.keys.include?(dest) or dest[0] == "D"
57
+ master_admin_users_id = @master_admin_users_id.dup
58
+ if dest == @channels_id[config.stats_channel]
59
+ #master_admin_users_id << user
60
+ user = "" # for the case we are on the stats channel
61
+ end
62
+ if (from_user.id != user and
63
+ (config.masters.include?(from_user.name) or master_admin_users_id.include?(from_user.id) or dest == @channels_id[config.stats_channel]) and #Jal
64
+ (typem == :on_dm or dest[0] == "D" or dest == @channels_id[config.stats_channel]))
65
+ on_dm_master = true #master admin user
66
+ else
67
+ on_dm_master = false
68
+ end
69
+ wrong = false
70
+ exclude_channel_members = false
71
+ include_channel_members = false
72
+ members_list = []
73
+ if exclude_members_channel != "" or members_channel != ""
74
+ if members_channel != ""
75
+ channel_members = members_channel
76
+ include_channel_members = true
77
+ else
78
+ channel_members = exclude_members_channel
79
+ exclude_channel_members = true
80
+ end
81
+ get_channels_name_and_id() unless @channels_id.keys.include?(channel_members)
82
+
83
+ tm = get_channel_members(channel_members)
84
+ if tm.nil?
85
+ message << ":exclamation: Add the Smart Bot to *<##{channel_members}>* channel first."
86
+ wrong = true
87
+ else
88
+ tm.each do |m|
89
+ user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
90
+ members_list << user_info.name unless user_info.is_app_user or user_info.is_bot
50
91
  end
51
- save_stats(__method__)
52
- get_channels_name_and_id() unless @channels_name.keys.include?(dest)
53
- master_admin_users_id = @master_admin_users_id.dup
54
- if dest == @channels_id[config.stats_channel]
55
- #master_admin_users_id << user
56
- user = '' # for the case we are on the stats channel
92
+ end
93
+ end
94
+
95
+ if header.size > 0
96
+ headers = ["date", "bot_channel", "bot_channel_id", "dest_channel", "dest_channel_id", "type_message", "user_name", "user_id", "text", "command", "files", "time_zone", "job_title"]
97
+ header.each do |h|
98
+ if !headers.include?(h.downcase)
99
+ message << ":exclamation: Wrong header #{h}. It should be one of the following: #{headers.join(", ")}"
100
+ wrong = true
57
101
  end
58
- if (from_user.id != user and
59
- (config.masters.include?(from_user.name) or master_admin_users_id.include?(from_user.id) or dest == @channels_id[config.stats_channel]) and #Jal
60
- (typem==:on_dm or dest[0]=='D' or dest == @channels_id[config.stats_channel] ))
61
- on_dm_master = true #master admin user
62
- else
63
- on_dm_master = false
102
+ end
103
+ if regexp.size > 0
104
+ regexp.each do |r|
105
+ begin
106
+ Regexp.new(r)
107
+ rescue
108
+ message << ":exclamation: Wrong regexp #{r}."
109
+ wrong = true
110
+ end
64
111
  end
65
- wrong = false
66
- exclude_channel_members = false
67
- include_channel_members = false
68
- members_list = []
69
- if exclude_members_channel!='' or members_channel!=''
70
- if members_channel!=''
71
- channel_members = members_channel
72
- include_channel_members = true
73
- else
74
- channel_members = exclude_members_channel
75
- exclude_channel_members = true
76
- end
77
- get_channels_name_and_id() unless @channels_id.keys.include?(channel_members)
112
+ end
113
+ end
78
114
 
79
- tm = get_channel_members(channel_members)
80
- if tm.nil?
81
- message << ":exclamation: Add the Smart Bot to *<##{channel_members}>* channel first."
82
- wrong = true
115
+ tzone_users = {}
116
+ job_title_users = {}
117
+ users_by_job_title = {}
118
+ unless wrong
119
+ if on_dm_master or (from_user.id == user) # normal user can only see own stats
120
+ if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
121
+ message << "No stats"
122
+ else
123
+ from = "#{Time.now.strftime("%Y-%m")}-01" if from == ""
124
+ to = "#{Time.now.strftime("%Y-%m-%d")}" if to == ""
125
+ from_short = from
126
+ to_short = to
127
+ from_file = from[0..3] + "-" + from[5..6]
128
+ to_file = to[0..3] + "-" + to[5..6]
129
+ from += " 00:00:00 +0000"
130
+ to += " 23:59:59 +0000"
131
+ rows = []
132
+ rows_month = {}
133
+ users_month = {}
134
+ commands_month = {}
135
+ users_id_name = {}
136
+ users_name_id = {}
137
+ count_users = {}
138
+ count_channels_dest = {}
139
+ # to translate global and enterprise users since sometimes was returning different names/ids
140
+ #if from[0..3]=='2020' # this was an issue only on that period
141
+ Dir["#{config.stats_path}.*.log"].sort.each do |file|
142
+ if file >= "#{config.stats_path}.#{from_file}.log" and file <= "#{config.stats_path}.#{to_file}.log"
143
+ CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
144
+ unless users_id_name.key?(row[:user_id])
145
+ users_id_name[row[:user_id]] = row[:user_name]
146
+ users_name_id[row[:user_name]] = row[:user_id]
147
+ end
148
+ end
149
+ end
150
+ end
151
+ #end
152
+ if user != ""
153
+ user_info = @users.select { |u| u.id == user or (u.key?(:enterprise_user) and u.enterprise_user.id == user) }[-1]
154
+ if user_info.nil? # for the case the user is populated from outside of slack
155
+ user_name = user
156
+ user_id = user
83
157
  else
84
- tm.each do |m|
85
- user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
86
- members_list << user_info.name unless user_info.is_app_user or user_info.is_bot
158
+ if users_id_name.key?(user_info.id)
159
+ user_name = users_id_name[user_info.id]
160
+ else
161
+ user_name = user_info.name
162
+ end
163
+ if users_name_id.key?(user_info.name)
164
+ user_id = users_name_id[user_info.name]
165
+ else
166
+ user_id = user_info.id
87
167
  end
88
168
  end
89
- end
90
- tzone_users = {}
91
- job_title_users = {}
92
- users_by_job_title = {}
93
-
94
- unless wrong
95
- if on_dm_master or (from_user.id == user) # normal user can only see own stats
96
- if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
97
- message<<'No stats'
98
- else
99
- from = "#{Time.now.strftime("%Y-%m")}-01" if from == ''
100
- to = "#{Time.now.strftime("%Y-%m-%d")}" if to == ''
101
- from_short = from
102
- to_short = to
103
- from_file = from[0..3] + '-' + from[5..6]
104
- to_file = to[0..3] + '-' + to[5..6]
105
- from+= " 00:00:00 +0000"
106
- to+= " 23:59:59 +0000"
107
- rows = []
108
- rows_month = {}
109
- users_month = {}
110
- commands_month = {}
111
- users_id_name = {}
112
- users_name_id = {}
113
- count_users = {}
114
- count_channels_dest = {}
115
-
116
- # to translate global and enterprise users since sometimes was returning different names/ids
117
- #if from[0..3]=='2020' # this was an issue only on that period
118
- Dir["#{config.stats_path}.*.log"].sort.each do |file|
119
- if file >= "#{config.stats_path}.#{from_file}.log" and file <= "#{config.stats_path}.#{to_file}.log"
120
- CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
121
- unless users_id_name.key?(row[:user_id])
122
- users_id_name[row[:user_id]] = row[:user_name]
123
- users_name_id[row[:user_name]] = row[:user_id]
124
- end
125
- end
126
- end
127
- end
128
- #end
129
-
130
- if user!=''
131
- user_info = @users.select{|u| u.id == user or (u.key?(:enterprise_user) and u.enterprise_user.id == user)}[-1]
132
- if user_info.nil? # for the case the user is populated from outside of slack
133
- user_name = user
134
- user_id = user
135
- else
136
- if users_id_name.key?(user_info.id)
137
- user_name = users_id_name[user_info.id]
138
- else
139
- user_name = user_info.name
140
- end
141
- if users_name_id.key?(user_info.name)
142
- user_id = users_name_id[user_info.name]
143
- else
144
- user_id = user_info.id
145
- end
146
- end
147
- end
148
- master_admins = config.masters.dup
149
- if users_id_name.size > 0
150
- config.masters.each do |u|
151
- if users_id_name.key?(u)
152
- master_admins << users_id_name[u]
153
- elsif users_name_id.key?(u)
154
- master_admins << users_name_id[u]
155
- end
169
+ end
170
+ master_admins = config.masters.dup
171
+ if users_id_name.size > 0
172
+ config.masters.each do |u|
173
+ if users_id_name.key?(u)
174
+ master_admins << users_id_name[u]
175
+ elsif users_name_id.key?(u)
176
+ master_admins << users_name_id[u]
177
+ end
178
+ end
179
+ end
180
+ Dir["#{config.stats_path}.*.log"].sort.each do |file|
181
+ if file >= "#{config.stats_path}.#{from_file}.log" and file <= "#{config.stats_path}.#{to_file}.log"
182
+ CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
183
+ if (include_channel_members and members_list.include?(row[:user_name])) or
184
+ (exclude_channel_members and !members_list.include?(row[:user_name])) or
185
+ (!include_channel_members and !exclude_channel_members)
186
+ row[:date] = row[:date].to_s
187
+ if row[:dest_channel_id].to_s[0] == "D"
188
+ row[:dest_channel] = "DM"
189
+ elsif row[:dest_channel].to_s == ""
190
+ row[:dest_channel] = row[:dest_channel_id]
191
+ end
192
+ if users_name_id.size > 0
193
+ row[:user_name] = users_id_name[row[:user_id]]
194
+ row[:user_id] = users_name_id[row[:user_name]]
195
+ else
196
+ users_id_name[row[:user_id]] ||= row[:user_name]
197
+ end
198
+ if !exclude_masters or (exclude_masters and !master_admins.include?(row[:user_name]) and
199
+ !master_admins.include?(row[:user_id]) and
200
+ !master_admin_users_id.include?(row[:user_id]))
201
+ if !exclude_routines or (exclude_routines and !row[:user_name].match?(/^routine\//))
202
+ unless header.empty?
203
+ add = true
204
+ header.each_with_index do |h, i|
205
+ if row[h.downcase.to_sym].to_s.match?(Regexp.new(regexp[i])) == false
206
+ add = false
207
+ break
208
+ end
156
209
  end
157
- end
158
-
159
- Dir["#{config.stats_path}.*.log"].sort.each do |file|
160
- if file >= "#{config.stats_path}.#{from_file}.log" and file <= "#{config.stats_path}.#{to_file}.log"
161
- CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
162
- if (include_channel_members and members_list.include?(row[:user_name])) or
163
- (exclude_channel_members and !members_list.include?(row[:user_name])) or
164
- (!include_channel_members and !exclude_channel_members)
165
-
166
- row[:date] = row[:date].to_s
167
- if row[:dest_channel_id].to_s[0]=='D'
168
- row[:dest_channel] = 'DM'
169
- elsif row[:dest_channel].to_s == ''
170
- row[:dest_channel] = row[:dest_channel_id]
171
- end
172
- if users_name_id.size > 0
173
- row[:user_name] = users_id_name[row[:user_id]]
174
- row[:user_id] = users_name_id[row[:user_name]]
175
- else
176
- users_id_name[row[:user_id]] ||= row[:user_name]
177
- end
178
- if !exclude_masters or (exclude_masters and !master_admins.include?(row[:user_name]) and
179
- !master_admins.include?(row[:user_id]) and
180
- !master_admin_users_id.include?(row[:user_id]))
181
- if !exclude_routines or (exclude_routines and !row[:user_name].match?(/^routine\//) )
182
- if exclude_command == '' or (exclude_command!='' and row[:command]!=exclude_command)
183
- if st_command == '' or (st_command != '' and row[:command] == st_command)
184
- if row[:bot_channel_id] == channel_id or channel_id == '' or row[:dest_channel_id] == channel_id
185
- if row[:date] >= from and row[:date] <= to
186
- count_users[row[:user_id]] ||= 0
187
- count_users[row[:user_id]] += 1
188
- if user=='' or (user!='' and row[:user_name] == user_name) or (user!='' and row[:user_id] == user_id)
189
- rows << row.to_h
190
- count_channels_dest[row[:dest_channel]] ||= 0
191
- count_channels_dest[row[:dest_channel]] += 1
192
- if monthly
193
- rows_month[row[:date][0..6]] = 0 unless rows_month.key?(row[:date][0..6])
194
- users_month[row[:date][0..6]] = [] unless users_month.key?(row[:date][0..6])
195
- commands_month[row[:date][0..6]] = [] unless commands_month.key?(row[:date][0..6])
196
- rows_month[row[:date][0..6]] += 1
197
- users_month[row[:date][0..6]] << row[:user_id]
198
- commands_month[row[:date][0..6]] << row[:command]
199
- end
200
- end
201
- end
202
- end
203
- end
204
- end
205
- end
206
- end
210
+ end
211
+ if header.empty? or (header.size > 0 and add)
212
+ if exclude_command == "" or (exclude_command != "" and row[:command] != exclude_command)
213
+ if st_command == "" or (st_command != "" and row[:command] == st_command)
214
+ if row[:bot_channel_id] == channel_id or channel_id == "" or row[:dest_channel_id] == channel_id
215
+ if row[:date] >= from and row[:date] <= to
216
+ count_users[row[:user_id]] ||= 0
217
+ count_users[row[:user_id]] += 1
218
+ if user == "" or (user != "" and row[:user_name] == user_name) or (user != "" and row[:user_id] == user_id)
219
+ rows << row.to_h
220
+ count_channels_dest[row[:dest_channel]] ||= 0
221
+ count_channels_dest[row[:dest_channel]] += 1
222
+ if monthly
223
+ rows_month[row[:date][0..6]] = 0 unless rows_month.key?(row[:date][0..6])
224
+ users_month[row[:date][0..6]] = [] unless users_month.key?(row[:date][0..6])
225
+ commands_month[row[:date][0..6]] = [] unless commands_month.key?(row[:date][0..6])
226
+ rows_month[row[:date][0..6]] += 1
227
+ users_month[row[:date][0..6]] << row[:user_id]
228
+ commands_month[row[:date][0..6]] << row[:command]
229
+ end
207
230
  end
231
+ end
208
232
  end
233
+ end
209
234
  end
235
+ end
210
236
  end
211
- total = rows.size
212
- if exclude_masters
213
- message << 'Excluding master admins'
214
- end
215
- if exclude_routines
216
- message << 'Excluding routines'
217
- end
218
- if exclude_command != ''
219
- message << "Excluding command #{exclude_command}"
220
- end
221
- if st_command != ''
222
- message << "Including only command #{st_command}"
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
242
+ total = rows.size
243
+ if exclude_masters
244
+ message << "Excluding master admins"
245
+ end
246
+ if exclude_routines
247
+ message << "Excluding routines"
248
+ end
249
+ if exclude_command != ""
250
+ message << "Excluding command #{exclude_command}"
251
+ end
252
+ if st_command != ""
253
+ message << "Including only command #{st_command}"
254
+ end
255
+ if include_channel_members
256
+ message << "Including only members of <##{members_channel}>"
257
+ end
258
+ if exclude_channel_members
259
+ message << "Including only members that are not members of <##{exclude_members_channel}>"
260
+ end
261
+ if header.size > 0
262
+ header.each_with_index do |h, i|
263
+ message << "Including only #{h} that match /#{regexp[i]}/i"
264
+ end
265
+ end
266
+ if user != ""
267
+ if user == from_user.id
268
+ message << "Bot stats for <@#{user}>"
269
+ else
270
+ message << "Showing only user <@#{user}>"
271
+ end
272
+ end
273
+ if channel_id == ""
274
+ message << "*Total calls*: #{total} from #{from_short} to #{to_short}"
275
+ else
276
+ message << "*Total calls <##{channel_id}>*: #{total} from #{from_short} to #{to_short}"
277
+ end
278
+ unless count_users.size == 0 or total == 0 or user == ""
279
+ my_place = (count_users.sort_by(&:last).reverse.to_h.keys.index(user_id) + 1)
280
+ message << "\tYou are the *\# #{my_place}* of *#{count_users.size}* users"
281
+ end
282
+ if total > 0
283
+ if monthly
284
+ if on_dm_master
285
+ message << "*Totals by month / commands / users (%new)*"
286
+ else
287
+ message << "*Totals by month / commands*"
288
+ end
289
+
290
+ all_users = []
291
+ new_users = []
292
+ rows_month.each do |k, v|
293
+ if all_users.empty?
294
+ message_new_users = ""
295
+ else
296
+ new_users = (users_month[k] - all_users).uniq
297
+ message_new_users = "(#{new_users.size * 100 / users_month[k].uniq.size}%)"
298
+ end
299
+ all_users += users_month[k]
300
+ if on_dm_master
301
+ message << "\t#{k}: #{v} (#{(v.to_f * 100 / total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{message_new_users}"
302
+ else
303
+ message << "\t#{k}: #{v} (#{(v.to_f * 100 / total).round(2)}%) / #{commands_month[k].uniq.size}"
304
+ end
305
+ end
306
+ end
307
+
308
+ if channel_id == ""
309
+ message << "*SmartBots*"
310
+ channels = rows.bot_channel.uniq.sort
311
+ channels.each do |channel|
312
+ count = rows.count { |h| h.bot_channel == channel }
313
+ channel_info = @channels_list.select { |c| c.name.to_s.downcase == channel.to_s.downcase }[-1]
314
+ if @channels_id.key?(channel) and !channel_info.is_private
315
+ c = "<##{@channels_id[channel]}>"
316
+ else
317
+ c = channel
318
+ end
319
+ message << "\t#{c}: #{count} (#{(count.to_f * 100 / total).round(2)}%)"
320
+ end
321
+ end
322
+ channels_dest_attachment = []
323
+ count_channels_dest = count_channels_dest.sort_by(&:last).reverse.to_h
324
+ if count_channels_dest.size > 10
325
+ message << "*From Channel* - #{count_channels_dest.size} (Top 10)"
326
+ else
327
+ message << "*From Channel* - #{count_channels_dest.size}"
328
+ end
329
+
330
+ count_channels_dest.keys[0..9].each do |ch|
331
+ channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase }[-1]
332
+ if @channels_id.key?(ch) and !channel_info.is_private
333
+ c = "<##{@channels_id[ch]}>"
334
+ else
335
+ c = ch
336
+ end
337
+ message << "\t#{c}: #{count_channels_dest[ch]} (#{(count_channels_dest[ch].to_f * 100 / total).round(2)}%)"
338
+ end
339
+ if count_channels_dest.size > 10 and all_data
340
+ count_channels_dest.each do |ch, value|
341
+ channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase }[-1]
342
+ channels_dest_attachment << "\t##{ch}: #{value} (#{(value.to_f * 100 / total).round(2)}%)"
343
+ end
344
+ end
345
+
346
+ users_attachment = []
347
+ if user == ""
348
+ users = rows.user_id.uniq.sort
349
+ if rows[0].key?(:time_zone) #then save_stats is saving the time zone already
350
+ rows.time_zone.each do |time_zone|
351
+ unless time_zone == ""
352
+ tzone_users[time_zone] ||= 0
353
+ tzone_users[time_zone] += 1
354
+ end
355
+ end
356
+ else
357
+ rows.user_id.each_with_index do |usr, i|
358
+ if rows[i].values.size >= 12 #then save_stats is saving the time zone already but not all the data
359
+ unless rows[i].values[11] == ""
360
+ tzone_users[rows[i].values[11]] ||= 0
361
+ tzone_users[rows[i].values[11]] += 1
223
362
  end
224
- if include_channel_members
225
- message << "Including only members of <##{members_channel}>"
363
+ else
364
+ user_info = @users.select { |u| u.id == usr or (u.key?(:enterprise_user) and u.enterprise_user.id == usr) }[-1]
365
+ unless user_info.nil? or user_info.is_app_user or user_info.is_bot
366
+ tzone_users[user_info.tz_label] ||= 0
367
+ tzone_users[user_info.tz_label] += 1
226
368
  end
227
- if exclude_channel_members
228
- message << "Including only members that are not members of <##{exclude_members_channel}>"
369
+ end
370
+ end
371
+ end
372
+ if rows[0].key?(:job_title) #then save_stats is saving the job title already
373
+ rows.job_title.each_with_index do |job_title, idx|
374
+ unless job_title.to_s == ""
375
+ unless job_title_users.key?(job_title)
376
+ job_title = job_title.to_s.split.map { |x| x[0].upcase + x[1..-1] }.join(" ")
377
+ job_title_users[job_title] ||= 0
378
+ users_by_job_title[job_title] ||= []
229
379
  end
230
- if user!=''
231
- if user==from_user.id
232
- message << "Bot stats for <@#{user}>"
380
+ job_title_users[job_title] += 1
381
+ users_by_job_title[job_title] << rows.user_name[idx]
382
+ end
383
+ end
384
+ else
385
+ rows.user_id.each_with_index do |usr, i|
386
+ unless usr.include?("routine/")
387
+ if rows[i].values.size >= 13 #then save_stats is saving the job_title already but not all the data
388
+ unless rows[i].values[12].to_s == ""
389
+ if job_title_users.key?(rows[i].values[12].to_s)
390
+ job_title = rows[i].values[12]
233
391
  else
234
- message << "Showing only user <@#{user}>"
392
+ job_title = rows[i].values[12].to_s.split.map { |x| x[0].upcase + x[1..-1] }.join(" ")
393
+ job_title_users[job_title] ||= 0
394
+ users_by_job_title[job_title] ||= []
235
395
  end
236
- end
237
- if channel_id == ''
238
- message << "*Total calls*: #{total} from #{from_short} to #{to_short}"
396
+ job_title_users[job_title] += 1
397
+ users_by_job_title[job_title] << rows.user_name[i]
398
+ end
239
399
  else
240
- message << "*Total calls <##{channel_id}>*: #{total} from #{from_short} to #{to_short}"
241
- end
242
- unless count_users.size == 0 or total == 0 or user == ''
243
- my_place = (count_users.sort_by(&:last).reverse.to_h.keys.index(user_id)+1)
244
- message <<"\tYou are the *\# #{my_place}* of *#{count_users.size}* users"
245
- end
246
- if total > 0
247
- if monthly
248
- if on_dm_master
249
- message << '*Totals by month / commands / users (%new)*'
250
- else
251
- message << '*Totals by month / commands*'
252
- end
253
-
254
- all_users = []
255
- new_users = []
256
- rows_month.each do |k,v|
257
- if all_users.empty?
258
- message_new_users = ''
259
- else
260
- new_users = (users_month[k]-all_users).uniq
261
- message_new_users = "(#{new_users.size*100/users_month[k].uniq.size}%)"
262
- end
263
- all_users += users_month[k]
264
- if on_dm_master
265
- message << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{message_new_users}"
266
- else
267
- message << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size}"
268
- end
269
- end
270
- end
271
-
272
- if channel_id == ''
273
- message << "*SmartBots*"
274
- channels = rows.bot_channel.uniq.sort
275
- channels.each do |channel|
276
- count = rows.count {|h| h.bot_channel==channel}
277
- channel_info = @channels_list.select { |c| c.name.to_s.downcase == channel.to_s.downcase}[-1]
278
- if @channels_id.key?(channel) and !channel_info.is_private
279
- c = "<##{@channels_id[channel]}>"
280
- else
281
- c = channel
282
- end
283
- message << "\t#{c}: #{count} (#{(count.to_f*100/total).round(2)}%)"
284
- end
285
- end
286
- channels_dest_attachment = []
287
- count_channels_dest = count_channels_dest.sort_by(&:last).reverse.to_h
288
- if count_channels_dest.size > 10
289
- message << "*From Channel* - #{count_channels_dest.size} (Top 10)"
400
+ user_info = @users.select { |u| u.id == usr or (u.key?(:enterprise_user) and u.enterprise_user.id == usr) }[-1]
401
+ unless user_info.nil? or user_info.is_app_user or user_info.is_bot
402
+ if job_title_users.key?(user_info.profile.title)
403
+ job_title = user_info.profile.title
290
404
  else
291
- message << "*From Channel* - #{count_channels_dest.size}"
292
- end
293
-
294
- count_channels_dest.keys[0..9].each do |ch|
295
- channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase}[-1]
296
- if @channels_id.key?(ch) and !channel_info.is_private
297
- c = "<##{@channels_id[ch]}>"
298
- else
299
- c = ch
300
- end
301
- message << "\t#{c}: #{count_channels_dest[ch]} (#{(count_channels_dest[ch].to_f*100/total).round(2)}%)"
405
+ job_title = user_info.profile.title.split.map { |x| x[0].upcase + x[1..-1] }.join(" ")
302
406
  end
303
- if count_channels_dest.size > 10 and all_data
304
- count_channels_dest.each do |ch, value|
305
- channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase}[-1]
306
- channels_dest_attachment << "\t##{ch}: #{value} (#{(value.to_f*100/total).round(2)}%)"
307
- end
407
+ unless job_title.to_s == ""
408
+ job_title_users[job_title] ||= 0
409
+ job_title_users[job_title] += 1
410
+ users_by_job_title[job_title] ||= []
411
+ users_by_job_title[job_title] << rows.user_name[i]
308
412
  end
309
-
310
- users_attachment = []
311
- if user==''
312
- users = rows.user_id.uniq.sort
313
- if rows[0].key?(:time_zone) #then save_stats is saving the time zone already
314
- rows.time_zone.each do |time_zone|
315
- unless time_zone == ''
316
- tzone_users[time_zone] ||= 0
317
- tzone_users[time_zone] += 1
318
- end
319
- end
320
- else
321
- rows.user_id.each_with_index do |usr, i|
322
- if rows[i].values.size >= 12 #then save_stats is saving the time zone already but not all the data
323
- unless rows[i].values[11] == ''
324
- tzone_users[rows[i].values[11]] ||= 0
325
- tzone_users[rows[i].values[11]] += 1
326
- end
327
- else
328
- user_info = @users.select { |u| u.id == usr or (u.key?(:enterprise_user) and u.enterprise_user.id == usr) }[-1]
329
- unless user_info.nil? or user_info.is_app_user or user_info.is_bot
330
- tzone_users[user_info.tz_label] ||= 0
331
- tzone_users[user_info.tz_label] += 1
332
- end
333
- end
334
- end
335
- end
336
- if rows[0].key?(:job_title) #then save_stats is saving the job title already
337
- rows.job_title.each_with_index do |job_title, idx|
338
- job_title = job_title.to_s.split.map(&:capitalize).join(' ')
339
- job_title_users[job_title] ||= 0
340
- job_title_users[job_title] += 1
341
- users_by_job_title[job_title] ||= []
342
- users_by_job_title[job_title] << rows.user_name[idx]
343
- end
344
- else
345
- rows.user_id.each_with_index do |usr, i|
346
- if rows[i].values.size >= 13 #then save_stats is saving the job_title already but not all the data
347
- job_title = rows[i].values[12].to_s.split.map(&:capitalize).join(' ')
348
- job_title_users[job_title] ||= 0
349
- job_title_users[job_title] += 1
350
- users_by_job_title[job_title] ||= []
351
- users_by_job_title[job_title] << rows.user_name[i]
352
- else
353
- user_info = @users.select { |u| u.id == usr or (u.key?(:enterprise_user) and u.enterprise_user.id == usr) }[-1]
354
- unless user_info.nil? or user_info.is_app_user or user_info.is_bot
355
- job_title = user_info.profile.title.split.map(&:capitalize).join(' ')
356
- job_title_users[job_title] ||= 0
357
- job_title_users[job_title] += 1
358
- users_by_job_title[job_title] ||= []
359
- users_by_job_title[job_title] << rows.user_name[i]
360
- end
361
- end
362
- end
363
- end
364
- total_users_by_job_title = 0
365
- users_by_job_title.each do |job_title, users|
366
- users.uniq!
367
- total_users_by_job_title += users.size
368
- end
369
- if users.size > 10
370
- message << "*Users* - #{users.size} (Top 10)"
371
- else
372
- message << "*Users* - #{users.size}"
373
- end
374
- count_user = {}
375
- users.each do |user|
376
- count = rows.count {|h| h.user_id==user}
377
- count_user[user] = count
378
- end
379
- i = 0
380
- total_without_routines = total
381
- count_user.sort_by {|k,v| -v}.each do |user, count|
382
- i+=1
383
- if user.include?('routine/')
384
- user_link = users_id_name[user]
385
- total_without_routines -= count
386
- else
387
- user_link = "<@#{user}>"
388
- end
389
- if i <= 10
390
- message << "\t#{user_link}: #{count} (#{(count.to_f*100/total).round(2)}%)"
391
- end
392
- if users.size > 10 and all_data
393
- users_attachment << "\t#{users_id_name[user]}: #{count} (#{(count.to_f*100/total).round(2)}%)"
394
- end
395
- end
413
+ end
414
+ end
415
+ end
416
+ end
417
+ end
418
+ users_by_job_title.each do |job_title, users|
419
+ users.uniq!
420
+ end
421
+ if users.size > 10
422
+ message << "*Users* - #{users.size} (Top 10)"
423
+ else
424
+ message << "*Users* - #{users.size}"
425
+ end
426
+ count_user = {}
427
+ users.each do |user|
428
+ count = rows.count { |h| h.user_id == user }
429
+ count_user[user] = count
430
+ end
431
+ i = 0
432
+ total_without_routines = total
433
+ count_user.sort_by { |k, v| -v }.each do |user, count|
434
+ i += 1
435
+ if user.include?("routine/")
436
+ user_link = users_id_name[user]
437
+ total_without_routines -= count
438
+ else
439
+ user_link = "<@#{user}>"
440
+ end
441
+ if i <= 10
442
+ message << "\t#{user_link}: #{count} (#{(count.to_f * 100 / total).round(2)}%)"
443
+ end
444
+ if users.size > 10 and all_data
445
+ users_attachment << "\t#{users_id_name[user]}: #{count} (#{(count.to_f * 100 / total).round(2)}%)"
446
+ end
447
+ end
448
+ if tzone_users.size > 0
449
+ message << "*Time Zones*"
450
+ total_known = 0
451
+ tzone_users.each do |tzone, num|
452
+ unless tzone.to_s == ""
453
+ message << "\t#{tzone}: #{num} (#{(num.to_f * 100 / total_without_routines).round(2)}%)"
454
+ total_known += num
455
+ end
456
+ end
457
+ total_unknown = total_without_routines - total_known
458
+ message << "\tUnknown: #{total_unknown} (#{(total_unknown.to_f * 100 / total_without_routines).round(2)}%)" if total_unknown > 0
459
+ end
460
+ if users.size > 0
461
+ if job_title_users.size > 10
462
+ message << "*Job Titles* - #{job_title_users.size} (Top 10)"
463
+ else
464
+ message << "*Job Titles* - #{job_title_users.size}"
465
+ end
466
+ total_known = 0
467
+ i = 0
468
+ job_title_users.sort_by { |k, v| -v }.each do |jtitle, num|
469
+ unless jtitle.to_s == ""
470
+ i += 1
471
+ if i <= 10
472
+ message << "\t#{jtitle}: #{num} (#{(num.to_f * 100 / total_without_routines).round(2)}%)"
473
+ end
474
+ total_known += num
475
+ end
476
+ end
477
+ total_unknown = total_without_routines - total_known
478
+ message << "\tUnknown: #{total_unknown} (#{(total_unknown.to_f * 100 / total_without_routines).round(2)}%)" if total_unknown > 0
479
+ end
480
+ if users.size > 0
481
+ if users_by_job_title.size > 10
482
+ message << "*Num Users by Job Title* (Top 10)"
483
+ else
484
+ message << "*Num Users by Job Title*"
485
+ end
486
+ i = 0
487
+ users_by_job_title.sort_by { |k, v| -v.size }.each do |jtitle, usersj|
488
+ i += 1
489
+ if i <= 10
490
+ message << "\t#{jtitle}: #{usersj.size} (#{(usersj.size.to_f * 100 / users.size).round(2)}%)"
491
+ end
492
+ end
493
+ end
494
+ end
495
+ commands_attachment = []
396
496
 
397
- if tzone_users.size > 0
398
- message << "*Time Zones*"
399
- total_known = 0
400
- tzone_users.each do |tzone, num|
401
- unless tzone.to_s == ''
402
- message << "\t#{tzone}: #{num} (#{(num.to_f*100/total_without_routines).round(2)}%)"
403
- total_known+=num
404
- end
405
- end
406
- total_unknown = total_without_routines - total_known
407
- message << "\tUnknown: #{total_unknown} (#{(total_unknown.to_f*100/total_without_routines).round(2)}%)" if total_unknown > 0
408
- end
409
-
410
- if job_title_users.size > 0
411
- if job_title_users.size > 10
412
- message << "*Job Titles* - #{job_title_users.size} (Top 10)"
413
- else
414
- message << "*Job Titles* - #{job_title_users.size}"
415
- end
416
- total_known = 0
417
- i = 0
418
- job_title_users.sort_by {|k,v| -v}.each do |jtitle, num|
419
- unless jtitle.to_s == ''
420
- i += 1
421
- if i <= 10
422
- message << "\t#{jtitle}: #{num} (#{(num.to_f*100/total_without_routines).round(2)}%)"
423
- end
424
- total_known+=num
425
- end
426
- end
427
- total_unknown = total_without_routines - total_known
428
- message << "\tUnknown: #{total_unknown} (#{(total_unknown.to_f*100/total_without_routines).round(2)}%)" if total_unknown > 0
429
- end
430
- if users_by_job_title.size > 0
431
- if users_by_job_title.size > 10
432
- message << "*Num Users by Job Title* (Top 10)"
433
- else
434
- message << "*Num Users by Job Title*"
435
- end
436
- i = 0
437
- users_by_job_title.sort_by {|k,v| -v.size}.each do |jtitle, users|
438
- i += 1
439
- if i <= 10
440
- jtitle = 'Unknown' if jtitle.to_s == ''
441
- message << "\t#{jtitle}: #{users.size} (#{(users.size.to_f*100/total_users_by_job_title).round(2)}%)"
442
- end
443
- end
444
- end
445
- end
446
- commands_attachment = []
497
+ if st_command == ""
498
+ commands = rows.command.uniq.sort
499
+ count_command = {}
500
+ commands.each do |command|
501
+ count = rows.count { |h| h.command == command }
502
+ count_command[command] = count
503
+ end
447
504
 
448
- if st_command == ''
449
- commands = rows.command.uniq.sort
450
- count_command = {}
451
- commands.each do |command|
452
- count = rows.count {|h| h.command==command}
453
- count_command[command] = count
454
- end
505
+ if commands.size > 10
506
+ message << "*Commands* - #{commands.size} (Top 10)"
507
+ else
508
+ message << "*Commands* - #{commands.size}"
509
+ end
455
510
 
456
- if commands.size > 10
457
- message << "*Commands* - #{commands.size} (Top 10)"
458
- else
459
- message << "*Commands* - #{commands.size}"
460
- end
511
+ i = 0
512
+ count_command.sort_by { |k, v| -v }.each do |command, count|
513
+ i += 1
514
+ if i <= 10
515
+ message << "\t#{command}: #{count} (#{(count.to_f * 100 / total).round(2)}%)"
516
+ end
517
+ if commands.size > 10 and all_data
518
+ commands_attachment << "\t#{command}: #{count} (#{(count.to_f * 100 / total).round(2)}%)"
519
+ end
520
+ end
521
+ end
461
522
 
462
- i = 0
463
- count_command.sort_by {|k,v| -v}.each do |command, count|
464
- i+=1
465
- if i <= 10
466
- message << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
467
- end
468
- if commands.size > 10 and all_data
469
- commands_attachment << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
470
- end
471
- end
472
- end
473
-
474
- message << "*Message type*"
475
- types = rows.type_message.uniq.sort
476
- types.each do |type|
477
- count = rows.count {|h| h.type_message==type}
478
- message << "\t#{type}: #{count} (#{(count.to_f*100/total).round(2)}%)"
479
- end
523
+ message << "*Message type*"
524
+ types = rows.type_message.uniq.sort
525
+ types.each do |type|
526
+ count = rows.count { |h| h.type_message == type }
527
+ message << "\t#{type}: #{count} (#{(count.to_f * 100 / total).round(2)}%)"
528
+ end
480
529
 
481
- if on_dm_master
482
- message << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].type_message} #{rows[-1].user_name} #{rows[-1].command}"
483
- end
484
- if users_attachment.size>0
485
- send_file(dest, "", 'users.txt', "", 'text/plain', "text", content: users_attachment.join("\n"))
486
- end
487
- if commands_attachment.size>0
488
- send_file(dest, "", 'commands.txt', "", 'text/plain', "text", content: commands_attachment.join("\n"))
489
- end
490
- if channels_dest_attachment.size>0
491
- send_file(dest, "", 'channels_dest.txt', "", 'text/plain', "text", content: channels_dest_attachment.join("\n"))
492
- end
493
- end
494
- end
495
- else
496
- message<<"Only Master admin users on a private conversation with the bot can see this kind of bot stats."
530
+ if on_dm_master
531
+ message << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].type_message} #{rows[-1].user_name} #{rows[-1].command}"
532
+ end
533
+ if users_attachment.size > 0
534
+ send_file(dest, "", "users.txt", "", "text/plain", "text", content: users_attachment.join("\n"))
535
+ end
536
+ if commands_attachment.size > 0
537
+ send_file(dest, "", "commands.txt", "", "text/plain", "text", content: commands_attachment.join("\n"))
538
+ end
539
+ if channels_dest_attachment.size > 0
540
+ send_file(dest, "", "channels_dest.txt", "", "text/plain", "text", content: channels_dest_attachment.join("\n"))
497
541
  end
542
+ end
498
543
  end
499
- respond "#{message.join("\n")}", dest
544
+ else
545
+ message << "Only Master admin users on a private conversation with the bot can see this kind of bot stats."
546
+ end
500
547
  end
501
- end
548
+ unreact :runner
549
+ respond "#{message.join("\n")}", dest
550
+ end
551
+ end
@@ -342,7 +342,14 @@ class SlackSmartBot
342
342
  if (typem == :on_master or typem == :on_bot) and dest[0]!='D' and dest!=@channels_id[config.stats_channel] #routine bot stats to be published on DM
343
343
  st_channel = dchannel
344
344
  end
345
- bot_stats(dest, user, typem, st_channel, st_from, st_to, st_user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data, members_channel, exclude_members_channel)
345
+ res = opts.scan(/(\w+)\s+\/([^\/]+)\//i)
346
+ header = []
347
+ regexp = []
348
+ res.each do |r|
349
+ header << r[0]
350
+ regexp << r[1]
351
+ end
352
+ bot_stats(dest, user, typem, st_channel, st_from, st_to, st_user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data, members_channel, exclude_members_channel, header, regexp)
346
353
  when /\A(set|turn)\s+maintenance\s+(on|off)\s*()\z/im, /\A(set|turn)\s+maintenance\s+(on)\s*(.+)\s*\z/im
347
354
  status = $2.downcase
348
355
  message = $3.to_s
data/whats_new.txt CHANGED
@@ -1,4 +1,4 @@
1
- *Version 1.12.7* Released 2022-Nov-08
1
+ *Version 1.12.8* Released 2022-Nov-17
2
2
 
3
3
  *For General users*
4
4
  - `run repl` accepts local parameters and precode to be supplied (<https://github.com/MarioRuiz/slack-smart-bot/issues/60|#60>).
@@ -17,6 +17,7 @@
17
17
  - Bot Stats is now saving the job title of the user (<https://github.com/MarioRuiz/slack-smart-bot/issues/77|#77>)
18
18
  - Any member of smartbot-stats channel can use the `bot stats` command on the channel (<https://github.com/MarioRuiz/slack-smart-bot/issues/78|#78>)
19
19
  - Added options for `bot stats` command: today, yesterday, this week, last week, this year, last year (<https://github.com/MarioRuiz/slack-smart-bot/issues/79|#79>)
20
+ - `bot stats HEADER /regexp/` filter results by stats header following the regexp supplied (<https://github.com/MarioRuiz/slack-smart-bot/issues/81|#81>)
20
21
  ------------------------------
21
22
 
22
23
  *Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/b1a368c3342094e886f53d96dc4d12ecd81ab04b/whats_new.txt|1.11.0>
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.12.7
4
+ version: 1.12.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mario Ruiz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-08 00:00:00.000000000 Z
11
+ date: 2022-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slack-ruby-client