slack-smart-bot 1.9.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +184 -16
- data/lib/slack/smart-bot/comm/ask.rb +55 -49
- data/lib/slack/smart-bot/comm/delete.rb +13 -0
- data/lib/slack/smart-bot/comm/dont_understand.rb +3 -3
- data/lib/slack/smart-bot/comm/event_hello.rb +8 -4
- data/lib/slack/smart-bot/comm/get_channel_members.rb +13 -4
- data/lib/slack/smart-bot/comm/get_channels.rb +31 -16
- data/lib/slack/smart-bot/comm/get_presence.rb +20 -0
- data/lib/slack/smart-bot/comm/get_user_info.rb +12 -8
- data/lib/slack/smart-bot/comm/get_users.rb +24 -0
- data/lib/slack/smart-bot/comm/react.rb +19 -2
- data/lib/slack/smart-bot/comm/respond.rb +224 -53
- data/lib/slack/smart-bot/comm/respond_direct.rb +2 -3
- data/lib/slack/smart-bot/comm/respond_thread.rb +5 -0
- data/lib/slack/smart-bot/comm/send_file.rb +38 -34
- data/lib/slack/smart-bot/comm/send_msg_channel.rb +27 -22
- data/lib/slack/smart-bot/comm/send_msg_user.rb +59 -33
- data/lib/slack/smart-bot/comm/unreact.rb +22 -18
- data/lib/slack/smart-bot/comm.rb +4 -0
- data/lib/slack/smart-bot/commands/general/add_admin.rb +51 -0
- data/lib/slack/smart-bot/commands/general/add_announcement.rb +32 -0
- data/lib/slack/smart-bot/commands/general/add_team.rb +80 -0
- data/lib/slack/smart-bot/commands/general/allow_access.rb +67 -0
- data/lib/slack/smart-bot/commands/general/bot_help.rb +69 -33
- data/lib/slack/smart-bot/commands/general/bye_bot.rb +0 -7
- data/lib/slack/smart-bot/commands/general/delete_announcement.rb +34 -0
- data/lib/slack/smart-bot/commands/general/delete_share.rb +34 -0
- data/lib/slack/smart-bot/commands/general/delete_team.rb +34 -0
- data/lib/slack/smart-bot/commands/general/deny_access.rb +36 -0
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +16 -11
- data/lib/slack/smart-bot/commands/general/ping_team.rb +100 -0
- data/lib/slack/smart-bot/commands/general/poster.rb +116 -0
- data/lib/slack/smart-bot/commands/general/remove_admin.rb +58 -0
- data/lib/slack/smart-bot/commands/general/see_access.rb +24 -0
- data/lib/slack/smart-bot/commands/general/see_admins.rb +33 -0
- data/lib/slack/smart-bot/commands/general/see_announcements.rb +115 -0
- data/lib/slack/smart-bot/commands/general/see_command_ids.rb +29 -0
- data/lib/slack/smart-bot/commands/general/see_favorite_commands.rb +53 -0
- data/lib/slack/smart-bot/commands/general/see_shares.rb +41 -0
- data/lib/slack/smart-bot/commands/general/see_statuses.rb +91 -0
- data/lib/slack/smart-bot/commands/general/see_teams.rb +252 -0
- data/lib/slack/smart-bot/commands/general/share_messages.rb +58 -0
- data/lib/slack/smart-bot/commands/general/update_team.rb +109 -0
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +504 -0
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +4 -6
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +45 -14
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +4 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +6 -3
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +3 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +4 -4
- data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +8 -2
- data/lib/slack/smart-bot/commands/on_bot/admin/see_result_routine.rb +33 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +13 -10
- data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +6 -3
- data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +3 -1
- data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +4 -1
- data/lib/slack/smart-bot/commands/on_bot/admin_master/delete_message.rb +25 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb +34 -0
- data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +37 -0
- data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +4 -5
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +7 -8
- data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +400 -0
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/bot_status.rb +3 -4
- data/lib/slack/smart-bot/commands/on_bot/general/leaderboard.rb +201 -0
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/stop_using_rules.rb +12 -6
- data/lib/slack/smart-bot/commands/on_bot/general/suggest_command.rb +36 -0
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/use_rules.rb +13 -11
- data/lib/slack/smart-bot/commands/{general → on_bot/general}/whats_new.rb +2 -1
- data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +4 -5
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +76 -21
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +3 -4
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +15 -7
- data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +5 -6
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +5 -6
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +45 -12
- data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +7 -3
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +4 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +3 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +33 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb +39 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +10 -1
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +28 -14
- data/lib/slack/smart-bot/commands/on_master/where_smartbot.rb +41 -0
- data/lib/slack/smart-bot/commands.rb +36 -5
- data/lib/slack/smart-bot/listen.rb +31 -33
- data/lib/slack/smart-bot/process.rb +234 -73
- data/lib/slack/smart-bot/process_first.rb +119 -38
- data/lib/slack/smart-bot/treat_message.rb +310 -237
- data/lib/slack/smart-bot/utils/build_help.rb +2 -2
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +81 -46
- data/lib/slack/smart-bot/utils/get_access_channels.rb +13 -0
- data/lib/slack/smart-bot/utils/get_admins_channels.rb +13 -0
- data/lib/slack/smart-bot/utils/get_bots_created.rb +28 -8
- data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +7 -2
- data/lib/slack/smart-bot/utils/get_command_ids.rb +84 -0
- data/lib/slack/smart-bot/utils/get_help.rb +79 -73
- data/lib/slack/smart-bot/utils/get_repls.rb +22 -2
- data/lib/slack/smart-bot/utils/get_routines.rb +22 -2
- data/lib/slack/smart-bot/utils/get_shares.rb +12 -0
- data/lib/slack/smart-bot/utils/get_teams.rb +22 -0
- data/lib/slack/smart-bot/utils/has_access.rb +28 -0
- data/lib/slack/smart-bot/utils/is_admin.rb +27 -0
- data/lib/slack/smart-bot/utils/save_stats.rb +46 -41
- data/lib/slack/smart-bot/utils/save_status.rb +67 -0
- data/lib/slack/smart-bot/utils/update_access_channels.rb +8 -0
- data/lib/slack/smart-bot/utils/update_admins_channels.rb +8 -0
- data/lib/slack/smart-bot/utils/update_bots_file.rb +28 -7
- data/lib/slack/smart-bot/utils/update_repls.rb +7 -4
- data/lib/slack/smart-bot/utils/update_routines.rb +9 -3
- data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +13 -6
- data/lib/slack/smart-bot/utils/update_teams.rb +16 -0
- data/lib/slack/smart-bot/utils.rb +11 -0
- data/lib/slack-smart-bot.rb +72 -12
- data/lib/slack-smart-bot_general_commands.rb +61 -0
- data/lib/slack-smart-bot_general_rules.rb +5 -2
- data/lib/slack-smart-bot_rules.rb +43 -17
- data/whats_new.txt +20 -15
- metadata +76 -9
- data/lib/slack/smart-bot/commands/general/bot_stats.rb +0 -313
@@ -0,0 +1,400 @@
|
|
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 exclude COMMAND_ID`
|
20
|
+
# help: `bot stats monthly`
|
21
|
+
# help: `bot stats alldata`
|
22
|
+
# help: To see the bot stats
|
23
|
+
# 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
|
24
|
+
# helpmaster: You need to set stats to true to generate the stats when running the bot instance.
|
25
|
+
# help: members #CHANNEL will return stats for only members of the channel supplied
|
26
|
+
# help: exclude members #CHANNEL will return stats for only members that are not members of the channel supplied
|
27
|
+
# help: If alldata option supplied then it will be attached files including all data and not only the top 10.
|
28
|
+
# help: Examples:
|
29
|
+
# help: _bot stats #sales_
|
30
|
+
# helpmaster: _bot stats @peter.wind_
|
31
|
+
# help: _bot stats #sales from 2019/12/15 to 2019/12/31_
|
32
|
+
# help: _bot stats #sales today_
|
33
|
+
# help: _bot stats #sales from 2020-01-01 monthly_
|
34
|
+
# help: _bot stats exclude routines masters from 2021/01/01 monthly_
|
35
|
+
# help: _bot stats members #development from 2022/01/01 to 2022/01/31_
|
36
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
|
37
|
+
# help: command_id: :bot_stats
|
38
|
+
# help:
|
39
|
+
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)
|
40
|
+
require 'csv'
|
41
|
+
if config.stats
|
42
|
+
message = []
|
43
|
+
else
|
44
|
+
message = ["You need to set stats to true to generate the stats when running the bot instance."]
|
45
|
+
end
|
46
|
+
save_stats(__method__)
|
47
|
+
if (from_user.id != user and (config.masters.include?(from_user.name) or @master_admin_users_id.include?(from_user.id)) and (typem==:on_dm or dest[0]=='D'))
|
48
|
+
on_dm_master = true #master admin user
|
49
|
+
else
|
50
|
+
on_dm_master = false
|
51
|
+
end
|
52
|
+
wrong = false
|
53
|
+
exclude_channel_members = false
|
54
|
+
include_channel_members = false
|
55
|
+
members_list = []
|
56
|
+
if exclude_members_channel!='' or members_channel!=''
|
57
|
+
if members_channel!=''
|
58
|
+
channel_members = members_channel
|
59
|
+
include_channel_members = true
|
60
|
+
else
|
61
|
+
channel_members = exclude_members_channel
|
62
|
+
exclude_channel_members = true
|
63
|
+
end
|
64
|
+
get_channels_name_and_id() unless @channels_id.keys.include?(channel_members)
|
65
|
+
|
66
|
+
tm = get_channel_members(channel_members)
|
67
|
+
if tm.nil?
|
68
|
+
message << ":exclamation: Add the Smart Bot to *<##{channel_members}>* channel first."
|
69
|
+
wrong = true
|
70
|
+
else
|
71
|
+
tm.each do |m|
|
72
|
+
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
|
73
|
+
members_list << user_info.name unless user_info.is_app_user or user_info.is_bot
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
tzone_users = {}
|
78
|
+
|
79
|
+
unless wrong
|
80
|
+
if on_dm_master or (from_user.id == user) # normal user can only see own stats
|
81
|
+
if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
|
82
|
+
message<<'No stats'
|
83
|
+
else
|
84
|
+
from = "#{Time.now.strftime("%Y-%m")}-01" if from == ''
|
85
|
+
to = "#{Time.now.strftime("%Y-%m-%d")}" if to == ''
|
86
|
+
from_short = from
|
87
|
+
to_short = to
|
88
|
+
from_file = from[0..3] + '-' + from[5..6]
|
89
|
+
to_file = to[0..3] + '-' + to[5..6]
|
90
|
+
from+= " 00:00:00 +0000"
|
91
|
+
to+= " 23:59:59 +0000"
|
92
|
+
rows = []
|
93
|
+
rows_month = {}
|
94
|
+
users_month = {}
|
95
|
+
commands_month = {}
|
96
|
+
users_id_name = {}
|
97
|
+
users_name_id = {}
|
98
|
+
count_users = {}
|
99
|
+
count_channels_dest = {}
|
100
|
+
|
101
|
+
# to translate global and enterprise users since sometimes was returning different names/ids
|
102
|
+
#if from[0..3]=='2020' # this was an issue only on that period
|
103
|
+
Dir["#{config.stats_path}.*.log"].sort.each do |file|
|
104
|
+
if file >= "#{config.stats_path}.#{from_file}.log" and file <= "#{config.stats_path}.#{to_file}.log"
|
105
|
+
CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
|
106
|
+
unless users_id_name.key?(row[:user_id])
|
107
|
+
users_id_name[row[:user_id]] = row[:user_name]
|
108
|
+
users_name_id[row[:user_name]] = row[:user_id]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
#end
|
114
|
+
|
115
|
+
if user!=''
|
116
|
+
user_info = @users.select{|u| u.id == user or (u.key?(:enterprise_user) and u.enterprise_user.id == user)}[-1]
|
117
|
+
if user_info.nil? # for the case the user is populated from outside of slack
|
118
|
+
user_name = user
|
119
|
+
user_id = user
|
120
|
+
else
|
121
|
+
if users_id_name.key?(user_info.id)
|
122
|
+
user_name = users_id_name[user_info.id]
|
123
|
+
else
|
124
|
+
user_name = user_info.name
|
125
|
+
end
|
126
|
+
if users_name_id.key?(user_info.name)
|
127
|
+
user_id = users_name_id[user_info.name]
|
128
|
+
else
|
129
|
+
user_id = user_info.id
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
master_admins = config.masters.dup
|
134
|
+
if users_id_name.size > 0
|
135
|
+
config.masters.each do |u|
|
136
|
+
if users_id_name.key?(u)
|
137
|
+
master_admins << users_id_name[u]
|
138
|
+
elsif users_name_id.key?(u)
|
139
|
+
master_admins << users_name_id[u]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
Dir["#{config.stats_path}.*.log"].sort.each do |file|
|
145
|
+
if file >= "#{config.stats_path}.#{from_file}.log" and file <= "#{config.stats_path}.#{to_file}.log"
|
146
|
+
CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
|
147
|
+
if (include_channel_members and members_list.include?(row[:user_name])) or
|
148
|
+
(exclude_channel_members and !members_list.include?(row[:user_name])) or
|
149
|
+
(!include_channel_members and !exclude_channel_members)
|
150
|
+
|
151
|
+
row[:date] = row[:date].to_s
|
152
|
+
if row[:dest_channel_id].to_s[0]=='D'
|
153
|
+
row[:dest_channel] = 'DM'
|
154
|
+
elsif row[:dest_channel].to_s == ''
|
155
|
+
row[:dest_channel] = row[:dest_channel_id]
|
156
|
+
end
|
157
|
+
if users_name_id.size > 0
|
158
|
+
row[:user_name] = users_id_name[row[:user_id]]
|
159
|
+
row[:user_id] = users_name_id[row[:user_name]]
|
160
|
+
else
|
161
|
+
users_id_name[row[:user_id]] ||= row[:user_name]
|
162
|
+
end
|
163
|
+
if !exclude_masters or (exclude_masters and !master_admins.include?(row[:user_name]) and
|
164
|
+
!master_admins.include?(row[:user_id]) and
|
165
|
+
!@master_admin_users_id.include?(row[:user_id]))
|
166
|
+
if !exclude_routines or (exclude_routines and !row[:user_name].match?(/^routine\//) )
|
167
|
+
if exclude_command == '' or (exclude_command!='' and row[:command]!=exclude_command)
|
168
|
+
if st_command == '' or (st_command != '' and row[:command] == st_command)
|
169
|
+
if row[:bot_channel_id] == channel_id or channel_id == '' or row[:dest_channel_id] == channel_id
|
170
|
+
if row[:date] >= from and row[:date] <= to
|
171
|
+
count_users[row[:user_id]] ||= 0
|
172
|
+
count_users[row[:user_id]] += 1
|
173
|
+
if user=='' or (user!='' and row[:user_name] == user_name) or (user!='' and row[:user_id] == user_id)
|
174
|
+
rows << row.to_h
|
175
|
+
count_channels_dest[row[:dest_channel]] ||= 0
|
176
|
+
count_channels_dest[row[:dest_channel]] += 1
|
177
|
+
if monthly
|
178
|
+
rows_month[row[:date][0..6]] = 0 unless rows_month.key?(row[:date][0..6])
|
179
|
+
users_month[row[:date][0..6]] = [] unless users_month.key?(row[:date][0..6])
|
180
|
+
commands_month[row[:date][0..6]] = [] unless commands_month.key?(row[:date][0..6])
|
181
|
+
rows_month[row[:date][0..6]] += 1
|
182
|
+
users_month[row[:date][0..6]] << row[:user_id]
|
183
|
+
commands_month[row[:date][0..6]] << row[:command]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
total = rows.size
|
197
|
+
if exclude_masters
|
198
|
+
message << 'Excluding master admins'
|
199
|
+
end
|
200
|
+
if exclude_routines
|
201
|
+
message << 'Excluding routines'
|
202
|
+
end
|
203
|
+
if exclude_command != ''
|
204
|
+
message << "Excluding command #{exclude_command}"
|
205
|
+
end
|
206
|
+
if st_command != ''
|
207
|
+
message << "Including only command #{st_command}"
|
208
|
+
end
|
209
|
+
if include_channel_members
|
210
|
+
message << "Including only members of <##{members_channel}>"
|
211
|
+
end
|
212
|
+
if exclude_channel_members
|
213
|
+
message << "Including only members that are not members of <##{exclude_members_channel}>"
|
214
|
+
end
|
215
|
+
if user!=''
|
216
|
+
if user==from_user.id
|
217
|
+
message << "Bot stats for <@#{user}>"
|
218
|
+
else
|
219
|
+
message << "Showing only user <@#{user}>"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
if channel_id == ''
|
223
|
+
message << "*Total calls*: #{total} from #{from_short} to #{to_short}"
|
224
|
+
else
|
225
|
+
message << "*Total calls <##{channel_id}>*: #{total} from #{from_short} to #{to_short}"
|
226
|
+
end
|
227
|
+
unless count_users.size == 0 or total == 0 or user == ''
|
228
|
+
my_place = (count_users.sort_by(&:last).reverse.to_h.keys.index(user_id)+1)
|
229
|
+
message <<"\tYou are the *\# #{my_place}* of *#{count_users.size}* users"
|
230
|
+
end
|
231
|
+
if total > 0
|
232
|
+
if monthly
|
233
|
+
if on_dm_master
|
234
|
+
message << '*Totals by month / commands / users (%new)*'
|
235
|
+
else
|
236
|
+
message << '*Totals by month / commands*'
|
237
|
+
end
|
238
|
+
|
239
|
+
all_users = []
|
240
|
+
new_users = []
|
241
|
+
rows_month.each do |k,v|
|
242
|
+
if all_users.empty?
|
243
|
+
message_new_users = ''
|
244
|
+
else
|
245
|
+
new_users = (users_month[k]-all_users).uniq
|
246
|
+
message_new_users = "(#{new_users.size*100/users_month[k].uniq.size}%)"
|
247
|
+
end
|
248
|
+
all_users += users_month[k]
|
249
|
+
if on_dm_master
|
250
|
+
message << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{message_new_users}"
|
251
|
+
else
|
252
|
+
message << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size}"
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
if channel_id == ''
|
258
|
+
message << "*SmartBots*"
|
259
|
+
channels = rows.bot_channel.uniq.sort
|
260
|
+
channels.each do |channel|
|
261
|
+
count = rows.count {|h| h.bot_channel==channel}
|
262
|
+
channel_info = @channels_list.select { |c| c.name.to_s.downcase == channel.to_s.downcase}[-1]
|
263
|
+
if @channels_id.key?(channel) and !channel_info.is_private
|
264
|
+
c = "<##{@channels_id[channel]}>"
|
265
|
+
else
|
266
|
+
c = channel
|
267
|
+
end
|
268
|
+
message << "\t#{c}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
269
|
+
end
|
270
|
+
end
|
271
|
+
channels_dest_attachment = []
|
272
|
+
count_channels_dest = count_channels_dest.sort_by(&:last).reverse.to_h
|
273
|
+
if count_channels_dest.size > 10
|
274
|
+
message << "*From Channel* - #{count_channels_dest.size} (Top 10)"
|
275
|
+
else
|
276
|
+
message << "*From Channel* - #{count_channels_dest.size}"
|
277
|
+
end
|
278
|
+
|
279
|
+
count_channels_dest.keys[0..9].each do |ch|
|
280
|
+
channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase}[-1]
|
281
|
+
if @channels_id.key?(ch) and !channel_info.is_private
|
282
|
+
c = "<##{@channels_id[ch]}>"
|
283
|
+
else
|
284
|
+
c = ch
|
285
|
+
end
|
286
|
+
message << "\t#{c}: #{count_channels_dest[ch]} (#{(count_channels_dest[ch].to_f*100/total).round(2)}%)"
|
287
|
+
end
|
288
|
+
if count_channels_dest.size > 10 and all_data
|
289
|
+
count_channels_dest.each do |ch, value|
|
290
|
+
channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase}[-1]
|
291
|
+
channels_dest_attachment << "\t##{ch}: #{value} (#{(value.to_f*100/total).round(2)}%)"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
users_attachment = []
|
296
|
+
if user==''
|
297
|
+
users = rows.user_id.uniq.sort
|
298
|
+
rows.user_id.each do |usr|
|
299
|
+
user_info = @users.select { |u| u.id == usr or (u.key?(:enterprise_user) and u.enterprise_user.id == usr) }[-1]
|
300
|
+
unless user_info.nil? or user_info.is_app_user or user_info.is_bot
|
301
|
+
tzone_users[user_info.tz_label] ||= 0
|
302
|
+
tzone_users[user_info.tz_label] += 1
|
303
|
+
end
|
304
|
+
end
|
305
|
+
if users.size > 10
|
306
|
+
message << "*Users* - #{users.size} (Top 10)"
|
307
|
+
else
|
308
|
+
message << "*Users* - #{users.size}"
|
309
|
+
end
|
310
|
+
count_user = {}
|
311
|
+
users.each do |user|
|
312
|
+
count = rows.count {|h| h.user_id==user}
|
313
|
+
count_user[user] = count
|
314
|
+
end
|
315
|
+
i = 0
|
316
|
+
total_without_routines = total
|
317
|
+
count_user.sort_by {|k,v| -v}.each do |user, count|
|
318
|
+
i+=1
|
319
|
+
if user.include?('routine/')
|
320
|
+
user_link = users_id_name[user]
|
321
|
+
total_without_routines -= count
|
322
|
+
else
|
323
|
+
user_link = "<@#{user}>"
|
324
|
+
end
|
325
|
+
if i <= 10
|
326
|
+
message << "\t#{user_link}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
327
|
+
end
|
328
|
+
if users.size > 10 and all_data
|
329
|
+
users_attachment << "\t#{users_id_name[user]}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
if tzone_users.size > 0
|
334
|
+
message << "*Time Zones*"
|
335
|
+
total_known = 0
|
336
|
+
tzone_users.each do |tzone, num|
|
337
|
+
message << "\t#{tzone}: #{num} (#{(num.to_f*100/total_without_routines).round(2)}%)"
|
338
|
+
total_known+=num
|
339
|
+
end
|
340
|
+
total_unknown = total_without_routines - total_known
|
341
|
+
message << "\tUnknown: #{total_unknown} (#{(total_unknown.to_f*100/total_without_routines).round(2)}%)" if total_unknown > 0
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
345
|
+
commands_attachment = []
|
346
|
+
|
347
|
+
if st_command == ''
|
348
|
+
commands = rows.command.uniq.sort
|
349
|
+
count_command = {}
|
350
|
+
commands.each do |command|
|
351
|
+
count = rows.count {|h| h.command==command}
|
352
|
+
count_command[command] = count
|
353
|
+
end
|
354
|
+
|
355
|
+
if commands.size > 10
|
356
|
+
message << "*Commands* - #{commands.size} (Top 10)"
|
357
|
+
else
|
358
|
+
message << "*Commands* - #{commands.size}"
|
359
|
+
end
|
360
|
+
|
361
|
+
i = 0
|
362
|
+
count_command.sort_by {|k,v| -v}.each do |command, count|
|
363
|
+
i+=1
|
364
|
+
if i <= 10
|
365
|
+
message << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
366
|
+
end
|
367
|
+
if commands.size > 10 and all_data
|
368
|
+
commands_attachment << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
message << "*Message type*"
|
374
|
+
types = rows.type_message.uniq.sort
|
375
|
+
types.each do |type|
|
376
|
+
count = rows.count {|h| h.type_message==type}
|
377
|
+
message << "\t#{type}: #{count} (#{(count.to_f*100/total).round(2)}%)"
|
378
|
+
end
|
379
|
+
|
380
|
+
if on_dm_master
|
381
|
+
message << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].type_message} #{rows[-1].user_name} #{rows[-1].command}"
|
382
|
+
end
|
383
|
+
if users_attachment.size>0
|
384
|
+
send_file(dest, "", 'users.txt', "", 'text/plain', "text", content: users_attachment.join("\n"))
|
385
|
+
end
|
386
|
+
if commands_attachment.size>0
|
387
|
+
send_file(dest, "", 'commands.txt', "", 'text/plain', "text", content: commands_attachment.join("\n"))
|
388
|
+
end
|
389
|
+
if channels_dest_attachment.size>0
|
390
|
+
send_file(dest, "", 'channels_dest.txt', "", 'text/plain', "text", content: channels_dest_attachment.join("\n"))
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
else
|
395
|
+
message<<"Only Master admin users on a private conversation with the bot can see this kind of bot stats."
|
396
|
+
end
|
397
|
+
end
|
398
|
+
respond "#{message.join("\n")}", dest
|
399
|
+
end
|
400
|
+
end
|
@@ -3,14 +3,13 @@ class SlackSmartBot
|
|
3
3
|
# helpadmin: `bot status`
|
4
4
|
# helpadmin: Displays the status of the bot
|
5
5
|
# helpadmin: If on master channel and admin user also it will display info about bots created
|
6
|
+
# helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
|
7
|
+
# helpadmin: command_id: :bot_status
|
6
8
|
# helpadmin:
|
7
9
|
def bot_status(dest, user)
|
8
10
|
save_stats(__method__)
|
9
11
|
get_bots_created()
|
10
|
-
if
|
11
|
-
(!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id)))
|
12
|
-
respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>"
|
13
|
-
else
|
12
|
+
if has_access?(__method__, user)
|
14
13
|
gems_remote = `gem list slack-smart-bot --remote`
|
15
14
|
version_remote = gems_remote.to_s().scan(/slack-smart-bot \((\d+\.\d+\.\d+)/).join
|
16
15
|
version_message = ""
|
@@ -0,0 +1,201 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
# help: ----------------------------------------------
|
3
|
+
# help: `leaderboard`
|
4
|
+
# help: `ranking`
|
5
|
+
# help: `podium`
|
6
|
+
# help: `leaderboard from YYYY/MM/DD`
|
7
|
+
# help: `leaderboard from YYYY/MM/DD to YYYY/MM/DD`
|
8
|
+
# help: `leaderboard PERIOD`
|
9
|
+
# help: It will present some useful information about the use of the SmartBot in the period specified.
|
10
|
+
# help: If no 'from' and 'to' specified then it will be considered 'last week'
|
11
|
+
# help: PERIOD: today, yesterday, last week, this week, last month, this month, last year, this year
|
12
|
+
# help: The results will exclude master admins and routines.
|
13
|
+
# help: For a more detailed data use the command `bot stats`
|
14
|
+
# help: Examples:
|
15
|
+
# help: _leaderboard_
|
16
|
+
# help: _podium from 2021/05/01_
|
17
|
+
# help: _leaderboard from 2021/05/01 to 2021/05/31_
|
18
|
+
# help: _ranking today_
|
19
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
|
20
|
+
# help: command_id: :leaderboard
|
21
|
+
# help:
|
22
|
+
|
23
|
+
def leaderboard(from, to, period)
|
24
|
+
exclude_masters = true
|
25
|
+
exclude_routines = true
|
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 !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
|
34
|
+
message<<'No stats'
|
35
|
+
else
|
36
|
+
if period == ''
|
37
|
+
message << "*Leaderboard SmartBot <##@channel_id> from #{from} to #{to}*\n"
|
38
|
+
else
|
39
|
+
message << "*Leaderboard SmartBot <##@channel_id> #{period}* (#{from} -> #{to})\n"
|
40
|
+
end
|
41
|
+
from_short = from
|
42
|
+
to_short = to
|
43
|
+
from_file = from[0..3] + '-' + from[5..6]
|
44
|
+
to_file = to[0..3] + '-' + to[5..6]
|
45
|
+
from+= " 00:00:00 +0000"
|
46
|
+
to+= " 23:59:59 +0000"
|
47
|
+
rows = []
|
48
|
+
users_id_name = {}
|
49
|
+
users_name_id = {}
|
50
|
+
count_users = {}
|
51
|
+
count_channels_dest = {}
|
52
|
+
count_commands_uniq_user = {}
|
53
|
+
|
54
|
+
# to translate global and enterprise users since sometimes was returning different names/ids
|
55
|
+
if from[0..3]=='2020' # this was an issue only on that period
|
56
|
+
Dir["#{config.stats_path}.*.log"].sort.each do |file|
|
57
|
+
if file >= "#{config.stats_path}.#{from_file}.log" or file <= "#{config.stats_path}.#{to_file}.log"
|
58
|
+
CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
|
59
|
+
unless users_id_name.key?(row[:user_id])
|
60
|
+
users_id_name[row[:user_id]] = row[:user_name]
|
61
|
+
end
|
62
|
+
unless users_name_id.key?(row[:user_name])
|
63
|
+
users_name_id[row[:user_name]] = row[:user_id]
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
master_admins = config.masters.dup
|
72
|
+
if users_id_name.size > 0
|
73
|
+
config.masters.each do |u|
|
74
|
+
if users_id_name.key?(u)
|
75
|
+
master_admins << users_id_name[u]
|
76
|
+
elsif users_name_id.key?(u)
|
77
|
+
master_admins << users_name_id[u]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
Dir["#{config.stats_path}.*.log"].sort.each do |file|
|
83
|
+
if file >= "#{config.stats_path}.#{from_file}.log" and file <= "#{config.stats_path}.#{to_file}.log"
|
84
|
+
CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
|
85
|
+
row[:date] = row[:date].to_s
|
86
|
+
if row[:dest_channel_id].to_s[0]=='D'
|
87
|
+
row[:dest_channel] = 'DM'
|
88
|
+
elsif row[:dest_channel].to_s == ''
|
89
|
+
row[:dest_channel] = row[:dest_channel_id]
|
90
|
+
end
|
91
|
+
if users_name_id.size > 0
|
92
|
+
row[:user_name] = users_id_name[row[:user_id]]
|
93
|
+
row[:user_id] = users_name_id[row[:user_name]]
|
94
|
+
else
|
95
|
+
users_id_name[row[:user_id]] ||= row[:user_name]
|
96
|
+
end
|
97
|
+
if !exclude_masters or (exclude_masters and !master_admins.include?(row[:user_name]) and
|
98
|
+
!master_admins.include?(row[:user_id]) and
|
99
|
+
!@master_admin_users_id.include?(row[:user_id]))
|
100
|
+
if !exclude_routines or (exclude_routines and !row[:user_name].match?(/^routine\//) )
|
101
|
+
if row[:bot_channel_id] == @channel_id
|
102
|
+
if row[:date] >= from and row[:date] <= to
|
103
|
+
count_users[row[:user_id]] ||= 0
|
104
|
+
count_users[row[:user_id]] += 1
|
105
|
+
rows << row.to_h
|
106
|
+
count_channels_dest[row[:dest_channel]] ||= 0
|
107
|
+
count_channels_dest[row[:dest_channel]] += 1
|
108
|
+
count_commands_uniq_user[row[:user_id]] ||= []
|
109
|
+
count_commands_uniq_user[row[:user_id]] << row[:command] unless count_commands_uniq_user[row[:user_id]].include?(row[:command])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
total = rows.size
|
119
|
+
|
120
|
+
if total > 0
|
121
|
+
|
122
|
+
users = rows.user_id.uniq.sort
|
123
|
+
count_user = {}
|
124
|
+
users.each do |user|
|
125
|
+
count = rows.count {|h| h.user_id==user}
|
126
|
+
count_user[user] = count
|
127
|
+
end
|
128
|
+
mtc = nil
|
129
|
+
mtu = []
|
130
|
+
i = 0
|
131
|
+
count_user.sort_by {|k,v| -v}.each do |user, count|
|
132
|
+
if i >= 3
|
133
|
+
break
|
134
|
+
elsif mtc.nil? or mtc == count or i < 3
|
135
|
+
mtu << "*<@#{users_id_name[user]}>* (#{count})"
|
136
|
+
mtc = count
|
137
|
+
else
|
138
|
+
break
|
139
|
+
end
|
140
|
+
i+=1
|
141
|
+
end
|
142
|
+
message << "\t :boom: Users that called more commands: \n\t\t\t\t#{mtu.join("\n\t\t\t\t")}"
|
143
|
+
|
144
|
+
mtc = nil
|
145
|
+
mtu = []
|
146
|
+
i = 0
|
147
|
+
count_commands_uniq_user.sort_by {|k,v| -v.size}.each do |user, cmds|
|
148
|
+
if i >= 3
|
149
|
+
break
|
150
|
+
elsif mtc.nil? or mtc == cmds.size or i < 3
|
151
|
+
mtu << "*<@#{users_id_name[user]}>* (#{cmds.size})"
|
152
|
+
mtc = cmds.size
|
153
|
+
else
|
154
|
+
break
|
155
|
+
end
|
156
|
+
i+=1
|
157
|
+
end
|
158
|
+
message << "\t :stethoscope: Users that called more different commands: \n\t\t\t\t#{mtu.join("\n\t\t\t\t")}"
|
159
|
+
|
160
|
+
commands_attachment = []
|
161
|
+
|
162
|
+
commands = rows.command.uniq.sort
|
163
|
+
count_command = {}
|
164
|
+
commands.each do |command|
|
165
|
+
count = rows.count {|h| h.command==command}
|
166
|
+
count_command[command] = count
|
167
|
+
end
|
168
|
+
|
169
|
+
mtu = []
|
170
|
+
count_command.sort_by {|k,v| -v}[0..2].each do |command, count|
|
171
|
+
mtu << "*`#{command.gsub('_',' ')}`* (#{count})"
|
172
|
+
end
|
173
|
+
message << "\t :four_leaf_clover: Most used commands: \n\t\t\t\t#{mtu.join("\n\t\t\t\t")}"
|
174
|
+
|
175
|
+
count_channels_dest = count_channels_dest.sort_by(&:last).reverse.to_h
|
176
|
+
count_channels_dest.keys[0..0].each do |ch|
|
177
|
+
if ch=='DM'
|
178
|
+
message << "\t :star: Most used channel: *DM* (#{(count_channels_dest[ch].to_f*100/total).round(2)}%)"
|
179
|
+
else
|
180
|
+
message << "\t :star: Most used channel: *<##{@channels_id[ch]}>* (#{(count_channels_dest[ch].to_f*100/total).round(2)}%)"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
types = rows.type_message.uniq.sort
|
185
|
+
count_type = {}
|
186
|
+
types.each do |type|
|
187
|
+
count = rows.count {|h| h.type_message==type}
|
188
|
+
count_type[type] = count
|
189
|
+
end
|
190
|
+
|
191
|
+
count_type.sort_by {|k,v| -v}[0..0].each do |type, count|
|
192
|
+
message << "\t :house_with_garden: Most calls came from *#{type}* (#{(count.to_f*100/total).round(2)}%)"
|
193
|
+
end
|
194
|
+
else
|
195
|
+
message << 'No data yet'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
respond "#{message.join("\n")}"
|
199
|
+
|
200
|
+
end
|
201
|
+
end
|
@@ -1,10 +1,14 @@
|
|
1
1
|
class SlackSmartBot
|
2
2
|
# help: ----------------------------------------------
|
3
3
|
# help: `stop using rules from CHANNEL`
|
4
|
+
# help: `stop using CHANNEL`
|
4
5
|
# help: it will stop using the rules from the specified channel.
|
6
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#using-rules-from-other-channels|more info>
|
7
|
+
# help: command_id: :stop_using_rules
|
5
8
|
# help:
|
6
9
|
def stop_using_rules(dest, channel, user, dchannel)
|
7
10
|
save_stats(__method__)
|
11
|
+
channel.gsub!('#','') # for the case the channel name is in plain text including #
|
8
12
|
if @channels_id.key?(channel)
|
9
13
|
channel_id = @channels_id[channel]
|
10
14
|
else
|
@@ -12,11 +16,12 @@ class SlackSmartBot
|
|
12
16
|
end
|
13
17
|
|
14
18
|
if dest[0] == "C" or dest[0] == "G" #channel
|
15
|
-
if @rules_imported.key?(user.
|
16
|
-
if @rules_imported[user.
|
19
|
+
if @rules_imported.key?(user.name) and @rules_imported[user.name].key?(dchannel)
|
20
|
+
if @rules_imported[user.name][dchannel] != channel_id
|
17
21
|
respond "You are not using those rules.", dest
|
18
22
|
else
|
19
|
-
@rules_imported[user.
|
23
|
+
@rules_imported[user.name].delete(dchannel)
|
24
|
+
sleep 0.5
|
20
25
|
update_rules_imported()
|
21
26
|
respond "You won't be using those rules from now on.", dest
|
22
27
|
|
@@ -27,11 +32,12 @@ class SlackSmartBot
|
|
27
32
|
respond "You were not using those rules.", dest
|
28
33
|
end
|
29
34
|
else #direct message
|
30
|
-
if @rules_imported.key?(user.
|
31
|
-
if @rules_imported[user.
|
35
|
+
if @rules_imported.key?(user.name) and @rules_imported[user.name].key?(user.name)
|
36
|
+
if @rules_imported[user.name][user.name] != channel_id
|
32
37
|
respond "You are not using those rules.", dest
|
33
38
|
else
|
34
|
-
@rules_imported[user.
|
39
|
+
@rules_imported[user.name].delete(user.name)
|
40
|
+
sleep 0.5
|
35
41
|
update_rules_imported()
|
36
42
|
respond "You won't be using those rules from now on.", dest
|
37
43
|
|