bright 1.3 → 2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Rakefile +0 -1
- data/bright.gemspec +12 -14
- data/lib/bright/address.rb +5 -5
- data/lib/bright/connection.rb +7 -9
- data/lib/bright/contact.rb +7 -9
- data/lib/bright/cursor_response_collection.rb +8 -10
- data/lib/bright/email_address.rb +1 -2
- data/lib/bright/enrollment.rb +2 -2
- data/lib/bright/errors.rb +0 -1
- data/lib/bright/helpers/blank_helper.rb +0 -2
- data/lib/bright/model.rb +13 -13
- data/lib/bright/phone_number.rb +1 -2
- data/lib/bright/response_collection.rb +8 -8
- data/lib/bright/school.rb +1 -4
- data/lib/bright/sis_apis/aeries.rb +18 -19
- data/lib/bright/sis_apis/base.rb +3 -5
- data/lib/bright/sis_apis/bright_sis.rb +82 -84
- data/lib/bright/sis_apis/focus.rb +78 -84
- data/lib/bright/sis_apis/one_roster/infinite_campus.rb +15 -0
- data/lib/bright/sis_apis/one_roster/skyward.rb +6 -0
- data/lib/bright/sis_apis/{infinite_campus.rb → one_roster.rb} +91 -100
- data/lib/bright/sis_apis/power_school.rb +105 -107
- data/lib/bright/sis_apis/synergy.rb +6 -8
- data/lib/bright/sis_apis/tsis.rb +54 -54
- data/lib/bright/student.rb +15 -19
- data/lib/bright/version.rb +1 -1
- data/lib/bright.rb +14 -12
- metadata +6 -5
- data/lib/bright/sis_apis/skyward.rb +0 -277
@@ -1,22 +1,21 @@
|
|
1
|
-
require
|
1
|
+
require "oauth"
|
2
2
|
|
3
3
|
module Bright
|
4
4
|
module SisApi
|
5
|
-
class
|
6
|
-
|
7
|
-
@@
|
8
|
-
@@
|
9
|
-
@@api_version = "1.1"
|
5
|
+
class OneRoster < Base
|
6
|
+
@@description = "Connects to the OneRoster API for accessing student information"
|
7
|
+
@@doc_url = "https://www.imsglobal.org/sites/default/files/spec/oneroster/v1p2/rostering-informationmodel/OneRosterv1p2RosteringService_InfoModelv1p0.html"
|
8
|
+
@@api_version = "1.2"
|
10
9
|
|
11
10
|
attr_accessor :connection_options, :schools_cache, :school_years_cache
|
12
11
|
|
13
12
|
DEMOGRAPHICS_CONVERSION = {
|
14
|
-
"americanIndianOrAlaskaNative"=>"American Indian Or Alaska Native",
|
15
|
-
"asian"=>"Asian",
|
16
|
-
"blackOrAfricanAmerican"=>"Black Or African American",
|
17
|
-
"nativeHawaiianOrOtherPacificIslander"=>"Native Hawaiian Or Other Pacific Islander",
|
18
|
-
"white"=>"White",
|
19
|
-
"hispanicOrLatinoEthnicity"=>"Hispanic Or Latino"
|
13
|
+
"americanIndianOrAlaskaNative" => "American Indian Or Alaska Native",
|
14
|
+
"asian" => "Asian",
|
15
|
+
"blackOrAfricanAmerican" => "Black Or African American",
|
16
|
+
"nativeHawaiianOrOtherPacificIslander" => "Native Hawaiian Or Other Pacific Islander",
|
17
|
+
"white" => "White",
|
18
|
+
"hispanicOrLatinoEthnicity" => "Hispanic Or Latino"
|
20
19
|
}
|
21
20
|
|
22
21
|
def initialize(options = {})
|
@@ -31,36 +30,36 @@ module Bright
|
|
31
30
|
end
|
32
31
|
|
33
32
|
def api_version
|
34
|
-
Gem::Version.new(
|
33
|
+
Gem::Version.new(connection_options.dig(:api_version) || @@api_version)
|
35
34
|
end
|
36
35
|
|
37
36
|
def get_student_by_api_id(api_id, params = {})
|
38
|
-
if api_version <= Gem::Version.new("1.1")
|
39
|
-
|
37
|
+
params = if api_version <= Gem::Version.new("1.1")
|
38
|
+
{role: "student"}.merge(params)
|
40
39
|
else
|
41
|
-
|
40
|
+
{roles: "student"}.merge(params)
|
42
41
|
end
|
43
|
-
st_hsh =
|
42
|
+
st_hsh = request(:get, "users/#{api_id}", params)
|
44
43
|
Student.new(convert_to_user_data(st_hsh["user"])) if st_hsh and st_hsh["user"]
|
45
44
|
end
|
46
45
|
|
47
46
|
def get_student(params = {}, options = {})
|
48
|
-
|
47
|
+
get_students(params, options.merge(limit: 1, wrap_in_collection: false)).first
|
49
48
|
end
|
50
49
|
|
51
50
|
def get_students(params = {}, options = {})
|
52
|
-
if api_version <= Gem::Version.new("1.1")
|
53
|
-
|
51
|
+
params = if api_version <= Gem::Version.new("1.1")
|
52
|
+
{role: "student"}.merge(params)
|
54
53
|
else
|
55
|
-
|
54
|
+
{roles: "student"}.merge(params)
|
56
55
|
end
|
57
56
|
params[:limit] = params[:limit] || options[:limit] || 100
|
58
|
-
students_response_hash =
|
57
|
+
students_response_hash = request(:get, "users", map_search_params(params))
|
59
58
|
total_results = students_response_hash[:response_headers]["x-total-count"].to_i
|
60
59
|
if students_response_hash and students_response_hash["users"]
|
61
60
|
students_hash = [students_response_hash["users"]].flatten
|
62
61
|
|
63
|
-
students = students_hash.compact.collect {|st_hsh|
|
62
|
+
students = students_hash.compact.collect { |st_hsh|
|
64
63
|
Student.new(convert_to_user_data(st_hsh))
|
65
64
|
}
|
66
65
|
end
|
@@ -69,14 +68,14 @@ module Bright
|
|
69
68
|
load_more_call = proc { |page|
|
70
69
|
# pages start at one, so add a page here
|
71
70
|
params[:offset] = (params[:limit].to_i * page)
|
72
|
-
api.get_students(params, {:
|
71
|
+
api.get_students(params, {wrap_in_collection: false})
|
73
72
|
}
|
74
73
|
ResponseCollection.new({
|
75
|
-
:
|
76
|
-
:
|
77
|
-
:
|
78
|
-
:
|
79
|
-
:
|
74
|
+
seed_page: students,
|
75
|
+
total: total_results,
|
76
|
+
per_page: params[:limit],
|
77
|
+
load_more_call: load_more_call,
|
78
|
+
no_threads: options[:no_threads]
|
80
79
|
})
|
81
80
|
else
|
82
81
|
students
|
@@ -92,22 +91,22 @@ module Bright
|
|
92
91
|
end
|
93
92
|
|
94
93
|
def get_school_by_api_id(api_id, params = {})
|
95
|
-
sc_hsh =
|
94
|
+
sc_hsh = request(:get, "schools/#{api_id}", params)
|
96
95
|
School.new(convert_to_school_data(sc_hsh["org"])) if sc_hsh and sc_hsh["org"]
|
97
96
|
end
|
98
97
|
|
99
98
|
def get_school(params = {}, options = {})
|
100
|
-
|
99
|
+
get_schools(params, options.merge(limit: 1, wrap_in_collection: false)).first
|
101
100
|
end
|
102
101
|
|
103
102
|
def get_schools(params = {}, options = {})
|
104
103
|
params[:limit] = params[:limit] || options[:limit] || 100
|
105
|
-
schools_response_hash =
|
104
|
+
schools_response_hash = request(:get, "schools", map_school_search_params(params))
|
106
105
|
total_results = schools_response_hash[:response_headers]["x-total-count"].to_i
|
107
106
|
if schools_response_hash and schools_response_hash["orgs"]
|
108
107
|
schools_hash = [schools_response_hash["orgs"]].flatten
|
109
108
|
|
110
|
-
schools = schools_hash.compact.collect {|sc_hsh|
|
109
|
+
schools = schools_hash.compact.collect { |sc_hsh|
|
111
110
|
School.new(convert_to_school_data(sc_hsh))
|
112
111
|
}
|
113
112
|
end
|
@@ -116,27 +115,27 @@ module Bright
|
|
116
115
|
load_more_call = proc { |page|
|
117
116
|
# pages start at one, so add a page here
|
118
117
|
params[:offset] = (params[:limit].to_i * page)
|
119
|
-
api.get_schools(params, {:
|
118
|
+
api.get_schools(params, {wrap_in_collection: false})
|
120
119
|
}
|
121
120
|
ResponseCollection.new({
|
122
|
-
:
|
123
|
-
:
|
124
|
-
:
|
125
|
-
:
|
126
|
-
:
|
121
|
+
seed_page: schools,
|
122
|
+
total: total_results,
|
123
|
+
per_page: params[:limit],
|
124
|
+
load_more_call: load_more_call,
|
125
|
+
no_threads: options[:no_threads]
|
127
126
|
})
|
128
127
|
else
|
129
128
|
schools
|
130
129
|
end
|
131
130
|
end
|
132
131
|
|
133
|
-
def get_contact_by_api_id(api_id, params ={})
|
134
|
-
contact_hsh =
|
132
|
+
def get_contact_by_api_id(api_id, params = {})
|
133
|
+
contact_hsh = request(:get, "users/#{api_id}", params)
|
135
134
|
Contact.new(convert_to_user_data(contact_hsh["user"], bright_type: "Contact")) if contact_hsh and contact_hsh["user"]
|
136
135
|
end
|
137
136
|
|
138
137
|
def request(method, path, params = {})
|
139
|
-
uri
|
138
|
+
uri = "#{connection_options[:uri]}/#{path}"
|
140
139
|
body = nil
|
141
140
|
if method == :get
|
142
141
|
query = URI.encode_www_form(params)
|
@@ -147,7 +146,7 @@ module Bright
|
|
147
146
|
|
148
147
|
response = connection_retry_wrapper {
|
149
148
|
connection = Bright::Connection.new(uri)
|
150
|
-
headers =
|
149
|
+
headers = headers_for_auth(uri)
|
151
150
|
connection.request(method, body, headers)
|
152
151
|
}
|
153
152
|
|
@@ -166,46 +165,45 @@ module Bright
|
|
166
165
|
def headers_for_auth(uri)
|
167
166
|
case api_version
|
168
167
|
when Gem::Version.new("1.1")
|
169
|
-
site = URI.parse(
|
168
|
+
site = URI.parse(connection_options[:uri])
|
170
169
|
site = "#{site.scheme}://#{site.host}"
|
171
|
-
consumer = OAuth::Consumer.new(
|
172
|
-
options = {:
|
170
|
+
consumer = OAuth::Consumer.new(connection_options[:client_id], connection_options[:client_secret], {site: site, scheme: :header})
|
171
|
+
options = {timestamp: Time.now.to_i, nonce: SecureRandom.uuid}
|
173
172
|
{"Authorization" => consumer.create_signed_request(:get, uri, nil, options)["Authorization"]}
|
174
173
|
when Gem::Version.new("1.2")
|
175
|
-
if
|
176
|
-
|
174
|
+
if connection_options[:access_token].nil? or connection_options[:access_token_expires] < Time.now
|
175
|
+
retrieve_access_token
|
177
176
|
end
|
178
177
|
{
|
179
|
-
"Authorization" => "Bearer #{
|
180
|
-
"Accept" => "application/json
|
181
|
-
"Content-Type" =>"application/json
|
178
|
+
"Authorization" => "Bearer #{connection_options[:access_token]}",
|
179
|
+
"Accept" => "application/json",
|
180
|
+
"Content-Type" => "application/json"
|
182
181
|
}
|
183
182
|
end
|
184
183
|
end
|
185
184
|
|
186
185
|
def retrieve_access_token
|
187
|
-
connection = Bright::Connection.new(
|
186
|
+
connection = Bright::Connection.new(connection_options[:token_uri])
|
188
187
|
response = connection.request(:post,
|
189
188
|
{
|
190
189
|
"grant_type" => "client_credentials",
|
191
|
-
"username" =>
|
192
|
-
"password" =>
|
190
|
+
"username" => connection_options[:client_id],
|
191
|
+
"password" => connection_options[:client_secret]
|
193
192
|
},
|
194
|
-
|
195
|
-
)
|
193
|
+
headers_for_access_token)
|
196
194
|
if !response.error?
|
197
195
|
response_hash = JSON.parse(response.body)
|
198
196
|
end
|
199
197
|
if response_hash["access_token"]
|
200
|
-
|
201
|
-
|
198
|
+
connection_options[:access_token] = response_hash["access_token"]
|
199
|
+
connection_options[:access_token_expires] = (Time.now - 10) + response_hash["expires_in"]
|
202
200
|
end
|
203
201
|
response_hash
|
204
202
|
end
|
205
203
|
|
206
204
|
def headers_for_access_token
|
207
205
|
{
|
208
|
-
"Authorization" => "Basic #{Base64.strict_encode64("#{
|
206
|
+
"Authorization" => "Basic #{Base64.strict_encode64("#{connection_options[:client_id]}:#{connection_options[:client_secret]}")}",
|
209
207
|
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
210
208
|
}
|
211
209
|
end
|
@@ -215,7 +213,7 @@ module Bright
|
|
215
213
|
default_params = {}
|
216
214
|
|
217
215
|
filter = []
|
218
|
-
params.each do |k,v|
|
216
|
+
params.each do |k, v|
|
219
217
|
case k.to_s
|
220
218
|
when "first_name"
|
221
219
|
filter << "givenName='#{v}'"
|
@@ -236,14 +234,14 @@ module Bright
|
|
236
234
|
unless filter.empty?
|
237
235
|
params = {"filter" => filter.join(" AND ")}
|
238
236
|
end
|
239
|
-
default_params.merge(params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
237
|
+
default_params.merge(params).reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
240
238
|
end
|
241
239
|
|
242
240
|
def map_school_search_params(params)
|
243
241
|
params = params.dup
|
244
242
|
default_params = {}
|
245
243
|
filter = []
|
246
|
-
params.each do |k,v|
|
244
|
+
params.each do |k, v|
|
247
245
|
case k.to_s
|
248
246
|
when "number"
|
249
247
|
filter << "identifier='#{v}'"
|
@@ -256,50 +254,46 @@ module Bright
|
|
256
254
|
unless filter.empty?
|
257
255
|
params = {"filter" => filter.join(" AND ")}
|
258
256
|
end
|
259
|
-
default_params.merge(params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
257
|
+
default_params.merge(params).reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
260
258
|
end
|
261
259
|
|
262
260
|
def convert_to_school_data(school_params)
|
263
261
|
return {} if school_params.blank?
|
264
|
-
|
265
|
-
:
|
266
|
-
:
|
267
|
-
:
|
268
|
-
:
|
262
|
+
{
|
263
|
+
api_id: school_params["sourcedId"],
|
264
|
+
name: school_params["name"],
|
265
|
+
number: school_params["identifier"],
|
266
|
+
last_modified: school_params["dateLastModified"]
|
269
267
|
}
|
270
|
-
return school_data_hsh
|
271
268
|
end
|
272
269
|
|
273
270
|
def convert_to_user_data(user_params, bright_type: "Student")
|
274
271
|
return {} if user_params.blank?
|
275
272
|
user_data_hsh = {
|
276
|
-
:
|
277
|
-
:
|
278
|
-
:
|
279
|
-
:
|
280
|
-
:
|
281
|
-
}.reject{|k,v| v.blank?}
|
273
|
+
api_id: user_params["sourcedId"],
|
274
|
+
first_name: user_params["givenName"],
|
275
|
+
middle_name: user_params["middleName"],
|
276
|
+
last_name: user_params["familyName"],
|
277
|
+
last_modified: user_params["dateLastModified"]
|
278
|
+
}.reject { |k, v| v.blank? }
|
282
279
|
unless user_params["identifier"].blank?
|
283
280
|
user_data_hsh[:sis_student_id] = user_params["identifier"]
|
284
281
|
end
|
285
|
-
unless user_params["userMasterIdentifier"].blank?
|
286
|
-
user_data_hsh[:state_student_id] = user_params["userMasterIdentifier"]
|
287
|
-
end
|
288
282
|
unless user_params["userIds"].blank?
|
289
|
-
if (state_id_hsh = user_params["userIds"].detect{|user_id_hsh| user_id_hsh["type"] == "stateID"})
|
283
|
+
if (state_id_hsh = user_params["userIds"].detect { |user_id_hsh| user_id_hsh["type"] == "stateID" })
|
290
284
|
user_data_hsh[:state_student_id] = state_id_hsh["identifier"]
|
291
285
|
end
|
292
286
|
end
|
293
287
|
unless user_params["email"].blank?
|
294
288
|
user_data_hsh[:email_address] = {
|
295
|
-
:
|
289
|
+
email_address: user_params["email"]
|
296
290
|
}
|
297
291
|
end
|
298
292
|
unless user_params["orgs"].blank?
|
299
|
-
if (s = user_params["orgs"].detect{|org| org["href"] =~ /\/schools\//})
|
293
|
+
if (s = user_params["orgs"].detect { |org| org["href"] =~ /\/schools\// })
|
300
294
|
self.schools_cache ||= {}
|
301
295
|
if (attending_school = self.schools_cache[s["sourcedId"]]).nil?
|
302
|
-
attending_school =
|
296
|
+
attending_school = get_school_by_api_id(s["sourcedId"])
|
303
297
|
self.schools_cache[attending_school.api_id] = attending_school
|
304
298
|
end
|
305
299
|
end
|
@@ -308,26 +302,24 @@ module Bright
|
|
308
302
|
end
|
309
303
|
end
|
310
304
|
unless user_params["phone"].blank?
|
311
|
-
user_data_hsh[:phone_numbers] = [{:
|
305
|
+
user_data_hsh[:phone_numbers] = [{phone_number: user_params["phone"]}]
|
312
306
|
end
|
313
307
|
unless user_params["sms"].blank?
|
314
308
|
user_data_hsh[:phone_numbers] ||= []
|
315
|
-
user_data_hsh[:phone_numbers] << {:
|
309
|
+
user_data_hsh[:phone_numbers] << {phone_number: user_params["sms"]}
|
316
310
|
end
|
317
311
|
|
318
|
-
#add the demographic information
|
312
|
+
# add the demographic information
|
319
313
|
demographics_hash = get_demographic_information(user_data_hsh[:api_id])
|
320
314
|
user_data_hsh.merge!(demographics_hash) unless demographics_hash.blank?
|
321
315
|
|
322
|
-
#if you're a student, build the contacts too
|
316
|
+
# if you're a student, build the contacts too
|
323
317
|
if bright_type == "Student" and !user_params["agents"].blank?
|
324
318
|
user_data_hsh[:contacts] = user_params["agents"].collect do |agent_hsh|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
raise e
|
330
|
-
end
|
319
|
+
get_contact_by_api_id(agent_hsh["sourcedId"])
|
320
|
+
rescue Bright::ResponseError => e
|
321
|
+
if !e.message.to_s.include?("404")
|
322
|
+
raise e
|
331
323
|
end
|
332
324
|
end.compact
|
333
325
|
user_data_hsh[:grade] = (user_params["grades"] || []).first
|
@@ -336,7 +328,7 @@ module Bright
|
|
336
328
|
end
|
337
329
|
end
|
338
330
|
|
339
|
-
|
331
|
+
user_data_hsh
|
340
332
|
end
|
341
333
|
|
342
334
|
def get_demographic_information(api_id)
|
@@ -345,7 +337,7 @@ module Bright
|
|
345
337
|
begin
|
346
338
|
demographics_params = request(:get, "demographics/#{api_id}")["demographics"]
|
347
339
|
rescue Bright::ResponseError => e
|
348
|
-
if e.message.to_s.include?(
|
340
|
+
if e.message.to_s.include?("404")
|
349
341
|
return demographic_hsh
|
350
342
|
else
|
351
343
|
raise e
|
@@ -368,22 +360,21 @@ module Bright
|
|
368
360
|
end
|
369
361
|
end
|
370
362
|
end
|
371
|
-
|
363
|
+
demographic_hsh
|
372
364
|
end
|
373
365
|
|
374
366
|
def get_grade_school_year(date = Date.today)
|
375
|
-
#return the school year of a specific date
|
367
|
+
# return the school year of a specific date
|
376
368
|
self.school_years_cache ||= {}
|
377
369
|
if self.school_years_cache[date].nil?
|
378
|
-
academic_periods_params =
|
379
|
-
school_years = academic_periods_params.map{|ap| ap["schoolYear"]}.uniq
|
370
|
+
academic_periods_params = request(:get, "academicSessions", {"filter" => "startDate<='#{date}' AND endDate>='#{date}' AND status='active'"})["academicSessions"]
|
371
|
+
school_years = academic_periods_params.map { |ap| ap["schoolYear"] }.uniq
|
380
372
|
if school_years.size == 1
|
381
373
|
self.school_years_cache[date] = school_years.first
|
382
374
|
end
|
383
375
|
end
|
384
|
-
|
376
|
+
self.school_years_cache[date]
|
385
377
|
end
|
386
|
-
|
387
378
|
end
|
388
379
|
end
|
389
380
|
end
|