strongmind-platform-sdk 3.9.4 → 3.10.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 +3 -0
- data/Gemfile.lock +25 -5
- data/lib/platform_sdk/canvas_api/client.rb +412 -0
- data/lib/platform_sdk/canvas_api.rb +14 -0
- data/lib/platform_sdk/identity/clients.rb +3 -3
- data/lib/platform_sdk/version.rb +1 -1
- data/lib/platform_sdk.rb +2 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2255b872c20eeb033920fa418c2bb7986ca2d4857fc920a61f2d8fd64c9053b6
|
4
|
+
data.tar.gz: 884e3636bc8381f7f083a95875a6596e3f24f9b1152abb2c45ce0613b73dd305
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33b930fd8737f76287c5f781f61f27f766156019bbc9dcc4a0cd596dfe28499cb39cb99cd52c04405c8fa0e7fed068786ef47a847c09310174687ea7e2f35abf
|
7
|
+
data.tar.gz: 65e2ed64748ebe2b6c76fb9fa7262a31611384af3d2a2a0c035d1103936e994e24adefdd4409259bb3ae022a6b640ba37f2c0e029acd4516d2b26d94b320d8b5
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
strongmind-platform-sdk (3.
|
4
|
+
strongmind-platform-sdk (3.10.0)
|
5
5
|
aws-sdk-secretsmanager (~> 1.66)
|
6
6
|
devise
|
7
7
|
faraday (~> 2.5, >= 2.5.2)
|
8
8
|
faraday-retry
|
9
9
|
jwt
|
10
10
|
learnosity-sdk (~> 0.2.2)
|
11
|
+
multi_json
|
11
12
|
omniauth
|
12
13
|
omniauth-rails_csrf_protection
|
13
14
|
omniauth_openid_connect
|
@@ -38,15 +39,18 @@ GEM
|
|
38
39
|
i18n (>= 1.6, < 2)
|
39
40
|
minitest (>= 5.1)
|
40
41
|
tzinfo (~> 2.0)
|
42
|
+
addressable (2.8.6)
|
43
|
+
public_suffix (>= 2.0.2, < 6.0)
|
41
44
|
aes_key_wrap (1.1.0)
|
42
45
|
ast (2.4.2)
|
43
46
|
attr_required (1.0.2)
|
44
47
|
aws-eventstream (1.3.0)
|
45
|
-
aws-partitions (1.
|
46
|
-
aws-sdk-core (3.191.
|
48
|
+
aws-partitions (1.893.0)
|
49
|
+
aws-sdk-core (3.191.2)
|
47
50
|
aws-eventstream (~> 1, >= 1.3.0)
|
48
51
|
aws-partitions (~> 1, >= 1.651.0)
|
49
52
|
aws-sigv4 (~> 1.8)
|
53
|
+
base64
|
50
54
|
jmespath (~> 1, >= 1.6.1)
|
51
55
|
aws-sdk-secretsmanager (1.90.0)
|
52
56
|
aws-sdk-core (~> 3, >= 3.191.0)
|
@@ -55,9 +59,13 @@ GEM
|
|
55
59
|
aws-eventstream (~> 1, >= 1.0.2)
|
56
60
|
base64 (0.2.0)
|
57
61
|
bcrypt (3.1.20)
|
58
|
-
|
62
|
+
bigdecimal (3.1.6)
|
63
|
+
bindata (2.5.0)
|
59
64
|
builder (3.2.4)
|
60
65
|
concurrent-ruby (1.2.2)
|
66
|
+
crack (1.0.0)
|
67
|
+
bigdecimal
|
68
|
+
rexml
|
61
69
|
crass (1.0.6)
|
62
70
|
date (3.3.4)
|
63
71
|
devise (4.9.3)
|
@@ -85,6 +93,7 @@ GEM
|
|
85
93
|
faraday-retry (2.1.0)
|
86
94
|
faraday (~> 2.0)
|
87
95
|
ffi (1.15.5)
|
96
|
+
hashdiff (1.1.0)
|
88
97
|
hashie (5.0.0)
|
89
98
|
i18n (1.13.0)
|
90
99
|
concurrent-ruby (~> 1.0)
|
@@ -112,6 +121,7 @@ GEM
|
|
112
121
|
mini_mime (1.1.5)
|
113
122
|
mini_portile2 (2.8.5)
|
114
123
|
minitest (5.18.0)
|
124
|
+
multi_json (1.15.0)
|
115
125
|
net-imap (0.4.10)
|
116
126
|
date
|
117
127
|
net-protocol
|
@@ -121,9 +131,13 @@ GEM
|
|
121
131
|
timeout
|
122
132
|
net-smtp (0.4.0.1)
|
123
133
|
net-protocol
|
124
|
-
nokogiri (1.16.
|
134
|
+
nokogiri (1.16.2)
|
125
135
|
mini_portile2 (~> 2.8.2)
|
126
136
|
racc (~> 1.4)
|
137
|
+
nokogiri (1.16.2-x86_64-darwin)
|
138
|
+
racc (~> 1.4)
|
139
|
+
nokogiri (1.16.2-x86_64-linux)
|
140
|
+
racc (~> 1.4)
|
127
141
|
omniauth (2.1.2)
|
128
142
|
hashie (>= 3.4.6)
|
129
143
|
rack (>= 2.2.3)
|
@@ -243,6 +257,10 @@ GEM
|
|
243
257
|
activesupport
|
244
258
|
faraday (~> 2.0)
|
245
259
|
faraday-follow_redirects
|
260
|
+
webmock (3.22.0)
|
261
|
+
addressable (>= 2.8.0)
|
262
|
+
crack (>= 0.3.2)
|
263
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
246
264
|
zeitwerk (2.6.13)
|
247
265
|
|
248
266
|
PLATFORMS
|
@@ -257,12 +275,14 @@ DEPENDENCIES
|
|
257
275
|
faraday-retry
|
258
276
|
jwt (~> 1.5, >= 1.5.4)
|
259
277
|
learnosity-sdk (~> 0.2.2)
|
278
|
+
multi_json
|
260
279
|
rake (~> 13.0)
|
261
280
|
rspec (~> 3.6, >= 3.6.0)
|
262
281
|
rubocop
|
263
282
|
sentry-ruby
|
264
283
|
strongmind-oneroster-client (~> 2.0.3)
|
265
284
|
strongmind-platform-sdk!
|
285
|
+
webmock
|
266
286
|
|
267
287
|
BUNDLED WITH
|
268
288
|
2.3.16
|
@@ -0,0 +1,412 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "faraday"
|
3
|
+
|
4
|
+
module PlatformSdk
|
5
|
+
module CanvasApiWrapper
|
6
|
+
# DataPipeline::Client
|
7
|
+
class Client
|
8
|
+
attr_reader :host, :token, :connection
|
9
|
+
|
10
|
+
PAGE_SIZE = 10
|
11
|
+
|
12
|
+
# @param domain [String]
|
13
|
+
# @param token [String]
|
14
|
+
def initialize(domain:, token:)
|
15
|
+
@host = "https://#{domain}"
|
16
|
+
@token = token
|
17
|
+
@connection = Faraday.new(url: host, headers: { 'Authorization' => "Bearer #{token}" })
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param course_id [Integer]
|
21
|
+
# @returns [Array]
|
22
|
+
def course_modules(course_id:)
|
23
|
+
response = @connection.get("/api/v1/courses/#{course_id}/modules")
|
24
|
+
handle_rate_limiting response
|
25
|
+
if success?(response.status)
|
26
|
+
paginated_items headers: response.headers, initial_response: response.body
|
27
|
+
else
|
28
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
29
|
+
error_messages = ''
|
30
|
+
result[:errors].each do |error|
|
31
|
+
error_messages << "#{error[:message]} "
|
32
|
+
end
|
33
|
+
raise "Error getting course modules: #{error_messages}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param course_id [Integer]
|
38
|
+
# @param module_id [Integer]
|
39
|
+
# @returns [Array]
|
40
|
+
def module_items(course_id:, module_id:)
|
41
|
+
response = @connection.get("/api/v1/courses/#{course_id}/modules/#{module_id}/items?per_page=#{PAGE_SIZE}")
|
42
|
+
handle_rate_limiting response
|
43
|
+
if success?(response.status)
|
44
|
+
paginated_items headers: response.headers, initial_response: response.body
|
45
|
+
else
|
46
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
47
|
+
error_messages = ''
|
48
|
+
result[:errors].each do |error|
|
49
|
+
error_messages << "#{error[:message]} "
|
50
|
+
end
|
51
|
+
raise "Error getting module items: #{error_messages}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param course_id [Integer]
|
56
|
+
# @param module_id [Integer]
|
57
|
+
# @param user_id [Integer]
|
58
|
+
# @returns [Array]
|
59
|
+
def user_module_items(course_id:, module_id:, user_id:)
|
60
|
+
uri = "/api/v1/courses/#{course_id}/modules/#{module_id}/items?as_user_id=#{user_id}&per_page=#{PAGE_SIZE}"
|
61
|
+
response = @connection.get(uri)
|
62
|
+
handle_rate_limiting response
|
63
|
+
if success?(response.status)
|
64
|
+
paginated_items headers: response.headers, initial_response: response.body
|
65
|
+
else
|
66
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
67
|
+
error_messages = ''
|
68
|
+
result[:errors].each do |error|
|
69
|
+
error_messages << "#{error[:message]} "
|
70
|
+
end
|
71
|
+
raise "Error getting module items: #{error_messages}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param course_id [Integer]
|
76
|
+
# @param module_id [Integer]
|
77
|
+
# @returns [Array]
|
78
|
+
def assignments(course_id:, module_id:)
|
79
|
+
response = @connection.get("/api/v1/courses/#{course_id}/modules/#{module_id}/items?per_page=#{PAGE_SIZE}")
|
80
|
+
handle_rate_limiting response
|
81
|
+
if success?(response.status)
|
82
|
+
assignments = paginated_items headers: response.headers, initial_response: response.body
|
83
|
+
assignments.select { |item| item[:type] == 'Assignment' }
|
84
|
+
else
|
85
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
86
|
+
error_messages = ''
|
87
|
+
result[:errors].each do |error|
|
88
|
+
error_messages << "#{error[:message]} "
|
89
|
+
end
|
90
|
+
raise "Error getting assignments: #{error_messages}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# @param course_id [Integer]
|
95
|
+
def assignment(course_id:, assignment_id:)
|
96
|
+
uri = "api/v1/courses/#{course_id}/assignments/#{assignment_id}"
|
97
|
+
response = @connection.get(uri)
|
98
|
+
handle_rate_limiting response
|
99
|
+
if success?(response.status)
|
100
|
+
MultiJson.load response.body, symbolize_keys: true
|
101
|
+
else
|
102
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
103
|
+
error_messages = ''
|
104
|
+
result[:errors].each do |error|
|
105
|
+
error_messages << "#{error[:message]} "
|
106
|
+
end
|
107
|
+
raise "Error getting quiz submissions#{error_messages}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param course_id [Integer]
|
112
|
+
# @param module_id [Integer]
|
113
|
+
# @param module_item_id [Integer]
|
114
|
+
def module_item(course_id:, module_id:, module_item_id:)
|
115
|
+
response = @connection.get("/api/v1/courses/#{course_id}/modules/#{module_id}/items/#{module_item_id}")
|
116
|
+
handle_rate_limiting response
|
117
|
+
if success?(response.status)
|
118
|
+
MultiJson.load response.body, symbolize_keys: true
|
119
|
+
else
|
120
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
121
|
+
error_messages = ''
|
122
|
+
result[:errors].each do |error|
|
123
|
+
error_messages << "#{error[:message]} "
|
124
|
+
end
|
125
|
+
raise "Error getting module item: #{error_messages}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def user_module_item(course_id:, module_id:, module_item_id:, user_id:)
|
130
|
+
response = @connection.get("/api/v1/courses/#{course_id}/modules/#{module_id}/items/#{module_item_id}?as_user_id=#{user_id}")
|
131
|
+
handle_rate_limiting response
|
132
|
+
if success?(response.status)
|
133
|
+
MultiJson.load response.body, symbolize_keys: true
|
134
|
+
else
|
135
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
136
|
+
error_messages = ''
|
137
|
+
result[:errors].each do |error|
|
138
|
+
error_messages << "#{error[:message]} "
|
139
|
+
end
|
140
|
+
raise "Error getting module item: #{error_messages}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# @param course_id [Integer]
|
145
|
+
# @param assignment_id [Integer]
|
146
|
+
def submissions(course_id:, assignment_id:)
|
147
|
+
response = @connection.get("/api/v1/courses/#{course_id}/assignments/#{assignment_id}/submissions/")
|
148
|
+
handle_rate_limiting response
|
149
|
+
if success?(response.status)
|
150
|
+
paginated_items headers: response.headers, initial_response: response.body
|
151
|
+
else
|
152
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
153
|
+
error_messages = ''
|
154
|
+
result[:errors].each do |error|
|
155
|
+
error_messages << "#{error[:message]} "
|
156
|
+
end
|
157
|
+
raise "Error getting submissions: #{error_messages}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def update_submission_excused(course_id:, assignment_id:, user_id:)
|
162
|
+
uri = "/api/v1/courses/#{course_id}/assignments/#{assignment_id}/submissions/#{user_id}"
|
163
|
+
response = @connection.put(uri) do |req|
|
164
|
+
req.headers["Content-Type"] = "application/json"
|
165
|
+
req.body = {
|
166
|
+
submission: {
|
167
|
+
excuse: true
|
168
|
+
}
|
169
|
+
}.to_json
|
170
|
+
end
|
171
|
+
handle_rate_limiting response
|
172
|
+
if success?(response.status)
|
173
|
+
MultiJson.load response.body, symbolize_keys: true
|
174
|
+
else
|
175
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
176
|
+
error_messages = ''
|
177
|
+
result[:errors].each do |error|
|
178
|
+
error_messages << "#{error[:message]} "
|
179
|
+
end
|
180
|
+
raise "Error update submissions to excused: #{error_messages}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def update_submission_excused_with_comment(course_id:, assignment_id:, user_id:, comment:)
|
185
|
+
uri = "/api/v1/courses/#{course_id}/assignments/#{assignment_id}/submissions/#{user_id}"
|
186
|
+
response = @connection.put(uri) do |req|
|
187
|
+
req.headers['Content-Type'] = 'application/json'
|
188
|
+
req.body = {
|
189
|
+
'comment': {
|
190
|
+
'text_comment': comment
|
191
|
+
},
|
192
|
+
'submission': {
|
193
|
+
'excuse': true
|
194
|
+
}
|
195
|
+
}.to_json
|
196
|
+
end
|
197
|
+
if success?(response.status)
|
198
|
+
MultiJson.load response.body, symbolize_keys: true
|
199
|
+
else
|
200
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
201
|
+
error_messages = ''
|
202
|
+
result[:errors].each do |error|
|
203
|
+
error_messages << "#{error[:message]} "
|
204
|
+
end
|
205
|
+
raise "Error update submissions to excused: #{error_messages}"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# @param course_id [Integer]
|
210
|
+
def course_students(course_id:)
|
211
|
+
uri = "/api/v1/courses/#{course_id}/users?per_page=#{PAGE_SIZE}"
|
212
|
+
params = { 'enrollment_type[]' => 'student' }
|
213
|
+
response = @connection.get(uri, params)
|
214
|
+
handle_rate_limiting response
|
215
|
+
if success?(response.status)
|
216
|
+
paginated_items headers: response.headers, initial_response: response.body
|
217
|
+
else
|
218
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
219
|
+
error_messages = ''
|
220
|
+
result[:errors].each do |error|
|
221
|
+
error_messages << "#{error[:message]} "
|
222
|
+
end
|
223
|
+
raise "Error getting course students: #{error_messages}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# @param course_id [Integer]
|
228
|
+
# @param quiz_id [Integer]
|
229
|
+
def quiz(course_id:, quiz_id:)
|
230
|
+
uri = "/api/v1/courses/#{course_id}/quizzes/#{quiz_id}"
|
231
|
+
response = @connection.get(uri)
|
232
|
+
handle_rate_limiting response
|
233
|
+
if success?(response.status)
|
234
|
+
MultiJson.load response.body, symbolize_keys: true
|
235
|
+
else
|
236
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
237
|
+
error_messages = ''
|
238
|
+
result[:errors].each do |error|
|
239
|
+
error_messages << "#{error[:message]} "
|
240
|
+
end
|
241
|
+
raise "Error getting quiz: #{error_messages}"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# @param course_id [Integer]
|
246
|
+
# @param quiz_id [Integer]
|
247
|
+
# @param user_id [Integer]
|
248
|
+
# @return [Array]
|
249
|
+
def quiz_submissions(course_id:, quiz_id:, user_id:)
|
250
|
+
uri = "api/v1/courses/#{course_id}/quizzes/#{quiz_id}/submissions?user=#{user_id}&per_page=#{PAGE_SIZE}"
|
251
|
+
response = @connection.get(uri)
|
252
|
+
handle_rate_limiting response
|
253
|
+
if success?(response.status)
|
254
|
+
paginated_items headers: response.headers, initial_response: response.body
|
255
|
+
else
|
256
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
257
|
+
error_messages = ''
|
258
|
+
result[:errors].each do |error|
|
259
|
+
error_messages << "#{error[:message]} "
|
260
|
+
end
|
261
|
+
raise "Error getting quiz submissions#{error_messages}"
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# @param course_id [Integer]
|
266
|
+
# @param quiz_id [Integer]
|
267
|
+
# @param user_id [Integer]
|
268
|
+
def post_create_quiz_submission(course_id:, quiz_id:, user_id:)
|
269
|
+
uri = "api/v1/courses/#{course_id}/quizzes/#{quiz_id}/submissions?as_user_id=#{user_id}"
|
270
|
+
response = @connection.post(uri)
|
271
|
+
handle_rate_limiting response
|
272
|
+
if success?(response.status)
|
273
|
+
MultiJson.load response.body, symbolize_keys: true
|
274
|
+
else
|
275
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
276
|
+
message = 'Error creating quiz submission'
|
277
|
+
if response.status == 403
|
278
|
+
raise "#{message}: #{result[:message]}"
|
279
|
+
end
|
280
|
+
if result[:errors]
|
281
|
+
raise parse_response_errors message:, result:
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# @param course_id [Integer]
|
287
|
+
# @param quiz_id [Integer]
|
288
|
+
# @param submission_id [Integer]
|
289
|
+
# @param attempt [Integer]
|
290
|
+
# @param validation_token [String]
|
291
|
+
# @return [Hash]
|
292
|
+
def post_complete_quiz_submission(course_id:, quiz_id:, submission_id:, attempt:, validation_token:)
|
293
|
+
uri = "api/v1/courses/#{course_id}/quizzes/#{quiz_id}/submissions/#{submission_id}/complete"
|
294
|
+
response = @connection.post(uri) do |req|
|
295
|
+
req.headers['Content-Type'] = 'application/json'
|
296
|
+
req.body = { attempt:, validation_token: }.to_json
|
297
|
+
end
|
298
|
+
handle_rate_limiting response
|
299
|
+
if success?(response.status)
|
300
|
+
MultiJson.load response.body, symbolize_keys: true
|
301
|
+
else
|
302
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
303
|
+
message = 'Error completing quiz submission'
|
304
|
+
if response.status == 403
|
305
|
+
raise "#{message}: #{result[:message]}"
|
306
|
+
end
|
307
|
+
if result[:errors]
|
308
|
+
raise parse_response_errors message:, result:
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# @param course_id [Integer]
|
314
|
+
# @param module_id [Integer]
|
315
|
+
# @param module_item_id [Integer]
|
316
|
+
# @param user_id [Integer]
|
317
|
+
# @return nil
|
318
|
+
def post_mark_module_item_read(course_id:, module_id:, module_item_id:, user_id:)
|
319
|
+
uri = "api/v1/courses/#{course_id}/modules/#{module_id}/items/#{module_item_id}/mark_read?as_user_id=#{user_id}"
|
320
|
+
response = @connection.post(uri)
|
321
|
+
handle_rate_limiting response
|
322
|
+
if success?(response.status)
|
323
|
+
MultiJson.load response.body, symbolize_keys: true
|
324
|
+
else
|
325
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
326
|
+
message = 'Error marking module items read'
|
327
|
+
if response.status == 403
|
328
|
+
raise "#{message}: #{result[:message]}"
|
329
|
+
end
|
330
|
+
if result[:errors]
|
331
|
+
raise parse_response_errors message:, result:
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def post_discussion_topic_entry(course_id:, topic_id:, user_id:, message:)
|
337
|
+
uri = "api/v1/courses/#{course_id}/discussion_topics/#{topic_id}/entries?as_user_id=#{user_id}"
|
338
|
+
response = @connection.post(uri) do |req|
|
339
|
+
req.headers['Content-Type'] = 'application/json'
|
340
|
+
req.body = { 'message': message.to_s }.to_json
|
341
|
+
end
|
342
|
+
handle_rate_limiting response
|
343
|
+
if success?(response.status)
|
344
|
+
MultiJson.load response.body, symbolize_keys: true
|
345
|
+
else
|
346
|
+
result = MultiJson.load response.body, symbolize_keys: true
|
347
|
+
error_messages = ''
|
348
|
+
result[:errors]&.each do |error|
|
349
|
+
error_messages << "#{error[:message]} "
|
350
|
+
end
|
351
|
+
raise "Error posting a reply: #{error_messages}"
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
private
|
356
|
+
|
357
|
+
# @param headers [Faraday::Utils::Headers]
|
358
|
+
# @return [Array]
|
359
|
+
def paginated_items(headers:, initial_response:)
|
360
|
+
pages = page_links(headers:)
|
361
|
+
items = []
|
362
|
+
items.append MultiJson.load(initial_response, symbolize_keys: true)
|
363
|
+
while pages[:current] != pages[:last]
|
364
|
+
response = @connection.get(pages[:next][:url])
|
365
|
+
handle_rate_limiting response
|
366
|
+
pages = page_links(headers: response.headers)
|
367
|
+
items.append MultiJson.load(response.body, symbolize_keys: true)
|
368
|
+
end
|
369
|
+
items.flatten
|
370
|
+
end
|
371
|
+
|
372
|
+
# @param headers [Faraday::Utils::Headers]
|
373
|
+
# @return [Hash]
|
374
|
+
def page_links(headers:)
|
375
|
+
parts = headers[:link].split(',')
|
376
|
+
parts.map do |part, _|
|
377
|
+
section = part.split(';')
|
378
|
+
name = section[1][/rel="(.*)"/, 1].to_sym
|
379
|
+
url = section[0][/<(.*)>/, 1]
|
380
|
+
[name, { url: }]
|
381
|
+
end.to_h
|
382
|
+
end
|
383
|
+
|
384
|
+
# @param response_code [Integer]
|
385
|
+
# @return [Boolean]
|
386
|
+
def success?(response_code)
|
387
|
+
!!(response_code.to_s =~ /2[0-9]/)
|
388
|
+
end
|
389
|
+
|
390
|
+
# @param message [String]
|
391
|
+
# @param result [Hash]
|
392
|
+
# @return [String]
|
393
|
+
def parse_response_errors(message:, result:)
|
394
|
+
error_messages = ''
|
395
|
+
result[:errors].each do |error|
|
396
|
+
error_messages << "#{error[:message]} "
|
397
|
+
end
|
398
|
+
"#{message}: {#{error_messages}"
|
399
|
+
end
|
400
|
+
|
401
|
+
def handle_rate_limiting(response)
|
402
|
+
remaining_requests = response.headers["X-Rate-Limit-Remaining"].to_i
|
403
|
+
reset_time = response.headers["X-Rate-Limit-Reset"].to_i
|
404
|
+
|
405
|
+
return unless remaining_requests.zero?
|
406
|
+
|
407
|
+
sleep_time = [reset_time - Time.now.to_i, 0].max + 1
|
408
|
+
sleep(sleep_time)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "faraday"
|
4
|
+
require "faraday/net_http"
|
5
|
+
require "faraday/retry"
|
6
|
+
require "platform_sdk/canvas_api/client"
|
7
|
+
|
8
|
+
module PlatformSdk
|
9
|
+
module CanvasApiWrapper
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -75,12 +75,12 @@ module PlatformSdk
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def refresh_session(session: {})
|
78
|
-
raise ArgumentError if session[:
|
78
|
+
raise ArgumentError if session[:access_token].nil? || session[:refresh_token].nil?
|
79
79
|
|
80
|
-
refreshed_tokens = refresh_token(jwt: session[:
|
80
|
+
refreshed_tokens = refresh_token(jwt: session[:access_token], refresh_token: session[:refresh_token])
|
81
81
|
|
82
82
|
return if refreshed_tokens.nil?
|
83
|
-
|
83
|
+
|
84
84
|
session[:id_token] = refreshed_tokens[:id_token]
|
85
85
|
session[:access_token] = refreshed_tokens[:access_token]
|
86
86
|
session[:refresh_token] = refreshed_tokens[:refresh_token]
|
data/lib/platform_sdk/version.rb
CHANGED
data/lib/platform_sdk.rb
CHANGED
@@ -11,6 +11,8 @@ require "platform_sdk/data_pipeline"
|
|
11
11
|
require "platform_sdk/pencil_spaces"
|
12
12
|
require "platform_sdk/edfi"
|
13
13
|
require "platform_sdk/sentry"
|
14
|
+
require "platform_sdk/learnosity_api"
|
15
|
+
require "platform_sdk/canvas_api"
|
14
16
|
|
15
17
|
module PlatformSdk
|
16
18
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strongmind-platform-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Platform Team
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -184,6 +184,20 @@ dependencies:
|
|
184
184
|
- - ">="
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: '0'
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: multi_json
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
type: :runtime
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
187
201
|
description: Includes a wrapper for the swagger generated OneRoster management clients
|
188
202
|
email:
|
189
203
|
- horseshoes@strongmind.com
|
@@ -214,6 +228,8 @@ files:
|
|
214
228
|
- lib/platform_sdk.rb
|
215
229
|
- lib/platform_sdk/aws.rb
|
216
230
|
- lib/platform_sdk/aws/secrets_manager_client.rb
|
231
|
+
- lib/platform_sdk/canvas_api.rb
|
232
|
+
- lib/platform_sdk/canvas_api/client.rb
|
217
233
|
- lib/platform_sdk/data_pipeline.rb
|
218
234
|
- lib/platform_sdk/data_pipeline/data_pipeline_client.rb
|
219
235
|
- lib/platform_sdk/edfi.rb
|