canvas_sync 0.22.5 → 0.22.8
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/README.md +0 -0
- data/lib/canvas_sync/concerns/api_syncable.rb +9 -6
- data/lib/canvas_sync/concerns/sync_mapping.rb +11 -1
- data/lib/canvas_sync/generators/templates/migrations/create_enrollments.rb +1 -0
- data/lib/canvas_sync/generators/templates/models/course_progress.rb +8 -0
- data/lib/canvas_sync/importers/bulk_importer.rb +39 -69
- data/lib/canvas_sync/job.rb +0 -0
- data/lib/canvas_sync/job_batches/batch.rb +1 -1
- data/lib/canvas_sync/job_batches/chain_builder.rb +3 -24
- data/lib/canvas_sync/job_batches/jobs/managed_batch_job.rb +0 -4
- data/lib/canvas_sync/job_batches/status.rb +0 -1
- data/lib/canvas_sync/job_uniqueness/lock_context.rb +3 -15
- data/lib/canvas_sync/jobs/term_batches_job.rb +1 -4
- data/lib/canvas_sync/processors/model_mappings.yml +3 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/canvas_sync/canvas_sync_spec.rb +41 -59
- data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +4 -0
- data/spec/dummy/app/models/course_progress.rb +8 -0
- data/spec/dummy/app/models/learning_outcome_result.rb +0 -0
- data/spec/dummy/app/models/rubric.rb +0 -0
- data/spec/dummy/app/models/rubric_assessment.rb +0 -0
- data/spec/dummy/app/models/rubric_association.rb +0 -0
- data/spec/dummy/app/models/user.rb +0 -0
- data/spec/dummy/db/migrate/20190702203624_create_enrollments.rb +1 -0
- data/spec/dummy/db/migrate/20240408223326_create_course_nicknames.rb +0 -0
- data/spec/dummy/db/migrate/20240509105100_create_rubrics.rb +0 -0
- data/spec/dummy/db/schema.rb +1 -0
- metadata +196 -211
- data/lib/canvas_sync/concerns/auto_relations.rb +0 -11
@@ -2,6 +2,18 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe CanvasSync do
|
4
4
|
describe '.provisioning_sync' do
|
5
|
+
it 'invokes the first job in the queue and passes on the rest of the job chain' do
|
6
|
+
expected_job_chain = CanvasSync.default_provisioning_report_chain(['courses'], term_scope: nil).normalize![:args][0]
|
7
|
+
|
8
|
+
expect(CanvasSync::Jobs::BeginSyncChainJob).to receive(:perform_later)
|
9
|
+
.with(
|
10
|
+
expected_job_chain,
|
11
|
+
anything
|
12
|
+
)
|
13
|
+
|
14
|
+
CanvasSync.provisioning_sync(['courses'])
|
15
|
+
end
|
16
|
+
|
5
17
|
context 'an invalid model is passed in' do
|
6
18
|
it 'raises a helpful exception' do
|
7
19
|
expect {
|
@@ -18,25 +30,22 @@ RSpec.describe CanvasSync do
|
|
18
30
|
provisioning: { c: 3 },
|
19
31
|
global: { d: 4 },
|
20
32
|
})
|
21
|
-
expect(chain.normalize!).to
|
33
|
+
expect(chain.normalize!).to eq({
|
22
34
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
23
|
-
:chain_link=>String,
|
24
35
|
:args => [
|
25
36
|
[
|
26
37
|
{
|
27
38
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
28
|
-
:chain_link=>String,
|
29
39
|
:args=>[
|
30
40
|
[
|
31
|
-
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
41
|
+
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users"], :b=>2}},
|
32
42
|
{
|
33
43
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
34
|
-
:chain_link=>String,
|
35
44
|
:args=>[],
|
36
45
|
:kwargs=>{
|
37
46
|
:term_scope=>"active",
|
38
47
|
:sub_jobs=>[
|
39
|
-
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
48
|
+
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"], :c=>3}},
|
40
49
|
],
|
41
50
|
},
|
42
51
|
},
|
@@ -53,23 +62,20 @@ RSpec.describe CanvasSync do
|
|
53
62
|
context 'we are syncing users with a term scope' do
|
54
63
|
it 'syncs the users in a separate job that runs first' do
|
55
64
|
chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], term_scope: :active)
|
56
|
-
expect(chain.normalize!).to
|
65
|
+
expect(chain.normalize!).to eq({
|
57
66
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
58
|
-
:chain_link=>String,
|
59
67
|
:args => [[
|
60
68
|
{
|
61
69
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
62
|
-
:chain_link=>String,
|
63
70
|
:args=>[
|
64
71
|
[
|
65
|
-
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
72
|
+
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users"]}},
|
66
73
|
{
|
67
74
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
68
|
-
:chain_link=>String,
|
69
75
|
:args=>[],
|
70
76
|
:kwargs=>{
|
71
77
|
:sub_jobs=>[
|
72
|
-
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
78
|
+
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}
|
73
79
|
],
|
74
80
|
:term_scope=>"active",
|
75
81
|
}
|
@@ -87,20 +93,17 @@ RSpec.describe CanvasSync do
|
|
87
93
|
context 'we are syncing users without a term scope' do
|
88
94
|
it 'syncs users along with the rest of the provisioning report' do
|
89
95
|
chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'])
|
90
|
-
expect(chain.normalize!).to
|
96
|
+
expect(chain.normalize!).to eq({
|
91
97
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
92
|
-
:chain_link=>String,
|
93
98
|
:args => [[
|
94
99
|
{
|
95
100
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
96
|
-
:chain_link=>String,
|
97
101
|
:args=>[[
|
98
102
|
{
|
99
103
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
100
|
-
:chain_link=>String,
|
101
104
|
:args=>[],
|
102
105
|
:kwargs=>{
|
103
|
-
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
106
|
+
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "courses"]}}],
|
104
107
|
:term_scope=>nil,
|
105
108
|
}
|
106
109
|
}
|
@@ -116,21 +119,18 @@ RSpec.describe CanvasSync do
|
|
116
119
|
context 'we are syncing roles with a term scope' do
|
117
120
|
it 'syncs the roles in a separate job that runs first' do
|
118
121
|
chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'], term_scope: :active)
|
119
|
-
expect(chain.normalize!).to
|
122
|
+
expect(chain.normalize!).to eq({
|
120
123
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
121
|
-
:chain_link=>String,
|
122
124
|
:args => [[
|
123
125
|
{
|
124
126
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
125
|
-
:chain_link=>String,
|
126
127
|
:args=>[[
|
127
|
-
{:job=>"CanvasSync::Jobs::SyncRolesJob", :
|
128
|
+
{:job=>"CanvasSync::Jobs::SyncRolesJob", :options=>{}},
|
128
129
|
{
|
129
130
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
130
|
-
:chain_link=>String,
|
131
131
|
:args=>[],
|
132
132
|
:kwargs=>{
|
133
|
-
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
133
|
+
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}],
|
134
134
|
:term_scope=>"active",
|
135
135
|
}
|
136
136
|
},
|
@@ -146,21 +146,18 @@ RSpec.describe CanvasSync do
|
|
146
146
|
context 'we are syncing roles without a term scope' do
|
147
147
|
it 'syncs roles separately even with no term scope' do
|
148
148
|
chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'])
|
149
|
-
expect(chain.normalize!).to
|
149
|
+
expect(chain.normalize!).to eq({
|
150
150
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
151
|
-
:chain_link=>String,
|
152
151
|
:args => [[
|
153
152
|
{
|
154
153
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
155
|
-
:chain_link=>String,
|
156
154
|
:args=>[[
|
157
|
-
{:job=>"CanvasSync::Jobs::SyncRolesJob", :
|
155
|
+
{:job=>"CanvasSync::Jobs::SyncRolesJob", :options=>{}},
|
158
156
|
{
|
159
157
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
160
|
-
:chain_link=>String,
|
161
158
|
:args=>[],
|
162
159
|
:kwargs=>{
|
163
|
-
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
160
|
+
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}],
|
164
161
|
:term_scope=>nil,
|
165
162
|
}
|
166
163
|
}
|
@@ -176,21 +173,18 @@ RSpec.describe CanvasSync do
|
|
176
173
|
context 'we are syncing admins with a term scope' do
|
177
174
|
it 'syncs the admins in a separate job that runs first' do
|
178
175
|
chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'], term_scope: :active)
|
179
|
-
expect(chain.normalize!).to
|
176
|
+
expect(chain.normalize!).to eq({
|
180
177
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
181
|
-
:chain_link=>String,
|
182
178
|
:args => [[
|
183
179
|
{
|
184
180
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
185
|
-
:chain_link=>String,
|
186
181
|
:args=>[[
|
187
|
-
{:job=>"CanvasSync::Jobs::SyncAdminsJob", :
|
182
|
+
{:job=>"CanvasSync::Jobs::SyncAdminsJob", :options=>{}},
|
188
183
|
{
|
189
184
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
190
|
-
:chain_link=>String,
|
191
185
|
:args=>[],
|
192
186
|
:kwargs=>{
|
193
|
-
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
187
|
+
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}],
|
194
188
|
:term_scope=>"active"
|
195
189
|
}
|
196
190
|
}
|
@@ -206,21 +200,18 @@ RSpec.describe CanvasSync do
|
|
206
200
|
context 'we are syncing admins without a term scope' do
|
207
201
|
it 'syncs admins separately even with no term scope' do
|
208
202
|
chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'])
|
209
|
-
expect(chain.normalize!).to
|
203
|
+
expect(chain.normalize!).to eq({
|
210
204
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
211
|
-
:chain_link=>String,
|
212
205
|
:args => [[
|
213
206
|
{
|
214
207
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
215
|
-
:chain_link=>String,
|
216
208
|
:args=>[[
|
217
|
-
{:job=>"CanvasSync::Jobs::SyncAdminsJob", :
|
209
|
+
{:job=>"CanvasSync::Jobs::SyncAdminsJob", :options=>{}},
|
218
210
|
{
|
219
211
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
220
|
-
:chain_link=>String,
|
221
212
|
:args=>[],
|
222
213
|
:kwargs=>{
|
223
|
-
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
214
|
+
:sub_jobs=>[{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["courses"]}}],
|
224
215
|
:term_scope=>nil
|
225
216
|
}
|
226
217
|
}
|
@@ -237,22 +228,19 @@ RSpec.describe CanvasSync do
|
|
237
228
|
it "appends the SyncAssignmentsJob" do
|
238
229
|
chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignments])
|
239
230
|
|
240
|
-
expect(chain.normalize!).to
|
231
|
+
expect(chain.normalize!).to eq({
|
241
232
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
242
|
-
:chain_link=>String,
|
243
233
|
:args => [[
|
244
234
|
{
|
245
235
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
246
|
-
:chain_link=>String,
|
247
236
|
:args=>[[
|
248
237
|
{
|
249
238
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
250
|
-
:chain_link=>String,
|
251
239
|
:args=>[],
|
252
240
|
:kwargs=>{
|
253
241
|
:sub_jobs=>[
|
254
|
-
{:job=>"CanvasSync::Jobs::SyncAssignmentsJob", :
|
255
|
-
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
242
|
+
{:job=>"CanvasSync::Jobs::SyncAssignmentsJob", :options=>{}},
|
243
|
+
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"]}}
|
256
244
|
],
|
257
245
|
:term_scope=>nil
|
258
246
|
}
|
@@ -270,22 +258,19 @@ RSpec.describe CanvasSync do
|
|
270
258
|
it "appends the SyncSubmissionsJob" do
|
271
259
|
chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments submissions])
|
272
260
|
|
273
|
-
expect(chain.normalize!).to
|
261
|
+
expect(chain.normalize!).to eq({
|
274
262
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
275
|
-
:chain_link=>String,
|
276
263
|
:args => [[
|
277
264
|
{
|
278
265
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
279
|
-
:chain_link=>String,
|
280
266
|
:args=>[[
|
281
267
|
{
|
282
268
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
283
|
-
:chain_link=>String,
|
284
269
|
:args=>[],
|
285
270
|
:kwargs=>{
|
286
271
|
:sub_jobs=>[
|
287
|
-
{:job=>"CanvasSync::Jobs::SyncSubmissionsJob", :
|
288
|
-
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
272
|
+
{:job=>"CanvasSync::Jobs::SyncSubmissionsJob", :options=>{}},
|
273
|
+
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"]}}
|
289
274
|
],
|
290
275
|
:term_scope=>nil
|
291
276
|
}
|
@@ -303,22 +288,19 @@ RSpec.describe CanvasSync do
|
|
303
288
|
it "appends the SyncAssignmentGroupsJob" do
|
304
289
|
chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignment_groups])
|
305
290
|
|
306
|
-
expect(chain.normalize!).to
|
291
|
+
expect(chain.normalize!).to eq({
|
307
292
|
:job => "CanvasSync::Jobs::BeginSyncChainJob",
|
308
|
-
:chain_link=>String,
|
309
293
|
:args => [[
|
310
294
|
{
|
311
295
|
:job=>"CanvasSync::JobBatches::ConcurrentBatchJob",
|
312
|
-
:chain_link=>String,
|
313
296
|
:args=>[[
|
314
297
|
{
|
315
298
|
:job=>"CanvasSync::Jobs::SyncTermsJob",
|
316
|
-
:chain_link=>String,
|
317
299
|
:args=>[],
|
318
300
|
:kwargs=>{
|
319
301
|
:sub_jobs=>[
|
320
|
-
{:job=>"CanvasSync::Jobs::SyncAssignmentGroupsJob", :
|
321
|
-
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :
|
302
|
+
{:job=>"CanvasSync::Jobs::SyncAssignmentGroupsJob", :options=>{}},
|
303
|
+
{:job=>"CanvasSync::Jobs::SyncProvisioningReportJob", :options=>{:models=>["users", "enrollments"]}}
|
322
304
|
],
|
323
305
|
:term_scope=>nil
|
324
306
|
}
|
@@ -12,6 +12,10 @@ RSpec.describe CanvasSync::Processors::ProvisioningReportProcessor do
|
|
12
12
|
|
13
13
|
context "with User#sis_id column" do
|
14
14
|
before do
|
15
|
+
# this could be refactored into a method that prevents caching the variables unless the environment is prod
|
16
|
+
CanvasSync::Concerns::SyncMapping::Mapping.instance_variable_set(:@mappings, nil)
|
17
|
+
CanvasSync::Concerns::SyncMapping::Mapping.instance_variable_set(:@legacy_mappings, nil)
|
18
|
+
|
15
19
|
self.use_transactional_tests = false
|
16
20
|
ActiveRecord::Migration.add_column :users, :sis_id, :string
|
17
21
|
User.reset_column_information
|
@@ -9,6 +9,7 @@
|
|
9
9
|
# CourseProgress is not a Canvas model. It is a table built from the Custom Report
|
10
10
|
class CourseProgress < ApplicationRecord
|
11
11
|
include CanvasSync::Record
|
12
|
+
include CanvasSync::Concerns::ApiSyncable
|
12
13
|
|
13
14
|
canvas_sync_features :defaults
|
14
15
|
|
@@ -17,4 +18,11 @@ class CourseProgress < ApplicationRecord
|
|
17
18
|
|
18
19
|
validates_presence_of :canvas_user_id, :canvas_course_id
|
19
20
|
validates_uniqueness_of :canvas_user_id, scope: :canvas_course_id
|
21
|
+
|
22
|
+
api_syncable({
|
23
|
+
requirement_count: :requirement_count,
|
24
|
+
requirement_completed_count: :requirement_completed_count,
|
25
|
+
# provisioning report has completion_date instead of completed_at in the API
|
26
|
+
completion_date: :completed_at
|
27
|
+
}, -> (api) { api.course_progress(canvas_course_id, canvas_user_id) })
|
20
28
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -210,6 +210,7 @@ ActiveRecord::Schema.define(version: 2024_05_23_101010) do
|
|
210
210
|
t.bigint "canvas_section_id"
|
211
211
|
t.string "workflow_state"
|
212
212
|
t.string "base_role_type"
|
213
|
+
t.datetime "completed_at"
|
213
214
|
t.datetime "created_at", null: false
|
214
215
|
t.datetime "updated_at", null: false
|
215
216
|
t.index ["canvas_course_id"], name: "index_enrollments_on_canvas_course_id"
|