-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add Resident Advisor support (#2579)
- Loading branch information
1 parent
f7eac59
commit cbb3a64
Showing
8 changed files
with
382 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# frozen_string_literal: true | ||
|
||
module CalendarImporter::Events | ||
class ResidentAdvisor < Base | ||
def initialize(event) | ||
super | ||
@event = event | ||
end | ||
|
||
def uid | ||
@event['id'] | ||
end | ||
|
||
def summary | ||
@event['title'] | ||
end | ||
|
||
def description | ||
@event['content'] || '' | ||
end | ||
|
||
def place | ||
'' # N/A | ||
end | ||
|
||
def publisher_url | ||
"https://ra.co#{@event['contentUrl']}" | ||
end | ||
|
||
def location | ||
return @event['venue']['address'] if @event['venue'] | ||
end | ||
|
||
def dtstart | ||
@event['startTime'] | ||
end | ||
|
||
def dtend | ||
@event['endTime'] | ||
end | ||
|
||
def occurrences_between(*) | ||
[Dates.new(dtstart, dtend)] | ||
end | ||
|
||
def online_event? | ||
return # I don't think RA supports online events | ||
|
||
# return unless @event['is_online_event'] | ||
|
||
# online_address = OnlineAddress.find_or_create_by(url: @event['link'], link_type: 'indirect') | ||
# online_address.id | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# frozen_string_literal: true | ||
|
||
module CalendarImporter::Parsers | ||
class ResidentAdvisor < Base | ||
NAME = 'Resident Advisor' | ||
KEY = 'residentadvisor' | ||
DOMAINS = %w[ra.co].freeze | ||
RA_ENDPOINT = 'https://ra.co/graphql' | ||
RA_REGEX = %r{^https://ra\.co/(promoters|clubs)/(\d+)$} # Accept club or promoter URLs | ||
|
||
def self.allowlist_pattern | ||
RA_REGEX | ||
end | ||
|
||
def download_calendar | ||
ra_entity = ra_entity(@url) | ||
return unless ra_entity | ||
|
||
if ra_entity[0] == :promoters | ||
get_promoter_events(ra_entity[1]) | ||
elsif ra_entity[0] == :clubs | ||
get_club_events(ra_entity[1]) | ||
end | ||
end | ||
|
||
def import_events_from(data) | ||
data.map { |d| CalendarImporter::Events::ResidentAdvisor.new(d) } | ||
end | ||
|
||
# Converts an RA URL into [(promoter OR club), (id of entity)] | ||
def ra_entity(url) | ||
result = RA_REGEX.match(url) | ||
return false unless result | ||
|
||
[result[1].to_sym, result[2].to_i] | ||
end | ||
|
||
def get_promoter_events(id) | ||
# LATEST query is discovered via introspection. | ||
# I think it gives the next 10 events. | ||
query = <<~GRAPHQL | ||
promoter(id: #{id}) { | ||
id | ||
name | ||
events(type: LATEST) { | ||
id | ||
title | ||
content | ||
startTime | ||
endTime | ||
contentUrl | ||
venue { | ||
id | ||
name | ||
address | ||
} | ||
} | ||
} | ||
GRAPHQL | ||
|
||
events = query_graphql_endpoint(query) | ||
events['data']['promoter']['events'] | ||
end | ||
|
||
def get_club_events(id) | ||
# LATEST query is discovered via introspection. | ||
# I think it gives the next 10 events. | ||
query = <<~GRAPHQL | ||
venue(id: #{id}) { | ||
id | ||
name | ||
address | ||
events(type: LATEST) { | ||
id | ||
title | ||
content | ||
startTime | ||
endTime | ||
contentUrl | ||
} | ||
} | ||
GRAPHQL | ||
|
||
events = query_graphql_endpoint(query) | ||
events['data']['venue']['events'] | ||
end | ||
|
||
# Send a POST request to the GraphQL endpoint | ||
# TODO: Migrate into a generic GraphQL base class | ||
def query_graphql_endpoint(query) | ||
HTTParty.post(RA_ENDPOINT, | ||
body: postify_query_string(query), | ||
headers: { 'Content-Type': 'application/json', | ||
'Accept': 'application/json', | ||
'User-Agent': 'Mozilla/5.0' }) | ||
end | ||
|
||
# Massage a GraphQL query into a post request body | ||
def postify_query_string(query) | ||
"{\"query\": \"{#{query}}\"}".gsub("\n", '') | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# How the importer works | ||
|
||
Calendars can be imported through the following rake tasks: | ||
|
||
``` | ||
rails events:import_all_calendars # Imports all calendars - usually in dev environment | ||
rails events:import_calendars[:id] # Imports one calendar - usually in a dev environment | ||
rails events:scan_for_calendars_needing_import # Imports only updated calendars - run as a cronjob in a production environment | ||
``` | ||
|
||
They can also be triggered in the Calendar interface in the web admin. | ||
|
||
All of these tasks create `CalendarImporterJob`s (/app/jobs/calendar_importer_job.rb). This job is how all external URLs get turned into Events and imported into PlaceCal, with Calendars being effectively the configuration for how to import them. | ||
|
||
1. `CalendarImporterJob` looks up each Calendar. It creates a... | ||
2. `CalendarImporter::CalendarImporterTask`, which identifies the calendar type and attempts to load it using a... | ||
3. `CalendarImporter::Parsers::MyParser`, which queries a URL and sends the data from it to... | ||
4. `CalendarImporter::EventResolver`, which analyses event data and creates one or more... | ||
5. `CalendarImporter::Events::MyParser`, which attempts to load an event into PlaceCal | ||
|
||
## Adding a new importer | ||
|
||
Importers require two parts: | ||
|
||
1. A **CalendarImporter::Parsers**, which reads a remote URL and turns it into something Rails can work with | ||
2. A **CalendarImporter::Events**, which takes the data and creates one or more Events inside PlaceCal. | ||
|
||
### CalendarImporter::Parsers | ||
|
||
1. Create `/app/jobs/calendar_importer/parsers/my_parser.rb` and link it from `/app/jobs/calendar_importer/calendar_importer.rb`. | ||
2. Implement a `#download_calendar` method that returns event data. | ||
3. Implement an `#import_events_from(data)` method that invokes a `CalendarImporter::Events`. | ||
|
||
### CalendarImporter::Events | ||
|
||
1. Create `/app/jobs/calendar_importer/events/my_parser.rb`. | ||
2. Add methods to map your retrieved events onto PlaceCal Events model (nb: we should define this more clearly) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.