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.
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