slack-smart-bot 1.11.0 → 1.12.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 +44 -3
- data/lib/slack/smart-bot/comm/respond.rb +8 -2
- data/lib/slack/smart-bot/comm/set_status.rb +21 -0
- data/lib/slack/smart-bot/comm.rb +1 -0
- data/lib/slack/smart-bot/commands/general/add_memo_team.rb +117 -0
- data/lib/slack/smart-bot/commands/general/add_vacation.rb +51 -0
- data/lib/slack/smart-bot/commands/general/delete_memo_team.rb +69 -0
- data/lib/slack/smart-bot/commands/general/delete_team.rb +21 -1
- data/lib/slack/smart-bot/commands/general/remove_vacation.rb +27 -0
- data/lib/slack/smart-bot/commands/general/see_announcements.rb +1 -1
- data/lib/slack/smart-bot/commands/general/see_statuses.rb +1 -1
- data/lib/slack/smart-bot/commands/general/see_teams.rb +182 -32
- data/lib/slack/smart-bot/commands/general/see_vacations.rb +58 -0
- data/lib/slack/smart-bot/commands/general/see_vacations_team.rb +136 -0
- data/lib/slack/smart-bot/commands/general/set_memo_status.rb +58 -0
- data/lib/slack/smart-bot/commands/general/update_team.rb +22 -1
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +172 -4
- data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +21 -5
- data/lib/slack/smart-bot/commands/on_bot/kill_repl.rb +32 -0
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +113 -33
- data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +3 -1
- data/lib/slack/smart-bot/commands.rb +8 -0
- data/lib/slack/smart-bot/process.rb +17 -7
- data/lib/slack/smart-bot/treat_message.rb +11 -1
- data/lib/slack/smart-bot/utils/check_vacations.rb +43 -0
- data/lib/slack/smart-bot/utils/get_admins_channels.rb +23 -3
- data/lib/slack/smart-bot/utils/get_command_ids.rb +1 -1
- data/lib/slack/smart-bot/utils/get_help.rb +4 -3
- data/lib/slack/smart-bot/utils/get_vacations.rb +22 -0
- data/lib/slack/smart-bot/utils/save_stats.rb +9 -2
- data/lib/slack/smart-bot/utils/save_status.rb +1 -1
- data/lib/slack/smart-bot/utils/update_admins_channels.rb +20 -3
- data/lib/slack/smart-bot/utils/update_vacations.rb +16 -0
- data/lib/slack/smart-bot/utils.rb +3 -0
- data/lib/slack-smart-bot.rb +22 -2
- data/whats_new.txt +12 -17
- metadata +19 -7
@@ -5,12 +5,12 @@ class SlackSmartBot
|
|
5
5
|
get_teams()
|
6
6
|
teams = @teams.deep_copy
|
7
7
|
if teams.empty?
|
8
|
-
respond "There are no teams added yet. Use `add team` command to add a team."
|
9
|
-
elsif team_name.to_s != "" and !teams.key?(team_name.to_sym) and (teams.keys.select {|t| (t.to_s.gsub(
|
8
|
+
respond "There are no teams added yet. Use `add team` command to add a team."
|
9
|
+
elsif team_name.to_s != "" and !teams.key?(team_name.to_sym) and (teams.keys.select { |t| (t.to_s.gsub("-", "").gsub("_", "") == team_name.to_s) }).empty?
|
10
10
|
respond "It seems like the team *#{team_name}* doesn't exist.\nRelated commands `add team TEAM_NAME PROPERTIES`, `see team TEAM_NAME`, `see teams`"
|
11
11
|
else
|
12
12
|
users_link = (Thread.current[:dest][0] == "D")
|
13
|
-
filter = (search !=
|
13
|
+
filter = (search != "")
|
14
14
|
react :runner
|
15
15
|
@users = get_users() if add_stats
|
16
16
|
|
@@ -19,7 +19,7 @@ class SlackSmartBot
|
|
19
19
|
search_channels = []
|
20
20
|
search_info = []
|
21
21
|
if filter
|
22
|
-
search.split(
|
22
|
+
search.split(" ").each do |s|
|
23
23
|
if s.match(/<@(\w+)>/i)
|
24
24
|
m = $1
|
25
25
|
user_info = @users.select { |u| u.id.downcase == m.downcase or (u.key?(:enterprise_user) and u.enterprise_user.id.downcase == m.downcase) }[-1]
|
@@ -29,28 +29,28 @@ class SlackSmartBot
|
|
29
29
|
search_channels << @channels_name[c] if @channels_name.key?(c)
|
30
30
|
else
|
31
31
|
search_info << s
|
32
|
-
end
|
32
|
+
end
|
33
33
|
end
|
34
34
|
end
|
35
|
-
if team_name.to_s ==
|
35
|
+
if team_name.to_s == "" and search.to_s == ""
|
36
36
|
dest = :on_thread
|
37
|
-
messages.unshift(
|
37
|
+
messages.unshift("Since there are many lines returned the results are returned on a thread by default.")
|
38
38
|
else
|
39
39
|
dest = Thread.current[:dest]
|
40
40
|
end
|
41
41
|
|
42
42
|
teams.each do |name, team|
|
43
43
|
filter ? add = false : add = true
|
44
|
-
if team_name.to_s == "" or (team_name.to_s == name.to_s) or (name.to_s.gsub(
|
44
|
+
if team_name.to_s == "" or (team_name.to_s == name.to_s) or (name.to_s.gsub("-", "").gsub("_", "") == team_name.to_s)
|
45
45
|
message = []
|
46
46
|
message << "*#{name.capitalize}*"
|
47
47
|
|
48
48
|
if filter and search_info.size > 0
|
49
49
|
all_info = true
|
50
50
|
search_info.each do |s|
|
51
|
-
if (team.members.keys.find { |e| /#{s}/i =~ e})
|
52
|
-
add = true
|
53
|
-
break
|
51
|
+
if (team.members.keys.find { |e| /#{s}/i =~ e })
|
52
|
+
add = true
|
53
|
+
break
|
54
54
|
end
|
55
55
|
if !name.match?(/#{s}/i)
|
56
56
|
all_info = false
|
@@ -68,7 +68,8 @@ class SlackSmartBot
|
|
68
68
|
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) or u.name == m or (u.key?(:enterprise_user) and u.enterprise_user.name == m) }[-1]
|
69
69
|
assigned_members.delete(m) if user_info.nil? or user_info.deleted
|
70
70
|
end
|
71
|
-
|
71
|
+
channels_members = []
|
72
|
+
all_team_members = assigned_members.dup
|
72
73
|
if team.channels.key?("members")
|
73
74
|
team_members = []
|
74
75
|
team.channels["members"].each do |ch|
|
@@ -77,6 +78,7 @@ class SlackSmartBot
|
|
77
78
|
if tm.nil?
|
78
79
|
respond ":exclamation: Add the Smart Bot to *##{ch}* channel to be able to get the list of members.", dest
|
79
80
|
else
|
81
|
+
channels_members << @channels_id[ch]
|
80
82
|
tm.each do |m|
|
81
83
|
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
|
82
84
|
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
@@ -88,6 +90,7 @@ class SlackSmartBot
|
|
88
90
|
unassigned_members = team_members - assigned_members
|
89
91
|
unassigned_members.delete(config.nick)
|
90
92
|
not_on_team_channel = assigned_members - team_members
|
93
|
+
all_team_members += team_members
|
91
94
|
else
|
92
95
|
unassigned_members = []
|
93
96
|
not_on_team_channel = []
|
@@ -96,7 +99,7 @@ class SlackSmartBot
|
|
96
99
|
um = unassigned_members.dup
|
97
100
|
um.each do |m|
|
98
101
|
user_info = @users.select { |u| u.name == m or (u.key?(:enterprise_user) and u.enterprise_user.name == m) }[-1]
|
99
|
-
unless user_info.nil? or user_info.profile.title.to_s==
|
102
|
+
unless user_info.nil? or user_info.profile.title.to_s == ""
|
100
103
|
team.members[user_info.profile.title.to_snake_case] ||= []
|
101
104
|
team.members[user_info.profile.title.to_snake_case] << m
|
102
105
|
unassigned_members.delete(m)
|
@@ -117,9 +120,9 @@ class SlackSmartBot
|
|
117
120
|
if filter and search_info.size > 0
|
118
121
|
all_info = true
|
119
122
|
search_info.each do |s|
|
120
|
-
if (team.members.keys.find { |e| /#{s}/i =~ e})
|
121
|
-
add = true
|
122
|
-
break
|
123
|
+
if (team.members.keys.find { |e| /#{s}/i =~ e })
|
124
|
+
add = true
|
125
|
+
break
|
123
126
|
end
|
124
127
|
if !team.info.match?(/#{s}/i)
|
125
128
|
all_info = false
|
@@ -134,7 +137,7 @@ class SlackSmartBot
|
|
134
137
|
team.members.each do |type, members|
|
135
138
|
message << " _`#{type}`_: "
|
136
139
|
members.each do |member|
|
137
|
-
types = [":palm_tree:", ":spiral_calendar_pad:", ":face_with_thermometer:"]
|
140
|
+
types = [":palm_tree:", ":spiral_calendar_pad:", ":face_with_thermometer:", ":baby:"]
|
138
141
|
member_info = @users.select { |u| u.name == member }[-1]
|
139
142
|
if !member_info.nil? and !member_info.deleted
|
140
143
|
member_id = member_info.id
|
@@ -146,7 +149,7 @@ class SlackSmartBot
|
|
146
149
|
active = (get_presence(member_id).presence.to_s == "active")
|
147
150
|
if active
|
148
151
|
user_info = @users.select { |u| u.id == member_id or (u.key?(:enterprise_user) and u.enterprise_user.name == member_id) }[-1]
|
149
|
-
if (user_info.tz_offset-user.tz_offset).abs <= (4*3600)
|
152
|
+
if (user_info.tz_offset - user.tz_offset).abs <= (4 * 3600)
|
150
153
|
status = ":large_green_circle:"
|
151
154
|
else
|
152
155
|
status = ":large_yellow_circle:"
|
@@ -158,19 +161,19 @@ class SlackSmartBot
|
|
158
161
|
else
|
159
162
|
status = ":exclamation:"
|
160
163
|
end
|
161
|
-
unless status ==
|
164
|
+
unless status == ":exclamation:"
|
162
165
|
if users_link
|
163
166
|
message[-1] += " #{status}<@#{member}>, "
|
164
167
|
else
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
message[-1] += " #{status} #{name}, "
|
168
|
+
user_info = @users.select { |u| u.name == member or (u.key?(:enterprise_user) and u.enterprise_user.name == member) }[-1]
|
169
|
+
unless user_info.nil?
|
170
|
+
if user_info.profile.display_name == ""
|
171
|
+
name = user_info.name
|
172
|
+
else
|
173
|
+
name = user_info.profile.display_name
|
173
174
|
end
|
175
|
+
message[-1] += " #{status} #{name}, "
|
176
|
+
end
|
174
177
|
end
|
175
178
|
end
|
176
179
|
end
|
@@ -186,7 +189,7 @@ class SlackSmartBot
|
|
186
189
|
members.each do |m|
|
187
190
|
user_info = @users.select { |u| u.name == m or (u.key?(:enterprise_user) and u.enterprise_user.name == m) }[-1]
|
188
191
|
unless user_info.nil? or user_info.deleted
|
189
|
-
if user_info.profile.display_name ==
|
192
|
+
if user_info.profile.display_name == ""
|
190
193
|
name = user_info.name
|
191
194
|
else
|
192
195
|
name = user_info.profile.display_name
|
@@ -200,20 +203,164 @@ class SlackSmartBot
|
|
200
203
|
end
|
201
204
|
end
|
202
205
|
|
203
|
-
|
204
206
|
if add
|
205
207
|
message << " > *_channels_*"
|
206
208
|
team.channels.each do |type, channels|
|
207
209
|
channel_ids = []
|
208
210
|
channels.each do |ch|
|
209
|
-
channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase}[-1]
|
210
|
-
if @channels_id.key?(ch) and (!channel_info.is_private or (channel_info.is_private and (team.members.values+[team.creator]).flatten.include?(user.name)))
|
211
|
+
channel_info = @channels_list.select { |c| c.name.to_s.downcase == ch.to_s.downcase }[-1]
|
212
|
+
if @channels_id.key?(ch) and (!channel_info.is_private or (channel_info.is_private and (team.members.values + [team.creator]).flatten.include?(user.name)))
|
211
213
|
channel_ids << @channels_id[ch]
|
212
214
|
end
|
213
215
|
end
|
214
216
|
message << " _`#{type}`_: <##{channel_ids.join("> <#")}>" unless channel_ids.empty?
|
215
217
|
end
|
216
218
|
|
219
|
+
unless !team.key?(:memos) or team.memos.empty? or (team_name.to_s == "" and search.to_s == "")
|
220
|
+
all_memos = {}
|
221
|
+
team.memos.each do |memo|
|
222
|
+
if memo.privacy.empty? or
|
223
|
+
(memo.privacy == "private" and (all_team_members.include?(user.name) and (users_link or channels_members.include?(Thread.current[:dest])))) or
|
224
|
+
(memo.privacy == "personal" and memo.user == user.name and users_link)
|
225
|
+
if memo.type == "jira" and config.jira.host != ""
|
226
|
+
http = NiceHttp.new(config.jira.host)
|
227
|
+
http.headers.authorization = NiceHttpUtils.basic_authentication(user: config.jira.user, password: config.jira.password)
|
228
|
+
if memo.message.match?(/^\w+\-\d+$/)
|
229
|
+
resp = http.get("/rest/api/latest/issue/#{memo.message}")
|
230
|
+
issues = [resp.data.json] if resp.code == 200
|
231
|
+
else
|
232
|
+
resp = http.get("/rest/api/latest/search/?jql=#{memo.message}")
|
233
|
+
issues = resp.data.json().issues if resp.code == 200
|
234
|
+
end
|
235
|
+
if resp.code == 200
|
236
|
+
unless issues.empty?
|
237
|
+
issues.each do |issue|
|
238
|
+
jira_memo = { jira: true, github: false, status: "", memo_id: memo.memo_id, topic: memo.topic, privacy: memo.privacy, user: memo.user, date: memo.date, message: "", type: memo.type }
|
239
|
+
jira_memo.message = issue.fields.summary
|
240
|
+
jira_memo.user = issue.fields.reporter.name
|
241
|
+
jira_memo.date = issue.fields.created
|
242
|
+
if memo.topic == :no_topic and !issue.fields.labels.empty?
|
243
|
+
jira_memo.topic = issue.fields.labels.sort.join("_").split(" ").join("_")
|
244
|
+
end
|
245
|
+
case issue.fields.issuetype.name
|
246
|
+
when "Story"; jira_memo.type = ":abc:"
|
247
|
+
when "Bug"; jira_memo.type = ":bug:"
|
248
|
+
when "Task"; jira_memo.type = ":clock1:"
|
249
|
+
when "New Feature", "Improvement"; jira_memo.type = ":sunny:"
|
250
|
+
else jira_memo.type = ":memo:"
|
251
|
+
end
|
252
|
+
case issue.fields.status.statusCategory.name
|
253
|
+
when "Done"; jira_memo.status = ":heavy_check_mark:"
|
254
|
+
when "To Do"; jira_memo.status = ":new:"
|
255
|
+
when "In Progress"; jira_memo.status = ":runner:"
|
256
|
+
else jira_memo.status = ":heavy_minus_sign:"
|
257
|
+
end
|
258
|
+
#todo: check if possible to add link to status instead of jira issue
|
259
|
+
#jira_memo.status = " <#{config.jira.host}/browse/#{issue[:key]}|#{jira_memo.status}> "
|
260
|
+
jira_memo.status += " <#{config.jira.host}/browse/#{issue[:key]}|#{issue[:key]}>"
|
261
|
+
|
262
|
+
all_memos[jira_memo.topic] ||= []
|
263
|
+
all_memos[jira_memo.topic] << jira_memo
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
http.close
|
268
|
+
elsif memo.type == "github" and config.github.host != ""
|
269
|
+
http = NiceHttp.new(config.github.host)
|
270
|
+
http.headers.authorization = "token #{config.github.token}"
|
271
|
+
memo.message+="?" unless memo.message.include?('?')
|
272
|
+
memo.message+="&per_page=50"
|
273
|
+
|
274
|
+
resp = http.get("/repos/#{memo.message}")
|
275
|
+
issues = resp.data.json()
|
276
|
+
issues = [issues] unless issues.is_a?(Array)
|
277
|
+
if resp.code == 200
|
278
|
+
unless issues.empty?
|
279
|
+
issues.each do |issue|
|
280
|
+
github_memo = { jira: false, github: true, status: "", memo_id: memo.memo_id, topic: memo.topic, privacy: memo.privacy, user: memo.user, date: memo.date, message: "", type: memo.type }
|
281
|
+
github_memo.message = issue.title
|
282
|
+
github_memo.user = issue.user.login
|
283
|
+
github_memo.date = issue.created_at
|
284
|
+
if issue.labels.empty?
|
285
|
+
labels = ''
|
286
|
+
else
|
287
|
+
labels = issue.labels.name.sort.join("_").split(" ").join("_")
|
288
|
+
end
|
289
|
+
if memo.topic == :no_topic and !issue.labels.empty?
|
290
|
+
github_memo.topic = labels
|
291
|
+
end
|
292
|
+
case labels
|
293
|
+
when /bug/i; github_memo.type = ":bug:"
|
294
|
+
when /docum/i; github_memo.type = ":abc:"
|
295
|
+
when /task/i; github_memo.type = ":clock1:"
|
296
|
+
when /enhancem/i, /improvement/i; github_memo.type = ":sunny:"
|
297
|
+
else github_memo.type = ":memo:"
|
298
|
+
end
|
299
|
+
if issue.key?(:events_url)
|
300
|
+
resp_events = http.get(issue.events_url)
|
301
|
+
events = resp_events.data.json(:event)
|
302
|
+
issue.state = "in progress" if events.include?('referenced')
|
303
|
+
end
|
304
|
+
case issue.state
|
305
|
+
when "closed"; github_memo.status = ":heavy_check_mark:"
|
306
|
+
when "open"; github_memo.status = ":new:"
|
307
|
+
when "in progress"; github_memo.status = ":runner:"
|
308
|
+
else github_memo.status = ":heavy_minus_sign:"
|
309
|
+
end
|
310
|
+
#todo: check if possible to add link to status instead of github issue
|
311
|
+
github_memo.status += " <#{issue.html_url}|##{issue.number}>"
|
312
|
+
|
313
|
+
all_memos[github_memo.topic] ||= []
|
314
|
+
all_memos[github_memo.topic] << github_memo
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
http.close
|
319
|
+
else
|
320
|
+
memo.jira = false
|
321
|
+
memo.github = false
|
322
|
+
all_memos[memo.topic] ||= []
|
323
|
+
case memo.type
|
324
|
+
when "memo"; memo.type = ":memo:"
|
325
|
+
when "note"; memo.type = ":abc:"
|
326
|
+
when "bug"; memo.type = ":bug:"
|
327
|
+
when "task"; memo.type = ":clock1:"
|
328
|
+
when "feature"; memo.type = ":sunny:"
|
329
|
+
when "issue"; memo.type = ":hammer:"
|
330
|
+
else memo.type = ":heavy_minus_sign:"
|
331
|
+
end
|
332
|
+
all_memos[memo.topic] << memo
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
message << " > *_memos_*" unless all_memos.empty?
|
337
|
+
|
338
|
+
if all_memos.key?(:no_topic)
|
339
|
+
all_memos[:no_topic].sort_by { |memo| memo[:date] }.each do |memo|
|
340
|
+
case memo.privacy
|
341
|
+
when "private"; priv = " `private`"
|
342
|
+
when "personal"; priv = " `personal`"
|
343
|
+
else priv = ""
|
344
|
+
end
|
345
|
+
message << " #{memo.type} #{memo.date.gsub("-", "/")[0..9]}: #{memo.status} #{memo.message} (#{memo.user} #{memo.memo_id})#{priv}"
|
346
|
+
end
|
347
|
+
end
|
348
|
+
all_memos[:no_topic] = []
|
349
|
+
all_memos.each do |topic, mems|
|
350
|
+
unless mems.empty?
|
351
|
+
message << " _`#{topic}`_:"
|
352
|
+
mems.sort_by { |m| m[:date] }.each do |memo|
|
353
|
+
case memo.privacy
|
354
|
+
when "private"; priv = " `private`"
|
355
|
+
when "personal"; priv = " `personal`"
|
356
|
+
else priv = ""
|
357
|
+
end
|
358
|
+
message << " #{memo.type} #{memo.date.gsub("-", "/")[0..9]}: #{memo.status} #{memo.message} (#{memo.user} #{memo.memo_id})#{priv}"
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
217
364
|
unless team.info.empty?
|
218
365
|
team.info.split("\n").each do |m|
|
219
366
|
message << ">#{m}"
|
@@ -236,7 +383,7 @@ class SlackSmartBot
|
|
236
383
|
if team_name.to_s != ""
|
237
384
|
message = "\n\n:palm_tree: On vacation / "
|
238
385
|
message += ":spiral_calendar_pad: In a meeting / "
|
239
|
-
message += ":face_with_thermometer: Sick leave / "
|
386
|
+
message += ":face_with_thermometer: :baby: Sick leave / "
|
240
387
|
message += ":white_circle: Away / "
|
241
388
|
message += ":large_yellow_circle: Available in remote timezone / "
|
242
389
|
message += ":large_green_circle: Available"
|
@@ -246,6 +393,9 @@ class SlackSmartBot
|
|
246
393
|
messages.each do |msg|
|
247
394
|
respond msg, dest, unfurl_links: false, unfurl_media: false
|
248
395
|
end
|
396
|
+
unless team_name.to_s.empty?
|
397
|
+
see_vacations_team(user, team_name, Date.today.strftime("%Y/%m/%d"), add_stats: false)
|
398
|
+
end
|
249
399
|
end
|
250
400
|
end
|
251
401
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def see_vacations(user, from_user: '', add_stats: true)
|
3
|
+
save_stats(__method__) if add_stats
|
4
|
+
|
5
|
+
get_vacations()
|
6
|
+
|
7
|
+
from_user_name = ''
|
8
|
+
|
9
|
+
if from_user.empty?
|
10
|
+
from_user_name = user.name
|
11
|
+
else
|
12
|
+
@users = get_users() if @users.empty?
|
13
|
+
user_info = @users.select{|u| u.id == from_user or (u.key?(:enterprise_user) and u.enterprise_user.id == from_user)}[-1]
|
14
|
+
from_user_name = user_info.name
|
15
|
+
end
|
16
|
+
|
17
|
+
if !@vacations.key?(from_user_name) or @vacations[from_user_name].periods.empty?
|
18
|
+
if from_user.empty?
|
19
|
+
respond "You didn't add any time off yet. Use `add vacation from YYYY/MM/DD to YYYY/MM/DD`"
|
20
|
+
else
|
21
|
+
respond "No time off added yet for <@#{from_user}>"
|
22
|
+
end
|
23
|
+
else
|
24
|
+
messages = []
|
25
|
+
messages << "*Time off <@#{from_user}>*" if !from_user.empty?
|
26
|
+
today = Date.today.strftime("%Y/%m/%d")
|
27
|
+
current_added = false
|
28
|
+
past_added = false
|
29
|
+
@vacations[from_user_name].periods.sort_by { |v| v[:from]}.reverse.each do |vac|
|
30
|
+
if !current_added and vac.to >= today
|
31
|
+
messages << "*Current and future periods*"
|
32
|
+
current_added = true
|
33
|
+
end
|
34
|
+
if !past_added and vac.to < today and from_user.empty?
|
35
|
+
messages << "\n*Past periods*"
|
36
|
+
past_added = true
|
37
|
+
end
|
38
|
+
unless !from_user.empty? and vac.to < today
|
39
|
+
if !from_user.empty?
|
40
|
+
icon = ":beach_with_umbrella:"
|
41
|
+
elsif vac.type == 'vacation'
|
42
|
+
icon = ':palm_tree:'
|
43
|
+
elsif vac.type == 'sick'
|
44
|
+
icon = ':face_with_thermometer:'
|
45
|
+
elsif vac.type == 'sick child'
|
46
|
+
icon = ':baby:'
|
47
|
+
end
|
48
|
+
if vac.from == vac.to
|
49
|
+
messages << " #{icon} #{vac.from} ##{vac.vacation_id}"
|
50
|
+
else
|
51
|
+
messages << " #{icon} #{vac.from} -> #{vac.to} ##{vac.vacation_id}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
respond messages.join("\n")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def see_vacations_team(user, team_name, date, add_stats: true)
|
3
|
+
save_stats(__method__) if add_stats
|
4
|
+
|
5
|
+
get_teams()
|
6
|
+
teams = @teams.deep_copy
|
7
|
+
if teams.empty?
|
8
|
+
respond "There are no teams added yet. Use `add team` command to add a team."
|
9
|
+
elsif team_name.to_s != "" and !teams.key?(team_name.to_sym) and (teams.keys.select { |t| (t.to_s.gsub("-", "").gsub("_", "") == team_name.to_s) }).empty?
|
10
|
+
respond "It seems like the team *#{team_name}* doesn't exist.\nRelated commands `add team TEAM_NAME PROPERTIES`, `see team TEAM_NAME`, `see teams`"
|
11
|
+
else
|
12
|
+
teams.each do |name, team|
|
13
|
+
if team_name==name.to_s or (name.to_s.gsub("-", "").gsub("_", "") == team_name.to_s)
|
14
|
+
team_name = name.to_s
|
15
|
+
break
|
16
|
+
end
|
17
|
+
end
|
18
|
+
date.gsub!('-','/')
|
19
|
+
get_vacations()
|
20
|
+
team = teams[team_name.to_sym]
|
21
|
+
assigned_members = team.members.values.flatten
|
22
|
+
assigned_members.uniq!
|
23
|
+
assigned_members.dup.each do |m|
|
24
|
+
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) or u.name == m or (u.key?(:enterprise_user) and u.enterprise_user.name == m) }[-1]
|
25
|
+
assigned_members.delete(m) if user_info.nil? or user_info.deleted
|
26
|
+
end
|
27
|
+
|
28
|
+
channels_members = []
|
29
|
+
all_team_members = assigned_members.dup
|
30
|
+
if team.channels.key?("members")
|
31
|
+
team_members = []
|
32
|
+
team.channels["members"].each do |ch|
|
33
|
+
get_channels_name_and_id() unless @channels_id.key?(ch)
|
34
|
+
tm = get_channel_members(@channels_id[ch])
|
35
|
+
if tm.nil?
|
36
|
+
respond ":exclamation: Add the Smart Bot to *##{ch}* channel to be able to get the list of members.", dest
|
37
|
+
else
|
38
|
+
channels_members << @channels_id[ch]
|
39
|
+
tm.each do |m|
|
40
|
+
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
|
41
|
+
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
team_members.flatten!
|
46
|
+
all_team_members += team_members
|
47
|
+
all_team_members.uniq!
|
48
|
+
end
|
49
|
+
unless all_team_members.empty?
|
50
|
+
blocks_header =
|
51
|
+
{
|
52
|
+
"type": "context",
|
53
|
+
elements: [
|
54
|
+
{
|
55
|
+
type: "mrkdwn",
|
56
|
+
text: "*Time Off #{team_name} team* from #{date} ",
|
57
|
+
},
|
58
|
+
],
|
59
|
+
}
|
60
|
+
|
61
|
+
from = Date.parse(date, "%Y/%m/%d")
|
62
|
+
blocks = []
|
63
|
+
all_team_members.each do |m|
|
64
|
+
@users = get_users() if @users.empty?
|
65
|
+
info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) or u.name == m or (u.key?(:enterprise_user) and u.enterprise_user.name == m) }[-1]
|
66
|
+
unless info.nil?
|
67
|
+
info = get_user_info(info.id)
|
68
|
+
if @vacations.key?(m)
|
69
|
+
v = ""
|
70
|
+
(from..(from+20)).each do |d|
|
71
|
+
v+="#{d.strftime("%d")} " if d.wday==1 or d==from
|
72
|
+
on_vacation = false
|
73
|
+
@vacations[m].periods.each do |p|
|
74
|
+
if p.from <= d.strftime("%Y/%m/%d") and p.to >= d.strftime("%Y/%m/%d")
|
75
|
+
if d.wday == 0 or d.wday == 6
|
76
|
+
v+=":large_orange_square: "
|
77
|
+
else
|
78
|
+
v+=":large_red_square: "
|
79
|
+
end
|
80
|
+
on_vacation=true
|
81
|
+
break
|
82
|
+
end
|
83
|
+
end
|
84
|
+
unless on_vacation
|
85
|
+
if d.wday == 0 or d.wday == 6
|
86
|
+
v += ":large_yellow_square: "
|
87
|
+
else
|
88
|
+
v+= ":white_square: "
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
v = ""
|
94
|
+
(from..(from+20)).each do |d|
|
95
|
+
if d.wday==1 or d==from
|
96
|
+
v += "#{d.strftime("%d")} "
|
97
|
+
end
|
98
|
+
if d.wday == 0 or d.wday == 6
|
99
|
+
v += ":large_yellow_square: "
|
100
|
+
else
|
101
|
+
v += ":white_square: "
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
blocks << {
|
107
|
+
type: "context",
|
108
|
+
elements: [
|
109
|
+
{
|
110
|
+
type: "image",
|
111
|
+
image_url: info.user.profile.image_24,
|
112
|
+
alt_text: info.user.name,
|
113
|
+
},
|
114
|
+
{
|
115
|
+
type: "plain_text",
|
116
|
+
text: v
|
117
|
+
}
|
118
|
+
],
|
119
|
+
}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
first = true
|
123
|
+
blocks.each_slice(10).each do |b|
|
124
|
+
if first
|
125
|
+
b.unshift(blocks_header)
|
126
|
+
first = false
|
127
|
+
end
|
128
|
+
respond blocks: b
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def set_memo_status(user, team_name, memo_id, status)
|
3
|
+
save_stats(__method__) if answer.empty?
|
4
|
+
|
5
|
+
get_teams()
|
6
|
+
if @teams.key?(team_name.to_sym)
|
7
|
+
assigned_members = @teams[team_name.to_sym].members.values.flatten
|
8
|
+
assigned_members.uniq!
|
9
|
+
all_team_members = assigned_members.dup
|
10
|
+
team_members = []
|
11
|
+
if @teams[team_name.to_sym].channels.key?("members")
|
12
|
+
@teams[team_name.to_sym].channels["members"].each do |ch|
|
13
|
+
get_channels_name_and_id() unless @channels_id.key?(ch)
|
14
|
+
tm = get_channel_members(@channels_id[ch])
|
15
|
+
tm.each do |m|
|
16
|
+
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
|
17
|
+
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
team_members.flatten!
|
22
|
+
team_members.uniq!
|
23
|
+
all_team_members += team_members
|
24
|
+
all_team_members.uniq!
|
25
|
+
end
|
26
|
+
|
27
|
+
if !@teams.key?(team_name.to_sym)
|
28
|
+
respond "It seems like the team *#{team_name}* doesn't exist.\nRelated commands `add team TEAM_NAME PROPERTIES`, `see team TEAM_NAME`, `see teams`"
|
29
|
+
elsif !(all_team_members + config.masters).flatten.include?(user.name)
|
30
|
+
respond "You have to be a member of the team or a Master admin to be able to set the status of a memo."
|
31
|
+
elsif !@teams[team_name.to_sym].key?(:memos) or @teams[team_name.to_sym][:memos].empty? or !@teams[team_name.to_sym][:memos].memo_id.include?(memo_id.to_i)
|
32
|
+
respond "It seems like there is no memo with id #{memo_id}"
|
33
|
+
elsif @teams[team_name.to_sym][:memos].memo_id.include?(memo_id.to_i)
|
34
|
+
memo_selected = @teams[team_name.to_sym][:memos].select { |m| m.memo_id == memo_id.to_i }[-1]
|
35
|
+
if memo_selected.type == 'jira' or memo_selected.type == 'github'
|
36
|
+
#todo: add tests for jira and github
|
37
|
+
respond "The memo specified is a #{memo_selected.type} and the status in those cases are linked to the specific issues in #{memo_selected.type}."
|
38
|
+
elsif memo_selected.privacy == "personal" and memo_selected.user != user.name
|
39
|
+
respond "Only the creator can set the status of a personal memo."
|
40
|
+
else
|
41
|
+
answer_delete
|
42
|
+
memos = []
|
43
|
+
message = ""
|
44
|
+
get_teams()
|
45
|
+
@teams[team_name.to_sym][:memos].each do |memo|
|
46
|
+
if memo.memo_id == memo_id.to_i
|
47
|
+
memo.status = status
|
48
|
+
message = memo.message
|
49
|
+
end
|
50
|
+
memos << memo
|
51
|
+
end
|
52
|
+
@teams[team_name.to_sym][:memos] = memos
|
53
|
+
update_teams()
|
54
|
+
respond "The memo status has been updated on team #{team_name}: #{message}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -2,9 +2,29 @@ class SlackSmartBot
|
|
2
2
|
def update_team(user, team_name, new_name: "", new_info: "", delete_opts: "", add_opts: "")
|
3
3
|
save_stats(__method__)
|
4
4
|
get_teams()
|
5
|
+
if @teams.key?(team_name.to_sym)
|
6
|
+
assigned_members = @teams[team_name.to_sym].members.values.flatten
|
7
|
+
assigned_members.uniq!
|
8
|
+
all_team_members = assigned_members.dup
|
9
|
+
team_members = []
|
10
|
+
if @teams[team_name.to_sym].channels.key?("members")
|
11
|
+
@teams[team_name.to_sym].channels["members"].each do |ch|
|
12
|
+
get_channels_name_and_id() unless @channels_id.key?(ch)
|
13
|
+
tm = get_channel_members(@channels_id[ch])
|
14
|
+
tm.each do |m|
|
15
|
+
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
|
16
|
+
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
team_members.flatten!
|
21
|
+
team_members.uniq!
|
22
|
+
all_team_members += team_members
|
23
|
+
all_team_members.uniq!
|
24
|
+
end
|
5
25
|
if !@teams.key?(team_name.to_sym)
|
6
26
|
respond "It seems like the team *#{team_name}* doesn't exist.\nRelated commands `add team TEAM_NAME PROPERTIES`, `see team TEAM_NAME`, `see teams`"
|
7
|
-
elsif !(
|
27
|
+
elsif !(all_team_members + [@teams[team_name.to_sym].creator] + config.masters).flatten.include?(user.name)
|
8
28
|
respond "You have to be a member of the team, the creator or a Master admin to be able to update this team."
|
9
29
|
else
|
10
30
|
wrong = false
|
@@ -69,6 +89,7 @@ class SlackSmartBot
|
|
69
89
|
last_type = opt
|
70
90
|
elsif opt.match(/<@(\w+)>/i)
|
71
91
|
member_id = $1
|
92
|
+
last_type = 'no_type' if last_type.nil?
|
72
93
|
member_info = @users.select { |u| u.id == member_id or (u.key?(:enterprise_user) and u.enterprise_user.id == member_id) }[-1]
|
73
94
|
@teams[team_name.to_sym].members[last_type] ||= []
|
74
95
|
@teams[team_name.to_sym].members[last_type] << member_info.name
|