71 lines
1.8 KiB
Ruby
71 lines
1.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module DiscourseCalendar
|
|
class UsersOnHoliday
|
|
def self.from(calendar_events)
|
|
calendar_events
|
|
.filter { |e| e.user_id.present? && e.username.present? }
|
|
.filter { |e| e.underway? || e.in_future? }
|
|
.group_by(&:user_id)
|
|
.map { |_, events| current_holiday(events) }
|
|
.compact
|
|
.to_h
|
|
end
|
|
|
|
private
|
|
|
|
def self.current_holiday(user_events)
|
|
ends_at = holiday_ends_at(user_events)
|
|
return nil unless ends_at
|
|
|
|
[user_events[0].user_id, { username: user_events[0].username, ends_at: ends_at }]
|
|
end
|
|
|
|
# If a user has several holidays one after another
|
|
# we want to show the farthest end date.
|
|
#
|
|
# Let's say today is Monday and I am sick,
|
|
# and I also have days off from Tuesday to Friday:
|
|
#
|
|
# sick ▭
|
|
# days off ▭▭▭▭
|
|
#
|
|
# We want to show Friday as an end date of my holiday.
|
|
#
|
|
# This algorithm also works in case the holidays intersect,
|
|
# like this:
|
|
#
|
|
# event_1 ▭▭▭▭
|
|
# event_2 ▭▭▭▭
|
|
# event_3 ▭▭▭▭
|
|
#
|
|
# or like this:
|
|
#
|
|
# event_1 ▭▭▭▭
|
|
# event_2 ▭▭▭▭▭▭▭▭
|
|
# event_3 ▭▭▭▭▭▭▭▭▭▭
|
|
#
|
|
# or like this:
|
|
#
|
|
# event_1 ▭▭▭▭▭▭▭▭▭▭
|
|
# event_2 ▭
|
|
#
|
|
def self.holiday_ends_at(events)
|
|
sorted_events = events.sort_by(&:start_date)
|
|
return nil if sorted_events.first.in_future?
|
|
return sorted_events.first.ends_at if events.count == 1
|
|
|
|
result = sorted_events.first.ends_at
|
|
sorted_events.each_cons(2) do |pair|
|
|
if pair[0].ends_at < pair[1].start_date
|
|
return result
|
|
elsif pair[1].ends_at > result
|
|
result = pair[1].ends_at
|
|
end
|
|
end
|
|
|
|
result
|
|
end
|
|
end
|
|
end
|