Skip to content

Commit 5979514

Browse files
committed
review(#1161): path more precise, location check, added contact
1 parent 979e51e commit 5979514

3 files changed

Lines changed: 50 additions & 74 deletions

File tree

lib/ingestors/concerns/ical_ingestor_export_url.rb

Lines changed: 0 additions & 49 deletions
This file was deleted.

lib/ingestors/ical_ingestor.rb

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

test/unit/ingestors/ical_ingestor_test.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,10 @@ class IcalIngestorTest < ActiveSupport::TestCase
192192
calevent = Object.new # fake calevent
193193

194194
# Stub a method that will raise an error
195-
def ingestor.assign_basic_info(*)
196-
raise StandardError, 'test failure'
195+
ingestor.stub(:assign_basic_info, ->(*) { raise StandardError, 'test failure' }) do
196+
ingestor.send(:process_calevent, calevent)
197197
end
198198

199-
ingestor.send(:process_calevent, calevent)
200-
201199
assert_includes ingestor.messages.last, 'Process iCalendar failed with: test failure'
202200
end
203201

0 commit comments

Comments
 (0)