canvas_sync 0.12.0 → 0.16.1

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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/canvas_sync.rb +85 -30
  4. data/lib/canvas_sync/api_syncable.rb +4 -162
  5. data/lib/canvas_sync/class_callback_executor.rb +35 -0
  6. data/lib/canvas_sync/concerns/account/ancestry.rb +60 -0
  7. data/lib/canvas_sync/concerns/api_syncable.rb +189 -0
  8. data/lib/canvas_sync/concerns/legacy_columns.rb +34 -0
  9. data/lib/canvas_sync/generators/templates/migrations/create_group_memberships.rb +18 -0
  10. data/lib/canvas_sync/generators/templates/migrations/create_groups.rb +23 -0
  11. data/lib/canvas_sync/generators/templates/migrations/create_pseudonyms.rb +18 -0
  12. data/lib/canvas_sync/generators/templates/migrations/create_submissions.rb +1 -0
  13. data/lib/canvas_sync/generators/templates/models/account.rb +11 -1
  14. data/lib/canvas_sync/generators/templates/models/admin.rb +2 -1
  15. data/lib/canvas_sync/generators/templates/models/assignment.rb +2 -1
  16. data/lib/canvas_sync/generators/templates/models/assignment_group.rb +2 -1
  17. data/lib/canvas_sync/generators/templates/models/context_module.rb +2 -1
  18. data/lib/canvas_sync/generators/templates/models/context_module_item.rb +2 -1
  19. data/lib/canvas_sync/generators/templates/models/course.rb +4 -2
  20. data/lib/canvas_sync/generators/templates/models/enrollment.rb +2 -1
  21. data/lib/canvas_sync/generators/templates/models/group.rb +19 -0
  22. data/lib/canvas_sync/generators/templates/models/group_membership.rb +17 -0
  23. data/lib/canvas_sync/generators/templates/models/pseudonym.rb +8 -0
  24. data/lib/canvas_sync/generators/templates/models/role.rb +2 -1
  25. data/lib/canvas_sync/generators/templates/models/section.rb +2 -1
  26. data/lib/canvas_sync/generators/templates/models/submission.rb +3 -1
  27. data/lib/canvas_sync/generators/templates/models/term.rb +2 -1
  28. data/lib/canvas_sync/generators/templates/models/user.rb +4 -1
  29. data/lib/canvas_sync/importers/bulk_importer.rb +7 -1
  30. data/lib/canvas_sync/importers/legacy_importer.rb +4 -2
  31. data/lib/canvas_sync/job.rb +3 -1
  32. data/lib/canvas_sync/job_chain.rb +57 -0
  33. data/lib/canvas_sync/jobs/{sync_users_job.rb → sync_accounts_job.rb} +11 -6
  34. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +2 -0
  35. data/lib/canvas_sync/processors/model_mappings.yml +81 -0
  36. data/lib/canvas_sync/processors/provisioning_report_processor.rb +28 -0
  37. data/lib/canvas_sync/record.rb +9 -0
  38. data/lib/canvas_sync/version.rb +1 -1
  39. data/spec/canvas_sync/canvas_sync_spec.rb +19 -16
  40. data/spec/canvas_sync/models/accounts_spec.rb +3 -0
  41. data/spec/canvas_sync/models/course_spec.rb +4 -0
  42. data/spec/canvas_sync/models/group_membership_spec.rb +26 -0
  43. data/spec/canvas_sync/models/group_spec.rb +26 -0
  44. data/spec/canvas_sync/models/user_spec.rb +2 -0
  45. data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +20 -0
  46. data/spec/dummy/app/models/account.rb +8 -1
  47. data/spec/dummy/app/models/admin.rb +2 -1
  48. data/spec/dummy/app/models/assignment.rb +2 -1
  49. data/spec/dummy/app/models/assignment_group.rb +2 -1
  50. data/spec/dummy/app/models/context_module.rb +2 -1
  51. data/spec/dummy/app/models/context_module_item.rb +2 -1
  52. data/spec/dummy/app/models/course.rb +4 -2
  53. data/spec/dummy/app/models/enrollment.rb +2 -1
  54. data/spec/dummy/app/models/group.rb +25 -0
  55. data/spec/dummy/app/models/group_membership.rb +23 -0
  56. data/spec/dummy/app/models/role.rb +2 -1
  57. data/spec/dummy/app/models/section.rb +2 -1
  58. data/spec/dummy/app/models/submission.rb +2 -1
  59. data/spec/dummy/app/models/term.rb +2 -1
  60. data/spec/dummy/app/models/user.rb +3 -1
  61. data/spec/dummy/config/application.rb +12 -1
  62. data/spec/dummy/config/database.yml +11 -11
  63. data/spec/dummy/config/environments/development.rb +3 -3
  64. data/spec/dummy/config/initializers/assets.rb +1 -1
  65. data/spec/dummy/db/migrate/20190702203627_create_submissions.rb +1 -0
  66. data/spec/dummy/db/migrate/20200415171620_create_groups.rb +29 -0
  67. data/spec/dummy/db/migrate/20200416214248_create_group_memberships.rb +24 -0
  68. data/spec/dummy/db/schema.rb +31 -1
  69. data/spec/factories/group_factory.rb +8 -0
  70. data/spec/factories/group_membership_factory.rb +6 -0
  71. data/spec/support/fixtures/reports/group_memberships.csv +3 -0
  72. data/spec/support/fixtures/reports/groups.csv +3 -0
  73. data/spec/support/fixtures/reports/submissions.csv +3 -3
  74. metadata +36 -6
  75. data/spec/canvas_sync/jobs/sync_users_job_spec.rb +0 -15
@@ -1,7 +1,8 @@
1
1
  # <%= autogenerated_model_warning %>
2
2
 
3
3
  class Role < ApplicationRecord
4
- include CanvasSync::ApiSyncable
4
+ include CanvasSync::Record
5
+ include CanvasSync::Concerns::ApiSyncable
5
6
 
6
7
  validates :canvas_id, uniqueness: true, presence: true
7
8
  has_many :admins, foreign_key: :canvas_role_id, primary_key: :canvas_id
@@ -1,7 +1,8 @@
1
1
  # <%= autogenerated_model_warning %>
2
2
 
3
3
  class Section < ApplicationRecord
4
- include CanvasSync::ApiSyncable
4
+ include CanvasSync::Record
5
+ include CanvasSync::Concerns::ApiSyncable
5
6
 
6
7
  validates :canvas_id, uniqueness: true, presence: true
7
8
  belongs_to :course, primary_key: :canvas_id, foreign_key: :canvas_course_id, optional: true
@@ -1,7 +1,8 @@
1
1
  # <%= autogenerated_model_warning %>
2
2
 
3
3
  class Submission < ApplicationRecord
4
- include CanvasSync::ApiSyncable
4
+ include CanvasSync::Record
5
+ include CanvasSync::Concerns::ApiSyncable
5
6
 
6
7
  validates :canvas_id, uniqueness: true, presence: true
7
8
  belongs_to :assignment, primary_key: :canvas_id, foreign_key: :canvas_assignment_id, optional: true
@@ -13,6 +14,7 @@ class Submission < ApplicationRecord
13
14
  canvas_user_id: :user_id,
14
15
  submitted_at: :submitted_at,
15
16
  graded_at: :graded_at,
17
+ cached_due_date: :due_at,
16
18
  score: :score,
17
19
  excused: :excused,
18
20
  workflow_state: :workflow_state,
@@ -1,7 +1,8 @@
1
1
  # <%= autogenerated_model_warning %>
2
2
 
3
3
  class Term < ApplicationRecord
4
- include CanvasSync::ApiSyncable
4
+ include CanvasSync::Record
5
+ include CanvasSync::Concerns::ApiSyncable
5
6
 
6
7
  validates :canvas_id, uniqueness: true, presence: true
7
8
  has_many :courses, foreign_key: :canvas_term_id, primary_key: :canvas_id
@@ -1,13 +1,16 @@
1
1
  # <%= autogenerated_model_warning %>
2
2
 
3
3
  class User < ApplicationRecord
4
- include CanvasSync::ApiSyncable
4
+ include CanvasSync::Record
5
+ include CanvasSync::Concerns::ApiSyncable
5
6
 
6
7
  validates :canvas_id, uniqueness: true, presence: true
8
+ has_many :pseudonyms, primary_key: :canvas_id, foreign_key: :canvas_user_id
7
9
  has_many :enrollments, primary_key: :canvas_id, foreign_key: :canvas_user_id
8
10
  has_many :admins, primary_key: :canvas_id, foreign_key: :canvas_user_id
9
11
  has_many :admin_roles, through: :admins, source: :role
10
12
  has_many :submissions, primary_key: :canvas_id, foreign_key: :canvas_user_id
13
+ has_many :group_memberships, primary_key: :canvas_id, foreign_key: :canvas_user_id
11
14
 
12
15
  api_syncable({
13
16
  sis_id: :sis_user_id,
@@ -17,7 +17,13 @@ module CanvasSync
17
17
  # Note: passing the key [:on_duplicate_key_ignore] will override the default behavior of [:on_duplicate_key_update]
18
18
  # @yieldparam [Array] row if a block is passed in it will yield the current row from the CSV.
19
19
  # This can be used if you need to filter or massage the data in any way.
20
- def self.import(report_file_path, mapping, klass, conflict_target, import_args: {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/LineLength
20
+ def self.import(report_file_path, mapping, klass, conflict_target, import_args: {}, &blk) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/LineLength
21
+ ClassCallbackExecutor.run_if_defined(klass, :sync_import) do
22
+ perform_in_batches(report_file_path, mapping, klass, conflict_target, import_args: import_args, &blk)
23
+ end
24
+ end
25
+
26
+ def self.perform_in_batches(report_file_path, mapping, klass, conflict_target, import_args: {})
21
27
  csv_column_names = mapping.keys
22
28
  database_column_names = mapping.values.map { |value| value[:database_column_name] }
23
29
  rows = []
@@ -8,8 +8,10 @@ module CanvasSync
8
8
  # @param report_file_path [String]
9
9
  # @param klass [Object]
10
10
  def self.import(report_file_path, klass, account_id, options)
11
- CSV.foreach(report_file_path, headers: true, header_converters: :symbol) do |row|
12
- klass.create_or_update_from_csv(row, account_id, options)
11
+ ClassCallbackExecutor.run_if_defined(klass, :sync_import) do
12
+ CSV.foreach(report_file_path, headers: true, header_converters: :symbol) do |row|
13
+ klass.create_or_update_from_csv(row, account_id, options)
14
+ end
13
15
  end
14
16
  end
15
17
  end
@@ -61,7 +61,9 @@ module CanvasSync
61
61
  if model.respond_to? :create_or_update
62
62
  model.create_or_update(params)
63
63
  elsif model.method_defined? :update_from_api_params!
64
- model.find_or_initialize_by(canvas_id: params['id']).update_from_api_params!(params)
64
+ instance = model.find_or_initialize_by(canvas_id: params['id'])
65
+ instance.update_from_api_params!(params)
66
+ instance
65
67
  else
66
68
  raise "Could not create/update #{model.name}. It must have a create_or_update(params) ClassMethod or implement ApiSyncable."
67
69
  end
@@ -0,0 +1,57 @@
1
+ module CanvasSync
2
+ class JobChain
3
+ attr_reader :chain_data
4
+
5
+ delegate_missing_to :chain_data
6
+
7
+ VALID_PLACEMENT_PARAMETERS = %i[before after].freeze
8
+
9
+ def initialize(chain_data)
10
+ @chain_data = chain_data
11
+ end
12
+
13
+ def jobs
14
+ chain_data[:jobs]
15
+ end
16
+
17
+ def global_options
18
+ chain_data[:global_options]
19
+ end
20
+
21
+ def merge_options(job, options)
22
+ jobs.each do |j|
23
+ j[:options].deep_merge!(options) if job_matches_pattern(j, job)
24
+ end
25
+ end
26
+
27
+ def insert(new_job, **kwargs)
28
+ invalid_params = kwargs.keys - VALID_PLACEMENT_PARAMETERS
29
+ raise "Invalid placement parameters: #{invalid_params.map(&:to_s).join(', ')}" if invalid_params.present?
30
+ raise "Exactly one placement parameter may be provided" if kwargs.values.compact!.length > 1
31
+
32
+ if !kwargs.present?
33
+ jobs << new_job
34
+ else
35
+ placement = kwargs.keys[0]
36
+ relative_to = kwargs.values[0]
37
+
38
+ index = jobs.index { |job| job_matches_pattern(job, relative_to) }
39
+ raise "Could not find a \"#{relative_to}\" job in the chain" if index.nil?
40
+
41
+ index += 1 if placement == :after
42
+ new_job[:job] = new_job[:job].to_s
43
+ jobs.insert(index, new_job)
44
+ end
45
+ end
46
+
47
+ def process!(extra_options: {})
48
+ CanvasSync::invoke_next(self, extra_options: extra_options)
49
+ end
50
+
51
+ private
52
+
53
+ def job_matches_pattern(job_entry, pattern)
54
+ job_entry[:job].to_s == pattern.to_s
55
+ end
56
+ end
57
+ end
@@ -1,24 +1,29 @@
1
1
  module CanvasSync
2
2
  module Jobs
3
- class SyncUsersJob < ReportStarter
4
- # Starts a provisioning report for just users.
3
+ class SyncAccountsJob < ReportStarter
4
+ # Starts a provisioning report for just accounts.
5
5
  #
6
- # Provisioning reports do not scope users by term, so when we are
6
+ # Provisioning reports do not scope accounts by term, so when we are
7
7
  # running provisioning by term we sync users first so we don't duplicate
8
- # the work of syncing all users for each term.
8
+ # the work of syncing all accounts for each term.
9
9
  #
10
10
  # @param job_chain [Hash]
11
11
  # @param options [Hash]
12
12
  def perform(job_chain, options)
13
+ unless options[:root_account] == false
14
+ acc_params = CanvasSync.get_canvas_sync_client(job_chain[:global_options]).account("self")
15
+ update_or_create_model(Account, acc_params)
16
+ end
17
+
13
18
  super(
14
19
  job_chain,
15
20
  "proservices_provisioning_csv",
16
21
  merge_report_params(job_chain, options, {
17
- users: true,
22
+ accounts: true,
18
23
  include_deleted: true,
19
24
  }, term_scope: false),
20
25
  CanvasSync::Processors::ProvisioningReportProcessor.to_s,
21
- { models: ["users"] },
26
+ { models: ["accounts"] },
22
27
  )
23
28
  end
24
29
  end
@@ -49,6 +49,8 @@ module CanvasSync
49
49
  }
50
50
 
51
51
  options[:models].each do |model|
52
+ # group_membership is the only model param that is singular :(
53
+ model = 'group_membership' if model == 'group_memberships'
52
54
  params[model] = true
53
55
  end
54
56
 
@@ -29,6 +29,25 @@ users:
29
29
  database_column_name: login_id
30
30
  type: string
31
31
 
32
+ pseudonyms:
33
+ conflict_target: pseudonym_id
34
+ report_columns:
35
+ pseudonym_id:
36
+ database_column_name: canvas_id
37
+ type: integer
38
+ canvas_user_id:
39
+ database_column_name: canvas_user_id
40
+ type: integer
41
+ sis_user_id:
42
+ database_column_name: sis_id
43
+ type: string
44
+ unique_id:
45
+ database_column_name: unique_id
46
+ type: string
47
+ status:
48
+ database_column_name: workflow_state
49
+ type: string
50
+
32
51
  accounts:
33
52
  conflict_target: canvas_account_id
34
53
  report_columns:
@@ -230,6 +249,9 @@ submissions:
230
249
  submission_date:
231
250
  database_column_name: submitted_at
232
251
  type: datetime
252
+ due_at:
253
+ database_column_name: due_at
254
+ type: datetime
233
255
  graded_date:
234
256
  database_column_name: graded_at
235
257
  type: datetime
@@ -326,3 +348,62 @@ context_module_items:
326
348
  assignment_id:
327
349
  database_column_name: canvas_assignment_id
328
350
  type: integer
351
+
352
+ groups:
353
+ conflict_target: canvas_group_id
354
+ report_columns:
355
+ canvas_group_id:
356
+ database_column_name: canvas_id
357
+ type: integer
358
+ group_id:
359
+ database_column_name: sis_id
360
+ type: string
361
+ canvas_group_category_id:
362
+ database_column_name: canvas_group_category_id
363
+ type: integer
364
+ group_category_id:
365
+ database_column_name: group_category_sis_id
366
+ type: integer
367
+ canvas_account_id:
368
+ database_column_name: canvas_account_id
369
+ type: integer
370
+ canvas_course_id:
371
+ database_column_name: canvas_course_id
372
+ type: integer
373
+ name:
374
+ database_column_name: name
375
+ type: string
376
+ status:
377
+ database_column_name: workflow_state
378
+ type: string
379
+ context_id:
380
+ database_column_name: context_id
381
+ type: integer
382
+ context_type:
383
+ database_column_name: context_type
384
+ type: string
385
+ max_membership:
386
+ database_column_name: max_membership
387
+ type: integer
388
+
389
+ group_memberships:
390
+ conflict_target: canvas_group_membership_id
391
+ report_columns:
392
+ canvas_group_membership_id:
393
+ database_column_name: canvas_id
394
+ type: integer
395
+ canvas_group_id:
396
+ database_column_name: canvas_group_id
397
+ type: integer
398
+ group_id:
399
+ database_column_name: group_sis_id
400
+ type: string
401
+ canvas_user_id:
402
+ database_column_name: canvas_user_id
403
+ type: integer
404
+ user_id:
405
+ database_column_name: user_sis_id
406
+ type: string
407
+ status:
408
+ database_column_name: workflow_state
409
+ type: string
@@ -78,6 +78,15 @@ module CanvasSync
78
78
  )
79
79
  end
80
80
 
81
+ def bulk_process_pseudonyms(report_file_path)
82
+ CanvasSync::Importers::BulkImporter.import(
83
+ report_file_path,
84
+ mapping[:pseudonyms][:report_columns],
85
+ Pseudonym,
86
+ mapping[:pseudonyms][:conflict_target].to_sym,
87
+ )
88
+ end
89
+
81
90
  def bulk_process_accounts(report_file_path)
82
91
  CanvasSync::Importers::BulkImporter.import(
83
92
  report_file_path,
@@ -122,6 +131,25 @@ module CanvasSync
122
131
  mapping[:xlist][:conflict_target].to_sym,
123
132
  )
124
133
  end
134
+
135
+ def bulk_process_groups(report_file_path)
136
+ CanvasSync::Importers::BulkImporter.import(
137
+ report_file_path,
138
+ mapping[:groups][:report_columns],
139
+ Group,
140
+ mapping[:groups][:conflict_target].to_sym,
141
+ )
142
+ end
143
+
144
+ # Note that group membership is singular because we override the model name param in sync_provisioning_report_job
145
+ def bulk_process_group_membership(report_file_path)
146
+ CanvasSync::Importers::BulkImporter.import(
147
+ report_file_path,
148
+ mapping[:group_memberships][:report_columns],
149
+ GroupMembership,
150
+ mapping[:group_memberships][:conflict_target].to_sym,
151
+ )
152
+ end
125
153
  end
126
154
  end
127
155
  end
@@ -0,0 +1,9 @@
1
+ module CanvasSync
2
+ module Record
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ define_model_callbacks :sync_import
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.12.0".freeze
2
+ VERSION = "0.16.1".freeze
3
3
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  RSpec.describe CanvasSync do
4
4
  describe '.provisioning_sync' do
5
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'], nil)
6
+ expected_job_chain = CanvasSync.default_provisioning_report_chain(['courses'], nil).chain_data
7
7
  first_job = expected_job_chain[:jobs].shift
8
8
 
9
9
  expect(CanvasSync::Jobs::SyncTermsJob).to receive(:perform_later)
@@ -31,10 +31,10 @@ RSpec.describe CanvasSync do
31
31
  provisioning: { c: 3 },
32
32
  global: { d: 4 },
33
33
  })
34
- expect(chain).to eq({
34
+ expect(chain.chain_data).to eq({
35
35
  jobs: [
36
36
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: { a: 1 } },
37
- { job: CanvasSync::Jobs::SyncUsersJob.to_s, options: { b: 2 } },
37
+ { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { models: ['users'], b: 2 } },
38
38
  { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: 'active', models: ['courses'], c: 3 } }
39
39
  ],
40
40
  global_options: { legacy_support: false, d: 4 }
@@ -44,10 +44,10 @@ RSpec.describe CanvasSync do
44
44
  context 'we are syncing users with a term scope' do
45
45
  it 'syncs the users in a separate job that runs first' do
46
46
  chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'], :active)
47
- expect(chain).to eq({
47
+ expect(chain.chain_data).to eq({
48
48
  jobs: [
49
49
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
50
- { job: CanvasSync::Jobs::SyncUsersJob.to_s, options: {} },
50
+ { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { models: ['users'] } },
51
51
  { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: 'active', models: ['courses'] } }
52
52
  ],
53
53
  global_options: { legacy_support: false }
@@ -58,7 +58,7 @@ RSpec.describe CanvasSync do
58
58
  context 'we are syncing users without a term scope' do
59
59
  it 'syncs users along with the rest of the provisioning report' do
60
60
  chain = CanvasSync.default_provisioning_report_chain(['users', 'courses'])
61
- expect(chain).to eq({
61
+ expect(chain.chain_data).to eq({
62
62
  jobs: [
63
63
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
64
64
  { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: ['users', 'courses'] } }
@@ -71,7 +71,7 @@ RSpec.describe CanvasSync do
71
71
  context 'we are syncing roles with a term scope' do
72
72
  it 'syncs the roles in a separate job that runs first' do
73
73
  chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'], :active)
74
- expect(chain).to eq({
74
+ expect(chain.chain_data).to eq({
75
75
  jobs: [
76
76
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
77
77
  { job: CanvasSync::Jobs::SyncRolesJob.to_s, options: {} },
@@ -85,7 +85,7 @@ RSpec.describe CanvasSync do
85
85
  context 'we are syncing roles without a term scope' do
86
86
  it 'syncs roles separately even with no term scope' do
87
87
  chain = CanvasSync.default_provisioning_report_chain(['roles', 'courses'])
88
- expect(chain).to eq({
88
+ expect(chain.chain_data).to eq({
89
89
  jobs: [
90
90
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
91
91
  { job: CanvasSync::Jobs::SyncRolesJob.to_s, options: {} },
@@ -99,7 +99,7 @@ RSpec.describe CanvasSync do
99
99
  context 'we are syncing admins with a term scope' do
100
100
  it 'syncs the admins in a separate job that runs first' do
101
101
  chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'], :active)
102
- expect(chain).to eq({
102
+ expect(chain.chain_data).to eq({
103
103
  jobs: [
104
104
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
105
105
  { job: CanvasSync::Jobs::SyncAdminsJob.to_s, options: {} },
@@ -113,7 +113,7 @@ RSpec.describe CanvasSync do
113
113
  context 'we are syncing admins without a term scope' do
114
114
  it 'syncs admins separately even with no term scope' do
115
115
  chain = CanvasSync.default_provisioning_report_chain(['admins', 'courses'])
116
- expect(chain).to eq({
116
+ expect(chain.chain_data).to eq({
117
117
  jobs: [
118
118
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
119
119
  { job: CanvasSync::Jobs::SyncAdminsJob.to_s, options: {} },
@@ -128,7 +128,7 @@ RSpec.describe CanvasSync do
128
128
  it "appends the SyncAssignmentsJob" do
129
129
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignments])
130
130
 
131
- expect(chain).to eq(
131
+ expect(chain.chain_data).to eq(
132
132
  jobs: [
133
133
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
134
134
  { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: %w[users enrollments] } },
@@ -143,7 +143,7 @@ RSpec.describe CanvasSync do
143
143
  it "appends the SyncSubmissionsJob" do
144
144
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments submissions])
145
145
 
146
- expect(chain).to eq(
146
+ expect(chain.chain_data).to eq(
147
147
  jobs: [
148
148
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
149
149
  { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: %w[users enrollments] } },
@@ -158,7 +158,7 @@ RSpec.describe CanvasSync do
158
158
  it "appends the SyncAssignmentGroupsJob" do
159
159
  chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignment_groups])
160
160
 
161
- expect(chain).to eq(
161
+ expect(chain.chain_data).to eq(
162
162
  jobs: [
163
163
  { job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
164
164
  { job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: %w[users enrollments] } },
@@ -185,7 +185,7 @@ RSpec.describe CanvasSync do
185
185
  }
186
186
  }
187
187
  ]
188
- )
188
+ ).chain_data
189
189
  first_job = expected_job_chain[:jobs].shift
190
190
 
191
191
  expect(CanvasSync::Jobs::SyncSimpleTableJob).to receive(:perform_later)
@@ -242,9 +242,12 @@ RSpec.describe CanvasSync do
242
242
  global_options: {}
243
243
  }
244
244
 
245
- expect(chain).to eq(expected_job_chain)
245
+ expect(chain.chain_data).to eq(expected_job_chain)
246
246
 
247
247
  end
248
248
  end
249
-
249
+
250
+ describe ".sync_scope" do
251
+
252
+ end
250
253
  end