slack-smart-bot 1.10.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +134 -23
  3. data/lib/slack/smart-bot/comm/delete.rb +13 -0
  4. data/lib/slack/smart-bot/comm/dont_understand.rb +2 -2
  5. data/lib/slack/smart-bot/comm/get_channel_members.rb +7 -3
  6. data/lib/slack/smart-bot/comm/get_presence.rb +20 -0
  7. data/lib/slack/smart-bot/comm/get_users.rb +1 -1
  8. data/lib/slack/smart-bot/comm/respond.rb +24 -13
  9. data/lib/slack/smart-bot/comm/send_msg_user.rb +12 -11
  10. data/lib/slack/smart-bot/comm/set_status.rb +21 -0
  11. data/lib/slack/smart-bot/comm.rb +3 -0
  12. data/lib/slack/smart-bot/commands/general/add_admin.rb +51 -0
  13. data/lib/slack/smart-bot/commands/general/add_announcement.rb +1 -1
  14. data/lib/slack/smart-bot/commands/general/add_memo_team.rb +117 -0
  15. data/lib/slack/smart-bot/commands/general/add_team.rb +80 -0
  16. data/lib/slack/smart-bot/commands/general/add_vacation.rb +51 -0
  17. data/lib/slack/smart-bot/commands/general/allow_access.rb +67 -0
  18. data/lib/slack/smart-bot/commands/general/bot_help.rb +20 -11
  19. data/lib/slack/smart-bot/commands/general/delete_announcement.rb +1 -1
  20. data/lib/slack/smart-bot/commands/general/delete_memo_team.rb +69 -0
  21. data/lib/slack/smart-bot/commands/general/delete_share.rb +1 -1
  22. data/lib/slack/smart-bot/commands/general/delete_team.rb +54 -0
  23. data/lib/slack/smart-bot/commands/general/deny_access.rb +36 -0
  24. data/lib/slack/smart-bot/commands/general/ping_team.rb +100 -0
  25. data/lib/slack/smart-bot/commands/general/poster.rb +116 -0
  26. data/lib/slack/smart-bot/commands/general/remove_admin.rb +58 -0
  27. data/lib/slack/smart-bot/commands/general/remove_vacation.rb +27 -0
  28. data/lib/slack/smart-bot/commands/general/see_access.rb +24 -0
  29. data/lib/slack/smart-bot/commands/general/see_admins.rb +33 -0
  30. data/lib/slack/smart-bot/commands/general/see_announcements.rb +7 -5
  31. data/lib/slack/smart-bot/commands/general/see_command_ids.rb +29 -0
  32. data/lib/slack/smart-bot/commands/general/see_favorite_commands.rb +3 -4
  33. data/lib/slack/smart-bot/commands/general/see_statuses.rb +34 -21
  34. data/lib/slack/smart-bot/commands/general/see_teams.rb +402 -0
  35. data/lib/slack/smart-bot/commands/general/see_vacations.rb +58 -0
  36. data/lib/slack/smart-bot/commands/general/see_vacations_team.rb +136 -0
  37. data/lib/slack/smart-bot/commands/general/set_memo_status.rb +58 -0
  38. data/lib/slack/smart-bot/commands/general/share_messages.rb +1 -1
  39. data/lib/slack/smart-bot/commands/general/update_team.rb +130 -0
  40. data/lib/slack/smart-bot/commands/general_bot_commands.rb +442 -13
  41. data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +2 -1
  42. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +2 -1
  43. data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +2 -1
  44. data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +2 -1
  45. data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +2 -1
  46. data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +2 -1
  47. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +3 -2
  48. data/lib/slack/smart-bot/commands/on_bot/admin/see_result_routine.rb +2 -1
  49. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +10 -9
  50. data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +2 -1
  51. data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +2 -1
  52. data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +2 -1
  53. data/lib/slack/smart-bot/commands/on_bot/admin_master/delete_message.rb +25 -0
  54. data/lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb +1 -0
  55. data/lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb +3 -1
  56. data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +15 -2
  57. data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +2 -1
  58. data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +5 -4
  59. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +416 -0
  60. data/lib/slack/smart-bot/commands/{general → on_bot/general}/bot_status.rb +1 -0
  61. data/lib/slack/smart-bot/commands/{general → on_bot/general}/leaderboard.rb +1 -0
  62. data/lib/slack/smart-bot/commands/{general → on_bot/general}/stop_using_rules.rb +1 -0
  63. data/lib/slack/smart-bot/commands/{general → on_bot/general}/suggest_command.rb +6 -0
  64. data/lib/slack/smart-bot/commands/{general → on_bot/general}/use_rules.rb +1 -0
  65. data/lib/slack/smart-bot/commands/{general → on_bot/general}/whats_new.rb +2 -1
  66. data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +2 -1
  67. data/lib/slack/smart-bot/commands/on_bot/kill_repl.rb +32 -0
  68. data/lib/slack/smart-bot/commands/on_bot/repl.rb +73 -15
  69. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +1 -0
  70. data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +117 -28
  71. data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +2 -1
  72. data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +3 -2
  73. data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +5 -4
  74. data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +3 -2
  75. data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +2 -1
  76. data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +6 -3
  77. data/lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb +2 -1
  78. data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +2 -1
  79. data/lib/slack/smart-bot/commands/on_master/create_bot.rb +1 -0
  80. data/lib/slack/smart-bot/commands/on_master/where_smartbot.rb +41 -0
  81. data/lib/slack/smart-bot/commands.rb +30 -7
  82. data/lib/slack/smart-bot/listen.rb +30 -30
  83. data/lib/slack/smart-bot/process.rb +53 -23
  84. data/lib/slack/smart-bot/process_first.rb +2 -2
  85. data/lib/slack/smart-bot/treat_message.rb +23 -17
  86. data/lib/slack/smart-bot/utils/build_help.rb +1 -1
  87. data/lib/slack/smart-bot/utils/check_vacations.rb +43 -0
  88. data/lib/slack/smart-bot/utils/create_routine_thread.rb +1 -1
  89. data/lib/slack/smart-bot/utils/get_access_channels.rb +13 -0
  90. data/lib/slack/smart-bot/utils/get_admins_channels.rb +33 -0
  91. data/lib/slack/smart-bot/utils/get_bots_created.rb +27 -10
  92. data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +7 -2
  93. data/lib/slack/smart-bot/utils/get_command_ids.rb +84 -0
  94. data/lib/slack/smart-bot/utils/get_help.rb +36 -19
  95. data/lib/slack/smart-bot/utils/get_repls.rb +22 -2
  96. data/lib/slack/smart-bot/utils/get_routines.rb +22 -2
  97. data/lib/slack/smart-bot/utils/get_teams.rb +22 -0
  98. data/lib/slack/smart-bot/utils/get_vacations.rb +22 -0
  99. data/lib/slack/smart-bot/utils/has_access.rb +25 -9
  100. data/lib/slack/smart-bot/utils/is_admin.rb +27 -0
  101. data/lib/slack/smart-bot/utils/save_stats.rb +52 -42
  102. data/lib/slack/smart-bot/utils/save_status.rb +22 -7
  103. data/lib/slack/smart-bot/utils/update_access_channels.rb +8 -0
  104. data/lib/slack/smart-bot/utils/update_admins_channels.rb +25 -0
  105. data/lib/slack/smart-bot/utils/update_bots_file.rb +28 -7
  106. data/lib/slack/smart-bot/utils/update_repls.rb +7 -4
  107. data/lib/slack/smart-bot/utils/update_routines.rb +9 -3
  108. data/lib/slack/smart-bot/utils/update_shortcuts_file.rb +13 -6
  109. data/lib/slack/smart-bot/utils/update_teams.rb +16 -0
  110. data/lib/slack/smart-bot/utils/update_vacations.rb +16 -0
  111. data/lib/slack/smart-bot/utils.rb +11 -0
  112. data/lib/slack-smart-bot.rb +50 -12
  113. data/lib/slack-smart-bot_general_commands.rb +16 -1
  114. data/whats_new.txt +12 -30
  115. metadata +78 -21
  116. data/lib/slack/smart-bot/commands/general/bot_stats.rb +0 -314
@@ -0,0 +1,416 @@
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
+ if rows[0].key?(:time_zone) #then save_stats is saving the time zone already
299
+ rows.time_zone.each do |time_zone|
300
+ unless time_zone == ''
301
+ tzone_users[time_zone] ||= 0
302
+ tzone_users[time_zone] += 1
303
+ end
304
+ end
305
+ else
306
+ rows.user_id.each_with_index do |usr, i|
307
+ if rows[i].values.size >= 12 #then save_stats is saving the time zone already but not all the data
308
+ unless rows[i].values[11] == ''
309
+ tzone_users[rows[i].values[11]] ||= 0
310
+ tzone_users[rows[i].values[11]] += 1
311
+ end
312
+ else
313
+ user_info = @users.select { |u| u.id == usr or (u.key?(:enterprise_user) and u.enterprise_user.id == usr) }[-1]
314
+ unless user_info.nil? or user_info.is_app_user or user_info.is_bot
315
+ tzone_users[user_info.tz_label] ||= 0
316
+ tzone_users[user_info.tz_label] += 1
317
+ end
318
+ end
319
+ end
320
+ end
321
+ if users.size > 10
322
+ message << "*Users* - #{users.size} (Top 10)"
323
+ else
324
+ message << "*Users* - #{users.size}"
325
+ end
326
+ count_user = {}
327
+ users.each do |user|
328
+ count = rows.count {|h| h.user_id==user}
329
+ count_user[user] = count
330
+ end
331
+ i = 0
332
+ total_without_routines = total
333
+ count_user.sort_by {|k,v| -v}.each do |user, count|
334
+ i+=1
335
+ if user.include?('routine/')
336
+ user_link = users_id_name[user]
337
+ total_without_routines -= count
338
+ else
339
+ user_link = "<@#{user}>"
340
+ end
341
+ if i <= 10
342
+ message << "\t#{user_link}: #{count} (#{(count.to_f*100/total).round(2)}%)"
343
+ end
344
+ if users.size > 10 and all_data
345
+ users_attachment << "\t#{users_id_name[user]}: #{count} (#{(count.to_f*100/total).round(2)}%)"
346
+ end
347
+ end
348
+
349
+ if tzone_users.size > 0
350
+ message << "*Time Zones*"
351
+ total_known = 0
352
+ tzone_users.each do |tzone, num|
353
+ message << "\t#{tzone}: #{num} (#{(num.to_f*100/total_without_routines).round(2)}%)"
354
+ total_known+=num
355
+ end
356
+ total_unknown = total_without_routines - total_known
357
+ message << "\tUnknown: #{total_unknown} (#{(total_unknown.to_f*100/total_without_routines).round(2)}%)" if total_unknown > 0
358
+ end
359
+
360
+ end
361
+ commands_attachment = []
362
+
363
+ if st_command == ''
364
+ commands = rows.command.uniq.sort
365
+ count_command = {}
366
+ commands.each do |command|
367
+ count = rows.count {|h| h.command==command}
368
+ count_command[command] = count
369
+ end
370
+
371
+ if commands.size > 10
372
+ message << "*Commands* - #{commands.size} (Top 10)"
373
+ else
374
+ message << "*Commands* - #{commands.size}"
375
+ end
376
+
377
+ i = 0
378
+ count_command.sort_by {|k,v| -v}.each do |command, count|
379
+ i+=1
380
+ if i <= 10
381
+ message << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
382
+ end
383
+ if commands.size > 10 and all_data
384
+ commands_attachment << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
385
+ end
386
+ end
387
+ end
388
+
389
+ message << "*Message type*"
390
+ types = rows.type_message.uniq.sort
391
+ types.each do |type|
392
+ count = rows.count {|h| h.type_message==type}
393
+ message << "\t#{type}: #{count} (#{(count.to_f*100/total).round(2)}%)"
394
+ end
395
+
396
+ if on_dm_master
397
+ message << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].type_message} #{rows[-1].user_name} #{rows[-1].command}"
398
+ end
399
+ if users_attachment.size>0
400
+ send_file(dest, "", 'users.txt', "", 'text/plain', "text", content: users_attachment.join("\n"))
401
+ end
402
+ if commands_attachment.size>0
403
+ send_file(dest, "", 'commands.txt', "", 'text/plain', "text", content: commands_attachment.join("\n"))
404
+ end
405
+ if channels_dest_attachment.size>0
406
+ send_file(dest, "", 'channels_dest.txt', "", 'text/plain', "text", content: channels_dest_attachment.join("\n"))
407
+ end
408
+ end
409
+ end
410
+ else
411
+ message<<"Only Master admin users on a private conversation with the bot can see this kind of bot stats."
412
+ end
413
+ end
414
+ respond "#{message.join("\n")}", dest
415
+ end
416
+ end
@@ -4,6 +4,7 @@ class SlackSmartBot
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
6
  # helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
7
+ # helpadmin: command_id: :bot_status
7
8
  # helpadmin:
8
9
  def bot_status(dest, user)
9
10
  save_stats(__method__)
@@ -17,6 +17,7 @@ class SlackSmartBot
17
17
  # help: _leaderboard from 2021/05/01 to 2021/05/31_
18
18
  # help: _ranking today_
19
19
  # help: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
20
+ # help: command_id: :leaderboard
20
21
  # help:
21
22
 
22
23
  def leaderboard(from, to, period)
@@ -4,6 +4,7 @@ class SlackSmartBot
4
4
  # help: `stop using CHANNEL`
5
5
  # help: it will stop using the rules from the specified channel.
6
6
  # help: <https://github.com/MarioRuiz/slack-smart-bot#using-rules-from-other-channels|more info>
7
+ # help: command_id: :stop_using_rules
7
8
  # help:
8
9
  def stop_using_rules(dest, channel, user, dchannel)
9
10
  save_stats(__method__)
@@ -10,12 +10,17 @@ class SlackSmartBot
10
10
  # help: it will display the help content for a random command.
11
11
  # help: if used 'rule' then it will display a random rule.
12
12
  # help: if used 'command' it will show any kind of command or rule.
13
+ # help: command_id: :suggest_command
13
14
  # help:
14
15
  def suggest_command(from, dest, dchannel, specific, rules_file)
15
16
  save_stats(__method__)
17
+ dont_suggest = []
16
18
  help_message = get_help(rules_file, dest, from, specific, true, descriptions: false, only_normal_user: true)
17
19
  commands = help_message.gsub(/====+/,'-'*30).split(/^\s*-------*$/).flatten
18
20
  commands.reject!{|c| c.match?(/These are specific commands for this bot on this/i) || c.match?(/\A\s*\z/)}
21
+ dont_suggest.each do |ds|
22
+ commands.reject!{|c| c.match?(/:#{ds}\s*$/i)}
23
+ end
19
24
  @last_suggested_commands ||= []
20
25
  @last_suggested_commands.shift if @last_suggested_commands.size >=5
21
26
  command = ''
@@ -23,6 +28,7 @@ class SlackSmartBot
23
28
  command = commands.sample
24
29
  end until !@last_suggested_commands.include?(command) or commands.size <= 5
25
30
  @last_suggested_commands << command
31
+ command.gsub!(/^\s*command_id:\s+:\w+\s*$/,'')
26
32
  message = "*Command suggestion*:\n#{command}"
27
33
  respond message, dest, unfurl_links: false, unfurl_media: false
28
34
  end
@@ -7,6 +7,7 @@ class SlackSmartBot
7
7
  # help: it will use the rules from the specified channel.
8
8
  # help: you need to be part of that channel to be able to use the rules.
9
9
  # help: <https://github.com/MarioRuiz/slack-smart-bot#using-rules-from-other-channels|more info>
10
+ # help: command_id: :use_rules
10
11
  # help:
11
12
  def use_rules(dest, channel, user, dchannel)
12
13
  save_stats(__method__)
@@ -3,11 +3,12 @@ class SlackSmartBot
3
3
  # help: ----------------------------------------------
4
4
  # help: `What's new`
5
5
  # help: It will display the last user changes on Slack Smart Bot
6
+ # help: command_id: :whats_new
6
7
  # help:
7
8
  def whats_new(user, dest, dchannel, from, display_name)
8
9
  if @status == :on
9
10
  save_stats(__method__)
10
- whats_new_file = (__FILE__).gsub(/lib\/slack\/smart-bot\/commands\/general\/whats_new\.rb$/, "whats_new.txt")
11
+ whats_new_file = (__FILE__).gsub(/lib\/slack\/smart-bot\/commands\/on_bot\/general\/whats_new\.rb$/, "whats_new.txt")
11
12
  whats_new = File.read(whats_new_file)
12
13
  whats_new.split(/^\-\-\-\-\-\-+$/).each do |msg|
13
14
  respond msg
@@ -5,6 +5,7 @@ class SlackSmartBot
5
5
  # help: `get live SESSION_NAME`
6
6
  # help: Will get the Ruby commands sent on that SESSION_NAME.
7
7
  # help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
8
+ # help: command_id: :get_repl
8
9
  # help:
9
10
  def get_repl(dest, user, session_name)
10
11
  #todo: add tests
@@ -15,7 +16,7 @@ class SlackSmartBot
15
16
  if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run")
16
17
  if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) and
17
18
  @repls[session_name][:creator_name]!=user.name and
18
- !config.admins.include?(user.name)
19
+ !is_admin?(user.name)
19
20
  respond "The REPL with session name: #{session_name} is private", dest
20
21
  else
21
22
  content = "require 'nice_http'\n"
@@ -0,0 +1,32 @@
1
+ class SlackSmartBot
2
+ # help: ----------------------------------------------
3
+ # help: `kill repl RUN_REPL_ID`
4
+ # help: Will kill a running repl previously executed with 'run repl' command.
5
+ # help: Only the user that run the repl or a master admin can kill the repl.
6
+ # help: Example:
7
+ # help: _kill repl X33JK_
8
+ # help: <https://github.com/MarioRuiz/slack-smart-bot#repl|more info>
9
+ # help: command_id: :kill_repl
10
+ # help:
11
+ def kill_repl(dest, user, repl_id)
12
+ #todo: add tests
13
+ if has_access?(__method__, user)
14
+ save_stats(__method__)
15
+ if !@run_repls.key?(repl_id)
16
+ respond "The run repl with id #{repl_id} doesn't exist"
17
+ elsif @run_repls[repl_id].user != user.name and !config.masters.include?(user.name)
18
+ respond "Only #{@run_repls[repl_id].user} or a master admin can kill this repl."
19
+ else
20
+ pids = `pgrep -P #{@run_repls[repl_id].pid}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
21
+ pids.each do |pd|
22
+ begin
23
+ Process.kill("KILL", pd)
24
+ rescue
25
+ end
26
+ end
27
+ respond "The repl #{@run_repls[repl_id].name} (id: #{repl_id}) has been killed."
28
+ @run_repls.delete(repl_id)
29
+ end
30
+ end
31
+ end
32
+ end