bright 0.2.0 → 1.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/LICENSE.txt +1 -1
- data/bright.gemspec +3 -3
- data/lib/bright/address.rb +6 -8
- data/lib/bright/connection.rb +49 -42
- data/lib/bright/contact.rb +53 -0
- data/lib/bright/cursor_response_collection.rb +45 -0
- data/lib/bright/errors.rb +13 -3
- data/lib/bright/helpers/boolean_parser_helper.rb +13 -0
- data/lib/bright/phone_number.rb +14 -2
- data/lib/bright/response_collection.rb +7 -7
- data/lib/bright/sis_apis/aeries.rb +34 -33
- data/lib/bright/sis_apis/base.rb +31 -5
- data/lib/bright/sis_apis/bright_sis.rb +70 -16
- data/lib/bright/sis_apis/infinite_campus.rb +254 -36
- data/lib/bright/sis_apis/power_school.rb +107 -66
- data/lib/bright/sis_apis/skyward.rb +276 -0
- data/lib/bright/sis_apis/tsis.rb +42 -40
- data/lib/bright/student.rb +27 -1
- data/lib/bright/version.rb +1 -1
- data/lib/bright.rb +8 -1
- metadata +17 -14
@@ -3,34 +3,34 @@ module Bright
|
|
3
3
|
class PowerSchool < Base
|
4
4
|
DATE_FORMAT = '%Y-%m-%d'
|
5
5
|
INVALID_SEARCH_CHAR_RE = /[\,\;]/
|
6
|
-
|
6
|
+
|
7
7
|
@@description = "Connects to the PowerSchool API for accessing student information"
|
8
8
|
@@doc_url = "http://psimages.sunnysideschools.org/api-developer-guide-1.6.0/"
|
9
9
|
@@api_version = "1.6.0"
|
10
|
-
|
10
|
+
|
11
11
|
attr_accessor :connection_options, :expansion_options
|
12
|
-
|
12
|
+
|
13
13
|
def initialize(options = {})
|
14
14
|
self.connection_options = options[:connection] || {}
|
15
15
|
self.expansion_options = options[:expansion] || {}
|
16
16
|
# {
|
17
|
-
# :client_id => "",
|
17
|
+
# :client_id => "",
|
18
18
|
# :client_secret => "",
|
19
19
|
# :uri => ""
|
20
20
|
# :access_token => "", #optional
|
21
21
|
# }
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def get_student_by_api_id(api_id, params = {})
|
25
25
|
params = self.apply_expansions(params)
|
26
26
|
st_hsh = self.request(:get, "ws/v1/student/#{api_id}", params)
|
27
27
|
Student.new(convert_to_student_data(st_hsh["student"])) if st_hsh and st_hsh["student"]
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def get_student(params = {}, options = {})
|
31
31
|
self.get_students(params, options.merge(:per_page => 1, :wrap_in_collection => false)).first
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def get_students(params = {}, options = {})
|
35
35
|
params = self.apply_expansions(params)
|
36
36
|
params = self.apply_options(params, options)
|
@@ -44,22 +44,23 @@ module Bright
|
|
44
44
|
students_response_hash = self.request(:get, 'ws/v1/district/student', self.map_student_search_params(params))
|
45
45
|
if students_response_hash and students_response_hash["students"] && students_response_hash["students"]["student"]
|
46
46
|
students_hash = [students_response_hash["students"]["student"]].flatten
|
47
|
-
|
47
|
+
|
48
48
|
students = students_hash.compact.collect {|st_hsh|
|
49
49
|
Student.new(convert_to_student_data(st_hsh))
|
50
50
|
}
|
51
|
-
|
51
|
+
|
52
52
|
if options[:wrap_in_collection] != false
|
53
53
|
api = self
|
54
54
|
load_more_call = proc { |page|
|
55
55
|
# pages start at one, so add a page here
|
56
|
-
|
56
|
+
params[:page] = (page + 1)
|
57
|
+
api.get_students(params, {:wrap_in_collection => false})
|
57
58
|
}
|
58
59
|
|
59
60
|
ResponseCollection.new({
|
60
|
-
:seed_page => students,
|
61
|
+
:seed_page => students,
|
61
62
|
:total => total_results,
|
62
|
-
:per_page => params[:pagesize],
|
63
|
+
:per_page => params[:pagesize],
|
63
64
|
:load_more_call => load_more_call
|
64
65
|
})
|
65
66
|
else
|
@@ -69,7 +70,7 @@ module Bright
|
|
69
70
|
[]
|
70
71
|
end
|
71
72
|
end
|
72
|
-
|
73
|
+
|
73
74
|
def create_student(student, additional_params = {})
|
74
75
|
response = self.request(:post, 'ws/v1/student', self.convert_from_student_data(student, "INSERT", additional_params))
|
75
76
|
if response["results"] and response["results"]["insert_count"] == 1
|
@@ -87,7 +88,7 @@ module Bright
|
|
87
88
|
end
|
88
89
|
student
|
89
90
|
end
|
90
|
-
|
91
|
+
|
91
92
|
def update_student(student, additional_params = {})
|
92
93
|
response = self.request(:post, 'ws/v1/student', self.convert_from_student_data(student, "UPDATE", additional_params))
|
93
94
|
if response["results"] and response["results"]["update_count"] == 1
|
@@ -98,11 +99,11 @@ module Bright
|
|
98
99
|
student
|
99
100
|
end
|
100
101
|
end
|
101
|
-
|
102
|
+
|
102
103
|
def subscribe_student(student)
|
103
104
|
raise NotImplementedError
|
104
105
|
end
|
105
|
-
|
106
|
+
|
106
107
|
def get_schools(params = {}, options = {})
|
107
108
|
params = self.apply_options(params, options)
|
108
109
|
|
@@ -113,32 +114,32 @@ module Bright
|
|
113
114
|
end
|
114
115
|
|
115
116
|
schools_response_hash = self.request(:get, 'ws/v1/district/school', params)
|
116
|
-
puts schools_response_hash.inspect
|
117
117
|
schools_hsh = [schools_response_hash["schools"]["school"]].flatten
|
118
|
-
|
118
|
+
|
119
119
|
schools = schools_hsh.compact.collect {|st_hsh|
|
120
120
|
School.new(convert_to_school_data(st_hsh))
|
121
121
|
}
|
122
|
-
|
122
|
+
|
123
123
|
if options[:wrap_in_collection] != false
|
124
124
|
api = self
|
125
125
|
load_more_call = proc { |page|
|
126
126
|
# pages start at one, so add a page here
|
127
|
-
|
127
|
+
params[:page] = (page + 1)
|
128
|
+
api.get_schools(params, {:wrap_in_collection => false})
|
128
129
|
}
|
129
130
|
|
130
131
|
ResponseCollection.new({
|
131
|
-
:seed_page => schools,
|
132
|
+
:seed_page => schools,
|
132
133
|
:total => total_results,
|
133
|
-
:per_page => params[:pagesize],
|
134
|
+
:per_page => params[:pagesize],
|
134
135
|
:load_more_call => load_more_call
|
135
136
|
})
|
136
137
|
else
|
137
138
|
schools
|
138
139
|
end
|
139
140
|
end
|
140
|
-
|
141
|
-
def
|
141
|
+
|
142
|
+
def retrieve_access_token
|
142
143
|
connection = Bright::Connection.new("#{self.connection_options[:uri]}/oauth/access_token/")
|
143
144
|
response = connection.request(:post, "grant_type=client_credentials", self.headers_for_access_token)
|
144
145
|
if !response.error?
|
@@ -149,7 +150,7 @@ module Bright
|
|
149
150
|
end
|
150
151
|
response_hash
|
151
152
|
end
|
152
|
-
|
153
|
+
|
153
154
|
def request(method, path, params = {})
|
154
155
|
uri = "#{self.connection_options[:uri]}/#{path}"
|
155
156
|
body = nil
|
@@ -159,12 +160,14 @@ module Bright
|
|
159
160
|
else
|
160
161
|
body = JSON.dump(params)
|
161
162
|
end
|
162
|
-
|
163
|
-
headers = self.headers_for_auth
|
164
163
|
|
165
|
-
|
166
|
-
response =
|
167
|
-
|
164
|
+
|
165
|
+
response = connection_retry_wrapper {
|
166
|
+
connection = Bright::Connection.new(uri)
|
167
|
+
headers = self.headers_for_auth
|
168
|
+
connection.request(method, body, headers)
|
169
|
+
}
|
170
|
+
|
168
171
|
if !response.error?
|
169
172
|
response_hash = JSON.parse(response.body)
|
170
173
|
else
|
@@ -173,13 +176,13 @@ module Bright
|
|
173
176
|
end
|
174
177
|
response_hash
|
175
178
|
end
|
176
|
-
|
179
|
+
|
177
180
|
protected
|
178
|
-
|
181
|
+
|
179
182
|
def map_student_search_params(params)
|
180
183
|
params = params.dup
|
181
184
|
default_params = {}
|
182
|
-
|
185
|
+
|
183
186
|
q = ""
|
184
187
|
%w(first_name middle_name last_name).each do |f|
|
185
188
|
if fn = params.delete(f.to_sym)
|
@@ -199,23 +202,23 @@ module Bright
|
|
199
202
|
|
200
203
|
default_params.merge(params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
201
204
|
end
|
202
|
-
|
205
|
+
|
203
206
|
def convert_to_student_data(attrs)
|
204
207
|
cattrs = {}
|
205
|
-
|
208
|
+
|
206
209
|
if attrs["name"]
|
207
210
|
cattrs[:first_name] = attrs["name"]["first_name"]
|
208
211
|
cattrs[:middle_name] = attrs["name"]["middle_name"]
|
209
212
|
cattrs[:last_name] = attrs["name"]["last_name"]
|
210
213
|
end
|
211
|
-
|
214
|
+
|
212
215
|
cattrs[:api_id] = attrs["id"].to_s
|
213
216
|
cattrs[:sis_student_id] = attrs["local_id"].to_s
|
214
|
-
cattrs[:state_student_id]
|
215
|
-
|
217
|
+
cattrs[:state_student_id] = attrs["state_province_id"].to_s
|
218
|
+
|
216
219
|
if attrs["demographics"]
|
217
220
|
if attrs["demographics"]["birth_date"]
|
218
|
-
begin
|
221
|
+
begin
|
219
222
|
cattrs[:birth_date] = Date.strptime(attrs["demographics"]["birth_date"], DATE_FORMAT)
|
220
223
|
rescue => e
|
221
224
|
puts "#{e.inspect} #{bd}"
|
@@ -227,17 +230,48 @@ module Bright
|
|
227
230
|
pg = attrs["demographics"]["projected_graduation_year"].to_i
|
228
231
|
cattrs[:projected_graduation_year] = pg if pg > 0
|
229
232
|
end
|
230
|
-
|
233
|
+
|
234
|
+
#Student Address
|
231
235
|
begin
|
232
|
-
|
233
|
-
|
234
|
-
|
236
|
+
cattrs[:addresses] = attrs["addresses"].to_a.collect{|a| self.convert_to_address_data(a)}.select{|a| !a[:street].blank?}.uniq{|a| a[:street]} if attrs["addresses"]
|
237
|
+
rescue
|
238
|
+
end
|
239
|
+
|
240
|
+
#Ethnicity / Race Info
|
241
|
+
if attrs["ethnicity_race"].is_a?(Hash)
|
242
|
+
if !(race_hshs = attrs.dig("ethnicity_race", "races")).nil?
|
243
|
+
#this should be an array, but it doesn't appear PS always sends it as one
|
244
|
+
cattrs[:race] = [race_hshs].flatten.map{|race_hsh| race_hsh["district_race_code"]}.compact.uniq
|
245
|
+
end
|
246
|
+
|
247
|
+
if !attrs.dig("ethnicity_race", "federal_ethnicity").nil?
|
248
|
+
cattrs[:hispanic_ethnicity] = attrs.dig("ethnicity_race", "federal_ethnicity").to_bool
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
#Contacts Info
|
253
|
+
[1,2].each do |contact_id|
|
254
|
+
if !attrs.dig("contact", "emergency_contact_name#{contact_id}").blank? and !attrs.dig("contact", "emergency_phone#{contact_id}").blank?
|
255
|
+
cattrs[:contacts] ||= []
|
256
|
+
contact_attrs = {
|
257
|
+
:first_name => attrs.dig("contact", "emergency_contact_name#{contact_id}").to_s.split(",").last.strip,
|
258
|
+
:last_name => attrs.dig("contact", "emergency_contact_name#{contact_id}").to_s.split(",").first.strip,
|
259
|
+
:phone_numbers => [
|
260
|
+
{
|
261
|
+
:phone_number => attrs.dig("contact", "emergency_phone#{contact_id}")
|
262
|
+
}
|
263
|
+
]
|
264
|
+
}
|
265
|
+
cattrs[:contacts] << contact_attrs
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
235
269
|
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
236
270
|
end
|
237
|
-
|
271
|
+
|
238
272
|
def convert_from_student_data(student, action = nil, additional_params = {})
|
239
273
|
return {} if student.nil?
|
240
|
-
|
274
|
+
|
241
275
|
student_data = {
|
242
276
|
:client_uid => student.client_id,
|
243
277
|
:action => action,
|
@@ -245,7 +279,7 @@ module Bright
|
|
245
279
|
:local_id => student.sis_student_id,
|
246
280
|
:state_province_id => student.state_student_id,
|
247
281
|
:name => {
|
248
|
-
:first_name => student.first_name,
|
282
|
+
:first_name => student.first_name,
|
249
283
|
:middle_name => student.middle_name,
|
250
284
|
:last_name => student.last_name
|
251
285
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?},
|
@@ -255,12 +289,12 @@ module Bright
|
|
255
289
|
:projected_graduation_year => student.projected_graduation_year
|
256
290
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
257
291
|
}.merge(additional_params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
258
|
-
|
292
|
+
|
259
293
|
# apply enrollment info
|
260
294
|
if student.enrollment
|
261
|
-
student_data.merge!(self.convert_from_enrollment_data(student.enrollment))
|
295
|
+
student_data.merge!(self.convert_from_enrollment_data(student.enrollment))
|
262
296
|
end
|
263
|
-
|
297
|
+
|
264
298
|
# apply addresses
|
265
299
|
address_data = {}
|
266
300
|
if ph = student.addresses.detect{|a| a.type == "physical"}
|
@@ -275,12 +309,12 @@ module Bright
|
|
275
309
|
address_data.merge!(self.convert_from_address_data(cany))
|
276
310
|
end
|
277
311
|
if address_data.size > 0
|
278
|
-
student_data.merge!({:addresses => address_data})
|
312
|
+
student_data.merge!({:addresses => address_data})
|
279
313
|
end
|
280
|
-
|
314
|
+
|
281
315
|
{:students => {:student => student_data}}
|
282
316
|
end
|
283
|
-
|
317
|
+
|
284
318
|
def convert_from_enrollment_data(enrollment)
|
285
319
|
return {} if enrollment.nil?
|
286
320
|
{:school_enrollment => {
|
@@ -294,17 +328,24 @@ module Bright
|
|
294
328
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
295
329
|
}
|
296
330
|
end
|
297
|
-
|
331
|
+
|
298
332
|
def convert_to_school_data(attrs)
|
299
333
|
cattrs = {}
|
300
|
-
|
301
334
|
cattrs[:api_id] = attrs["id"]
|
302
335
|
cattrs[:name] = attrs["name"]
|
303
336
|
cattrs[:number] = attrs["school_number"]
|
304
|
-
|
337
|
+
cattrs[:low_grade] = attrs["low_grade"]
|
338
|
+
cattrs[:high_grade] = attrs["high_grade"]
|
339
|
+
if (address_attributes = attrs.dig("addresses"))
|
340
|
+
cattrs[:address] = convert_to_address_data(address_attributes)
|
341
|
+
end
|
342
|
+
if (phone_number_attributes = attrs.dig("phones", "main", "number"))
|
343
|
+
cattrs[:phone_number] = {:phone_number => phone_number_attributes}
|
344
|
+
end
|
345
|
+
|
305
346
|
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
306
347
|
end
|
307
|
-
|
348
|
+
|
308
349
|
def convert_from_address_data(address)
|
309
350
|
{
|
310
351
|
(address.type || "physcial") => {
|
@@ -316,10 +357,10 @@ module Bright
|
|
316
357
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
317
358
|
}
|
318
359
|
end
|
319
|
-
|
360
|
+
|
320
361
|
def convert_to_address_data(attrs)
|
321
362
|
cattrs = {}
|
322
|
-
|
363
|
+
|
323
364
|
if attrs.is_a?(Array)
|
324
365
|
if attrs.first.is_a?(String)
|
325
366
|
cattrs[:type] = attrs.first
|
@@ -337,12 +378,12 @@ module Bright
|
|
337
378
|
cattrs[:state] = attrs["state_province"]
|
338
379
|
cattrs[:postal_code] = attrs["postal_code"]
|
339
380
|
if attrs["grid_location"] and lat_lng = attrs["grid_location"].split(/,\s?/)
|
340
|
-
cattrs[:
|
381
|
+
cattrs[:latitude], cattrs[:longitude] = lat_lng
|
341
382
|
end
|
342
|
-
|
383
|
+
|
343
384
|
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
344
385
|
end
|
345
|
-
|
386
|
+
|
346
387
|
def apply_expansions(params)
|
347
388
|
if self.expansion_options.empty?
|
348
389
|
hsh = self.request(:get, 'ws/v1/district/student', {:pagesize => 1, :q => "local_id==0"})
|
@@ -359,22 +400,22 @@ module Bright
|
|
359
400
|
:extensions => (%w(studentcorefields) & (self.expansion_options[:extensions] || [])).join(",")
|
360
401
|
}.reject{|k,v| v.empty?})
|
361
402
|
end
|
362
|
-
|
403
|
+
|
363
404
|
def apply_options(params, options)
|
364
405
|
options[:per_page] = params[:pagesize] ||= params.delete(:per_page) || options[:per_page] || 100
|
365
406
|
params[:page] ||= options[:page] || 1
|
366
407
|
params
|
367
408
|
end
|
368
|
-
|
409
|
+
|
369
410
|
def headers_for_access_token
|
370
411
|
{
|
371
412
|
"Authorization" => "Basic #{Base64.strict_encode64("#{self.connection_options[:client_id]}:#{self.connection_options[:client_secret]}")}",
|
372
413
|
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
373
414
|
}
|
374
415
|
end
|
375
|
-
|
416
|
+
|
376
417
|
def headers_for_auth
|
377
|
-
self.
|
418
|
+
self.retrieve_access_token if self.connection_options[:access_token].nil?
|
378
419
|
{
|
379
420
|
"Authorization" => "Bearer #{self.connection_options[:access_token]}",
|
380
421
|
"Accept" => "application/json;charset=UTF-8",
|
@@ -383,4 +424,4 @@ module Bright
|
|
383
424
|
end
|
384
425
|
end
|
385
426
|
end
|
386
|
-
end
|
427
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
module Bright
|
2
|
+
module SisApi
|
3
|
+
class Skyward < Base
|
4
|
+
|
5
|
+
@@description = "Connects to the Skyward API for accessing student information"
|
6
|
+
@@doc_url = "https://esdemo1.skyward.com/api/swagger/ui/index"
|
7
|
+
@@api_version = "v1"
|
8
|
+
|
9
|
+
attr_accessor :connection_options, :schools_cache
|
10
|
+
|
11
|
+
DEMOGRAPHICS_CONVERSION = {
|
12
|
+
"I"=>"American Indian Or Alaska Native",
|
13
|
+
"A"=>"Asian",
|
14
|
+
"B"=>"Black Or African American",
|
15
|
+
"P"=>"Native Hawaiian Or Other Pacific Islander",
|
16
|
+
"W"=>"White"
|
17
|
+
}
|
18
|
+
|
19
|
+
PHONE_TYPE_CONVERSION = {
|
20
|
+
"Cellular" => "Cell",
|
21
|
+
"Work" => "Work",
|
22
|
+
"Home" => "Home",
|
23
|
+
"Other" => "Other"
|
24
|
+
}
|
25
|
+
|
26
|
+
def initialize(options = {})
|
27
|
+
self.connection_options = options[:connection] || {}
|
28
|
+
# {
|
29
|
+
# :client_id => "",
|
30
|
+
# :client_secret => "",
|
31
|
+
# :uri => "https://skywardinstall.com/API"
|
32
|
+
# }
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_student_by_api_id(api_id, params = {})
|
36
|
+
st_hsh = self.request(:get, "v1/students/#{api_id}", params)[:parsed_body]
|
37
|
+
Student.new(convert_to_user_data(st_hsh, {:type => "Student"})) unless st_hsh.blank?
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_students(params = {}, options = {})
|
41
|
+
params["paging.limit"] = params[:limit] || options[:limit] || 1000
|
42
|
+
students_response = self.request(:get, 'v1/students', params)
|
43
|
+
if !students_response[:parsed_body].blank?
|
44
|
+
students = students_response[:parsed_body].compact.collect {|st_hsh|
|
45
|
+
Student.new(convert_to_user_data(st_hsh, {:type => "Student"}))
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
next_cursor = nil
|
50
|
+
if students_response[:headers]["Link"]
|
51
|
+
students_response[:headers]["Link"].split(",").each do |part, index|
|
52
|
+
section = part.split(';')
|
53
|
+
url = section[0][/<(.*)>/,1]
|
54
|
+
name = section[1][/rel="(.*)"/,1].to_s
|
55
|
+
if name == "next"
|
56
|
+
next_cursor = CGI.parse(URI.parse(url).query)["cursor"].first
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
if options[:wrap_in_collection] != false
|
61
|
+
api = self
|
62
|
+
load_more_call = proc {|cursor|
|
63
|
+
params["paging.cursor"] = cursor
|
64
|
+
options = {:wrap_in_collection => false, :include_cursor => true}
|
65
|
+
api.get_students(params, options)
|
66
|
+
}
|
67
|
+
CursorResponseCollection.new({
|
68
|
+
:seed_page => students,
|
69
|
+
:load_more_call => load_more_call,
|
70
|
+
:next_cursor => next_cursor
|
71
|
+
})
|
72
|
+
elsif options[:include_cursor] == true
|
73
|
+
return {:objects => students, :next_cursor => next_cursor}
|
74
|
+
else
|
75
|
+
return students
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_school_by_api_id(api_id, params = {})
|
80
|
+
sc_hsh = self.request(:get, "v1/schools/#{api_id}", params)[:parsed_body]
|
81
|
+
School.new(convert_to_school_data(sc_hsh)) unless sc_hsh.blank?
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_schools(params = {}, options = {})
|
85
|
+
params["paging.limit"] = params[:limit] || options[:limit] || 10000
|
86
|
+
schools_hshs = self.request(:get, "v1/schools", params)[:parsed_body]
|
87
|
+
if !schools_hshs.blank?
|
88
|
+
schools = schools_hshs.compact.collect {|sc_hsh|
|
89
|
+
School.new(convert_to_school_data(sc_hsh))
|
90
|
+
}
|
91
|
+
end
|
92
|
+
return schools
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_contact_by_api_id(api_id, params = {})
|
96
|
+
contact_hsh = self.request(:get, "v1/names/#{api_id}", params)[:parsed_body]
|
97
|
+
Contact.new(convert_to_user_data(contact_hsh, {:type => "Contact"})) unless contact_hsh.blank?
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_guardians_by_api_id(api_id, params = {})
|
101
|
+
guardians = []
|
102
|
+
guardians_array = self.request(:get, "v1/guardians", params.merge({"studentNameId" => api_id}))[:parsed_body]
|
103
|
+
if !guardians_array.blank?
|
104
|
+
guardians_array.each do |guardian_hsh|
|
105
|
+
relationship_type = guardian_hsh.delete("Students").detect{|s_hsh| s_hsh["StudentNameId"].to_s == api_id.to_s}["RelationshipDesc"]
|
106
|
+
guardian_hsh["RelationshipType"] = relationship_type
|
107
|
+
guardian_hsh["NameId"] = guardian_hsh.delete("GuardianNameId")
|
108
|
+
guardians << Contact.new(convert_to_user_data(guardian_hsh, {:type => "Contact"}))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return guardians
|
112
|
+
end
|
113
|
+
|
114
|
+
def retrieve_access_token
|
115
|
+
connection = Bright::Connection.new("#{self.connection_options[:uri]}/token")
|
116
|
+
response = connection.request(:post,
|
117
|
+
{"grant_type" => "password",
|
118
|
+
"username" => self.connection_options[:client_id],
|
119
|
+
"password" => self.connection_options[:client_secret]
|
120
|
+
},
|
121
|
+
self.headers_for_access_token)
|
122
|
+
if !response.error?
|
123
|
+
response_hash = JSON.parse(response.body)
|
124
|
+
end
|
125
|
+
if response_hash["access_token"]
|
126
|
+
self.connection_options[:access_token] = response_hash["access_token"]
|
127
|
+
self.connection_options[:access_token_expires] = (Time.now - 10) + response_hash["expires_in"]
|
128
|
+
end
|
129
|
+
response_hash
|
130
|
+
end
|
131
|
+
|
132
|
+
def request(method, path, params = {})
|
133
|
+
uri = "#{self.connection_options[:uri]}/#{path}"
|
134
|
+
body = nil
|
135
|
+
if method == :get
|
136
|
+
query = URI.encode_www_form(params)
|
137
|
+
uri += "?#{query}"
|
138
|
+
else
|
139
|
+
body = JSON.dump(params)
|
140
|
+
end
|
141
|
+
|
142
|
+
response = connection_retry_wrapper {
|
143
|
+
connection = Bright::Connection.new(uri)
|
144
|
+
headers = self.headers_for_auth
|
145
|
+
connection.request(method, body, headers)
|
146
|
+
}
|
147
|
+
|
148
|
+
if !response.error?
|
149
|
+
response_hash = JSON.parse(response.body)
|
150
|
+
else
|
151
|
+
puts "#{response.inspect}"
|
152
|
+
puts "#{response.body}"
|
153
|
+
end
|
154
|
+
return {:parsed_body => response_hash, :headers => response.headers}
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
|
159
|
+
def convert_to_user_data(user_params, options = {})
|
160
|
+
# :type => "Contact" || "Student"
|
161
|
+
return {} if user_params.blank?
|
162
|
+
|
163
|
+
user_data_hsh = {
|
164
|
+
:api_id => user_params["NameId"],
|
165
|
+
:first_name => user_params["FirstName"],
|
166
|
+
:middle_name => user_params["MiddleName"],
|
167
|
+
:last_name => user_params["LastName"],
|
168
|
+
:sis_student_id => user_params["DisplayId"],
|
169
|
+
:state_student_id => user_params["StateId"],
|
170
|
+
:projected_graduation_year => user_params["GradYr"],
|
171
|
+
:gender => user_params["Gender"],
|
172
|
+
:hispanic_ethnicity => user_params["HispanicLatinoEthnicity"],
|
173
|
+
:relationship_type => user_params["RelationshipType"]
|
174
|
+
}.reject{|k,v| v.blank?}
|
175
|
+
unless user_params["DateOfBirth"].blank?
|
176
|
+
user_data_hsh[:birth_date] = Date.parse(user_params["DateOfBirth"]).to_s
|
177
|
+
end
|
178
|
+
|
179
|
+
DEMOGRAPHICS_CONVERSION.each do |demographics_key, demographics_value|
|
180
|
+
if user_params["FederalRace"].to_s.upcase.include?(demographics_key)
|
181
|
+
user_data_hsh[:race] ||= []
|
182
|
+
user_data_hsh[:race] << demographics_value
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
unless user_params["SchoolEmail"].blank?
|
187
|
+
user_data_hsh[:email_address] = {
|
188
|
+
:email_address => user_params["SchoolEmail"]
|
189
|
+
}
|
190
|
+
end
|
191
|
+
|
192
|
+
unless user_params["Email"].blank?
|
193
|
+
user_data_hsh[:email_address] = {
|
194
|
+
:email_address => user_params["Email"]
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
unless user_params["DefaultSchoolId"].blank?
|
199
|
+
self.schools_cache ||= {}
|
200
|
+
if (attending_school = self.schools_cache[user_params["DefaultSchoolId"]]).nil?
|
201
|
+
attending_school = self.get_school_by_api_id(user_params["DefaultSchoolId"])
|
202
|
+
self.schools_cache[attending_school.api_id] = attending_school
|
203
|
+
end
|
204
|
+
user_data_hsh[:school] = attending_school
|
205
|
+
end
|
206
|
+
|
207
|
+
unless user_params["StreetAddress"].blank?
|
208
|
+
user_data_hsh[:addresses] = [{
|
209
|
+
:street => user_params["StreetAddress"],
|
210
|
+
:city => user_params["City"],
|
211
|
+
:state => user_params["State"],
|
212
|
+
:postal_code => user_params["ZipCode"]
|
213
|
+
}]
|
214
|
+
end
|
215
|
+
|
216
|
+
["PhoneNumber", "PhoneNumber2", "PhoneNumber3"].each do |phone_param|
|
217
|
+
if !user_params[phone_param].blank?
|
218
|
+
user_data_hsh[:phone_numbers] ||= []
|
219
|
+
user_data_hsh[:phone_numbers] << {
|
220
|
+
:phone_number => user_params[phone_param],
|
221
|
+
:type => PHONE_TYPE_CONVERSION[user_params["#{phone_param}Type"]]
|
222
|
+
}
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
if options[:type] == "Student"
|
227
|
+
#generate the contacts for a student
|
228
|
+
user_data_hsh[:contacts] = self.get_guardians_by_api_id(user_data_hsh[:api_id])
|
229
|
+
end
|
230
|
+
|
231
|
+
return user_data_hsh
|
232
|
+
end
|
233
|
+
|
234
|
+
def convert_to_school_data(school_params)
|
235
|
+
return {} if school_params.nil?
|
236
|
+
|
237
|
+
school_data_hsh = {
|
238
|
+
:api_id => school_params["SchoolId"],
|
239
|
+
:name => school_params["SchoolName"],
|
240
|
+
:low_grade => school_params["GradeLow"],
|
241
|
+
:high_grade => school_params["GradeHigh"],
|
242
|
+
}
|
243
|
+
|
244
|
+
unless school_params["StreetAddress"].blank?
|
245
|
+
school_data_hsh[:address] = {
|
246
|
+
:street => school_params["StreetAddress"],
|
247
|
+
:city => school_params["City"],
|
248
|
+
:state => school_params["State"],
|
249
|
+
:postal_code => school_params["ZipCode"]
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
return school_data_hsh
|
254
|
+
end
|
255
|
+
|
256
|
+
def headers_for_access_token
|
257
|
+
{
|
258
|
+
"Authorization" => "Basic #{Base64.strict_encode64("#{self.connection_options[:client_id]}:#{self.connection_options[:client_secret]}")}",
|
259
|
+
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
260
|
+
}
|
261
|
+
end
|
262
|
+
|
263
|
+
def headers_for_auth
|
264
|
+
if self.connection_options[:access_token].nil? or self.connection_options[:access_token_expires] < Time.now
|
265
|
+
self.retrieve_access_token
|
266
|
+
end
|
267
|
+
{
|
268
|
+
"Authorization" => "Bearer #{self.connection_options[:access_token]}",
|
269
|
+
"Accept" => "application/json;charset=UTF-8",
|
270
|
+
"Content-Type" =>"application/json;charset=UTF-8"
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|