-
Notifications
You must be signed in to change notification settings - Fork 0
/
every_action.rb
157 lines (132 loc) · 3.74 KB
/
every_action.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
require_relative 'timeslot'
class EveryActionClient
attr_reader :api_key, :username
def initialize(api_key, username: "sunrise-movement")
# Currently default to "sunrise-movement" for the EA username, because it
# seems like this will be constant across keys, but may need to update if
# we add more keys later.
@username = username
@api_key = api_key
end
def events_request
# Request upcoming events from the EveryAction API, iteratively handling pagination
url = "https://api.securevan.com/v4/events?startingAfter=#{Date.today-1}&$expand=onlineforms,locations,codes,shifts,roles,notes"
res = []
while url
resp = HTTParty.get(url,
basic_auth: {
username: username,
password: "#{api_key}|1"
},
headers: { "Content-Type" => "application/json" }
)
res += resp["items"]
url = resp["nextPageLink"]
end
res
end
def events
# Make events requests (possibly recursively), then wrap each response in a
# helper object for filtering and formatting
@events ||= events_request.map { |e| EveryActionEvent.new(e) }
end
def visible_events
events.select(&:should_appear_on_map?)
end
def map_entries
visible_events.map(&:map_entry)
end
end
class EveryActionEvent
attr_reader :data
def initialize(data)
# Initialize with the raw API response
@data = data
end
def has_hide_code?
data['codes'].any? { |c| c['name'] == 'hide from map' }
end
def should_appear_on_map?
# Events appear if they're associated with a published online form and if
# they're listed as active (and also if they're not excluded by event type,
# but that happens later)
registration_link.present? && data['isActive'] && !has_hide_code?
end
def event_type
# Get the event type from the response (w/ null-safety)
(data["eventType"] || {})["name"]
end
def timeslots
[
Timeslot.new(
Time.parse(data['startDate']),
Time.parse(data['endDate']),
data['dotNetTimeZoneId']
)
]
end
def map_entry
# The main method of this class -- this is the data we surface in the JSON.
entry = {
city: address['city'],
state: address['stateOrProvince'],
zip_code: address['zipOrPostalCode'],
location_name: location['name'],
event_source: 'everyaction',
event_type: event_type,
include_on_carousel: true, # by default, EA events are on the carousel
description: data['description'],
event_title: data['name'],
registration_link: registration_link,
timeslots: timeslots.map(&:as_json),
latitude: latitude,
longitude: longitude,
online_forms: online_forms.map(&:json_entry),
hub_id: nil
}
entry[:end_date] = entry[:timeslots].last[:end_date]
entry[:start_date] = entry[:timeslots].first[:start_date]
entry[:end_date_string] = entry[:timeslots].last[:end_date_string]
entry[:start_date_string] = entry[:timeslots].first[:start_date_string]
entry
end
def online_forms
# Select online forms that are currently published.
(data['onlineForms'] || []).
map{|f| EveryActionOnlineForm.new(f) }.
select(&:published?)
end
def registration_link
online_forms.first.try(:url)
end
def locations
data["locations"] || []
end
def location
locations.first || {}
end
def address
location['address'] || {}
end
def latitude
(address["geoLocation"] || {})["lat"]
end
def longitude
(address["geoLocation"] || {})["lon"]
end
end
class EveryActionOnlineForm
attr_reader :data
def initialize(data)
@data = data
end
def json_entry
data
end
def published?
data["status"] == "Published"
end
def url
data["url"]
end
end