bright 0.2.0 → 1.2
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 +6 -5
- 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/blank_helper.rb +40 -2
- data/lib/bright/helpers/boolean_parser_helper.rb +13 -0
- data/lib/bright/phone_number.rb +14 -2
- data/lib/bright/response_collection.rb +20 -19
- 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 +74 -18
- data/lib/bright/sis_apis/focus.rb +377 -0
- data/lib/bright/sis_apis/infinite_campus.rb +257 -37
- data/lib/bright/sis_apis/power_school.rb +111 -68
- 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 +28 -19
- metadata +33 -15
@@ -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,23 +44,25 @@ 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
|
-
:load_more_call => load_more_call
|
63
|
+
:per_page => params[:pagesize],
|
64
|
+
:load_more_call => load_more_call,
|
65
|
+
:no_threads => options[:no_threads]
|
64
66
|
})
|
65
67
|
else
|
66
68
|
students
|
@@ -69,7 +71,7 @@ module Bright
|
|
69
71
|
[]
|
70
72
|
end
|
71
73
|
end
|
72
|
-
|
74
|
+
|
73
75
|
def create_student(student, additional_params = {})
|
74
76
|
response = self.request(:post, 'ws/v1/student', self.convert_from_student_data(student, "INSERT", additional_params))
|
75
77
|
if response["results"] and response["results"]["insert_count"] == 1
|
@@ -87,7 +89,7 @@ module Bright
|
|
87
89
|
end
|
88
90
|
student
|
89
91
|
end
|
90
|
-
|
92
|
+
|
91
93
|
def update_student(student, additional_params = {})
|
92
94
|
response = self.request(:post, 'ws/v1/student', self.convert_from_student_data(student, "UPDATE", additional_params))
|
93
95
|
if response["results"] and response["results"]["update_count"] == 1
|
@@ -98,11 +100,11 @@ module Bright
|
|
98
100
|
student
|
99
101
|
end
|
100
102
|
end
|
101
|
-
|
103
|
+
|
102
104
|
def subscribe_student(student)
|
103
105
|
raise NotImplementedError
|
104
106
|
end
|
105
|
-
|
107
|
+
|
106
108
|
def get_schools(params = {}, options = {})
|
107
109
|
params = self.apply_options(params, options)
|
108
110
|
|
@@ -113,32 +115,33 @@ module Bright
|
|
113
115
|
end
|
114
116
|
|
115
117
|
schools_response_hash = self.request(:get, 'ws/v1/district/school', params)
|
116
|
-
puts schools_response_hash.inspect
|
117
118
|
schools_hsh = [schools_response_hash["schools"]["school"]].flatten
|
118
|
-
|
119
|
+
|
119
120
|
schools = schools_hsh.compact.collect {|st_hsh|
|
120
121
|
School.new(convert_to_school_data(st_hsh))
|
121
122
|
}
|
122
|
-
|
123
|
+
|
123
124
|
if options[:wrap_in_collection] != false
|
124
125
|
api = self
|
125
126
|
load_more_call = proc { |page|
|
126
127
|
# pages start at one, so add a page here
|
127
|
-
|
128
|
+
params[:page] = (page + 1)
|
129
|
+
api.get_schools(params, {:wrap_in_collection => false})
|
128
130
|
}
|
129
131
|
|
130
132
|
ResponseCollection.new({
|
131
|
-
:seed_page => schools,
|
133
|
+
:seed_page => schools,
|
132
134
|
:total => total_results,
|
133
|
-
:per_page => params[:pagesize],
|
134
|
-
:load_more_call => load_more_call
|
135
|
+
:per_page => params[:pagesize],
|
136
|
+
:load_more_call => load_more_call,
|
137
|
+
:no_threads => options[:no_threads]
|
135
138
|
})
|
136
139
|
else
|
137
140
|
schools
|
138
141
|
end
|
139
142
|
end
|
140
|
-
|
141
|
-
def
|
143
|
+
|
144
|
+
def retrieve_access_token
|
142
145
|
connection = Bright::Connection.new("#{self.connection_options[:uri]}/oauth/access_token/")
|
143
146
|
response = connection.request(:post, "grant_type=client_credentials", self.headers_for_access_token)
|
144
147
|
if !response.error?
|
@@ -149,7 +152,7 @@ module Bright
|
|
149
152
|
end
|
150
153
|
response_hash
|
151
154
|
end
|
152
|
-
|
155
|
+
|
153
156
|
def request(method, path, params = {})
|
154
157
|
uri = "#{self.connection_options[:uri]}/#{path}"
|
155
158
|
body = nil
|
@@ -159,12 +162,14 @@ module Bright
|
|
159
162
|
else
|
160
163
|
body = JSON.dump(params)
|
161
164
|
end
|
162
|
-
|
163
|
-
headers = self.headers_for_auth
|
164
165
|
|
165
|
-
|
166
|
-
response =
|
167
|
-
|
166
|
+
|
167
|
+
response = connection_retry_wrapper {
|
168
|
+
connection = Bright::Connection.new(uri)
|
169
|
+
headers = self.headers_for_auth
|
170
|
+
connection.request(method, body, headers)
|
171
|
+
}
|
172
|
+
|
168
173
|
if !response.error?
|
169
174
|
response_hash = JSON.parse(response.body)
|
170
175
|
else
|
@@ -173,13 +178,13 @@ module Bright
|
|
173
178
|
end
|
174
179
|
response_hash
|
175
180
|
end
|
176
|
-
|
181
|
+
|
177
182
|
protected
|
178
|
-
|
183
|
+
|
179
184
|
def map_student_search_params(params)
|
180
185
|
params = params.dup
|
181
186
|
default_params = {}
|
182
|
-
|
187
|
+
|
183
188
|
q = ""
|
184
189
|
%w(first_name middle_name last_name).each do |f|
|
185
190
|
if fn = params.delete(f.to_sym)
|
@@ -199,23 +204,23 @@ module Bright
|
|
199
204
|
|
200
205
|
default_params.merge(params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
201
206
|
end
|
202
|
-
|
207
|
+
|
203
208
|
def convert_to_student_data(attrs)
|
204
209
|
cattrs = {}
|
205
|
-
|
210
|
+
|
206
211
|
if attrs["name"]
|
207
212
|
cattrs[:first_name] = attrs["name"]["first_name"]
|
208
213
|
cattrs[:middle_name] = attrs["name"]["middle_name"]
|
209
214
|
cattrs[:last_name] = attrs["name"]["last_name"]
|
210
215
|
end
|
211
|
-
|
216
|
+
|
212
217
|
cattrs[:api_id] = attrs["id"].to_s
|
213
218
|
cattrs[:sis_student_id] = attrs["local_id"].to_s
|
214
|
-
cattrs[:state_student_id]
|
215
|
-
|
219
|
+
cattrs[:state_student_id] = attrs["state_province_id"].to_s
|
220
|
+
|
216
221
|
if attrs["demographics"]
|
217
222
|
if attrs["demographics"]["birth_date"]
|
218
|
-
begin
|
223
|
+
begin
|
219
224
|
cattrs[:birth_date] = Date.strptime(attrs["demographics"]["birth_date"], DATE_FORMAT)
|
220
225
|
rescue => e
|
221
226
|
puts "#{e.inspect} #{bd}"
|
@@ -227,17 +232,48 @@ module Bright
|
|
227
232
|
pg = attrs["demographics"]["projected_graduation_year"].to_i
|
228
233
|
cattrs[:projected_graduation_year] = pg if pg > 0
|
229
234
|
end
|
230
|
-
|
235
|
+
|
236
|
+
#Student Address
|
231
237
|
begin
|
232
|
-
|
233
|
-
|
234
|
-
|
238
|
+
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"]
|
239
|
+
rescue
|
240
|
+
end
|
241
|
+
|
242
|
+
#Ethnicity / Race Info
|
243
|
+
if attrs["ethnicity_race"].is_a?(Hash)
|
244
|
+
if !(race_hshs = attrs.dig("ethnicity_race", "races")).nil?
|
245
|
+
#this should be an array, but it doesn't appear PS always sends it as one
|
246
|
+
cattrs[:race] = [race_hshs].flatten.map{|race_hsh| race_hsh["district_race_code"]}.compact.uniq
|
247
|
+
end
|
248
|
+
|
249
|
+
if !attrs.dig("ethnicity_race", "federal_ethnicity").nil?
|
250
|
+
cattrs[:hispanic_ethnicity] = attrs.dig("ethnicity_race", "federal_ethnicity").to_bool
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
#Contacts Info
|
255
|
+
[1,2].each do |contact_id|
|
256
|
+
if !attrs.dig("contact", "emergency_contact_name#{contact_id}").blank? and !attrs.dig("contact", "emergency_phone#{contact_id}").blank?
|
257
|
+
cattrs[:contacts] ||= []
|
258
|
+
contact_attrs = {
|
259
|
+
:first_name => attrs.dig("contact", "emergency_contact_name#{contact_id}").to_s.split(",").last.strip,
|
260
|
+
:last_name => attrs.dig("contact", "emergency_contact_name#{contact_id}").to_s.split(",").first.strip,
|
261
|
+
:phone_numbers => [
|
262
|
+
{
|
263
|
+
:phone_number => attrs.dig("contact", "emergency_phone#{contact_id}")
|
264
|
+
}
|
265
|
+
]
|
266
|
+
}
|
267
|
+
cattrs[:contacts] << contact_attrs
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
235
271
|
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
236
272
|
end
|
237
|
-
|
273
|
+
|
238
274
|
def convert_from_student_data(student, action = nil, additional_params = {})
|
239
275
|
return {} if student.nil?
|
240
|
-
|
276
|
+
|
241
277
|
student_data = {
|
242
278
|
:client_uid => student.client_id,
|
243
279
|
:action => action,
|
@@ -245,7 +281,7 @@ module Bright
|
|
245
281
|
:local_id => student.sis_student_id,
|
246
282
|
:state_province_id => student.state_student_id,
|
247
283
|
:name => {
|
248
|
-
:first_name => student.first_name,
|
284
|
+
:first_name => student.first_name,
|
249
285
|
:middle_name => student.middle_name,
|
250
286
|
:last_name => student.last_name
|
251
287
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?},
|
@@ -255,12 +291,12 @@ module Bright
|
|
255
291
|
:projected_graduation_year => student.projected_graduation_year
|
256
292
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
257
293
|
}.merge(additional_params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
258
|
-
|
294
|
+
|
259
295
|
# apply enrollment info
|
260
296
|
if student.enrollment
|
261
|
-
student_data.merge!(self.convert_from_enrollment_data(student.enrollment))
|
297
|
+
student_data.merge!(self.convert_from_enrollment_data(student.enrollment))
|
262
298
|
end
|
263
|
-
|
299
|
+
|
264
300
|
# apply addresses
|
265
301
|
address_data = {}
|
266
302
|
if ph = student.addresses.detect{|a| a.type == "physical"}
|
@@ -275,12 +311,12 @@ module Bright
|
|
275
311
|
address_data.merge!(self.convert_from_address_data(cany))
|
276
312
|
end
|
277
313
|
if address_data.size > 0
|
278
|
-
student_data.merge!({:addresses => address_data})
|
314
|
+
student_data.merge!({:addresses => address_data})
|
279
315
|
end
|
280
|
-
|
316
|
+
|
281
317
|
{:students => {:student => student_data}}
|
282
318
|
end
|
283
|
-
|
319
|
+
|
284
320
|
def convert_from_enrollment_data(enrollment)
|
285
321
|
return {} if enrollment.nil?
|
286
322
|
{:school_enrollment => {
|
@@ -294,17 +330,24 @@ module Bright
|
|
294
330
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
295
331
|
}
|
296
332
|
end
|
297
|
-
|
333
|
+
|
298
334
|
def convert_to_school_data(attrs)
|
299
335
|
cattrs = {}
|
300
|
-
|
301
336
|
cattrs[:api_id] = attrs["id"]
|
302
337
|
cattrs[:name] = attrs["name"]
|
303
338
|
cattrs[:number] = attrs["school_number"]
|
304
|
-
|
339
|
+
cattrs[:low_grade] = attrs["low_grade"]
|
340
|
+
cattrs[:high_grade] = attrs["high_grade"]
|
341
|
+
if (address_attributes = attrs.dig("addresses"))
|
342
|
+
cattrs[:address] = convert_to_address_data(address_attributes)
|
343
|
+
end
|
344
|
+
if (phone_number_attributes = attrs.dig("phones", "main", "number"))
|
345
|
+
cattrs[:phone_number] = {:phone_number => phone_number_attributes}
|
346
|
+
end
|
347
|
+
|
305
348
|
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
306
349
|
end
|
307
|
-
|
350
|
+
|
308
351
|
def convert_from_address_data(address)
|
309
352
|
{
|
310
353
|
(address.type || "physcial") => {
|
@@ -316,10 +359,10 @@ module Bright
|
|
316
359
|
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
317
360
|
}
|
318
361
|
end
|
319
|
-
|
362
|
+
|
320
363
|
def convert_to_address_data(attrs)
|
321
364
|
cattrs = {}
|
322
|
-
|
365
|
+
|
323
366
|
if attrs.is_a?(Array)
|
324
367
|
if attrs.first.is_a?(String)
|
325
368
|
cattrs[:type] = attrs.first
|
@@ -337,12 +380,12 @@ module Bright
|
|
337
380
|
cattrs[:state] = attrs["state_province"]
|
338
381
|
cattrs[:postal_code] = attrs["postal_code"]
|
339
382
|
if attrs["grid_location"] and lat_lng = attrs["grid_location"].split(/,\s?/)
|
340
|
-
cattrs[:
|
383
|
+
cattrs[:latitude], cattrs[:longitude] = lat_lng
|
341
384
|
end
|
342
|
-
|
385
|
+
|
343
386
|
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
344
387
|
end
|
345
|
-
|
388
|
+
|
346
389
|
def apply_expansions(params)
|
347
390
|
if self.expansion_options.empty?
|
348
391
|
hsh = self.request(:get, 'ws/v1/district/student', {:pagesize => 1, :q => "local_id==0"})
|
@@ -359,22 +402,22 @@ module Bright
|
|
359
402
|
:extensions => (%w(studentcorefields) & (self.expansion_options[:extensions] || [])).join(",")
|
360
403
|
}.reject{|k,v| v.empty?})
|
361
404
|
end
|
362
|
-
|
405
|
+
|
363
406
|
def apply_options(params, options)
|
364
407
|
options[:per_page] = params[:pagesize] ||= params.delete(:per_page) || options[:per_page] || 100
|
365
408
|
params[:page] ||= options[:page] || 1
|
366
409
|
params
|
367
410
|
end
|
368
|
-
|
411
|
+
|
369
412
|
def headers_for_access_token
|
370
413
|
{
|
371
414
|
"Authorization" => "Basic #{Base64.strict_encode64("#{self.connection_options[:client_id]}:#{self.connection_options[:client_secret]}")}",
|
372
415
|
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
373
416
|
}
|
374
417
|
end
|
375
|
-
|
418
|
+
|
376
419
|
def headers_for_auth
|
377
|
-
self.
|
420
|
+
self.retrieve_access_token if self.connection_options[:access_token].nil?
|
378
421
|
{
|
379
422
|
"Authorization" => "Bearer #{self.connection_options[:access_token]}",
|
380
423
|
"Accept" => "application/json;charset=UTF-8",
|
@@ -383,4 +426,4 @@ module Bright
|
|
383
426
|
end
|
384
427
|
end
|
385
428
|
end
|
386
|
-
end
|
429
|
+
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
|