Skip to content

Commit

Permalink
feat: add online event detection (#1239)
Browse files Browse the repository at this point in the history
feat: add online_address_id and online_event? to base importer event
feat: add online address detection for eventbrite, ics, meetup, mcu
fix: only validate if an event is unique on creation
fix: make activerecord work in rake workers task
  • Loading branch information
lexiwitch committed May 19, 2022
1 parent 6556f56 commit 31413ef
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 23 deletions.
2 changes: 2 additions & 0 deletions app/jobs/calendar_importer/calendar_importer_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def run
next if parsed_event.is_private?
next if parsed_event.has_no_occurences?

parsed_event.determine_online_location

parsed_event.determine_location_for_strategy
# next if parsed_event.is_address_missing?

Expand Down
8 changes: 6 additions & 2 deletions app/jobs/calendar_importer/event_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def is_private?
end

def has_no_occurences?
occurences.count == 0
occurences.count.zero?
end

def is_address_missing?
Expand All @@ -36,6 +36,10 @@ def occurences
@occurences ||= data.occurrences_between(@from_date, Calendar.import_up_to)
end

def determine_online_location
data.online_address_id = data.online_event?
end

def determine_location_for_strategy
# this algorithm is derived from the notion doc at
# GFSC
Expand Down Expand Up @@ -206,7 +210,7 @@ def save_all_occurences

event_time[:are_spaces_available] = occurence.status if occurence.respond_to?(:status)

unless event.update data.attributes.merge(event_time)
unless event.update! data.attributes.merge(event_time)
notices << { event: event, errors: event.errors.full_messages }
end

Expand Down
13 changes: 11 additions & 2 deletions app/jobs/calendar_importer/events/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ def initialize(event)
@event = event
end

attr_accessor :place_id, :address_id, :partner_id
attr_accessor :place_id,
:address_id,
:partner_id,
:online_address_id

def rrule
nil
Expand Down Expand Up @@ -52,7 +55,8 @@ def attributes
place_id: place_id,
address_id: address_id,
partner_id: partner_id,
publisher_url: publisher_url
publisher_url: publisher_url,
online_address_id: online_address_id
}
end

Expand Down Expand Up @@ -95,5 +99,10 @@ def ip_class
def private?
ip_class&.casecmp('private')&.zero? || (description&.include?('#placecal-ignore'))
end

def online_event?
# TODO: Put in default here
return nil
end
end
end
12 changes: 10 additions & 2 deletions app/jobs/calendar_importer/events/eventbrite_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ def place

def location
return if place.blank?

address = place['address']

if address.present?
[ place['name'],
[
place['name'],
address['address_1'],
address['address_2'],
address['city'],
Expand All @@ -56,11 +58,17 @@ def dtend
end

def occurrences_between(*)
#TODO: Expand when multi-day events supported
# TODO: Expand when multi-day events supported
@occurrences = []
@occurrences << Dates.new(dtstart, dtend)
@occurrences
end

def online_event?
return nil unless @event['online_event']

online_address = OnlineAddress.find_or_create_by(url: @event['url'])
online_address.id
end
end
end
3 changes: 2 additions & 1 deletion app/jobs/calendar_importer/events/facebook_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def publisher_url

def location
return if place.blank?

address = place['location']
if address.present?
[place['name'], address['street'], address['city'], address['zip']].reject(&:blank?).join(', ')
Expand All @@ -52,7 +53,7 @@ def last_updated
@event.updated_time
end

#TODO: Make this a link back to facebook
# TODO: Make this a link back to facebook
def footer; end

def recurring_event?
Expand Down
45 changes: 45 additions & 0 deletions app/jobs/calendar_importer/events/ics_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,50 @@ def recurring_event?
def occurrences_between(from, to)
@event.occurrences_between(from, to)
end

def online_event?
# Either return the google conference value, or find the link in the description
link = @event.custom_properties.fetch 'x_google_conference', nil
link ||= find_event_link

return unless link

# Then grab the first element of either the match object or the conference array
# (The match object returns ICal Text, not a String, so we have to cast)
# (We can't use .first here because the match object doesn't support it!)
online_address = OnlineAddress.find_or_create_by url: link[0].to_s
online_address.id
end

private

def find_event_link
regex = event_link_regex
regex.match description
end

def event_link_regex
# (http(s)?://)? - will match against https:// or http:// or nothing
# [A-Za-z0-9]+ - will match against alphanumeric strings
# [^\s]+ - grab until we see a whitespace character
#
# We deal with the following strings:
# meet.jit.si/foobarbaz
# meet.google.com/kbv-byuf-cvq
# facebook.com/events/(really long url)
# us04web.zoom.us/j/(really long url)
# zoom.us/j/(really long url)

http = %r{(http(s)?://)?}
alphanum = %r{[A-Za-z0-9]+}
links = {
'jitsi': %r{#{http}meet.jit.si/[^\s]+},
'meets': %r{#{http}meet.google.com/[^\s]+},
'facebook': %r{#{http}facebook.com/events/[^\s]+},
'zoom': %r{#{http}(#{alphanum}\.)?zoom.us/j/[^\s]+}
}

Regexp.union links.values
end
end
end
8 changes: 3 additions & 5 deletions app/jobs/calendar_importer/events/manchester_uni_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,15 @@ def dtstart
date = @event.at_xpath('./ns:times[@type="local"] //ns:start //ns:date')
time = @event.at_xpath('./ns:times[@type="local"] //ns:start //ns:time')
DateTime.parse([date, time].join(', '))

rescue StandardError
rescue StandardError
nil
end

def dtend
date = @event.at_xpath('./ns:times[@type="local"] //ns:end //ns:date')
time = @event.at_xpath('./ns:times[@type="local"] //ns:end //ns:time')
DateTime.parse([date, time].join(', '))

rescue StandardError
rescue StandardError
nil
end

Expand All @@ -41,7 +39,7 @@ def recurring_event?
end

def occurrences_between(*)
#TODO: Expand when multi-day events supported
# TODO: Expand when multi-day events supported
@occurrences = []
@occurrences << Dates.new(dtstart, dtend)
@occurrences
Expand Down
9 changes: 8 additions & 1 deletion app/jobs/calendar_importer/events/meetup_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,14 @@ def dtend
end

def occurrences_between(*)
[ Dates.new(dtstart, dtend) ]
[Dates.new(dtstart, dtend)]
end

def online_event?
return unless @event['is_online_event']

online_address = OnlineAddress.find_or_create_by(url: @event['link'])
online_address.id
end
end
end
1 change: 0 additions & 1 deletion app/jobs/calendar_importer/events/ticketsolve_event.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module CalendarImporter::Events
class TicketsolveEvent < Base

def uid
@event.attribute('id').text
end
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/calendar_importer/parsers/eventbrite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def download_calendar
end

def import_events_from(data)
data.map { |d| CalendarImporter::Events::EventbriteEvent.new(d) }
data.map { |d| CalendarImporter::Events::EventbriteEvent.new(d) }
end
end
end
1 change: 0 additions & 1 deletion app/models/calendar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,3 @@ def is_busy?
calendar_state.in_queue? || calendar_state.in_worker?
end
end

12 changes: 7 additions & 5 deletions app/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Event < ApplicationRecord
validates :summary, :dtstart, :partner, presence: true
before_validation :set_address_from_place
validate :require_location
validate :unique_event
validate :unique_event, on: :create # If we are updating the event we don't want it to trigger!

before_save :sanitize_rrule

Expand Down Expand Up @@ -160,11 +160,13 @@ def set_address_from_place
end

def require_location
if calendar.present?
return if calendar.strategy == 'event'
return if calendar.strategy == 'no_location'
end
# 'event', 'no_location', and 'online_only' do not require a Location
return if %w[event no_location online_only].include?(calendar.strategy)

# If we have an online address we don't need a physical one
return if self.online_address_id.present?

# If the address exists then the error doesn't apply
return unless self.address_id.blank?

errors.add(:base, 'No place or address could be created or found for ' \
Expand Down
4 changes: 2 additions & 2 deletions lib/tasks/workers.rake
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require 'yaml'

namespace :workers do
desc 'Clear and remove all jobs'
task purge_all: [] do
task purge_all: :environment do
puts 'Force stopping all workers...'

# Force stop of all workers
Expand All @@ -25,7 +25,7 @@ namespace :workers do
end

desc 'Show any salient worker errors (You should pipe this into less)'
task inspect_errors: [] do
task inspect_errors: :environment do
workers = ActiveRecord::Base.connection
.execute('select * from delayed_jobs')
.to_a
Expand Down

0 comments on commit 31413ef

Please sign in to comment.