slack-smart-bot 1.11.0 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +44 -3
  3. data/lib/slack/smart-bot/comm/respond.rb +8 -2
  4. data/lib/slack/smart-bot/comm/set_status.rb +21 -0
  5. data/lib/slack/smart-bot/comm.rb +1 -0
  6. data/lib/slack/smart-bot/commands/general/add_memo_team.rb +117 -0
  7. data/lib/slack/smart-bot/commands/general/add_vacation.rb +51 -0
  8. data/lib/slack/smart-bot/commands/general/delete_memo_team.rb +69 -0
  9. data/lib/slack/smart-bot/commands/general/delete_team.rb +21 -1
  10. data/lib/slack/smart-bot/commands/general/remove_vacation.rb +27 -0
  11. data/lib/slack/smart-bot/commands/general/see_announcements.rb +1 -1
  12. data/lib/slack/smart-bot/commands/general/see_statuses.rb +1 -1
  13. data/lib/slack/smart-bot/commands/general/see_teams.rb +182 -32
  14. data/lib/slack/smart-bot/commands/general/see_vacations.rb +58 -0
  15. data/lib/slack/smart-bot/commands/general/see_vacations_team.rb +136 -0
  16. data/lib/slack/smart-bot/commands/general/set_memo_status.rb +58 -0
  17. data/lib/slack/smart-bot/commands/general/update_team.rb +22 -1
  18. data/lib/slack/smart-bot/commands/general_bot_commands.rb +172 -4
  19. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +21 -5
  20. data/lib/slack/smart-bot/commands/on_bot/kill_repl.rb +32 -0
  21. data/lib/slack/smart-bot/commands/on_bot/repl.rb +1 -0
  22. data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +113 -33
  23. data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +3 -1
  24. data/lib/slack/smart-bot/commands.rb +8 -0
  25. data/lib/slack/smart-bot/process.rb +17 -7
  26. data/lib/slack/smart-bot/treat_message.rb +11 -1
  27. data/lib/slack/smart-bot/utils/check_vacations.rb +43 -0
  28. data/lib/slack/smart-bot/utils/get_admins_channels.rb +23 -3
  29. data/lib/slack/smart-bot/utils/get_command_ids.rb +1 -1
  30. data/lib/slack/smart-bot/utils/get_help.rb +4 -3
  31. data/lib/slack/smart-bot/utils/get_vacations.rb +22 -0
  32. data/lib/slack/smart-bot/utils/save_stats.rb +9 -2
  33. data/lib/slack/smart-bot/utils/save_status.rb +1 -1
  34. data/lib/slack/smart-bot/utils/update_admins_channels.rb +20 -3
  35. data/lib/slack/smart-bot/utils/update_vacations.rb +16 -0
  36. data/lib/slack/smart-bot/utils.rb +3 -0
  37. data/lib/slack-smart-bot.rb +22 -2
  38. data/whats_new.txt +12 -17
  39. 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('-','').gsub('_','') == team_name.to_s)}).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
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(' ').each do |s|
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 == '' and search.to_s == ''
35
+ if team_name.to_s == "" and search.to_s == ""
36
36
  dest = :on_thread
37
- messages.unshift('Since there are many lines returned the results are returned on a thread by default.')
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('-','').gsub('_','') == team_name.to_s)
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 == ':exclamation:'
164
+ unless status == ":exclamation:"
162
165
  if users_link
163
166
  message[-1] += " #{status}<@#{member}>, "
164
167
  else
165
- user_info = @users.select { |u| u.name == member or (u.key?(:enterprise_user) and u.enterprise_user.name == member) }[-1]
166
- unless user_info.nil?
167
- if user_info.profile.display_name == ''
168
- name = user_info.name
169
- else
170
- name = user_info.profile.display_name
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 !(@teams[team_name.to_sym].members.values + [@teams[team_name.to_sym].creator] + config.masters).flatten.include?(user.name)
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