canvas_sync 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/lib/canvas_sync.rb +2 -0
  3. data/lib/canvas_sync/generators/templates/migrations/create_group_memberships.rb +18 -0
  4. data/lib/canvas_sync/generators/templates/migrations/create_groups.rb +23 -0
  5. data/lib/canvas_sync/generators/templates/models/account.rb +1 -0
  6. data/lib/canvas_sync/generators/templates/models/course.rb +1 -0
  7. data/lib/canvas_sync/generators/templates/models/group.rb +19 -0
  8. data/lib/canvas_sync/generators/templates/models/group_membership.rb +17 -0
  9. data/lib/canvas_sync/generators/templates/models/user.rb +1 -0
  10. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +2 -0
  11. data/lib/canvas_sync/processors/model_mappings.yml +59 -0
  12. data/lib/canvas_sync/processors/provisioning_report_processor.rb +19 -0
  13. data/lib/canvas_sync/version.rb +1 -1
  14. data/spec/canvas_sync/models/accounts_spec.rb +3 -0
  15. data/spec/canvas_sync/models/course_spec.rb +4 -0
  16. data/spec/canvas_sync/models/group_membership_spec.rb +26 -0
  17. data/spec/canvas_sync/models/group_spec.rb +26 -0
  18. data/spec/canvas_sync/models/user_spec.rb +2 -0
  19. data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +20 -0
  20. data/spec/dummy/app/models/account.rb +1 -0
  21. data/spec/dummy/app/models/course.rb +1 -0
  22. data/spec/dummy/app/models/group.rb +25 -0
  23. data/spec/dummy/app/models/group_membership.rb +23 -0
  24. data/spec/dummy/app/models/user.rb +1 -0
  25. data/spec/dummy/db/migrate/20200415171620_create_groups.rb +29 -0
  26. data/spec/dummy/db/migrate/20200416214248_create_group_memberships.rb +24 -0
  27. data/spec/dummy/db/schema.rb +30 -1
  28. data/spec/factories/group_factory.rb +8 -0
  29. data/spec/factories/group_membership_factory.rb +6 -0
  30. data/spec/support/fixtures/reports/group_memberships.csv +3 -0
  31. data/spec/support/fixtures/reports/groups.csv +3 -0
  32. metadata +28 -13
  33. data/spec/dummy/db/test.sqlite3 +0 -0
  34. data/spec/dummy/log/development.log +0 -1248
  35. data/spec/dummy/log/test.log +0 -43258
  36. data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +0 -3
  37. data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 5c8386afbd924c0148b5c2158d23ea7acd5b0b85349da51312103e1ea9368c54
4
- data.tar.gz: 051471b40b5a464b66df8ca7ae482874f2791c55604e28f7fe9ce54cb07f875a
2
+ SHA1:
3
+ metadata.gz: 6dc939cb0559d835965e4b61416fa79f19fdb0a4
4
+ data.tar.gz: 9e075f746f42ae230ed6219c8e16b00b77526748
5
5
  SHA512:
6
- metadata.gz: '00742595c4797ba758ef98ab8b034545eb2193a2cae92dfc585e720c7cd9adef663ba0aadcae2c7085e19497ff74461c6d5553d49114f42dac520c8fe48ca448'
7
- data.tar.gz: d8c7eb61e630bb65ea9aa2e86b86c03c2c1f87c151e127314c938f7d1b2438c90dfc5f5ddcc4cb74fe0b525bc4ef9c03dfb140d09fc10045b2f7f56b41524e43
6
+ metadata.gz: c4acb86d39b2aaf09ee9de7ae33d689bc28570babd3086098634fa85e0cca9f8144b22193e3b0d1e21c659e31c807e00899b670d0e52f8549e214b899aae17e2
7
+ data.tar.gz: a18ac0d166e5e61b24f0a00a0284db3c73ea9bf5ea642f4ac11ccbab0a7b436222d68e4930ed2c3f75d517fe0ef9ebb1bb4752019ea29c988f9ab27e92388f70
@@ -23,6 +23,8 @@ module CanvasSync
23
23
  SUPPORTED_MODELS = %w[
24
24
  users
25
25
  courses
26
+ groups
27
+ group_memberships
26
28
  accounts
27
29
  terms
28
30
  enrollments
@@ -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
@@ -12,6 +12,7 @@ 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
15
16
 
16
17
  api_syncable({
17
18
  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
@@ -9,6 +9,7 @@ class User < ApplicationRecord
9
9
  has_many :admins, primary_key: :canvas_id, foreign_key: :canvas_user_id
10
10
  has_many :admin_roles, through: :admins, source: :role
11
11
  has_many :submissions, primary_key: :canvas_id, foreign_key: :canvas_user_id
12
+ has_many :group_memberships, primary_key: :canvas_id, foreign_key: :canvas_user_id
12
13
 
13
14
  api_syncable({
14
15
  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
 
@@ -326,3 +326,62 @@ context_module_items:
326
326
  assignment_id:
327
327
  database_column_name: canvas_assignment_id
328
328
  type: integer
329
+
330
+ groups:
331
+ conflict_target: canvas_group_id
332
+ report_columns:
333
+ canvas_group_id:
334
+ database_column_name: canvas_id
335
+ type: integer
336
+ group_id:
337
+ database_column_name: sis_id
338
+ type: string
339
+ canvas_group_category_id:
340
+ database_column_name: canvas_group_category_id
341
+ type: integer
342
+ group_category_id:
343
+ database_column_name: group_category_sis_id
344
+ type: integer
345
+ canvas_account_id:
346
+ database_column_name: canvas_account_id
347
+ type: integer
348
+ canvas_course_id:
349
+ database_column_name: canvas_course_id
350
+ type: integer
351
+ name:
352
+ database_column_name: name
353
+ type: string
354
+ status:
355
+ database_column_name: workflow_state
356
+ type: string
357
+ context_id:
358
+ database_column_name: context_id
359
+ type: integer
360
+ context_type:
361
+ database_column_name: context_type
362
+ type: string
363
+ max_membership:
364
+ database_column_name: max_membership
365
+ type: integer
366
+
367
+ group_memberships:
368
+ conflict_target: canvas_group_membership_id
369
+ report_columns:
370
+ canvas_group_membership_id:
371
+ database_column_name: canvas_id
372
+ type: integer
373
+ canvas_group_id:
374
+ database_column_name: canvas_group_id
375
+ type: integer
376
+ group_id:
377
+ database_column_name: group_sis_id
378
+ type: string
379
+ canvas_user_id:
380
+ database_column_name: canvas_user_id
381
+ type: integer
382
+ user_id:
383
+ database_column_name: user_sis_id
384
+ type: string
385
+ status:
386
+ database_column_name: workflow_state
387
+ type: string
@@ -122,6 +122,25 @@ module CanvasSync
122
122
  mapping[:xlist][:conflict_target].to_sym,
123
123
  )
124
124
  end
125
+
126
+ def bulk_process_groups(report_file_path)
127
+ CanvasSync::Importers::BulkImporter.import(
128
+ report_file_path,
129
+ mapping[:groups][:report_columns],
130
+ Group,
131
+ mapping[:groups][:conflict_target].to_sym,
132
+ )
133
+ end
134
+
135
+ # Note that group membership is singular because we override the model name param in sync_provisioning_report_job
136
+ def bulk_process_group_membership(report_file_path)
137
+ CanvasSync::Importers::BulkImporter.import(
138
+ report_file_path,
139
+ mapping[:group_memberships][:report_columns],
140
+ GroupMembership,
141
+ mapping[:group_memberships][:conflict_target].to_sym,
142
+ )
143
+ end
125
144
  end
126
145
  end
127
146
  end
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.13.0".freeze
2
+ VERSION = "0.14.0".freeze
3
3
  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,
@@ -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