ps_utilities 0.3.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ps_utilities/connection.rb +57 -50
- data/lib/ps_utilities/pre_built_get.rb +27 -23
- data/lib/ps_utilities/pre_built_post.rb +20 -16
- data/lib/ps_utilities/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30083f1244c4e8ea1a53ab81b8f88ac3c10d177fb651218cfcbe9dca8bdc219f
|
4
|
+
data.tar.gz: c7f3991b61f85c224c48ca2bb3c172b8a2b24b50d28a8e14e1b80e9e5f831c4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 848cfcbb6cf7b71d1e205ac04c21ac14a7b75be92b47db43effa58d6d455ac5b20a90e0d022070e0f9c0e4e1925599fca75493ec5a8f30047205b13a758fbae3
|
7
|
+
data.tar.gz: f72b28802331533bb855536a2dcbf1ece95bab2fc3a4d09b7aeca883b4a1003c9d3ef1d2d403dd86d55b64ff5e641467f84125b86766370f8e10de41cdda0f66
|
@@ -24,30 +24,32 @@ module PsUtilities
|
|
24
24
|
|
25
25
|
class Connection
|
26
26
|
|
27
|
-
attr_reader :
|
28
|
-
attr_reader :
|
27
|
+
attr_reader :auth_path, :auth_token, :auth_info, :headers
|
28
|
+
attr_reader :api_data, :base_uri, :auth_path
|
29
|
+
attr_reader :client, :client_id, :client_secret
|
29
30
|
attr_reader :version
|
30
31
|
|
31
32
|
include PsUtilities::PreBuiltGet
|
32
33
|
include PsUtilities::PreBuiltPut
|
33
34
|
include PsUtilities::PreBuiltPost
|
34
35
|
|
35
|
-
# @param attributes: [Hash] - options include: { base_uri: ENV['
|
36
|
+
# @param attributes: [Hash] - options include: { base_uri: ENV['PS_BASE_URL'], auth_endpoint: (ENV['PS_AUTH_ENDPOINT'] || '/oauth/access_token'), client_id: ENV['PS_CLIENT_ID'], client_secret: ENV['PS_CLIENT_SECRET'] }
|
36
37
|
# @param headers: [Hash] - allows to change from json to xml (only do this if you are doing direct api calls and not using pre-built calls) returns and use a different useragent: { 'User-Agent' => "PsUtilities - #{version}", 'Accept' => 'application/json', 'Content-Type' => 'application/json'}
|
37
38
|
# @note preference is to use environment variables to initialize your server.
|
38
|
-
def initialize(
|
39
|
-
@version
|
40
|
-
@
|
41
|
-
@
|
42
|
-
@
|
43
|
-
@
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
raise ArgumentError, "missing
|
50
|
-
|
39
|
+
def initialize( header_info: {}, api_info: {}, client_info: {})
|
40
|
+
@version = "v#{PsUtilities::Version::VERSION}"
|
41
|
+
@client = client_defaults.merge(client_info)
|
42
|
+
@client_id = client[:client_id]
|
43
|
+
@client_secret = client[:client_secret]
|
44
|
+
@api_data = api_defaults.merge(api_info)
|
45
|
+
@base_uri = api_data[:base_uri]
|
46
|
+
@auth_path = api_data[:auth_endpoint]
|
47
|
+
@headers = header_defaults.merge(header_info)
|
48
|
+
|
49
|
+
raise ArgumentError, "missing client_secret" if client_secret.nil? or client_secret.empty?
|
50
|
+
raise ArgumentError, "missing client_id" if client_id.nil? or client_id.empty?
|
51
|
+
raise ArgumentError, "missing auth endpoint" if auth_path.nil? or auth_path.empty?
|
52
|
+
raise ArgumentError, "missing base_uri" if base_uri.nil? or base_uri.empty?
|
51
53
|
end
|
52
54
|
|
53
55
|
# this runs the various options:
|
@@ -57,12 +59,14 @@ module PsUtilities
|
|
57
59
|
# @param params: [Hash] - this is the data needed for using pre-built commands - see the individual command for details
|
58
60
|
# @note with no command an authenticatation check is done
|
59
61
|
def run(command: nil, api_path: "", options: {}, params: {})
|
60
|
-
authenticate
|
61
|
-
|
62
|
+
authenticate unless auth_valid?
|
63
|
+
|
62
64
|
case command
|
63
65
|
when nil, :authenticate
|
66
|
+
authenticate
|
64
67
|
when :delete, :get, :patch, :post, :put
|
65
|
-
api(command, api_path, options)
|
68
|
+
api(command, api_path, options) unless api_path.empty?
|
69
|
+
# TODO: panick if api_path empty
|
66
70
|
else
|
67
71
|
send(command, params)
|
68
72
|
end
|
@@ -71,7 +75,7 @@ module PsUtilities
|
|
71
75
|
private
|
72
76
|
|
73
77
|
def authorized_token
|
74
|
-
"#{
|
78
|
+
"#{auth_info['access_token']}"
|
75
79
|
end
|
76
80
|
|
77
81
|
# verb = :delete, :get, :patch, :post, :put
|
@@ -81,10 +85,6 @@ module PsUtilities
|
|
81
85
|
retries = 3
|
82
86
|
ps_url = base_uri + api_path
|
83
87
|
options = options.merge(headers)
|
84
|
-
pp "api-url"
|
85
|
-
pp ps_url
|
86
|
-
pp "api-options"
|
87
|
-
pp options
|
88
88
|
begin
|
89
89
|
HTTParty.send(verb, ps_url, options)
|
90
90
|
rescue Net::ReadTimeout, Net::OpenTimeout
|
@@ -101,7 +101,8 @@ module PsUtilities
|
|
101
101
|
{ headers:
|
102
102
|
{ 'User-Agent' => "PsUtilities - #{version}",
|
103
103
|
'Accept' => 'application/json',
|
104
|
-
'Content-Type' => 'application/json'
|
104
|
+
'Content-Type' => 'application/json'
|
105
|
+
}
|
105
106
|
}
|
106
107
|
end
|
107
108
|
|
@@ -110,46 +111,52 @@ module PsUtilities
|
|
110
111
|
ps_url = base_uri + auth_path
|
111
112
|
response = HTTParty.post(ps_url, {headers: auth_headers,
|
112
113
|
body: 'grant_type=client_credentials'})
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
114
|
+
if response.code.to_s.eql? "200"
|
115
|
+
@auth_info = response.parsed_response
|
116
|
+
@auth_info['token_expires'] = Time.now + response.parsed_response['expires_in'].to_i
|
117
|
+
@headers[:headers].merge!('Authorization' => 'Bearer ' + auth_info['access_token'])
|
118
|
+
return auth_info
|
119
|
+
else
|
120
|
+
# throw error if - error returned -- nothing else will work
|
121
|
+
raise AuthError.new("No Auth Token Returned", ps_url, client )
|
122
|
+
end
|
122
123
|
end
|
123
124
|
|
124
|
-
def
|
125
|
-
return false if
|
126
|
-
return false if
|
127
|
-
return false if
|
128
|
-
return false if
|
125
|
+
def auth_valid?(auth = auth_info)
|
126
|
+
return false if auth.nil?
|
127
|
+
return false if auth.empty?
|
128
|
+
return false if auth['access_token'].nil?
|
129
|
+
return false if auth['access_token'].empty?
|
130
|
+
return false if auth['token_expires'].nil?
|
131
|
+
return false if auth['token_expires'] < Time.now
|
129
132
|
return true
|
130
133
|
end
|
131
134
|
|
132
|
-
def auth_headers(
|
135
|
+
def auth_headers(credentials = client)
|
133
136
|
{ 'ContentType' => 'application/x-www-form-urlencoded;charset=UTF-8',
|
134
137
|
'Accept' => 'application/json',
|
135
|
-
'Authorization' => 'Basic ' +
|
138
|
+
'Authorization' => 'Basic ' + encode64_client(credentials)
|
136
139
|
}
|
140
|
+
# with(headers: {'Authorization' => "Basic #{ Base64.strict_encode64('user:pass').chomp}"})
|
137
141
|
end
|
138
142
|
|
139
|
-
def
|
140
|
-
ps_auth_text = [
|
141
|
-
|
142
|
-
|
143
|
-
Base64.encode64(ps_auth_text).gsub(/\n/, '')
|
143
|
+
def encode64_client(credentials = client)
|
144
|
+
ps_auth_text = [ credentials[:client_id], credentials[:client_secret] ].join(':')
|
145
|
+
Base64.encode64(ps_auth_text).chomp
|
146
|
+
# Base64.encode64(ps_auth_text).gsub(/\n/, '')
|
144
147
|
end
|
145
148
|
|
146
|
-
def
|
147
|
-
{
|
148
|
-
auth_endpoint: ENV['PS_AUTH_ENDPOINT'] || '/oauth/access_token',
|
149
|
-
client_id: ENV['PS_CLIENT_ID'],
|
149
|
+
def client_defaults
|
150
|
+
{ client_id: ENV['PS_CLIENT_ID'],
|
150
151
|
client_secret: ENV['PS_CLIENT_SECRET'],
|
151
152
|
}
|
152
153
|
end
|
153
154
|
|
155
|
+
def api_defaults
|
156
|
+
{ base_uri: ENV['PS_BASE_URL'],
|
157
|
+
auth_endpoint: ENV['PS_AUTH_ENDPOINT'] || '/oauth/access_token',
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
154
161
|
end
|
155
162
|
end
|
@@ -3,11 +3,11 @@ module PsUtilities
|
|
3
3
|
module PreBuiltGet
|
4
4
|
|
5
5
|
# return all active students within the district (special case of #get_all_matching_students) - a recursive search
|
6
|
-
# @param params [Hash] -
|
6
|
+
# @param params [Hash] - page_size: is the only parameter accepted - default is 100
|
7
7
|
# @return - (see #get_all_matching_students)
|
8
8
|
def get_all_active_students(params={})
|
9
|
-
|
10
|
-
|
9
|
+
page_size = params[:page_size] || 100
|
10
|
+
params = {status_code: 0, page_size: page_size}
|
11
11
|
get_all_matching_students(params)
|
12
12
|
end
|
13
13
|
alias_method :all_active_students, :get_all_active_students
|
@@ -117,12 +117,32 @@ module PsUtilities
|
|
117
117
|
return {"errorMessage"=>{"message"=>"A valid dcid must be entered."}} if "#{ps_dcid.to_i}".eql? "0"
|
118
118
|
|
119
119
|
answer = api(:get, api_path, options)
|
120
|
-
{ student: (answer["student"] || []) }
|
120
|
+
return { student: (answer["student"] || []) } if answer.code.to_s.eql? "200"
|
121
|
+
# return { student: (answer.parsed_response["student"] || []) } if answer.code.to_s.eql? "200"
|
122
|
+
return {"errorMessage"=>"#{answer.response}"}
|
121
123
|
end
|
122
124
|
alias_method :get_student, :get_one_student
|
123
125
|
|
124
126
|
private
|
125
127
|
|
128
|
+
# build the api query - you can use splats to match any character
|
129
|
+
# @param params [Hash] - valid keys include: :status_code (or :enroll_status), :username, :last_name, :first_name, :student_id (or :local_id), :id (or :dcid)
|
130
|
+
# @return [String] - "id==345;name.last_name==BA*"
|
131
|
+
def build_query(params)
|
132
|
+
query = []
|
133
|
+
query << "school_enrollment.enroll_status_code==#{params[:status_code]}" if params.has_key?(:status_code)
|
134
|
+
query << "school_enrollment.enroll_status==#{params[:enroll_status]}" if params.has_key?(:enroll_status)
|
135
|
+
query << "student_username==#{params[:username]}" if params.has_key?(:username)
|
136
|
+
query << "name.last_name==#{params[:last_name]}" if params.has_key?(:last_name)
|
137
|
+
query << "name.first_name==#{params[:first_name]}" if params.has_key?(:first_name)
|
138
|
+
query << "local_id==#{params[:local_id]}" if params.has_key?(:local_id)
|
139
|
+
query << "local_id==#{params[:student_id]}" if params.has_key?(:student_id)
|
140
|
+
query << "id==#{params[:dcid]}" if params.has_key?(:dcid)
|
141
|
+
query << "id==#{params[:id]}" if params.has_key?(:id)
|
142
|
+
answer = query.join(";")
|
143
|
+
answer
|
144
|
+
end
|
145
|
+
|
126
146
|
# given the number of students and page size calculate pages needed to return all students
|
127
147
|
# @param count [Integer] - total number of students matching filter
|
128
148
|
# @param page_size [Integer] - total number of students to be return per page
|
@@ -185,25 +205,9 @@ module PsUtilities
|
|
185
205
|
options[:query]["q"] = query unless query.empty?
|
186
206
|
return {"errorMessage"=>{"message"=>"A valid parameter must be entered."}} if query.empty?
|
187
207
|
# pp options
|
188
|
-
api(:get, api_path, options)
|
189
|
-
|
190
|
-
|
191
|
-
# build the api query - you can use splats to match any character
|
192
|
-
# @param params [Hash] - valid keys include: :status_code (or :enroll_status), :username, :last_name, :first_name, :student_id (or :local_id), :id (or :dcid)
|
193
|
-
# @return [String] - "id==345;name.last_name==BA*"
|
194
|
-
def build_query(params)
|
195
|
-
query = []
|
196
|
-
query << "school_enrollment.enroll_status_code==#{params[:status_code]}" if params.has_key?(:status_code)
|
197
|
-
query << "school_enrollment.enroll_status==#{params[:enroll_status]}" if params.has_key?(:enroll_status)
|
198
|
-
query << "student_username==#{params[:username]}" if params.has_key?(:username)
|
199
|
-
query << "name.last_name==#{params[:last_name]}" if params.has_key?(:last_name)
|
200
|
-
query << "name.first_name==#{params[:first_name]}" if params.has_key?(:first_name)
|
201
|
-
query << "local_id==#{params[:local_id]}" if params.has_key?(:local_id)
|
202
|
-
query << "local_id==#{params[:student_id]}" if params.has_key?(:student_id)
|
203
|
-
query << "id==#{params[:dcid]}" if params.has_key?(:dcid)
|
204
|
-
query << "id==#{params[:id]}" if params.has_key?(:id)
|
205
|
-
answer = query.join(";")
|
206
|
-
answer
|
208
|
+
answer = api(:get, api_path, options)
|
209
|
+
return answer.parsed_response if answer.code.to_s.eql? "200"
|
210
|
+
return {"errorMessage"=>"#{answer.response}"}
|
207
211
|
end
|
208
212
|
|
209
213
|
end
|
@@ -30,28 +30,36 @@ module PsUtilities
|
|
30
30
|
# ]
|
31
31
|
# }
|
32
32
|
# }
|
33
|
+
# @note create_students REQUIRED params are: :id
|
34
|
+
# @note create_students OPTIONAL params are:
|
35
|
+
# @note create_students INVALID params are:
|
33
36
|
def create_students(params)
|
34
37
|
action = "INSERT"
|
35
38
|
kids_api_array = build_kids_api_array(action, params)
|
36
39
|
options = { body: { students: { student: kids_api_array } }.to_json }
|
37
40
|
answer = api(:post, "/ws/v1/student", options)
|
41
|
+
return answer.parsed_response if answer.code.to_s.eql? "200"
|
42
|
+
return {"errorMessage"=>"#{answer.response}"}
|
38
43
|
end
|
39
44
|
alias_method :create_student, :create_students
|
40
45
|
|
41
46
|
# this updates and existing student record within PowerSchool
|
42
47
|
# (see #create_students)
|
48
|
+
# @note update_students REQUIRED params are: :last_name, :first_name, :entry_date, :exit_date, :school_number, :grade_level
|
49
|
+
# @note update_students OPTIONAL params are: :
|
50
|
+
# @note update_students INVALID params are:
|
43
51
|
def update_students(params)
|
44
|
-
pp "update students"
|
45
|
-
pp params
|
46
52
|
action = "UPDATE"
|
47
53
|
kids_api_array = build_kids_api_array(action, params)
|
48
|
-
pp kids_api_array
|
49
54
|
options = { body: { students: { student: kids_api_array } }.to_json }
|
50
|
-
pp options
|
51
55
|
answer = api(:post, "/ws/v1/student", options)
|
56
|
+
return answer.parsed_response if answer.code.to_s.eql? "200"
|
57
|
+
return {"errorMessage"=>"#{answer.response}"}
|
52
58
|
end
|
53
59
|
alias_method :update_student, :update_students
|
54
60
|
|
61
|
+
private
|
62
|
+
|
55
63
|
# @param action [String] - either "INSERT" or "UPDATE"
|
56
64
|
# @param params [Array of Hashes] - in this format -- students: [{kid_1_info}, {kid_2_info}]
|
57
65
|
# @return [Array of Hashes] - with data like below:
|
@@ -85,14 +93,12 @@ module PsUtilities
|
|
85
93
|
#]
|
86
94
|
# @note this is then sent to the API call with a body tag
|
87
95
|
def build_kids_api_array(action, params)
|
88
|
-
pp "build_kids_api_array"
|
89
|
-
pp params
|
90
96
|
students = []
|
91
97
|
api_array = []
|
92
|
-
students
|
93
|
-
students = params[:students] if params[:students]
|
94
|
-
|
95
|
-
return {"errorMessage"=>{"message"=>"
|
98
|
+
# students = [params[:student]] if not params[:student].nil? && params[:student].is_a?(Hash)
|
99
|
+
students = params[:students] #if not params[:students].nil? && params[:students].is_a?(Array)
|
100
|
+
if students.empty?
|
101
|
+
return {"errorMessage"=>{"message"=>"Bad student data - USE: {students: [{kid_data1}, {kid_data2}]}"}}
|
96
102
|
end
|
97
103
|
students.each do |kid|
|
98
104
|
# kid[:las_extensions] = true if params[:las_extensions]
|
@@ -174,13 +180,10 @@ module PsUtilities
|
|
174
180
|
# ]
|
175
181
|
# }
|
176
182
|
def build_kid_attributes(action, kid)
|
177
|
-
pp "build_kid_attributes"
|
178
|
-
pp kid
|
179
183
|
# ALWAYS NEEDED INFO
|
180
184
|
attribs = {action: action}
|
181
|
-
attribs[:id] = kid[:id] || kid[:dcid]
|
182
185
|
attribs[:client_uid] = kid[:student_id].to_s
|
183
|
-
attribs[:student_username] = kid[:username]
|
186
|
+
attribs[:student_username] = kid[:username] if kid[:username]
|
184
187
|
|
185
188
|
# REQUIRED ON ENROLLMENT (optional later)
|
186
189
|
attribs[:name] = {}
|
@@ -206,6 +209,7 @@ module PsUtilities
|
|
206
209
|
attribs[:school_enrollment][:school_id] = kid[:school_id] if kid[:school_id]
|
207
210
|
when 'UPDATE'
|
208
211
|
# don't allow nil / blank name updates
|
212
|
+
attribs[:id] = kid[:id] || kid[:dcid]
|
209
213
|
attribs[:name][:last_name] = kid[:last_name] if kid[:last_name]
|
210
214
|
attribs[:name][:first_name] = kid[:first_name] if kid[:first_name]
|
211
215
|
attribs[:name][:middle_name] = kid[:middle_name] if kid[:middle_name]
|
@@ -278,9 +282,9 @@ module PsUtilities
|
|
278
282
|
# Update LAS Database Extensions as needed
|
279
283
|
attribs["_extension_data"] = { "_table_extension" => [] }
|
280
284
|
# built-in extensions by PowerSchool
|
281
|
-
attribs["_extension_data"]["_table_extension"] << u_studentsuserfields(kid[:u_studentsuserfields])
|
285
|
+
attribs["_extension_data"]["_table_extension"] << u_studentsuserfields(kid[:u_studentsuserfields]) if kid[:u_studentsuserfields]
|
282
286
|
# school defined database extensions
|
283
|
-
attribs["_extension_data"]["_table_extension"] << u_students_extension(kid[:u_students_extension])
|
287
|
+
attribs["_extension_data"]["_table_extension"] << u_students_extension(kid[:u_students_extension]) if kid[:u_students_extension]
|
284
288
|
# if no extension data present make it empty
|
285
289
|
attribs["_extension_data"] = {} if attribs["_extension_data"]["_table_extension"].empty?
|
286
290
|
|
data/lib/ps_utilities/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ps_utilities
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Weisbecker
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-06-
|
12
|
+
date: 2018-06-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: httparty
|
@@ -67,6 +67,20 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '3.7'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: webmock
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '3.4'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '3.4'
|
70
84
|
description: 'Uses oauth2 to connection to the Powerschool API. Heavily refactored
|
71
85
|
code (not dependent on Rails) starting with: https://github.com/TomK32/powerschool'
|
72
86
|
email:
|