bright 1.3 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,8 +1,8 @@
|
|
1
1
|
module Bright
|
2
2
|
module SisApi
|
3
3
|
class PowerSchool < Base
|
4
|
-
DATE_FORMAT =
|
5
|
-
INVALID_SEARCH_CHAR_RE = /[
|
4
|
+
DATE_FORMAT = "%Y-%m-%d"
|
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/"
|
@@ -22,30 +22,30 @@ module Bright
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def get_student_by_api_id(api_id, params = {})
|
25
|
-
params =
|
26
|
-
st_hsh =
|
25
|
+
params = apply_expansions(params)
|
26
|
+
st_hsh = 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
|
+
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
|
-
params =
|
36
|
-
params =
|
35
|
+
params = apply_expansions(params)
|
36
|
+
params = apply_options(params, options)
|
37
37
|
|
38
38
|
if options[:wrap_in_collection] != false
|
39
|
-
students_count_response_hash =
|
39
|
+
students_count_response_hash = request(:get, "ws/v1/district/student/count", map_student_search_params(params))
|
40
40
|
# {"resource"=>{"count"=>293}}
|
41
41
|
total_results = students_count_response_hash["resource"]["count"].to_i if students_count_response_hash["resource"]
|
42
42
|
end
|
43
43
|
|
44
|
-
students_response_hash =
|
44
|
+
students_response_hash = request(:get, "ws/v1/district/student", 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
|
-
students = students_hash.compact.collect {|st_hsh|
|
48
|
+
students = students_hash.compact.collect { |st_hsh|
|
49
49
|
Student.new(convert_to_student_data(st_hsh))
|
50
50
|
}
|
51
51
|
|
@@ -54,15 +54,15 @@ module Bright
|
|
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, {:
|
57
|
+
api.get_students(params, {wrap_in_collection: false})
|
58
58
|
}
|
59
59
|
|
60
60
|
ResponseCollection.new({
|
61
|
-
:
|
62
|
-
:
|
63
|
-
:
|
64
|
-
:
|
65
|
-
:
|
61
|
+
seed_page: students,
|
62
|
+
total: total_results,
|
63
|
+
per_page: params[:pagesize],
|
64
|
+
load_more_call: load_more_call,
|
65
|
+
no_threads: options[:no_threads]
|
66
66
|
})
|
67
67
|
else
|
68
68
|
students
|
@@ -73,13 +73,13 @@ module Bright
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def create_student(student, additional_params = {})
|
76
|
-
response =
|
76
|
+
response = request(:post, "ws/v1/student", convert_from_student_data(student, "INSERT", additional_params))
|
77
77
|
if response["results"] and response["results"]["insert_count"] == 1
|
78
78
|
student.api_id = response["results"]["result"]["success_message"]["id"]
|
79
79
|
|
80
80
|
# update our local student object with any data the server might have updated
|
81
|
-
nstudent =
|
82
|
-
student.assign_attributes(
|
81
|
+
nstudent = get_student_by_api_id(student.api_id)
|
82
|
+
student.assign_attributes(Bright::Student.attribute_names.collect { |n| [n, nstudent.send(n)] }.to_h.reject { |k, v| v.nil? })
|
83
83
|
|
84
84
|
# enrollment is no longer needed as creation is over
|
85
85
|
student.enrollment = nil
|
@@ -91,10 +91,10 @@ module Bright
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def update_student(student, additional_params = {})
|
94
|
-
response =
|
94
|
+
response = request(:post, "ws/v1/student", convert_from_student_data(student, "UPDATE", additional_params))
|
95
95
|
if response["results"] and response["results"]["update_count"] == 1
|
96
96
|
student.api_id = response["results"]["result"]["success_message"]["id"]
|
97
|
-
|
97
|
+
get_student_by_api_id(student.api_id)
|
98
98
|
else
|
99
99
|
puts response.inspect
|
100
100
|
student
|
@@ -106,18 +106,18 @@ module Bright
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def get_schools(params = {}, options = {})
|
109
|
-
params =
|
109
|
+
params = apply_options(params, options)
|
110
110
|
|
111
111
|
if options[:wrap_in_collection] != false
|
112
|
-
schools_count_response_hash =
|
112
|
+
schools_count_response_hash = request(:get, "ws/v1/district/school/count", params)
|
113
113
|
# {"resource"=>{"count"=>293}}
|
114
114
|
total_results = schools_count_response_hash["resource"]["count"].to_i if schools_count_response_hash["resource"]
|
115
115
|
end
|
116
116
|
|
117
|
-
schools_response_hash =
|
117
|
+
schools_response_hash = request(:get, "ws/v1/district/school", params)
|
118
118
|
schools_hsh = [schools_response_hash["schools"]["school"]].flatten
|
119
119
|
|
120
|
-
schools = schools_hsh.compact.collect {|st_hsh|
|
120
|
+
schools = schools_hsh.compact.collect { |st_hsh|
|
121
121
|
School.new(convert_to_school_data(st_hsh))
|
122
122
|
}
|
123
123
|
|
@@ -126,15 +126,15 @@ module Bright
|
|
126
126
|
load_more_call = proc { |page|
|
127
127
|
# pages start at one, so add a page here
|
128
128
|
params[:page] = (page + 1)
|
129
|
-
api.get_schools(params, {:
|
129
|
+
api.get_schools(params, {wrap_in_collection: false})
|
130
130
|
}
|
131
131
|
|
132
132
|
ResponseCollection.new({
|
133
|
-
:
|
134
|
-
:
|
135
|
-
:
|
136
|
-
:
|
137
|
-
:
|
133
|
+
seed_page: schools,
|
134
|
+
total: total_results,
|
135
|
+
per_page: params[:pagesize],
|
136
|
+
load_more_call: load_more_call,
|
137
|
+
no_threads: options[:no_threads]
|
138
138
|
})
|
139
139
|
else
|
140
140
|
schools
|
@@ -142,19 +142,19 @@ module Bright
|
|
142
142
|
end
|
143
143
|
|
144
144
|
def retrieve_access_token
|
145
|
-
connection = Bright::Connection.new("#{
|
146
|
-
response = connection.request(:post, "grant_type=client_credentials",
|
145
|
+
connection = Bright::Connection.new("#{connection_options[:uri]}/oauth/access_token/")
|
146
|
+
response = connection.request(:post, "grant_type=client_credentials", headers_for_access_token)
|
147
147
|
if !response.error?
|
148
148
|
response_hash = JSON.parse(response.body)
|
149
149
|
end
|
150
150
|
if response_hash["access_token"]
|
151
|
-
|
151
|
+
connection_options[:access_token] = response_hash["access_token"]
|
152
152
|
end
|
153
153
|
response_hash
|
154
154
|
end
|
155
155
|
|
156
156
|
def request(method, path, params = {})
|
157
|
-
uri
|
157
|
+
uri = "#{connection_options[:uri]}/#{path}"
|
158
158
|
body = nil
|
159
159
|
if method == :get
|
160
160
|
query = URI.encode_www_form(params)
|
@@ -163,10 +163,9 @@ module Bright
|
|
163
163
|
body = JSON.dump(params)
|
164
164
|
end
|
165
165
|
|
166
|
-
|
167
166
|
response = connection_retry_wrapper {
|
168
167
|
connection = Bright::Connection.new(uri)
|
169
|
-
headers =
|
168
|
+
headers = headers_for_auth
|
170
169
|
connection.request(method, body, headers)
|
171
170
|
}
|
172
171
|
|
@@ -186,7 +185,7 @@ module Bright
|
|
186
185
|
default_params = {}
|
187
186
|
|
188
187
|
q = ""
|
189
|
-
%w
|
188
|
+
%w[first_name middle_name last_name].each do |f|
|
190
189
|
if fn = params.delete(f.to_sym)
|
191
190
|
fn = fn.gsub(INVALID_SEARCH_CHAR_RE, " ").strip
|
192
191
|
q += %(name.#{f}==#{fn};)
|
@@ -202,16 +201,16 @@ module Bright
|
|
202
201
|
end
|
203
202
|
params[:q] = q
|
204
203
|
|
205
|
-
default_params.merge(params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
204
|
+
default_params.merge(params).reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
206
205
|
end
|
207
206
|
|
208
207
|
def convert_to_student_data(attrs)
|
209
208
|
cattrs = {}
|
210
209
|
|
211
210
|
if attrs["name"]
|
212
|
-
cattrs[:first_name]
|
211
|
+
cattrs[:first_name] = attrs["name"]["first_name"]
|
213
212
|
cattrs[:middle_name] = attrs["name"]["middle_name"]
|
214
|
-
cattrs[:last_name]
|
213
|
+
cattrs[:last_name] = attrs["name"]["last_name"]
|
215
214
|
end
|
216
215
|
|
217
216
|
cattrs[:api_id] = attrs["id"].to_s
|
@@ -234,17 +233,17 @@ module Bright
|
|
234
233
|
cattrs[:projected_graduation_year] = pg if pg > 0
|
235
234
|
end
|
236
235
|
|
237
|
-
#Student Address
|
236
|
+
# Student Address
|
238
237
|
begin
|
239
|
-
cattrs[:addresses] = attrs["addresses"].to_a.collect{|a|
|
238
|
+
cattrs[:addresses] = attrs["addresses"].to_a.collect { |a| convert_to_address_data(a) }.select { |a| !a[:street].blank? }.uniq { |a| a[:street] } if attrs["addresses"]
|
240
239
|
rescue
|
241
240
|
end
|
242
241
|
|
243
|
-
#Ethnicity / Race Info
|
242
|
+
# Ethnicity / Race Info
|
244
243
|
if attrs["ethnicity_race"].is_a?(Hash)
|
245
244
|
if !(race_hshs = attrs.dig("ethnicity_race", "races")).nil?
|
246
|
-
#this should be an array, but it doesn't appear PS always sends it as one
|
247
|
-
cattrs[:race] = [race_hshs].flatten.map{|race_hsh| race_hsh["district_race_code"]}.compact.uniq
|
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
|
248
247
|
end
|
249
248
|
|
250
249
|
if !attrs.dig("ethnicity_race", "federal_ethnicity").nil?
|
@@ -255,16 +254,16 @@ module Bright
|
|
255
254
|
end
|
256
255
|
end
|
257
256
|
|
258
|
-
#Contacts Info
|
259
|
-
[1,2].each do |contact_id|
|
257
|
+
# Contacts Info
|
258
|
+
[1, 2].each do |contact_id|
|
260
259
|
if !attrs.dig("contact", "emergency_contact_name#{contact_id}").blank? and !attrs.dig("contact", "emergency_phone#{contact_id}").blank?
|
261
260
|
cattrs[:contacts] ||= []
|
262
261
|
contact_attrs = {
|
263
|
-
:
|
264
|
-
:
|
265
|
-
:
|
262
|
+
first_name: attrs.dig("contact", "emergency_contact_name#{contact_id}").to_s.split(",").last.strip,
|
263
|
+
last_name: attrs.dig("contact", "emergency_contact_name#{contact_id}").to_s.split(",").first.strip,
|
264
|
+
phone_numbers: [
|
266
265
|
{
|
267
|
-
:
|
266
|
+
phone_number: attrs.dig("contact", "emergency_phone#{contact_id}")
|
268
267
|
}
|
269
268
|
]
|
270
269
|
}
|
@@ -272,68 +271,67 @@ module Bright
|
|
272
271
|
end
|
273
272
|
end
|
274
273
|
|
275
|
-
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
274
|
+
cattrs.reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
276
275
|
end
|
277
276
|
|
278
277
|
def convert_from_student_data(student, action = nil, additional_params = {})
|
279
278
|
return {} if student.nil?
|
280
279
|
|
281
280
|
student_data = {
|
282
|
-
:
|
283
|
-
:
|
284
|
-
:
|
285
|
-
:
|
286
|
-
:
|
287
|
-
:
|
288
|
-
:
|
289
|
-
:
|
290
|
-
:
|
291
|
-
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?},
|
292
|
-
:
|
281
|
+
client_uid: student.client_id,
|
282
|
+
action: action,
|
283
|
+
id: student.api_id,
|
284
|
+
local_id: student.sis_student_id,
|
285
|
+
state_province_id: student.state_student_id,
|
286
|
+
name: {
|
287
|
+
first_name: student.first_name,
|
288
|
+
middle_name: student.middle_name,
|
289
|
+
last_name: student.last_name
|
290
|
+
}.reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? },
|
291
|
+
demographics: {
|
293
292
|
# To avoid a mismatch of attributes, we'll ignore for now
|
294
293
|
# :gender => student.gender.to_s[0].to_s.upcase,
|
295
|
-
:
|
296
|
-
:
|
297
|
-
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
298
|
-
}.merge(additional_params).reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
294
|
+
birth_date: (student.birth_date ? student.birth_date.strftime(DATE_FORMAT) : nil),
|
295
|
+
projected_graduation_year: student.projected_graduation_year
|
296
|
+
}.reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
297
|
+
}.merge(additional_params).reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
299
298
|
|
300
299
|
# apply enrollment info
|
301
300
|
if student.enrollment
|
302
|
-
student_data.merge!(
|
301
|
+
student_data.merge!(convert_from_enrollment_data(student.enrollment))
|
303
302
|
end
|
304
303
|
|
305
304
|
# apply addresses
|
306
305
|
address_data = {}
|
307
|
-
if ph = student.addresses.detect{|a| a.type == "physical"}
|
308
|
-
address_data.merge!(
|
306
|
+
if ph = student.addresses.detect { |a| a.type == "physical" }
|
307
|
+
address_data.merge!(convert_from_address_data(ph))
|
309
308
|
end
|
310
|
-
if mail = student.addresses.detect{|a| a.type == "mailing"}
|
311
|
-
address_data.merge!(
|
309
|
+
if mail = student.addresses.detect { |a| a.type == "mailing" }
|
310
|
+
address_data.merge!(convert_from_address_data(mail))
|
312
311
|
end
|
313
312
|
if ph.nil? and mail.nil? and any = student.addresses.first
|
314
313
|
cany = any.clone
|
315
314
|
cany.type = "physical"
|
316
|
-
address_data.merge!(
|
315
|
+
address_data.merge!(convert_from_address_data(cany))
|
317
316
|
end
|
318
317
|
if address_data.size > 0
|
319
|
-
student_data.merge!({:
|
318
|
+
student_data.merge!({addresses: address_data})
|
320
319
|
end
|
321
320
|
|
322
|
-
{:
|
321
|
+
{students: {student: student_data}}
|
323
322
|
end
|
324
323
|
|
325
324
|
def convert_from_enrollment_data(enrollment)
|
326
325
|
return {} if enrollment.nil?
|
327
|
-
{:
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
}
|
326
|
+
{school_enrollment: {
|
327
|
+
enroll_status: "A",
|
328
|
+
entry_date: (enrollment.entry_date || Date.today).strftime(DATE_FORMAT),
|
329
|
+
entry_comment: enrollment.entry_comment,
|
330
|
+
exit_date: (enrollment.exit_date || enrollment.entry_date || Date.today).strftime(DATE_FORMAT),
|
331
|
+
exit_comment: enrollment.exit_comment,
|
332
|
+
grade_level: enrollment.grade,
|
333
|
+
school_number: enrollment.school ? enrollment.school.number : nil
|
334
|
+
}.reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }}
|
337
335
|
end
|
338
336
|
|
339
337
|
def convert_to_school_data(attrs)
|
@@ -347,21 +345,21 @@ module Bright
|
|
347
345
|
cattrs[:address] = convert_to_address_data(address_attributes)
|
348
346
|
end
|
349
347
|
if (phone_number_attributes = attrs.dig("phones", "main", "number"))
|
350
|
-
cattrs[:phone_number] = {:
|
348
|
+
cattrs[:phone_number] = {phone_number: phone_number_attributes}
|
351
349
|
end
|
352
350
|
|
353
|
-
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
351
|
+
cattrs.reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
354
352
|
end
|
355
353
|
|
356
354
|
def convert_from_address_data(address)
|
357
355
|
{
|
358
|
-
|
359
|
-
:
|
360
|
-
:
|
361
|
-
:
|
362
|
-
:
|
363
|
-
:
|
364
|
-
}.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
356
|
+
address.type || "physcial" => {
|
357
|
+
street: "#{address.street} #{address.apt}", # powerschool doesn't appear to support passing the apt in the api
|
358
|
+
city: address.city,
|
359
|
+
state_province: address.state,
|
360
|
+
postal_code: address.postal_code,
|
361
|
+
grid_location: address.geographical_coordinates.to_s.gsub(",", ", ") # make sure there is a comma + space
|
362
|
+
}.reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
365
363
|
}
|
366
364
|
end
|
367
365
|
|
@@ -388,24 +386,24 @@ module Bright
|
|
388
386
|
cattrs[:latitude], cattrs[:longitude] = lat_lng
|
389
387
|
end
|
390
388
|
|
391
|
-
cattrs.reject{|k,v| v.respond_to?(:empty?) ? v.empty? : v.nil?}
|
389
|
+
cattrs.reject { |k, v| v.respond_to?(:empty?) ? v.empty? : v.nil? }
|
392
390
|
end
|
393
391
|
|
394
392
|
def apply_expansions(params)
|
395
|
-
if
|
396
|
-
hsh =
|
393
|
+
if expansion_options.empty?
|
394
|
+
hsh = request(:get, "ws/v1/district/student", {pagesize: 1, q: "local_id==0"})
|
397
395
|
if hsh and hsh["students"]
|
398
396
|
self.expansion_options = {
|
399
|
-
:
|
400
|
-
:
|
397
|
+
expansions: hsh["students"]["@expansions"].to_s.split(/,\s?/),
|
398
|
+
extensions: hsh["students"]["@extensions"].to_s.split(/,\s?/)
|
401
399
|
}
|
402
400
|
end
|
403
401
|
end
|
404
402
|
|
405
403
|
params.merge({
|
406
|
-
:
|
407
|
-
:
|
408
|
-
}.reject{|k,v| v.empty?})
|
404
|
+
expansions: (%w[demographics addresses ethnicity_race phones contact contact_info] & (expansion_options[:expansions] || [])).join(","),
|
405
|
+
extensions: (%w[studentcorefields] & (expansion_options[:extensions] || [])).join(",")
|
406
|
+
}.reject { |k, v| v.empty? })
|
409
407
|
end
|
410
408
|
|
411
409
|
def apply_options(params, options)
|
@@ -416,17 +414,17 @@ module Bright
|
|
416
414
|
|
417
415
|
def headers_for_access_token
|
418
416
|
{
|
419
|
-
"Authorization" => "Basic #{Base64.strict_encode64("#{
|
417
|
+
"Authorization" => "Basic #{Base64.strict_encode64("#{connection_options[:client_id]}:#{connection_options[:client_secret]}")}",
|
420
418
|
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
|
421
419
|
}
|
422
420
|
end
|
423
421
|
|
424
422
|
def headers_for_auth
|
425
|
-
|
423
|
+
retrieve_access_token if connection_options[:access_token].nil?
|
426
424
|
{
|
427
|
-
"Authorization" => "Bearer #{
|
425
|
+
"Authorization" => "Bearer #{connection_options[:access_token]}",
|
428
426
|
"Accept" => "application/json;charset=UTF-8",
|
429
|
-
"Content-Type" =>"application/json;charset=UTF-8"
|
427
|
+
"Content-Type" => "application/json;charset=UTF-8"
|
430
428
|
}
|
431
429
|
end
|
432
430
|
end
|
@@ -1,31 +1,29 @@
|
|
1
1
|
module Bright
|
2
2
|
module SisApi
|
3
3
|
class Synergy < Base
|
4
|
-
|
5
4
|
def get_student_by_api_id(api_id)
|
6
5
|
raise NotImplementedError
|
7
6
|
end
|
8
|
-
|
7
|
+
|
9
8
|
def get_student(params)
|
10
9
|
raise NotImplementedError
|
11
10
|
end
|
12
|
-
|
11
|
+
|
13
12
|
def get_students(params)
|
14
13
|
raise NotImplementedError
|
15
14
|
end
|
16
|
-
|
15
|
+
|
17
16
|
def create_student(student)
|
18
17
|
raise NotImplementedError
|
19
18
|
end
|
20
|
-
|
19
|
+
|
21
20
|
def update_student(student)
|
22
21
|
raise NotImplementedError
|
23
22
|
end
|
24
|
-
|
23
|
+
|
25
24
|
def get_schools(params)
|
26
25
|
raise NotImplementedError
|
27
26
|
end
|
28
|
-
|
29
27
|
end
|
30
28
|
end
|
31
|
-
end
|
29
|
+
end
|