diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 43809551..006b12d2 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -3,7 +3,8 @@ class ConferencesController < ApplicationController protect_from_forgery with: :null_session before_action :respond_to_options - load_and_authorize_resource find_by: :short_title, except: :show + load_and_authorize_resource find_by: :short_title, except: %i[show calendar] + skip_authorization_check only: :calendar def index @current = Conference.upcoming.reorder(start_date: :asc) @@ -76,7 +77,7 @@ class ConferencesController < ApplicationController event_schedules = conf.program.selected_event_schedules( includes: [{ event: %i[event_type speakers submitter] }] ) - calendar = icalendar_proposals(calendar, event_schedules.map(&:event), conf) + calendar = helpers.icalendar_proposals(calendar, event_schedules.map(&:event), conf) else calendar.event do |e| e.dtstart = conf.start_date diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index fd03abc6..c961d4d9 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -23,7 +23,7 @@ class SchedulesController < ApplicationController end format.ics do cal = Icalendar::Calendar.new - cal = icalendar_proposals(cal, event_schedules.map(&:event), @conference) + cal = helpers.icalendar_proposals(cal, event_schedules.map(&:event), @conference) cal.publish render inline: cal.to_ical end diff --git a/app/helpers/conference_helper.rb b/app/helpers/conference_helper.rb index f685ed89..95f6baa2 100644 --- a/app/helpers/conference_helper.rb +++ b/app/helpers/conference_helper.rb @@ -25,29 +25,45 @@ module ConferenceHelper # adds events to icalendar for proposals in a conference def icalendar_proposals(calendar, proposals, conference) proposals.each do |proposal| - calendar.event do |e| - e.dtstart = proposal.time - e.dtend = proposal.time + proposal.event_type.length * 60 - e.duration = "PT#{proposal.event_type.length}M" - e.created = proposal.created_at - e.last_modified = proposal.updated_at - e.summary = proposal.title - e.description = proposal.abstract - e.uid = proposal.guid - e.url = conference_program_proposal_url(conference.short_title, proposal.id) - v = conference.venue - if v - e.geo = v.latitude, v.longitude if v.latitude && v.longitude - location = '' - location += "#{proposal.room.name} - " if proposal.room.name - location += " - #{v.street}, " if v.street - location += "#{v.postalcode} #{v.city}, " if v.postalcode && v.city - location += "#{v.country_name}, " if v.country_name - e.location = location - end - e.categories = conference.title, "Difficulty: #{proposal.difficulty_level.title}", "Track: #{proposal.track.name}" - end + calendar.event { |e| populate_icalendar_event(e, proposal, conference) } end calendar end + + private + + def populate_icalendar_event(event, proposal, conference) + length = proposal.event_type&.length + event.dtstart = proposal.time + event.dtend = proposal.time + (length * 60) if proposal.time && length + event.duration = "PT#{length}M" if length + event.created = proposal.created_at + event.last_modified = proposal.updated_at + event.summary = proposal.title + event.description = proposal.abstract + event.uid = proposal.guid + event.url = conference_program_proposal_url(conference.short_title, proposal.id) + venue = conference.venue + if venue + event.geo = venue.latitude, venue.longitude if venue.latitude && venue.longitude + event.location = icalendar_event_location(proposal, venue) + end + event.categories = icalendar_event_categories(proposal, conference) + end + + def icalendar_event_location(proposal, venue) + location = '' + location += "#{proposal.room.name} - " if proposal.room&.name + location += " - #{venue.street}, " if venue.street + location += "#{venue.postalcode} #{venue.city}, " if venue.postalcode && venue.city + location += "#{venue.country_name}, " if venue.country_name + location + end + + def icalendar_event_categories(proposal, conference) + categories = [conference.title] + categories << "Difficulty: #{proposal.difficulty_level.title}" if proposal.difficulty_level + categories << "Track: #{proposal.track.name}" if proposal.track + categories + end end diff --git a/spec/controllers/conferences_controller_spec.rb b/spec/controllers/conferences_controller_spec.rb index c9a17d14..a64053ec 100644 --- a/spec/controllers/conferences_controller_spec.rb +++ b/spec/controllers/conferences_controller_spec.rb @@ -49,4 +49,25 @@ describe ConferencesController do end end + describe 'GET #calendar' do + it 'returns iCalendar data for all conferences' do + get :calendar, params: { format: :ics } + + expect(response).to be_successful + expect(response.content_type).to start_with('text/calendar') + expect(response.body).to start_with('BEGIN:VCALENDAR') + end + + it 'returns iCalendar data with full schedule when full=true' do + conference.program.update!(schedule_public: true) + create(:event_scheduled, program: conference.program) + + get :calendar, params: { full: true, format: :ics } + + expect(response).to be_successful + expect(response.content_type).to start_with('text/calendar') + expect(response.body).to start_with('BEGIN:VCALENDAR') + end + end + end diff --git a/spec/controllers/schedules_controller_spec.rb b/spec/controllers/schedules_controller_spec.rb index 2a6613b2..52444304 100644 --- a/spec/controllers/schedules_controller_spec.rb +++ b/spec/controllers/schedules_controller_spec.rb @@ -6,13 +6,13 @@ describe SchedulesController do let(:conference) { create(:conference, splashpage: create(:splashpage, public: true), venue: create(:venue)) } describe 'GET #show' do + before :each do + conference.program.update!(schedule_public: true) + create_pair(:event_scheduled, program: conference.program) + end + context 'XML' do before :each do - conference.program.schedule_public = true - conference.program.save! - create(:event_scheduled, program: conference.program) - create(:event_scheduled, program: conference.program) - get :show, params: { conference_id: conference.short_title, format: :xml } end @@ -26,5 +26,20 @@ describe SchedulesController do expect(response).to be_successful end end + + context 'iCalendar' do + before :each do + get :show, params: { conference_id: conference.short_title, format: :ics } + end + + it 'has 200 status code' do + expect(response).to be_successful + end + + it 'returns iCalendar data' do + expect(response.content_type).to start_with('text/calendar') + expect(response.body).to start_with('BEGIN:VCALENDAR') + end + end end end