canvas_sync 0.15.1 → 0.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/db/migrate/20170915210836_create_canvas_sync_job_log.rb +12 -31
  3. data/db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb +4 -13
  4. data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +3 -11
  5. data/lib/canvas_sync.rb +11 -27
  6. data/lib/canvas_sync/concerns/api_syncable.rb +27 -0
  7. data/lib/canvas_sync/concerns/legacy_columns.rb +5 -4
  8. data/lib/canvas_sync/generators/templates/migrations/create_submissions.rb +1 -0
  9. data/lib/canvas_sync/generators/templates/models/account.rb +3 -0
  10. data/lib/canvas_sync/generators/templates/models/submission.rb +1 -0
  11. data/lib/canvas_sync/importers/bulk_importer.rb +7 -4
  12. data/lib/canvas_sync/job.rb +8 -2
  13. data/lib/canvas_sync/job_chain.rb +46 -1
  14. data/lib/canvas_sync/jobs/fork_gather.rb +27 -12
  15. data/lib/canvas_sync/jobs/report_starter.rb +1 -1
  16. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +5 -5
  17. data/lib/canvas_sync/jobs/sync_simple_table_job.rb +4 -4
  18. data/lib/canvas_sync/misc_helper.rb +15 -0
  19. data/lib/canvas_sync/processors/assignment_groups_processor.rb +3 -2
  20. data/lib/canvas_sync/processors/assignments_processor.rb +3 -2
  21. data/lib/canvas_sync/processors/context_module_items_processor.rb +3 -2
  22. data/lib/canvas_sync/processors/context_modules_processor.rb +3 -2
  23. data/lib/canvas_sync/processors/model_mappings.yml +3 -0
  24. data/lib/canvas_sync/processors/normal_processor.rb +2 -1
  25. data/lib/canvas_sync/processors/provisioning_report_processor.rb +10 -2
  26. data/lib/canvas_sync/processors/submissions_processor.rb +3 -2
  27. data/lib/canvas_sync/version.rb +1 -1
  28. data/spec/canvas_sync/jobs/fork_gather_spec.rb +9 -9
  29. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +2 -2
  30. data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +1 -1
  31. data/spec/dummy/app/models/account.rb +3 -0
  32. data/spec/dummy/app/models/pseudonym.rb +14 -0
  33. data/spec/dummy/app/models/submission.rb +1 -0
  34. data/spec/dummy/app/models/user.rb +1 -0
  35. data/spec/dummy/db/migrate/20190702203627_create_submissions.rb +1 -0
  36. data/spec/dummy/db/migrate/20201016181346_create_pseudonyms.rb +24 -0
  37. data/spec/dummy/db/schema.rb +17 -4
  38. data/spec/dummy/db/test.sqlite3 +0 -0
  39. data/spec/dummy/log/development.log +1248 -0
  40. data/spec/dummy/log/test.log +43258 -0
  41. data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +3 -0
  42. data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +4 -0
  43. data/spec/support/fixtures/reports/submissions.csv +3 -3
  44. metadata +22 -8
@@ -9,15 +9,15 @@ module CanvasSync
9
9
  # @param options [Hash]
10
10
  def perform(job_chain, options)
11
11
  if options[:term_scope]
12
- sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |job_chain|
12
+ sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |fork_template|
13
13
  Term.send(options[:term_scope]).find_each.map do |term|
14
+ fork = fork_template.duplicate
14
15
  # Deep copy the job_chain so each report gets the correct term id passed into
15
16
  # its options with no side effects
16
17
  term_id = get_term_id(term)
17
- duped_job_chain = Marshal.load(Marshal.dump(job_chain))
18
- duped_job_chain[:global_options][:canvas_term_id] = term_id
18
+ fork[:global_options][:canvas_term_id] = term_id
19
19
  {
20
- job_chain: duped_job_chain,
20
+ job_chain: fork.serialize,
21
21
  params: report_params(options, term_id),
22
22
  options: options,
23
23
  }
@@ -0,0 +1,15 @@
1
+ require 'active_record'
2
+
3
+ module CanvasSync
4
+ module MiscHelper
5
+ MigrationClass = Rails.version < '5.0' ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]
6
+
7
+ def self.to_boolean(v)
8
+ if Rails.version < '5.0'
9
+ ActiveRecord::Type::Boolean.new.type_cast_from_user(v)
10
+ else
11
+ ActiveRecord::Type::Boolean.new.deserialize(v)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -8,15 +8,16 @@ module CanvasSync
8
8
  # @param options [Hash]
9
9
  class AssignmentGroupsProcessor < ReportProcessor
10
10
  def self.process(report_file_path, _options, report_id)
11
- new(report_file_path)
11
+ new(report_file_path, _options)
12
12
  end
13
13
 
14
- def initialize(report_file_path)
14
+ def initialize(report_file_path, options)
15
15
  CanvasSync::Importers::BulkImporter.import(
16
16
  report_file_path,
17
17
  mapping[:assignment_groups][:report_columns],
18
18
  AssignmentGroup,
19
19
  mapping[:assignment_groups][:conflict_target].to_sym,
20
+ import_args: options
20
21
  )
21
22
  end
22
23
  end
@@ -8,15 +8,16 @@ module CanvasSync
8
8
  # @param options [Hash]
9
9
  class AssignmentsProcessor < ReportProcessor
10
10
  def self.process(report_file_path, _options, report_id)
11
- new(report_file_path)
11
+ new(report_file_path, _options)
12
12
  end
13
13
 
14
- def initialize(report_file_path)
14
+ def initialize(report_file_path, options)
15
15
  CanvasSync::Importers::BulkImporter.import(
16
16
  report_file_path,
17
17
  mapping[:assignments][:report_columns],
18
18
  Assignment,
19
19
  mapping[:assignments][:conflict_target].to_sym,
20
+ import_args: options
20
21
  )
21
22
  end
22
23
  end
@@ -8,15 +8,16 @@ module CanvasSync
8
8
  # @param options [Hash]
9
9
  class ContextModuleItemsProcessor < ReportProcessor
10
10
  def self.process(report_file_path, _options, report_id)
11
- new(report_file_path)
11
+ new(report_file_path, _options)
12
12
  end
13
13
 
14
- def initialize(report_file_path)
14
+ def initialize(report_file_path, options)
15
15
  CanvasSync::Importers::BulkImporter.import(
16
16
  report_file_path,
17
17
  mapping[:context_module_items][:report_columns],
18
18
  ContextModuleItem,
19
19
  mapping[:context_module_items][:conflict_target].to_sym,
20
+ import_args: options
20
21
  )
21
22
  end
22
23
  end
@@ -8,15 +8,16 @@ module CanvasSync
8
8
  # @param options [Hash]
9
9
  class ContextModulesProcessor < ReportProcessor
10
10
  def self.process(report_file_path, _options, report_id)
11
- new(report_file_path)
11
+ new(report_file_path, _options)
12
12
  end
13
13
 
14
- def initialize(report_file_path)
14
+ def initialize(report_file_path, options)
15
15
  CanvasSync::Importers::BulkImporter.import(
16
16
  report_file_path,
17
17
  mapping[:context_modules][:report_columns],
18
18
  ContextModule,
19
19
  mapping[:context_modules][:conflict_target].to_sym,
20
+ import_args: options
20
21
  )
21
22
  end
22
23
  end
@@ -249,6 +249,9 @@ submissions:
249
249
  submission_date:
250
250
  database_column_name: submitted_at
251
251
  type: datetime
252
+ due_at:
253
+ database_column_name: due_at
254
+ type: datetime
252
255
  graded_date:
253
256
  database_column_name: graded_at
254
257
  type: datetime
@@ -18,7 +18,8 @@ module CanvasSync
18
18
  report_file_path,
19
19
  mapping[options[:mapping].to_sym][:report_columns],
20
20
  options[:klass].constantize,
21
- conflict_target ? conflict_target.to_sym : conflict_target
21
+ conflict_target ? conflict_target.to_sym : conflict_target,
22
+ import_args: options
22
23
  )
23
24
  end
24
25
  end
@@ -21,7 +21,6 @@ module CanvasSync
21
21
 
22
22
  def initialize(report_file_path, options) # rubocop:disable Metrics/AbcSize
23
23
  @options = options
24
-
25
24
  if options[:models].length == 1
26
25
  run_import(options[:models][0], report_file_path)
27
26
  else
@@ -75,6 +74,7 @@ module CanvasSync
75
74
  mapping[:users][:report_columns],
76
75
  User,
77
76
  mapping[:users][:conflict_target].to_sym,
77
+ import_args: @options
78
78
  )
79
79
  end
80
80
 
@@ -84,6 +84,7 @@ module CanvasSync
84
84
  mapping[:pseudonyms][:report_columns],
85
85
  Pseudonym,
86
86
  mapping[:pseudonyms][:conflict_target].to_sym,
87
+ import_args: @options
87
88
  )
88
89
  end
89
90
 
@@ -92,7 +93,8 @@ module CanvasSync
92
93
  report_file_path,
93
94
  mapping[:accounts][:report_columns],
94
95
  Account,
95
- mapping[:accounts][:conflict_target].to_sym
96
+ mapping[:accounts][:conflict_target].to_sym,
97
+ import_args: @options
96
98
  )
97
99
  end
98
100
 
@@ -102,6 +104,7 @@ module CanvasSync
102
104
  mapping[:courses][:report_columns],
103
105
  Course,
104
106
  mapping[:courses][:conflict_target].to_sym,
107
+ import_args: @options
105
108
  )
106
109
  end
107
110
 
@@ -111,6 +114,7 @@ module CanvasSync
111
114
  mapping[:enrollments][:report_columns],
112
115
  Enrollment,
113
116
  mapping[:enrollments][:conflict_target].to_sym,
117
+ import_args: @options
114
118
  )
115
119
  end
116
120
 
@@ -120,6 +124,7 @@ module CanvasSync
120
124
  mapping[:sections][:report_columns],
121
125
  Section,
122
126
  mapping[:sections][:conflict_target].to_sym,
127
+ import_args: @options
123
128
  )
124
129
  end
125
130
 
@@ -129,6 +134,7 @@ module CanvasSync
129
134
  mapping[:xlist][:report_columns],
130
135
  Section,
131
136
  mapping[:xlist][:conflict_target].to_sym,
137
+ import_args: @options
132
138
  )
133
139
  end
134
140
 
@@ -138,6 +144,7 @@ module CanvasSync
138
144
  mapping[:groups][:report_columns],
139
145
  Group,
140
146
  mapping[:groups][:conflict_target].to_sym,
147
+ import_args: @options
141
148
  )
142
149
  end
143
150
 
@@ -148,6 +155,7 @@ module CanvasSync
148
155
  mapping[:group_memberships][:report_columns],
149
156
  GroupMembership,
150
157
  mapping[:group_memberships][:conflict_target].to_sym,
158
+ import_args: @options
151
159
  )
152
160
  end
153
161
  end
@@ -8,15 +8,16 @@ module CanvasSync
8
8
  # @param options [Hash]
9
9
  class SubmissionsProcessor < ReportProcessor
10
10
  def self.process(report_file_path, _options, report_id)
11
- new(report_file_path)
11
+ new(report_file_path, _options)
12
12
  end
13
13
 
14
- def initialize(report_file_path)
14
+ def initialize(report_file_path, options)
15
15
  CanvasSync::Importers::BulkImporter.import(
16
16
  report_file_path,
17
17
  mapping[:submissions][:report_columns],
18
18
  Submission,
19
19
  mapping[:submissions][:conflict_target].to_sym,
20
+ import_args: options
20
21
  )
21
22
  end
22
23
  end
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.15.1".freeze
2
+ VERSION = "0.16.5".freeze
3
3
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  RSpec.describe CanvasSync::Jobs::ForkGather do
4
4
  describe '#perform' do
5
5
  let!(:job_log) { CanvasSync::JobLog.create!(job_id: 'BLAH', fork_count: 3) }
6
- let(:job_chain) { {jobs: [], global_options: { fork_path: ['BLAH'] }} }
6
+ let(:job_chain) { {jobs: [], fork_state: { forking_path: ['BLAH'], pre_fork_globals: [{}] }} }
7
7
 
8
8
  it 'decrements fork_count' do
9
9
  CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
@@ -21,16 +21,16 @@ RSpec.describe CanvasSync::Jobs::ForkGather do
21
21
  CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
22
22
  end
23
23
 
24
- it 'continues if no fork_path is specified' do
25
- job_chain[:global_options].delete(:fork_path)
24
+ it 'continues if no forking_path is specified' do
25
+ job_chain[:fork_state].delete(:forking_path)
26
26
  expect(CanvasSync).to receive(:invoke_next)
27
27
  CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
28
28
  end
29
29
 
30
- it 'pops the most-recent fork_path enrty' do
30
+ it 'pops the most-recent forking_path enrty' do
31
31
  job_log.update!(fork_count: 1)
32
32
  expect(CanvasSync).to receive(:invoke_next) do |*args|
33
- expect(args[0][:global_options][:fork_path]).to eq []
33
+ expect(args[0][:fork_state][:forking_path]).to eq []
34
34
  end
35
35
  CanvasSync::Jobs::ForkGather.perform_now(job_chain, {})
36
36
  end
@@ -47,8 +47,8 @@ RSpec.describe CanvasSync::Jobs::ForkGather do
47
47
  { job: 'CanvasSync::Jobs::ForkGather' },
48
48
  { job: 'CanvasSync::Jobs::ReportChecker' },
49
49
  ],
50
- global_options: {
51
- fork_path: ['BLAH'],
50
+ fork_state: {
51
+ forking_path: ['BLAH'],
52
52
  }
53
53
  }
54
54
  }
@@ -65,8 +65,8 @@ RSpec.describe CanvasSync::Jobs::ForkGather do
65
65
  expect(CanvasSync::Jobs::ForkGather.handle_branch_error(error, job_chain: job_chain)).to be nil
66
66
  end
67
67
 
68
- it 'does nothing if no fork_path is present' do
69
- job_chain[:global_options][:fork_path] = []
68
+ it 'does nothing if no forking_path is present' do
69
+ job_chain[:fork_state][:forking_path] = []
70
70
  expect(CanvasSync::Jobs::ForkGather.handle_branch_error(error, job_chain: job_chain)).to be nil
71
71
  end
72
72
  end
@@ -16,7 +16,7 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
16
16
 
17
17
  expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
18
18
  .with(
19
- expected_job_chain,
19
+ hash_including(expected_job_chain),
20
20
  'proservices_provisioning_csv',
21
21
  {
22
22
  parameters: {
@@ -36,7 +36,7 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
36
36
 
37
37
  expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
38
38
  .with(
39
- expected_job_chain_2,
39
+ hash_including(expected_job_chain_2),
40
40
  'proservices_provisioning_csv',
41
41
  {
42
42
  parameters: {
@@ -15,7 +15,7 @@ RSpec.describe CanvasSync::Jobs::SyncSimpleTableJob do
15
15
 
16
16
  expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
17
17
  .with(
18
- expected_job_chain,
18
+ hash_including(expected_job_chain),
19
19
  'proservices_provisioning_csv',
20
20
  {
21
21
  "parameters[include_deleted]" => true,
@@ -20,6 +20,9 @@ class Account < ApplicationRecord
20
20
  primary_key: :canvas_id, foreign_key: :canvas_parent_account_id
21
21
  has_many :groups, primary_key: :canvas_id, foreign_key: :canvas_account_id
22
22
 
23
+ scope :active, -> { where.not(workflow_state: 'deleted') }
24
+ # scope :should_canvas_sync, -> { active } # Optional - uses .active if not given
25
+
23
26
  api_syncable({
24
27
  name: :name,
25
28
  workflow_state: :workflow_state,
@@ -0,0 +1,14 @@
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 Pseudonym < ApplicationRecord
10
+ include CanvasSync::Record
11
+
12
+ validates :canvas_id, uniqueness: true, presence: true
13
+ belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id
14
+ end
@@ -20,6 +20,7 @@ class Submission < ApplicationRecord
20
20
  canvas_user_id: :user_id,
21
21
  submitted_at: :submitted_at,
22
22
  graded_at: :graded_at,
23
+ cached_due_date: :due_at,
23
24
  score: :score,
24
25
  excused: :excused,
25
26
  workflow_state: :workflow_state,
@@ -11,6 +11,7 @@ class User < ApplicationRecord
11
11
  include CanvasSync::Concerns::ApiSyncable
12
12
 
13
13
  validates :canvas_id, uniqueness: true, presence: true
14
+ has_many :pseudonyms, primary_key: :canvas_id, foreign_key: :canvas_user_id
14
15
  has_many :enrollments, primary_key: :canvas_id, foreign_key: :canvas_user_id
15
16
  has_many :admins, primary_key: :canvas_id, foreign_key: :canvas_user_id
16
17
  has_many :admin_roles, through: :admins, source: :role
@@ -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,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 CreatePseudonyms < ActiveRecord::Migration[5.1]
10
+ def change
11
+ create_table :pseudonyms do |t|
12
+ t.bigint :canvas_id, null: false
13
+ t.bigint :canvas_user_id
14
+ t.string :sis_id
15
+ t.string :unique_id
16
+ t.string :workflow_state
17
+
18
+ t.timestamps
19
+ end
20
+
21
+ add_index :pseudonyms, :canvas_id, unique: true
22
+ add_index :pseudonyms, :canvas_user_id
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: 2020_04_16_214248) do
13
+ ActiveRecord::Schema.define(version: 2020_10_16_181346) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -83,7 +83,7 @@ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
83
83
  t.index ["canvas_id"], name: "index_assignments_on_canvas_id", unique: true
84
84
  end
85
85
 
86
- create_table "canvas_sync_job_logs", force: :cascade do |t|
86
+ create_table "canvas_sync_job_logs", id: :serial, force: :cascade do |t|
87
87
  t.datetime "started_at"
88
88
  t.datetime "completed_at"
89
89
  t.string "exception"
@@ -92,8 +92,8 @@ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
92
92
  t.string "status"
93
93
  t.text "metadata"
94
94
  t.text "job_arguments"
95
- t.datetime "created_at", null: false
96
- t.datetime "updated_at", null: false
95
+ t.datetime "created_at"
96
+ t.datetime "updated_at"
97
97
  t.string "job_id"
98
98
  t.integer "fork_count"
99
99
  t.index ["job_id"], name: "index_canvas_sync_job_logs_on_job_id"
@@ -191,6 +191,18 @@ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
191
191
  t.index ["canvas_id"], name: "index_groups_on_canvas_id", unique: true
192
192
  end
193
193
 
194
+ create_table "pseudonyms", force: :cascade do |t|
195
+ t.bigint "canvas_id", null: false
196
+ t.bigint "canvas_user_id"
197
+ t.string "sis_id"
198
+ t.string "unique_id"
199
+ t.string "workflow_state"
200
+ t.datetime "created_at", null: false
201
+ t.datetime "updated_at", null: false
202
+ t.index ["canvas_id"], name: "index_pseudonyms_on_canvas_id", unique: true
203
+ t.index ["canvas_user_id"], name: "index_pseudonyms_on_canvas_user_id"
204
+ end
205
+
194
206
  create_table "roles", force: :cascade do |t|
195
207
  t.integer "canvas_id", null: false
196
208
  t.string "label"
@@ -225,6 +237,7 @@ ActiveRecord::Schema.define(version: 2020_04_16_214248) do
225
237
  t.bigint "canvas_assignment_id"
226
238
  t.bigint "canvas_user_id"
227
239
  t.datetime "submitted_at"
240
+ t.datetime "due_at"
228
241
  t.datetime "graded_at"
229
242
  t.float "score"
230
243
  t.float "points_possible"