@@ -9,7 +9,6 @@ module Ingestors
99 # Reads from direct ical / .ics / Indico (event or category) URLs, .xml sitemaps, and .txt sitemaps.
1010 class IcalIngestor < Ingestor
1111 include Ingestors ::Concerns ::SitemapHelpers
12- include Ingestors ::Concerns ::IcalIngestorExportUrl
1312
1413 def self . config
1514 {
@@ -37,13 +36,56 @@ def read(source_url)
3736 def process_url ( url )
3837 export_url = to_export ( url )
3938 events = Icalendar ::Event . parse ( open_url ( export_url , raise : true ) . set_encoding ( 'utf-8' ) )
39+ raise 'Not found' if events . nil? || events . empty?
40+
4041 events . each do |e |
4142 process_calevent ( e )
4243 end
4344 rescue StandardError => e
4445 @messages << "Process file url[#{ export_url } ] failed with: #{ e . message } "
4546 end
4647
48+ # 1. If the path already ends with '/events.ics', return as-is.
49+ # 2. If the host includes 'indico', ensures the path ends with '/events.ics'.
50+ # 3. Otherwise, append '?ical=true' query param if not already present.
51+ #
52+ # This method never mutates the original URL string.
53+ # Returns the updated URL string or nil if input is blank.
54+ def to_export ( url )
55+ return nil if url . blank?
56+
57+ uri = URI . parse ( url )
58+ path = uri . path . to_s
59+
60+ if path . match? ( %r{/(event|events)\. ics\z } )
61+ uri . to_s
62+ elsif uri . host &.include? ( 'indico' )
63+ ensure_events_ics_path ( uri )
64+ else
65+ ensure_ical_query ( uri )
66+ end
67+ end
68+
69+ # Ensures the Indico URL ends with '/events.ics'
70+ def ensure_events_ics_path ( uri )
71+ paths = uri . path . split ( '/' )
72+ uri . path = "#{ paths [ 0 ..2 ] . join ( '/' ) } /"
73+ if paths [ 1 ] == 'event'
74+ uri . path = File . join ( uri . path , 'event.ics' )
75+ elsif paths [ 1 ] == 'category'
76+ uri . path = File . join ( uri . path , 'events.ics' )
77+ end
78+ uri . to_s
79+ end
80+
81+ # Ensures the URL has '?ical=true' in its query params
82+ def ensure_ical_query ( uri )
83+ query = URI . decode_www_form ( uri . query . to_s ) . to_h
84+ query [ 'ical' ] = 'true' unless query [ 'ical' ] == 'true'
85+ uri . query = URI . encode_www_form ( query )
86+ uri . to_s
87+ end
88+
4789 # Builds the OpenStruct event and adds it in event.
4890 def process_calevent ( calevent )
4991 event_to_add = OpenStruct . new . tap do |event |
@@ -60,8 +102,9 @@ def process_calevent(calevent)
60102 def assign_basic_info ( event , calevent )
61103 event . url = calevent . url . to_s
62104 event . title = calevent . summary . to_s
63- event . description = process_description calevent . description
105+ event . description = calevent . description . to_s
64106 event . keywords = process_keywords ( calevent . categories )
107+ event . contact = calevent . contact . join ( ', ' )
65108 end
66109
67110 # Assigns to event: start, end, timezone.
@@ -73,21 +116,13 @@ def assign_time_info(event, calevent)
73116
74117 # Assigns to event: venue, online, city.
75118 def assign_location_info ( event , location )
76- return if location . blank? || ! location . present?
119+ return if location . blank?
77120
78121 event . venue = location . to_s
79122 event . online = location . downcase . include? ( 'online' )
80123 event . city , event . postcode , event . country = process_location ( location )
81124 end
82125
83- # Removes all `<br />` tags and converts HTML to MD.
84- def process_description ( input )
85- return input if input . nil?
86-
87- desc = input . to_s . gsub ( '' , '<br />' )
88- convert_description ( desc )
89- end
90-
91126 # Extracts the timezone identifier (TZID) from an iCalendar event's dtstart field.
92127 # Handles whether tzid shows up as an Array or a single string
93128 def get_tzid ( dtstart )
@@ -102,17 +137,9 @@ def get_tzid(dtstart)
102137 # Returns an array of 3 location characteristics: suburb, postcode, country
103138 # Everything is nil if location.blank or location is online
104139 def process_location ( location )
105- return [ nil , nil , nil ] if location . blank?
140+ return [ location [ 'suburb' ] , location [ 'postcode' ] , location [ 'country' ] ] if location . is_a? ( Array )
106141
107- if location . to_s . downcase . include? ( 'online' )
108- [ nil , nil , nil ]
109- else
110- [
111- location [ 'suburb' ] ,
112- location [ 'postcode' ] ,
113- location [ 'country' ]
114- ]
115- end
142+ [ nil , nil , nil ]
116143 end
117144
118145 # Returns keywords from the `CATEGORIES` ICal field
0 commit comments