canvas_sync 0.13.0 → 0.16.2

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/canvas_sync.rb +69 -15
  3. data/lib/canvas_sync/concerns/api_syncable.rb +1 -1
  4. data/lib/canvas_sync/concerns/legacy_columns.rb +5 -4
  5. data/lib/canvas_sync/generators/templates/migrations/create_group_memberships.rb +18 -0
  6. data/lib/canvas_sync/generators/templates/migrations/create_groups.rb +23 -0
  7. data/lib/canvas_sync/generators/templates/migrations/create_pseudonyms.rb +18 -0
  8. data/lib/canvas_sync/generators/templates/migrations/create_submissions.rb +1 -0
  9. data/lib/canvas_sync/generators/templates/models/account.rb +4 -0
  10. data/lib/canvas_sync/generators/templates/models/course.rb +1 -0
  11. data/lib/canvas_sync/generators/templates/models/group.rb +19 -0
  12. data/lib/canvas_sync/generators/templates/models/group_membership.rb +17 -0
  13. data/lib/canvas_sync/generators/templates/models/pseudonym.rb +8 -0
  14. data/lib/canvas_sync/generators/templates/models/submission.rb +1 -0
  15. data/lib/canvas_sync/generators/templates/models/user.rb +2 -0
  16. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +2 -0
  17. data/lib/canvas_sync/processors/model_mappings.yml +81 -0
  18. data/lib/canvas_sync/processors/provisioning_report_processor.rb +28 -0
  19. data/lib/canvas_sync/version.rb +1 -1
  20. data/spec/canvas_sync/canvas_sync_spec.rb +5 -2
  21. data/spec/canvas_sync/models/accounts_spec.rb +3 -0
  22. data/spec/canvas_sync/models/course_spec.rb +4 -0
  23. data/spec/canvas_sync/models/group_membership_spec.rb +26 -0
  24. data/spec/canvas_sync/models/group_spec.rb +26 -0
  25. data/spec/canvas_sync/models/user_spec.rb +2 -0
  26. data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +20 -0
  27. data/spec/dummy/app/models/account.rb +1 -0
  28. data/spec/dummy/app/models/course.rb +1 -0
  29. data/spec/dummy/app/models/group.rb +25 -0
  30. data/spec/dummy/app/models/group_membership.rb +23 -0
  31. data/spec/dummy/app/models/user.rb +1 -0
  32. data/spec/dummy/db/migrate/20190702203627_create_submissions.rb +1 -0
  33. data/spec/dummy/db/migrate/20200415171620_create_groups.rb +29 -0
  34. data/spec/dummy/db/migrate/20200416214248_create_group_memberships.rb +24 -0
  35. data/spec/dummy/db/schema.rb +31 -1
  36. data/spec/factories/group_factory.rb +8 -0
  37. data/spec/factories/group_membership_factory.rb +6 -0
  38. data/spec/support/fixtures/reports/group_memberships.csv +3 -0
  39. data/spec/support/fixtures/reports/groups.csv +3 -0
  40. data/spec/support/fixtures/reports/submissions.csv +3 -3
  41. metadata +33 -10
  42. data/lib/canvas_sync/jobs/sync_users_job.rb +0 -26
  43. data/spec/canvas_sync/jobs/sync_users_job_spec.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c8386afbd924c0148b5c2158d23ea7acd5b0b85349da51312103e1ea9368c54
4
- data.tar.gz: 051471b40b5a464b66df8ca7ae482874f2791c55604e28f7fe9ce54cb07f875a
3
+ metadata.gz: 3c6655d28b3ac244a94cd59da9f76f6878658bff43d1ca071dd7718b82a505ad
4
+ data.tar.gz: e8ee3801761dd8a84d80ea162ff11e079b219e1d1992788aecd49451c59efaf4
5
5
  SHA512:
6
- metadata.gz: '00742595c4797ba758ef98ab8b034545eb2193a2cae92dfc585e720c7cd9adef663ba0aadcae2c7085e19497ff74461c6d5553d49114f42dac520c8fe48ca448'
7
- data.tar.gz: d8c7eb61e630bb65ea9aa2e86b86c03c2c1f87c151e127314c938f7d1b2438c90dfc5f5ddcc4cb74fe0b525bc4ef9c03dfb140d09fc10045b2f7f56b41524e43
6
+ metadata.gz: 47a9f7e858cb510f191d1c62f99f112384dc62d3d9d62365369bad5b275d0168d1d5ace94a32b7f76921ee072ae49d3b940e6d56c2aeb51601e9daf52c86b36e
7
+ data.tar.gz: 84c5b5c9816a2ff8578bb32892739a8737fb6049526f24ef1416d7a5f404fc385f808ca9a7739b1d971baf06f81fe172351015332fe56a67a2e64417158e60d3
@@ -22,7 +22,10 @@ Dir[File.dirname(__FILE__) + "/canvas_sync/concerns/**/*.rb"].each { |file| req
22
22
  module CanvasSync
23
23
  SUPPORTED_MODELS = %w[
24
24
  users
25
+ pseudonyms
25
26
  courses
27
+ groups
28
+ group_memberships
26
29
  accounts
27
30
  terms
28
31
  enrollments
@@ -143,6 +146,10 @@ module CanvasSync
143
146
  terms.each do |t|
144
147
  return scope.send(t) if scope.respond_to?(t)
145
148
  end
149
+ model = scope.try(:model) || scope
150
+ if model.try(:column_names)&.include?(:workflow_state)
151
+ return scope.where.not(workflow_state: %w[deleted])
152
+ end
146
153
  Rails.logger.warn("Could not filter Syncable Scope for model '#{scope.try(:model)&.name || scope.name}'")
147
154
  scope
148
155
  end
@@ -193,7 +200,6 @@ module CanvasSync
193
200
  model_job_map = {
194
201
  terms: CanvasSync::Jobs::SyncTermsJob,
195
202
  accounts: CanvasSync::Jobs::SyncAccountsJob,
196
- users: CanvasSync::Jobs::SyncUsersJob,
197
203
  roles: CanvasSync::Jobs::SyncRolesJob,
198
204
  admins: CanvasSync::Jobs::SyncAdminsJob,
199
205
 
@@ -221,35 +227,41 @@ module CanvasSync
221
227
 
222
228
  # Accounts, users, roles, and admins are synced before provisioning because they cannot be scoped to term
223
229
  try_add_model_job.call('accounts')
224
- try_add_model_job.call('users') if term_scope.present?
230
+
231
+ # These Models use the provisioning report, but are not term-scoped,
232
+ # so we sync them before to ensure work is not duplicated
233
+ if term_scope.present?
234
+ models -= (first_provisioning_models = models & ['users', 'pseudonyms'])
235
+ jobs.concat(
236
+ generate_provisioning_jobs(first_provisioning_models, options)
237
+ )
238
+ end
239
+
225
240
  try_add_model_job.call('roles')
226
241
  try_add_model_job.call('admins')
227
-
228
242
  pre_provisioning_jobs = jobs
229
- jobs = []
230
243
 
231
244
  ###############################
232
245
  # Post provisioning report jobs
233
246
  ###############################
234
247
 
248
+ jobs = []
235
249
  try_add_model_job.call('assignments')
236
250
  try_add_model_job.call('submissions')
237
251
  try_add_model_job.call('assignment_groups')
238
252
  try_add_model_job.call('context_modules')
239
253
  try_add_model_job.call('context_module_items')
240
-
241
254
  post_provisioning_jobs = jobs
242
255
 
243
- jobs = pre_provisioning_jobs
244
- if models.present?
245
- provisioning_job = {
246
- job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s,
247
- options: { term_scope: term_scope, models: models },
248
- }
249
- provisioning_job[:options].merge!(options[:provisioning]) if options[:provisioning].present?
250
- jobs += Array.wrap(provisioning_job)
251
- end
252
- jobs += post_provisioning_jobs
256
+ ###############################
257
+ # Main provisioning job and queueing
258
+ ###############################
259
+
260
+ jobs = [
261
+ *pre_provisioning_jobs,
262
+ *generate_provisioning_jobs(models, options, job_options: { term_scope: term_scope }, only_split: ['users']),
263
+ *post_provisioning_jobs,
264
+ ]
253
265
 
254
266
  global_options = { legacy_support: legacy_support }
255
267
  global_options[:account_id] = account_id if account_id.present?
@@ -258,6 +270,48 @@ module CanvasSync
258
270
  JobChain.new(jobs: jobs, global_options: global_options)
259
271
  end
260
272
 
273
+ def group_by_job_options(model_list, options_hash, only_split: nil, default_key: :provisioning)
274
+ dup_models = [ *model_list ]
275
+ unique_option_models = {}
276
+
277
+ filtered_models = only_split ? (only_split & model_list) : model_list
278
+ filtered_models.each do |m|
279
+ mopts = options_hash[m.to_sym] || options_hash[default_key]
280
+ unique_option_models[mopts] ||= []
281
+ unique_option_models[mopts] << m
282
+ dup_models.delete(m)
283
+ end
284
+
285
+ if dup_models.present?
286
+ mopts = options_hash[default_key]
287
+ unique_option_models[mopts] ||= []
288
+ unique_option_models[mopts].concat(dup_models)
289
+ end
290
+
291
+ unique_option_models
292
+ end
293
+
294
+ def generate_provisioning_jobs(model_list, options_hash, job_options: {}, only_split: nil, default_key: :provisioning)
295
+ # Group the model options as best we can.
296
+ # This is mainly for backwards compatibility, since 'users' was previously it's own job
297
+ unique_option_models = group_by_job_options(
298
+ model_list,
299
+ options_hash,
300
+ only_split: only_split,
301
+ default_key: default_key,
302
+ )
303
+
304
+ unique_option_models.map do |mopts, models|
305
+ opts = { models: models }
306
+ opts.merge!(job_options)
307
+ opts.merge!(mopts) if mopts.present?
308
+ {
309
+ job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s,
310
+ options: opts,
311
+ }
312
+ end
313
+ end
314
+
261
315
  # Calls the canvas_sync_client in your app. If you have specified an account
262
316
  # ID when starting the job it will pass the account ID to your canvas_sync_client method.
263
317
  #
@@ -146,7 +146,7 @@ module CanvasSync::Concerns
146
146
  # Apply a response Hash from the API to this model's attributes and save if changed?
147
147
  # @param [Hash] api_params API-format Hash
148
148
  # @return [self] self
149
- def update_from_api_params(api_params, **kwargs)
149
+ def update_from_api_params(*args)
150
150
  assign_from_api_params(*args)
151
151
  save if changed?
152
152
  end
@@ -15,13 +15,14 @@ module CanvasSync::Concerns
15
15
  private
16
16
 
17
17
  def legacy_column_apply(cls)
18
- cid_column = "canvas_#{subclass.name.downcase}_id"
19
- column_names = subclass.columns.map(&:name)
18
+ return if cls.abstract_class
19
+ cid_column = "canvas_#{cls.name.downcase}_id"
20
+ column_names = cls.columns.map(&:name)
20
21
  return if column_names.include?('canvas_id') && column_names.include?(cid_column)
21
22
  if column_names.include?('canvas_id')
22
- subclass.alias_attribute(cid_column.to_sym, :canvas_id)
23
+ cls.alias_attribute(cid_column.to_sym, :canvas_id)
23
24
  elsif column_names.include?(cid_column)
24
- subclass.alias_attribute(:canvas_id, cid_column.to_sym)
25
+ cls.alias_attribute(:canvas_id, cid_column.to_sym)
25
26
  end
26
27
  rescue ActiveRecord::StatementInvalid
27
28
  end
@@ -0,0 +1,18 @@
1
+ # <%= autogenerated_migration_warning %>
2
+
3
+ class CreateGroupMemberships < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :group_memberships do |t|
6
+ t.bigint :canvas_id, null: false
7
+ t.bigint :canvas_user_id, null: false
8
+ t.bigint :canvas_group_id, null: false
9
+ t.string :group_sis_id
10
+ t.string :user_sis_id
11
+ t.string :workflow_state
12
+
13
+ t.timestamps
14
+ end
15
+
16
+ add_index :group_memberships, :canvas_id, unique: true
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # <%= autogenerated_migration_warning %>
2
+
3
+ class CreateGroups < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :groups do |t|
6
+ t.bigint :canvas_id, null: false
7
+ t.string :sis_id
8
+ t.bigint :canvas_group_category_id
9
+ t.string :group_category_sis_id
10
+ t.bigint :canvas_account_id
11
+ t.bigint :canvas_course_id
12
+ t.string :name
13
+ t.string :workflow_state
14
+ t.bigint :context_id
15
+ t.string :context_type
16
+ t.integer :max_membership
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ add_index :groups, :canvas_id, unique: true
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ # <%= autogenerated_migration_warning %>
2
+
3
+ class CreatePseudonyms < ActiveRecord::Migration[5.1]
4
+ def change
5
+ create_table :pseudonyms do |t|
6
+ t.bigint :canvas_id, null: false
7
+ t.bigint :canvas_user_id
8
+ t.string :sis_id
9
+ t.string :unique_id
10
+ t.string :workflow_state
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :pseudonyms, :canvas_id, unique: true
16
+ add_index :pseudonyms, :canvas_user_id
17
+ end
18
+ end
@@ -8,6 +8,7 @@ class CreateSubmissions < ActiveRecord::Migration[5.1]
8
8
  t.bigint :canvas_assignment_id
9
9
  t.bigint :canvas_user_id
10
10
  t.datetime :submitted_at
11
+ t.datetime :due_at
11
12
  t.datetime :graded_at
12
13
  t.float :score
13
14
  t.float :points_possible
@@ -12,6 +12,10 @@ class Account < ApplicationRecord
12
12
  primary_key: :canvas_id, foreign_key: :canvas_parent_account_id
13
13
  has_many :sub_accounts, class_name: 'Account',
14
14
  primary_key: :canvas_id, foreign_key: :canvas_parent_account_id
15
+ has_many :groups, primary_key: :canvas_id, foreign_key: :canvas_account_id
16
+
17
+ scope :active, -> { where.not(workflow_state: 'deleted') }
18
+ # scope :should_canvas_sync, -> { active } # Optional - uses .active if not given
15
19
 
16
20
  api_syncable({
17
21
  name: :name,
@@ -11,6 +11,7 @@ class Course < ApplicationRecord
11
11
  has_many :assignments, as: :context, primary_key: :canvas_id, foreign_key: :canvas_context_id, foreign_type: :canvas_context_type
12
12
  has_many :submissions, primary_key: :canvas_id, foreign_key: :canvas_course_id
13
13
  has_many :assignment_groups, primary_key: :canvas_id, foreign_key: :canvas_course_id
14
+ has_many :groups, primary_key: :canvas_id, foreign_key: :canvas_course_id
14
15
 
15
16
  api_syncable({
16
17
  sis_id: :sis_course_id,
@@ -0,0 +1,19 @@
1
+ # <%= autogenerated_model_warning %>
2
+
3
+ class Group < ApplicationRecord
4
+ include CanvasSync::Record
5
+ include CanvasSync::Concerns::ApiSyncable
6
+
7
+ validates :canvas_id, uniqueness: true, presence: true
8
+ belongs_to :course, primary_key: :canvas_id, foreign_key: :canvas_course_id, optional: true
9
+ belongs_to :account, primary_key: :canvas_id, foreign_key: :canvas_account_id, optional: true
10
+ has_many :group_memberships, primary_key: :canvas_id, foreign_key: :canvas_group_id
11
+
12
+ api_syncable({
13
+ canvas_id: :id,
14
+ name: :name,
15
+ canvas_course_id: :course_id,
16
+ sis_id: :sis_group_id,
17
+ workflow_state: ->(r){ 'available' },
18
+ }, -> (api) { api.group(canvas_id) })
19
+ end
@@ -0,0 +1,17 @@
1
+ # <%= autogenerated_model_warning %>
2
+
3
+ class GroupMembership < ApplicationRecord
4
+ include CanvasSync::Record
5
+ include CanvasSync::Concerns::ApiSyncable
6
+
7
+ validates :canvas_id, uniqueness: true, presence: true
8
+ belongs_to :group, primary_key: :canvas_id, foreign_key: :canvas_group_id
9
+ belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id
10
+
11
+ api_syncable({
12
+ canvas_id: :id,
13
+ canvas_group_id: :group_id,
14
+ canvas_user_id: :user_id,
15
+ workflow_state: :workflow_state,
16
+ }, -> (api) { api.group_membership(canvas_group_id, canvas_id) })
17
+ end
@@ -0,0 +1,8 @@
1
+ # <%= autogenerated_model_warning %>
2
+
3
+ class Pseudonym < ApplicationRecord
4
+ include CanvasSync::Record
5
+
6
+ validates :canvas_id, uniqueness: true, presence: true
7
+ belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id
8
+ end
@@ -14,6 +14,7 @@ class Submission < ApplicationRecord
14
14
  canvas_user_id: :user_id,
15
15
  submitted_at: :submitted_at,
16
16
  graded_at: :graded_at,
17
+ cached_due_date: :due_at,
17
18
  score: :score,
18
19
  excused: :excused,
19
20
  workflow_state: :workflow_state,
@@ -5,10 +5,12 @@ class User < ApplicationRecord
5
5
  include CanvasSync::Concerns::ApiSyncable
6
6
 
7
7
  validates :canvas_id, uniqueness: true, presence: true
8
+ has_many :pseudonyms, primary_key: :canvas_id, foreign_key: :canvas_user_id
8
9
  has_many :enrollments, primary_key: :canvas_id, foreign_key: :canvas_user_id
9
10
  has_many :admins, primary_key: :canvas_id, foreign_key: :canvas_user_id
10
11
  has_many :admin_roles, through: :admins, source: :role
11
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
12
14
 
13
15
  api_syncable({
14
16
  sis_id: :sis_user_id,
@@ -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
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.13.0".freeze
2
+ VERSION = "0.16.2".freeze
3
3
  end
@@ -34,7 +34,7 @@ RSpec.describe CanvasSync do
34
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 }
@@ -47,7 +47,7 @@ RSpec.describe CanvasSync do
47
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 }
@@ -247,4 +247,7 @@ RSpec.describe CanvasSync do
247
247
  end
248
248
  end
249
249
 
250
+ describe ".sync_scope" do
251
+
252
+ end
250
253
  end
@@ -8,4 +8,7 @@ RSpec.describe Account, type: :model do
8
8
  it { should validate_uniqueness_of(:canvas_id) }
9
9
  end
10
10
 
11
+ describe 'associations' do
12
+ it { should have_many(:groups) }
13
+ end
11
14
  end
@@ -41,5 +41,9 @@ RSpec.describe Course, type: :model do
41
41
  it do
42
42
  should have_many(:submissions)
43
43
  end
44
+
45
+ it do
46
+ should have_many(:groups)
47
+ end
44
48
  end
45
49
  end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe GroupMembership, type: :model do
4
+ let(:subject) {
5
+ FactoryGirl.create(:group_membership, group: FactoryGirl.create(:group), user: FactoryGirl.create(:user))
6
+ }
7
+
8
+ describe 'validations' do
9
+ it { should validate_presence_of(:canvas_id) }
10
+ it { should validate_uniqueness_of(:canvas_id) }
11
+ end
12
+
13
+ describe 'associations' do
14
+ it do
15
+ should belong_to(:group)
16
+ .with_primary_key(:canvas_id)
17
+ .with_foreign_key(:canvas_group_id)
18
+ end
19
+
20
+ it do
21
+ should belong_to(:user)
22
+ .with_primary_key(:canvas_id)
23
+ .with_foreign_key(:canvas_user_id)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Group, type: :model do
4
+ let(:subject) { FactoryGirl.create(:group) }
5
+
6
+ describe 'validations' do
7
+ it { should validate_presence_of(:canvas_id) }
8
+ it { should validate_uniqueness_of(:canvas_id) }
9
+ end
10
+
11
+ describe 'associations' do
12
+ it { should have_many(:group_memberships) }
13
+
14
+ it do
15
+ should belong_to(:course)
16
+ .with_primary_key(:canvas_id)
17
+ .with_foreign_key(:canvas_course_id)
18
+ end
19
+
20
+ it do
21
+ should belong_to(:account)
22
+ .with_primary_key(:canvas_id)
23
+ .with_foreign_key(:canvas_account_id)
24
+ end
25
+ end
26
+ end
@@ -9,6 +9,8 @@ RSpec.describe User, type: :model do
9
9
  end
10
10
 
11
11
  describe 'associations' do
12
+ it { should have_many(:group_memberships) }
13
+
12
14
  it do
13
15
  should have_many(:enrollments)
14
16
  .with_primary_key(:canvas_id)
@@ -42,6 +42,26 @@ RSpec.describe CanvasSync::Processors::ProvisioningReportProcessor do
42
42
  expect(cross_listed_section.canvas_nonxlist_course_id).to eq 2
43
43
  end
44
44
 
45
+ it 'processes groups' do
46
+ expect {
47
+ subject.process('spec/support/fixtures/reports/groups.csv', { models: ['groups'] }, 1)
48
+ }.to change { Group.count }.by(2)
49
+ group = Group.find_by_name('Group1')
50
+ expect(group.workflow_state).to eq 'available'
51
+ expect(group.canvas_account_id).to eq 1
52
+ expect(group.canvas_id).to eq 50
53
+ end
54
+
55
+ it 'processes group memberships' do
56
+ expect {
57
+ subject.process('spec/support/fixtures/reports/group_memberships.csv', { models: ['group_membership'] }, 1)
58
+ }.to change { GroupMembership.count }.by(2)
59
+ group = GroupMembership.find_by_canvas_id(50)
60
+ expect(group.workflow_state).to eq 'accepted'
61
+ expect(group.canvas_group_id).to eq 1
62
+ expect(group.canvas_user_id).to eq 10
63
+ end
64
+
45
65
  context 'options[:models] is multiple models' do
46
66
  it 'extracts the ZIP and processes each model' do
47
67
  user_count = User.count
@@ -18,6 +18,7 @@ class Account < ApplicationRecord
18
18
  primary_key: :canvas_id, foreign_key: :canvas_parent_account_id
19
19
  has_many :sub_accounts, class_name: 'Account',
20
20
  primary_key: :canvas_id, foreign_key: :canvas_parent_account_id
21
+ has_many :groups, primary_key: :canvas_id, foreign_key: :canvas_account_id
21
22
 
22
23
  api_syncable({
23
24
  name: :name,
@@ -17,6 +17,7 @@ class Course < ApplicationRecord
17
17
  has_many :assignments, as: :context, primary_key: :canvas_id, foreign_key: :canvas_context_id, foreign_type: :canvas_context_type
18
18
  has_many :submissions, primary_key: :canvas_id, foreign_key: :canvas_course_id
19
19
  has_many :assignment_groups, primary_key: :canvas_id, foreign_key: :canvas_course_id
20
+ has_many :groups, primary_key: :canvas_id, foreign_key: :canvas_course_id
20
21
 
21
22
  api_syncable({
22
23
  sis_id: :sis_course_id,
@@ -0,0 +1,25 @@
1
+ # #
2
+ # AUTO GENERATED MODEL
3
+ # This model was auto generated by the CanvasSync Gem.
4
+ # You can customize it as needed, but make sure you test
5
+ # any changes you make to the auto generated methods.
6
+ #
7
+
8
+
9
+ class Group < ApplicationRecord
10
+ include CanvasSync::Record
11
+ include CanvasSync::Concerns::ApiSyncable
12
+
13
+ validates :canvas_id, uniqueness: true, presence: true
14
+ belongs_to :course, primary_key: :canvas_id, foreign_key: :canvas_course_id, optional: true
15
+ belongs_to :account, primary_key: :canvas_id, foreign_key: :canvas_account_id, optional: true
16
+ has_many :group_memberships, primary_key: :canvas_id, foreign_key: :canvas_group_id
17
+
18
+ api_syncable({
19
+ canvas_id: :id,
20
+ name: :name,
21
+ canvas_course_id: :course_id,
22
+ sis_id: :sis_group_id,
23
+ workflow_state: ->(r){ 'available' },
24
+ }, -> (api) { api.group(canvas_id) })
25
+ end
@@ -0,0 +1,23 @@
1
+ # #
2
+ # AUTO GENERATED MODEL
3
+ # This model was auto generated by the CanvasSync Gem.
4
+ # You can customize it as needed, but make sure you test
5
+ # any changes you make to the auto generated methods.
6
+ #
7
+
8
+
9
+ class GroupMembership < ApplicationRecord
10
+ include CanvasSync::Record
11
+ include CanvasSync::Concerns::ApiSyncable
12
+
13
+ validates :canvas_id, uniqueness: true, presence: true
14
+ belongs_to :group, primary_key: :canvas_id, foreign_key: :canvas_group_id
15
+ belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id
16
+
17
+ api_syncable({
18
+ canvas_id: :id,
19
+ canvas_group_id: :group_id,
20
+ canvas_user_id: :user_id,
21
+ workflow_state: :workflow_state,
22
+ }, -> (api) { api.group_membership(canvas_group_id, canvas_id) })
23
+ end
@@ -15,6 +15,7 @@ class User < ApplicationRecord
15
15
  has_many :admins, primary_key: :canvas_id, foreign_key: :canvas_user_id
16
16
  has_many :admin_roles, through: :admins, source: :role
17
17
  has_many :submissions, primary_key: :canvas_id, foreign_key: :canvas_user_id
18
+ has_many :group_memberships, primary_key: :canvas_id, foreign_key: :canvas_user_id
18
19
 
19
20
  api_syncable({
20
21
  sis_id: :sis_user_id,
@@ -14,6 +14,7 @@ class CreateSubmissions < ActiveRecord::Migration[5.1]
14
14
  t.bigint :canvas_assignment_id
15
15
  t.bigint :canvas_user_id
16
16
  t.datetime :submitted_at
17
+ t.datetime :due_at
17
18
  t.datetime :graded_at
18
19
  t.float :score
19
20
  t.float :points_possible
@@ -0,0 +1,29 @@
1
+ # #
2
+ # AUTO GENERATED MIGRATION
3
+ # This migration was auto generated by the CanvasSync Gem.
4
+ # You can add new columns to this table, but removing or
5
+ # re-naming ones created here may break Canvas Syncing.
6
+ #
7
+
8
+
9
+ class CreateGroups < ActiveRecord::Migration[5.1]
10
+ def change
11
+ create_table :groups do |t|
12
+ t.bigint :canvas_id, null: false
13
+ t.string :sis_id
14
+ t.bigint :canvas_group_category_id
15
+ t.string :group_category_sis_id
16
+ t.bigint :canvas_account_id
17
+ t.bigint :canvas_course_id
18
+ t.string :name
19
+ t.string :workflow_state
20
+ t.bigint :context_id
21
+ t.string :context_type
22
+ t.integer :max_membership
23
+
24
+ t.timestamps
25
+ end
26
+
27
+ add_index :groups, :canvas_id, unique: true
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ # #
2
+ # AUTO GENERATED MIGRATION
3
+ # This migration was auto generated by the CanvasSync Gem.
4
+ # You can add new columns to this table, but removing or
5
+ # re-naming ones created here may break Canvas Syncing.
6
+ #
7
+
8
+
9
+ class CreateGroupMemberships < ActiveRecord::Migration[5.1]
10
+ def change
11
+ create_table :group_memberships do |t|
12
+ t.bigint :canvas_id, null: false
13
+ t.bigint :canvas_user_id, null: false
14
+ t.bigint :canvas_group_id, null: false
15
+ t.string :group_sis_id
16
+ t.string :user_sis_id
17
+ t.string :workflow_state
18
+
19
+ t.timestamps
20
+ end
21
+
22
+ add_index :group_memberships, :canvas_id, unique: true
23
+ end
24
+ end
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20190927204546) do
13
+ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -162,6 +162,35 @@ ActiveRecord::Schema.define(version: 20190927204546) do
162
162
  t.index ["canvas_user_id"], name: "index_enrollments_on_canvas_user_id"
163
163
  end
164
164
 
165
+ create_table "group_memberships", force: :cascade do |t|
166
+ t.bigint "canvas_id", null: false
167
+ t.bigint "canvas_user_id", null: false
168
+ t.bigint "canvas_group_id", null: false
169
+ t.string "group_sis_id"
170
+ t.string "user_sis_id"
171
+ t.string "workflow_state"
172
+ t.datetime "created_at", null: false
173
+ t.datetime "updated_at", null: false
174
+ t.index ["canvas_id"], name: "index_group_memberships_on_canvas_id", unique: true
175
+ end
176
+
177
+ create_table "groups", force: :cascade do |t|
178
+ t.bigint "canvas_id", null: false
179
+ t.string "sis_id"
180
+ t.bigint "canvas_group_category_id"
181
+ t.string "group_category_sis_id"
182
+ t.bigint "canvas_account_id"
183
+ t.bigint "canvas_course_id"
184
+ t.string "name"
185
+ t.string "workflow_state"
186
+ t.bigint "context_id"
187
+ t.string "context_type"
188
+ t.integer "max_membership"
189
+ t.datetime "created_at", null: false
190
+ t.datetime "updated_at", null: false
191
+ t.index ["canvas_id"], name: "index_groups_on_canvas_id", unique: true
192
+ end
193
+
165
194
  create_table "roles", force: :cascade do |t|
166
195
  t.integer "canvas_id", null: false
167
196
  t.string "label"
@@ -196,6 +225,7 @@ ActiveRecord::Schema.define(version: 20190927204546) do
196
225
  t.bigint "canvas_assignment_id"
197
226
  t.bigint "canvas_user_id"
198
227
  t.datetime "submitted_at"
228
+ t.datetime "due_at"
199
229
  t.datetime "graded_at"
200
230
  t.float "score"
201
231
  t.float "points_possible"
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ factory :group do
3
+ canvas_id { SecureRandom.random_number(100_000_000) }
4
+ sis_id { SecureRandom.hex }
5
+ name 'Some User Group'
6
+ workflow_state 'available'
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ FactoryGirl.define do
2
+ factory :group_membership do
3
+ canvas_id { SecureRandom.random_number(100_000_000) }
4
+ workflow_state 'accepted'
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ canvas_group_id,group_id,canvas_user_id,user_id,status,created_by_sis,canvas_group_membership_id
2
+ 1,,10,,accepted,false,50
3
+ 2,,11,,accepted,false,51
@@ -0,0 +1,3 @@
1
+ canvas_group_id,group_id,canvas_group_category_id,group_category_id,canvas_account_id,account_id,canvas_course_id,course_id,name,status,created_by_sis,context_id,context_type,max_membership
2
+ 50,sis1,10,,1,,,,Group1,available,false,1,Account,
3
+ 51,sis2,2,,,,1,coursesis,Group2,available,false,1,Course,1
@@ -1,3 +1,3 @@
1
- "canvas user id","sis user id","user name","canvas course id","sis course id","course name","assignment id","assignment name","submission date","graded date","score","points possible","submission id","workflow state","excused"
2
- 1,1,userName,1,1,courseName,1,assignmentName,2017-09-21 18:28:15 UTC,2017-09-21 19:36:23 UTC,5,10,1,graded,true
3
- 1,1,userName,1,1,courseName,2,assignment2Name,2017-09-21 18:28:15 UTC,2017-09-21 19:36:23 UTC,5,10,2,submitted,false
1
+ "canvas user id","sis user id","user name","canvas course id","sis course id","course name","assignment id","assignment name","submission date","graded date","score","points possible","submission id","workflow state","excused","due at"
2
+ 1,1,userName,1,1,courseName,1,assignmentName,2017-09-21 18:28:15 UTC,2017-09-21 19:36:23 UTC,5,10,1,graded,true,2017-09-27 18:28:15 UTC
3
+ 1,1,userName,1,1,courseName,2,assignment2Name,2017-09-21 18:28:15 UTC,2017-09-21 19:36:23 UTC,5,10,2,submitted,false,2017-09-28 18:28:15 UTC
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canvas_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.16.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Collings
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-04 00:00:00.000000000 Z
11
+ date: 2020-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -304,7 +304,7 @@ dependencies:
304
304
  - - ">="
305
305
  - !ruby/object:Gem::Version
306
306
  version: '0'
307
- description:
307
+ description:
308
308
  email:
309
309
  - ncollings@instructure.com
310
310
  executables: []
@@ -338,6 +338,9 @@ files:
338
338
  - lib/canvas_sync/generators/templates/migrations/create_context_modules.rb
339
339
  - lib/canvas_sync/generators/templates/migrations/create_courses.rb
340
340
  - lib/canvas_sync/generators/templates/migrations/create_enrollments.rb
341
+ - lib/canvas_sync/generators/templates/migrations/create_group_memberships.rb
342
+ - lib/canvas_sync/generators/templates/migrations/create_groups.rb
343
+ - lib/canvas_sync/generators/templates/migrations/create_pseudonyms.rb
341
344
  - lib/canvas_sync/generators/templates/migrations/create_roles.rb
342
345
  - lib/canvas_sync/generators/templates/migrations/create_sections.rb
343
346
  - lib/canvas_sync/generators/templates/migrations/create_submissions.rb
@@ -351,6 +354,9 @@ files:
351
354
  - lib/canvas_sync/generators/templates/models/context_module_item.rb
352
355
  - lib/canvas_sync/generators/templates/models/course.rb
353
356
  - lib/canvas_sync/generators/templates/models/enrollment.rb
357
+ - lib/canvas_sync/generators/templates/models/group.rb
358
+ - lib/canvas_sync/generators/templates/models/group_membership.rb
359
+ - lib/canvas_sync/generators/templates/models/pseudonym.rb
354
360
  - lib/canvas_sync/generators/templates/models/role.rb
355
361
  - lib/canvas_sync/generators/templates/models/section.rb
356
362
  - lib/canvas_sync/generators/templates/models/submission.rb
@@ -387,7 +393,6 @@ files:
387
393
  - lib/canvas_sync/jobs/sync_simple_table_job.rb
388
394
  - lib/canvas_sync/jobs/sync_submissions_job.rb
389
395
  - lib/canvas_sync/jobs/sync_terms_job.rb
390
- - lib/canvas_sync/jobs/sync_users_job.rb
391
396
  - lib/canvas_sync/processors/assignment_groups_processor.rb
392
397
  - lib/canvas_sync/processors/assignments_processor.rb
393
398
  - lib/canvas_sync/processors/context_module_items_processor.rb
@@ -416,7 +421,6 @@ files:
416
421
  - spec/canvas_sync/jobs/sync_simple_table_job_spec.rb
417
422
  - spec/canvas_sync/jobs/sync_submissions_job_spec.rb
418
423
  - spec/canvas_sync/jobs/sync_terms_job_spec.rb
419
- - spec/canvas_sync/jobs/sync_users_job_spec.rb
420
424
  - spec/canvas_sync/models/accounts_spec.rb
421
425
  - spec/canvas_sync/models/admins_spec.rb
422
426
  - spec/canvas_sync/models/assignment_group_spec.rb
@@ -425,6 +429,8 @@ files:
425
429
  - spec/canvas_sync/models/context_module_spec.rb
426
430
  - spec/canvas_sync/models/course_spec.rb
427
431
  - spec/canvas_sync/models/enrollment_spec.rb
432
+ - spec/canvas_sync/models/group_membership_spec.rb
433
+ - spec/canvas_sync/models/group_spec.rb
428
434
  - spec/canvas_sync/models/roles_spec.rb
429
435
  - spec/canvas_sync/models/section_spec.rb
430
436
  - spec/canvas_sync/models/submission_spec.rb
@@ -450,6 +456,8 @@ files:
450
456
  - spec/dummy/app/models/context_module_item.rb
451
457
  - spec/dummy/app/models/course.rb
452
458
  - spec/dummy/app/models/enrollment.rb
459
+ - spec/dummy/app/models/group.rb
460
+ - spec/dummy/app/models/group_membership.rb
453
461
  - spec/dummy/app/models/role.rb
454
462
  - spec/dummy/app/models/section.rb
455
463
  - spec/dummy/app/models/submission.rb
@@ -510,6 +518,8 @@ files:
510
518
  - spec/dummy/db/migrate/20190702203632_create_context_module_items.rb
511
519
  - spec/dummy/db/migrate/20190927204545_create_roles.rb
512
520
  - spec/dummy/db/migrate/20190927204546_create_admins.rb
521
+ - spec/dummy/db/migrate/20200415171620_create_groups.rb
522
+ - spec/dummy/db/migrate/20200416214248_create_group_memberships.rb
513
523
  - spec/dummy/db/schema.rb
514
524
  - spec/dummy/db/test.sqlite3
515
525
  - spec/dummy/log/development.log
@@ -522,6 +532,8 @@ files:
522
532
  - spec/factories/context_module_item_factory.rb
523
533
  - spec/factories/course_factory.rb
524
534
  - spec/factories/enrollment_factory.rb
535
+ - spec/factories/group_factory.rb
536
+ - spec/factories/group_membership_factory.rb
525
537
  - spec/factories/role_factory.rb
526
538
  - spec/factories/section_factory.rb
527
539
  - spec/factories/submission_factory.rb
@@ -540,6 +552,8 @@ files:
540
552
  - spec/support/fixtures/reports/context_modules.csv
541
553
  - spec/support/fixtures/reports/courses.csv
542
554
  - spec/support/fixtures/reports/enrollments.csv
555
+ - spec/support/fixtures/reports/group_memberships.csv
556
+ - spec/support/fixtures/reports/groups.csv
543
557
  - spec/support/fixtures/reports/provisioning_csv
544
558
  - spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv
545
559
  - spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv
@@ -550,7 +564,7 @@ files:
550
564
  homepage: https://instructure.com
551
565
  licenses: []
552
566
  metadata: {}
553
- post_install_message:
567
+ post_install_message:
554
568
  rdoc_options: []
555
569
  require_paths:
556
570
  - lib
@@ -565,8 +579,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
565
579
  - !ruby/object:Gem::Version
566
580
  version: '0'
567
581
  requirements: []
568
- rubygems_version: 3.0.3
569
- signing_key:
582
+ rubygems_version: 3.1.2
583
+ signing_key:
570
584
  specification_version: 4
571
585
  summary: Gem for generating Canvas models and migrations and syncing data from Canvas
572
586
  test_files:
@@ -586,7 +600,6 @@ test_files:
586
600
  - spec/canvas_sync/jobs/sync_simple_table_job_spec.rb
587
601
  - spec/canvas_sync/jobs/sync_submissions_job_spec.rb
588
602
  - spec/canvas_sync/jobs/sync_terms_job_spec.rb
589
- - spec/canvas_sync/jobs/sync_users_job_spec.rb
590
603
  - spec/canvas_sync/models/accounts_spec.rb
591
604
  - spec/canvas_sync/models/admins_spec.rb
592
605
  - spec/canvas_sync/models/assignment_group_spec.rb
@@ -595,6 +608,8 @@ test_files:
595
608
  - spec/canvas_sync/models/context_module_spec.rb
596
609
  - spec/canvas_sync/models/course_spec.rb
597
610
  - spec/canvas_sync/models/enrollment_spec.rb
611
+ - spec/canvas_sync/models/group_membership_spec.rb
612
+ - spec/canvas_sync/models/group_spec.rb
598
613
  - spec/canvas_sync/models/roles_spec.rb
599
614
  - spec/canvas_sync/models/section_spec.rb
600
615
  - spec/canvas_sync/models/submission_spec.rb
@@ -620,6 +635,8 @@ test_files:
620
635
  - spec/dummy/app/models/context_module_item.rb
621
636
  - spec/dummy/app/models/course.rb
622
637
  - spec/dummy/app/models/enrollment.rb
638
+ - spec/dummy/app/models/group.rb
639
+ - spec/dummy/app/models/group_membership.rb
623
640
  - spec/dummy/app/models/role.rb
624
641
  - spec/dummy/app/models/section.rb
625
642
  - spec/dummy/app/models/submission.rb
@@ -680,6 +697,8 @@ test_files:
680
697
  - spec/dummy/db/migrate/20190702203632_create_context_module_items.rb
681
698
  - spec/dummy/db/migrate/20190927204545_create_roles.rb
682
699
  - spec/dummy/db/migrate/20190927204546_create_admins.rb
700
+ - spec/dummy/db/migrate/20200415171620_create_groups.rb
701
+ - spec/dummy/db/migrate/20200416214248_create_group_memberships.rb
683
702
  - spec/dummy/db/schema.rb
684
703
  - spec/dummy/db/test.sqlite3
685
704
  - spec/dummy/log/development.log
@@ -692,6 +711,8 @@ test_files:
692
711
  - spec/factories/context_module_item_factory.rb
693
712
  - spec/factories/course_factory.rb
694
713
  - spec/factories/enrollment_factory.rb
714
+ - spec/factories/group_factory.rb
715
+ - spec/factories/group_membership_factory.rb
695
716
  - spec/factories/role_factory.rb
696
717
  - spec/factories/section_factory.rb
697
718
  - spec/factories/submission_factory.rb
@@ -710,6 +731,8 @@ test_files:
710
731
  - spec/support/fixtures/reports/context_modules.csv
711
732
  - spec/support/fixtures/reports/courses.csv
712
733
  - spec/support/fixtures/reports/enrollments.csv
734
+ - spec/support/fixtures/reports/group_memberships.csv
735
+ - spec/support/fixtures/reports/groups.csv
713
736
  - spec/support/fixtures/reports/provisioning_csv
714
737
  - spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv
715
738
  - spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv
@@ -1,26 +0,0 @@
1
- module CanvasSync
2
- module Jobs
3
- class SyncUsersJob < ReportStarter
4
- # Starts a provisioning report for just users.
5
- #
6
- # Provisioning reports do not scope users by term, so when we are
7
- # running provisioning by term we sync users first so we don't duplicate
8
- # the work of syncing all users for each term.
9
- #
10
- # @param job_chain [Hash]
11
- # @param options [Hash]
12
- def perform(job_chain, options)
13
- super(
14
- job_chain,
15
- "proservices_provisioning_csv",
16
- merge_report_params(job_chain, options, {
17
- users: true,
18
- include_deleted: true,
19
- }, term_scope: false),
20
- CanvasSync::Processors::ProvisioningReportProcessor.to_s,
21
- { models: ["users"] },
22
- )
23
- end
24
- end
25
- end
26
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe CanvasSync::Jobs::SyncUsersJob do
4
- describe '#perform' do
5
- it 'enqueues a ReportStarter for a provisioning report across all terms with just users' do
6
- expect_any_instance_of(Bearcat::Client).to receive(:start_report)
7
- .with('self', 'proservices_provisioning_csv', { parameters: { users: true, include_deleted: true } })
8
- .and_return({ 'id' => 1 })
9
-
10
- expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
11
-
12
- CanvasSync::Jobs::SyncUsersJob.perform_now({ jobs: [], global_options: {}}, {})
13
- end
14
- end
15
- end