diff --git a/app/models/calendar.rb b/app/models/calendar.rb index 49ac3ab9a28..241e7f0093f 100644 --- a/app/models/calendar.rb +++ b/app/models/calendar.rb @@ -2,24 +2,32 @@ class Calendar def combine_special_regular_calendar(user) - special_calendar = special_calendar_str(user) - regular_calendar = regular_calendar_str(user) + calendar_to_ical_str = generate_calendar_str(user) + regular_calendar_to_ical_str = generate_regular_calendar_str(user) - calendar_str = "#{special_calendar}#{regular_calendar}" - Icalendar::Calendar.parse(calendar_str).first + calendar_to_ical_str = "#{calendar_to_ical_str}#{regular_calendar_to_ical_str}" + Icalendar::Calendar.parse(calendar_to_ical_str).first end private - def special_calendar_str(user) - special_calendar = SpecialEventsCalendar.new - special_calendar_to_ical = special_calendar.convert_to_ical(user).to_ical - special_calendar_to_ical.gsub(/END:VCALENDAR\r?\n?\z/, '') + def generate_calendar_str(user) + events_list = EventList.new + personal_events_list = events_list.fetch_events_list(user) + events_icalendar_str = IcalendarStr.new + calendar_str = events_icalendar_str.convert_events_to_ical(personal_events_list) + + calendar_to_ical = calendar_str.to_ical + calendar_to_ical.gsub(/END:VCALENDAR\r?\n?\z/, '') end - def regular_calendar_str(user) - regular_calendar = RegularEventsCalendar.new - regular_calendar_to_ical = regular_calendar.convert_to_ical(user).to_ical + def generate_regular_calendar_str(user) + regular_events_list = EventList.new + personal_regular_events_list = regular_events_list.fetch_regular_events_list(user) + regular_events_icalendar_str = IcalendarStr.new + regular_calendar_str = regular_events_icalendar_str.convert_regular_events_to_ical(personal_regular_events_list) + + regular_calendar_to_ical = regular_calendar_str.to_ical regular_calendar_to_ical.gsub(/\A(?:BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:icalendar-ruby\r\nCALSCALE:GREGORIAN\r\n)/, '') end end diff --git a/app/models/event_list.rb b/app/models/event_list.rb new file mode 100644 index 00000000000..544b36b55ee --- /dev/null +++ b/app/models/event_list.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class EventList + def fetch_events_list(user) + participated_list = user.participations.pluck(:event_id) + upcoming_event_list = Event.where('start_at > ?', Date.current).pluck(:id) + + joined_events = Event.where(id: participated_list & upcoming_event_list) + upcoming_events = Event.where(id: upcoming_event_list).where.not(id: participated_list) + { + joined_events:, + upcoming_events: + } + end + + def fetch_regular_events_list(user) + participated_list = user.regular_event_participations.pluck(:regular_event_id) + regular_events_list = [] + RegularEvent.where(id: participated_list).where(finished: false).find_each do |event| + event.regular_event_repeat_rules.each do |repeat_rule| + current_date = Time.zone.today + + list_regular_event_for_year(event, repeat_rule, current_date, regular_events_list) + end + end + regular_events_list + end + + private + + def list_regular_event_for_year(event, repeat_rule, current_date, regular_events_list) + while current_date <= Time.zone.today + 1.year + if repeat_rule.frequency.zero? + day_of_the_week_symbol = DateAndTime::Calculations::DAYS_INTO_WEEK.key(repeat_rule.day_of_the_week) + event_date = current_date.next_occurring(day_of_the_week_symbol).to_date + event_date = event_date.next_occurring(day_of_the_week_symbol) while !event.hold_national_holiday && HolidayJp.holiday?(event_date) + current_date = event_date + 1 + else + event_date = event.possible_next_event_date(current_date, repeat_rule) + current_date = current_date.next_month.beginning_of_month + end + regular_events_list << { event_id: event.id, event_date: } + end + end +end diff --git a/app/models/icalendar_str.rb b/app/models/icalendar_str.rb new file mode 100644 index 00000000000..1c1b4fd537b --- /dev/null +++ b/app/models/icalendar_str.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +class IcalendarStr + def convert_events_to_ical(events_list) + event_cal = Icalendar::Calendar.new + + events_list[:joined_events].each do |event| + add_event_to_calendar(event_cal, event, true) + end + + events_list[:upcoming_events].each do |event| + add_event_to_calendar(event_cal, event, false) + end + event_cal + end + + def convert_regular_events_to_ical(regular_events_list) + regular_event_cal = Icalendar::Calendar.new + + add_regular_event_to_calendar(regular_event_cal, regular_events_list) + regular_event_cal + end + + private + + def add_event_to_calendar(event_cal, event, joined) + tzid = 'Asia/Tokyo' + event_cal.event do |e| + e.dtstart = Icalendar::Values::DateTime.new event.start_at, { 'tzid' => tzid } + e.dtend = Icalendar::Values::DateTime.new event.end_at, { 'tzid' => tzid } + e.summary = joined ? "【参加登録済】#{event.title}" : event.title + e.description = event.description + e.location = event.location + e.uid = "event#{event.id}" + e.sequence = Time.now.to_i + end + end + + def add_regular_event_to_calendar(regular_event_cal, regular_events_list) + regular_events_list.each do |regular_event| + tzid = 'Asia/Tokyo' + event_date = Date.parse(regular_event[:event_date].to_s) + event = RegularEvent.find(regular_event[:event_id]) + + regular_event_cal.event do |e| + e.dtstart = Icalendar::Values::DateTime.new( + DateTime.parse("#{event_date} #{event.start_at.strftime('%H:%M')}"), 'tzid' => tzid + ) + e.dtend = Icalendar::Values::DateTime.new( + DateTime.parse("#{event_date} #{event.end_at.strftime('%H:%M')}"), 'tzid' => tzid + ) + e.summary = event.title + e.description = event.description + e.uid = "event#{event.id}#{event_date}" + e.sequence = Time.now.to_i + end + end + end +end diff --git a/app/models/regular_events_calendar.rb b/app/models/regular_events_calendar.rb deleted file mode 100644 index d24af8b8678..00000000000 --- a/app/models/regular_events_calendar.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -class RegularEventsCalendar - def convert_to_ical(user) - holding_events = fetch_events(user) - cal = Icalendar::Calendar.new - - holding_events.each do |holding_event| - tzid = 'Asia/Tokyo' - event_date = Date.parse(holding_event[:event_date].to_s) - event = RegularEvent.find(holding_event[:event_id]) - - cal.event do |e| - e.dtstart = Icalendar::Values::DateTime.new( - DateTime.parse("#{event_date} #{event.start_at.strftime('%H:%M')}"), 'tzid' => tzid - ) - e.dtend = Icalendar::Values::DateTime.new( - DateTime.parse("#{event_date} #{event.end_at.strftime('%H:%M')}"), 'tzid' => tzid - ) - e.summary = event.title - e.description = event.description - e.uid = "event#{event.id}#{event_date}" - e.sequence = Time.now.to_i - end - end - cal - end - - private - - def fetch_events(user) - participated_list = user.regular_event_participations.pluck(:regular_event_id) - holding_events = [] - RegularEvent.where(id: participated_list).where(finished: false).find_each do |event| - event.regular_event_repeat_rules.each do |repeat_rule| - current_date = Time.zone.today - - while current_date <= Time.zone.today + 1.year - if repeat_rule.frequency.zero? - day_of_the_week_symbol = DateAndTime::Calculations::DAYS_INTO_WEEK.key(repeat_rule.day_of_the_week) - event_date = current_date.next_occurring(day_of_the_week_symbol).to_date - event_date = event_date.next_occurring(day_of_the_week_symbol) while !event.hold_national_holiday && HolidayJp.holiday?(event_date) - current_date = event_date + 1 - else - event_date = event.possible_next_event_date(current_date, repeat_rule) - current_date = current_date.next_month.beginning_of_month - end - holding_events << { event_id: event.id, event_date: } - end - end - end - holding_events - end -end diff --git a/app/models/special_events_calendar.rb b/app/models/special_events_calendar.rb deleted file mode 100644 index 9d14033c455..00000000000 --- a/app/models/special_events_calendar.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -class SpecialEventsCalendar - def convert_to_ical(user) - events_set = fetch_events(user) - cal = Icalendar::Calendar.new - - events_set[:joined_events].each do |event| - add_event_to_calendar(cal, event, true) - end - - events_set[:upcoming_events].each do |event| - add_event_to_calendar(cal, event, false) - end - cal - end - - private - - def fetch_events(user) - participated_list = user.participations.pluck(:event_id) - upcoming_event_list = Event.where('start_at > ?', Date.current).pluck(:id) - - joined_events = Event.where(id: participated_list & upcoming_event_list) - upcoming_events = Event.where(id: upcoming_event_list).where.not(id: participated_list) - { - joined_events:, - upcoming_events: - } - end - - def add_event_to_calendar(cal, event, joined) - tzid = 'Asia/Tokyo' - cal.event do |e| - e.dtstart = Icalendar::Values::DateTime.new event.start_at, { 'tzid' => tzid } - e.dtend = Icalendar::Values::DateTime.new event.end_at, { 'tzid' => tzid } - e.summary = joined ? "【参加登録済】#{event.title}" : event.title - e.description = event.description - e.location = event.location - e.uid = "event#{event.id}" - e.sequence = Time.now.to_i - end - end -end diff --git a/test/models/special_events_calendar_test.rb b/test/models/events_calendar_test.rb similarity index 51% rename from test/models/special_events_calendar_test.rb rename to test/models/events_calendar_test.rb index 9e858a1ed6d..a0bd8f7a060 100644 --- a/test/models/special_events_calendar_test.rb +++ b/test/models/events_calendar_test.rb @@ -2,18 +2,20 @@ require 'test_helper' -class SpecialEventsCalendarTest < ActiveSupport::TestCase - test 'check to convert special events' do +class EventsCalendarTest < ActiveSupport::TestCase + test 'check to generate icalendar' do travel_to Time.zone.local(2024, 3, 25, 10, 0, 0) do user = users(:kimura) - calendar = SpecialEventsCalendar.new - subscription_calendar = calendar.convert_to_ical(user) + calendar = Calendar.new + subscription_calendar = calendar.combine_special_regular_calendar(user).publish subscription_calendar.publish assert_match(/【参加登録済】未来のイベント\(参加済\)/, subscription_calendar.to_ical) assert_match(/未来のイベント\(未参加\)/, subscription_calendar.to_ical) assert_no_match(/過去のイベント/, subscription_calendar.to_ical) + assert_match(/参加反映テスト用定期イベント\(祝日非開催\)/, subscription_calendar.to_ical) + assert_no_match(/未参加反映テスト用定期イベント\(祝日非開催\)/, subscription_calendar.to_ical) end end end diff --git a/test/models/regular_events_calendar_test.rb b/test/models/regular_events_calendar_test.rb deleted file mode 100644 index 81c78ce6a06..00000000000 --- a/test/models/regular_events_calendar_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class RegularEventsCalendarTest < ActiveSupport::TestCase - test 'check to convert regular events' do - travel_to Time.zone.local(2024, 3, 12, 10, 0, 0) do - user = users(:kimura) - - calendar = RegularEventsCalendar.new - subscription_calendar = calendar.convert_to_ical(user) - - subscription_calendar.publish - assert_match(/参加反映テスト用定期イベント\(祝日非開催\)/, subscription_calendar.to_ical) - assert_no_match(/未参加反映テスト用定期イベント\(祝日非開催\)/, subscription_calendar.to_ical) - end - end -end