diff --git a/modules/meeting/app/services/meetings/ical_service.rb b/modules/meeting/app/services/meetings/ical_service.rb index 1451d04ee7e7..5eec3f22a35b 100644 --- a/modules/meeting/app/services/meetings/ical_service.rb +++ b/modules/meeting/app/services/meetings/ical_service.rb @@ -60,10 +60,12 @@ def generate_ical e.dtend = ical_datetime meeting.end_time, tzid e.url = url_helpers.meeting_url(meeting) e.summary = "[#{meeting.project.name}] #{meeting.title}" - e.description = ical_subject(meeting) + e.description = ical_subject e.uid = "#{meeting.id}@#{meeting.project.identifier}" - e.organizer = ical_organizer meeting + e.organizer = ical_organizer e.location = meeting.location.presence + + add_attendees(e) end end # rubocop:enable Metrics/AbcSize @@ -77,7 +79,27 @@ def ical_event(&) calendar.to_ical end - def ical_subject(meeting) + def add_attendees(event) + meeting.participants.includes(:user).find_each do |participant| + user = participant.user + next unless user + + address = Icalendar::Values::CalAddress.new( + "mailto:#{user.mail}", + { + "CN" => user.name, + "PARTSTAT" => "NEEDS-ACTION", + "RSVP" => "TRUE", + "CUTYPE" => "INDIVIDUAL", + "ROLE" => "REQ-PARTICIPANT" + } + ) + + event.append_attendee(address) + end + end + + def ical_subject "[#{meeting.project.name}] #{I18n.t(:label_meeting)}: #{meeting.title}" end @@ -85,7 +107,7 @@ def ical_datetime(time, timezone_id) Icalendar::Values::DateTime.new time.in_time_zone(timezone_id), 'tzid' => timezone_id end - def ical_organizer(meeting) + def ical_organizer Icalendar::Values::CalAddress.new("mailto:#{meeting.author.mail}", cn: meeting.author.name) end end diff --git a/modules/meeting/spec/services/meetings/ical_service_spec.rb b/modules/meeting/spec/services/meetings/ical_service_spec.rb index 21fb14dda484..38bb479b0d9d 100644 --- a/modules/meeting/spec/services/meetings/ical_service_spec.rb +++ b/modules/meeting/spec/services/meetings/ical_service_spec.rb @@ -29,17 +29,22 @@ require 'spec_helper' RSpec.describe Meetings::ICalService, type: :model do - let(:user) { build_stubbed(:user, firstname: 'Bob', lastname: 'Barker') } - let(:project) { build_stubbed(:project, name: 'My Project') } + shared_let(:user) { create(:user, firstname: 'Bob', lastname: 'Barker', mail: 'bob@example.com') } + shared_let(:user2) { create(:user, firstname: 'Foo', lastname: 'Fooer', mail: 'foo@example.com') } + shared_let(:project) { create(:project, name: 'My Project') } - let(:meeting) do - build_stubbed(:meeting, - author: user, - project:, - title: 'Important meeting', - location: 'https://example.com/meet/important-meeting', - start_time: Time.zone.parse("2021-01-19T10:00:00Z"), - duration: 1.0) + shared_let(:meeting) do + create(:meeting, + author: user, + project:, + title: 'Important meeting', + participants: [ + MeetingParticipant.new(user:), + MeetingParticipant.new(user: user2) + ], + location: 'https://example.com/meet/important-meeting', + start_time: Time.zone.parse("2021-01-19T10:00:00Z"), + duration: 1.0) end let(:service) { described_class.new(user:, meeting:) } @@ -68,6 +73,7 @@ it 'renders the ICS file', :aggregate_failures do expect(result).to be_a String + expect(entry.attendee.map(&:to_s)).to contain_exactly('mailto:foo@example.com', 'mailto:bob@example.com') expect(entry.dtstart.utc).to eq meeting.start_time expect(entry.dtend.utc).to eq meeting.start_time + 1.hour expect(entry.summary).to eq '[My Project] Important meeting'