canvas_sync 0.17.27 → 0.17.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/lib/canvas_sync/generators/templates/migrations/create_content_migrations.rb +24 -0
- data/lib/canvas_sync/generators/templates/models/content_migration.rb +10 -0
- data/lib/canvas_sync/job_batches/batch.rb +9 -23
- data/lib/canvas_sync/job_batches/callback.rb +4 -4
- data/lib/canvas_sync/job_batches/context_hash.rb +1 -1
- data/lib/canvas_sync/job_batches/jobs/managed_batch_job.rb +2 -2
- data/lib/canvas_sync/job_batches/pool.rb +6 -6
- data/lib/canvas_sync/job_batches/redis_model.rb +1 -1
- data/lib/canvas_sync/job_batches/sidekiq/web/helpers.rb +1 -1
- data/lib/canvas_sync/jobs/sync_content_migrations_job.rb +20 -0
- data/lib/canvas_sync/jobs/term_batches_job.rb +2 -2
- data/lib/canvas_sync/processors/content_migrations_processor.rb +19 -0
- data/lib/canvas_sync/processors/model_mappings.yml +40 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/lib/canvas_sync.rb +2 -0
- data/spec/canvas_sync/jobs/sync_content_migrations_job_spec.rb +30 -0
- data/spec/canvas_sync/processors/content_migrations_processor_spec.rb +13 -0
- data/spec/dummy/app/models/content_migration.rb +16 -0
- data/spec/dummy/db/migrate/20220308072643_create_content_migrations.rb +30 -0
- data/spec/dummy/db/schema.rb +19 -1
- data/spec/dummy/log/test.log +11952 -0
- data/spec/job_batching/batch_spec.rb +0 -6
- data/spec/support/fixtures/reports/content_migrations.csv +3 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef8cd570185754998d8c14cd67f87c6d60e3507f7996925bdc4a425cd7d43f1d
|
4
|
+
data.tar.gz: 931416870261971aaeccfc59bae91972c8d7a7277aab9da4ac18610c3352a7fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7262c43e7395e4c9de96a9d5c4688ff85299fcab3f97abcea719b6f73c36fb519c23ccf7a224605a8552d0e547fe135ecc055ac7f664d240f0cc1dd8a932e2bf
|
7
|
+
data.tar.gz: 524b36471a7b135856c2e3bd935e8ab7e057616c1bd3ed4a6d5e7a6d66c98f3236cf87d041f946a5e4ac149bef9830100619ba9e61568971f0e17898ae2f44f3
|
data/README.md
CHANGED
@@ -34,6 +34,7 @@ The following custom reports are required for the specified models:
|
|
34
34
|
- assignment_groups = "Assignment Group Export" (proserv_assignment_group_export_csv)
|
35
35
|
- context_modules = "Professional Services Context Modules Report" (proserv_context_modules_csv)
|
36
36
|
- context_module_items = "Professional Services Context Module Items Report" (proserv_context_module_items_csv)
|
37
|
+
- content_migrations = "Professional Services Content Migrations Report" (proserv_content_migrations_csv)
|
37
38
|
|
38
39
|
## Prerequisites
|
39
40
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# <%= autogenerated_migration_warning %>
|
2
|
+
|
3
|
+
class CreateContentMigrations < ActiveRecord::Migration[5.1]
|
4
|
+
def change
|
5
|
+
create_table :content_migrations do |t|
|
6
|
+
t.bigint :canvas_id
|
7
|
+
t.bigint :canvas_context_id
|
8
|
+
t.string :canvas_context_type
|
9
|
+
t.string :workflow_state
|
10
|
+
t.text :migration_settings
|
11
|
+
t.datetime :started_at
|
12
|
+
t.datetime :finished_at
|
13
|
+
t.float :progress
|
14
|
+
t.bigint :canvas_source_course_id
|
15
|
+
t.string :migration_type
|
16
|
+
t.bigint :canvas_child_subscription_id
|
17
|
+
t.bigint :canvas_root_account_id
|
18
|
+
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
|
22
|
+
add_index :content_migrations, :canvas_id, unique: true
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# <%= autogenerated_model_warning %>
|
2
|
+
|
3
|
+
class ContentMigration < ApplicationRecord
|
4
|
+
include CanvasSync::Record
|
5
|
+
include CanvasSync::Concerns::ApiSyncable
|
6
|
+
|
7
|
+
validates :canvas_id, uniqueness: true, presence: true
|
8
|
+
belongs_to :context, polymorphic: true, optional: true, primary_key: :canvas_id, foreign_key: :canvas_context_id, foreign_type: :canvas_context_type
|
9
|
+
|
10
|
+
end
|
@@ -242,7 +242,7 @@ module CanvasSync
|
|
242
242
|
_, pending, failed, children, complete, parent_bid = redis do |r|
|
243
243
|
return unless r.exists?("BID-#{bid}")
|
244
244
|
|
245
|
-
r.multi do
|
245
|
+
r.multi do |r|
|
246
246
|
r.sadd("BID-#{bid}-failed", jid)
|
247
247
|
|
248
248
|
r.hincrby("BID-#{bid}", "pending", 0)
|
@@ -260,29 +260,19 @@ module CanvasSync
|
|
260
260
|
end
|
261
261
|
end
|
262
262
|
|
263
|
+
# Dead jobs are a Sidekiq feature.
|
264
|
+
# If this is called for a job, process_failed_job was also called
|
263
265
|
def process_dead_job(bid, jid)
|
264
|
-
_,
|
266
|
+
_, dead_count = redis do |r|
|
265
267
|
return unless r.exists?("BID-#{bid}")
|
266
268
|
|
267
|
-
r.multi do
|
269
|
+
r.multi do |r|
|
268
270
|
r.sadd("BID-#{bid}-dead", jid)
|
269
|
-
|
270
271
|
r.scard("BID-#{bid}-dead")
|
271
|
-
r.hincrby("BID-#{bid}", "children", 0)
|
272
|
-
r.scard("BID-#{bid}-batches-complete")
|
273
|
-
r.hget("BID-#{bid}", "parent_bid")
|
274
|
-
|
275
272
|
r.expire("BID-#{bid}-dead", BID_EXPIRE_TTL)
|
276
273
|
end
|
277
274
|
end
|
278
275
|
|
279
|
-
if parent_bid
|
280
|
-
redis.multi do
|
281
|
-
r.sadd("BID-#{parent_bid}-dead", jid)
|
282
|
-
r.expire("BID-#{parent_bid}-dead", BID_EXPIRE_TTL)
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
276
|
enqueue_callbacks(:death, bid)
|
287
277
|
end
|
288
278
|
|
@@ -290,7 +280,7 @@ module CanvasSync
|
|
290
280
|
_, failed, pending, children, complete, success, parent_bid, keep_open = redis do |r|
|
291
281
|
return unless r.exists?("BID-#{bid}")
|
292
282
|
|
293
|
-
r.multi do
|
283
|
+
r.multi do |r|
|
294
284
|
r.srem("BID-#{bid}-failed", jid)
|
295
285
|
|
296
286
|
r.scard("BID-#{bid}-failed")
|
@@ -323,7 +313,7 @@ module CanvasSync
|
|
323
313
|
return unless r.exists?(batch_key)
|
324
314
|
return if r.hget(batch_key, 'keep_open') == 'true'
|
325
315
|
|
326
|
-
r.multi do
|
316
|
+
r.multi do |r|
|
327
317
|
r.smembers(callback_key)
|
328
318
|
r.hget(batch_key, "callback_queue")
|
329
319
|
r.hget(batch_key, "parent_bid")
|
@@ -442,12 +432,8 @@ module CanvasSync
|
|
442
432
|
class RedisProxy
|
443
433
|
def multi(*args, &block)
|
444
434
|
Batch.redis do |r|
|
445
|
-
|
446
|
-
|
447
|
-
block.call(r)
|
448
|
-
end
|
449
|
-
else
|
450
|
-
r.multi(*args, &block)
|
435
|
+
r.multi(*args) do |r|
|
436
|
+
block.call(r)
|
451
437
|
end
|
452
438
|
end
|
453
439
|
end
|
@@ -69,7 +69,7 @@ module CanvasSync
|
|
69
69
|
# This is a callback for a callback. In this case we need to check if we should cleanup the original bid.
|
70
70
|
origin_bid = opts['origin']['for_bid']
|
71
71
|
_, pending, success_ran = Batch.redis do |r|
|
72
|
-
r.multi do
|
72
|
+
r.multi do |r|
|
73
73
|
r.srem("BID-#{origin_bid}-pending_callbacks", opts['origin']['event'])
|
74
74
|
r.scard("BID-#{origin_bid}-pending_callbacks")
|
75
75
|
r.hget("BID-#{origin_bid}", "success")
|
@@ -88,7 +88,7 @@ module CanvasSync
|
|
88
88
|
return unless parent_bid
|
89
89
|
|
90
90
|
_, _, success, _, _, complete, pending, children, success, failure = Batch.redis do |r|
|
91
|
-
r.multi do
|
91
|
+
r.multi do |r|
|
92
92
|
r.sadd("BID-#{parent_bid}-batches-success", bid)
|
93
93
|
r.expire("BID-#{parent_bid}-batches-success", Batch::BID_EXPIRE_TTL)
|
94
94
|
r.scard("BID-#{parent_bid}-batches-success")
|
@@ -116,7 +116,7 @@ module CanvasSync
|
|
116
116
|
|
117
117
|
def complete(bid, status, parent_bid)
|
118
118
|
pending, children, success = Batch.redis do |r|
|
119
|
-
r.multi do
|
119
|
+
r.multi do |r|
|
120
120
|
r.hincrby("BID-#{bid}", "pending", 0)
|
121
121
|
r.hincrby("BID-#{bid}", "children", 0)
|
122
122
|
r.scard("BID-#{bid}-batches-success")
|
@@ -131,7 +131,7 @@ module CanvasSync
|
|
131
131
|
|
132
132
|
Batch.logger.debug {"Finalize parent complete bid: #{parent_bid}"}
|
133
133
|
_, _, complete, pending, children, failure = Batch.redis do |r|
|
134
|
-
r.multi do
|
134
|
+
r.multi do |r|
|
135
135
|
r.sadd("BID-#{parent_bid}-batches-complete", bid)
|
136
136
|
r.sadd("BID-#{parent_bid}-batches-failed", bid)
|
137
137
|
r.scard("BID-#{parent_bid}-batches-complete")
|
@@ -18,7 +18,7 @@ module CanvasSync
|
|
18
18
|
man_batch_id = SecureRandom.urlsafe_base64(10)
|
19
19
|
|
20
20
|
Batch.redis do |r|
|
21
|
-
r.multi do
|
21
|
+
r.multi do |r|
|
22
22
|
r.hset("MNGBID-#{man_batch_id}", "root_bid", root_batch.bid)
|
23
23
|
r.hset("MNGBID-#{man_batch_id}", "ordered", ordered)
|
24
24
|
r.hset("MNGBID-#{man_batch_id}", "concurrency", concurrency)
|
@@ -87,7 +87,7 @@ module CanvasSync
|
|
87
87
|
|
88
88
|
def self.perform_next_sequence_job(man_batch_id)
|
89
89
|
root_bid, ordered = Batch.redis do |r|
|
90
|
-
r.multi do
|
90
|
+
r.multi do |r|
|
91
91
|
r.hget("MNGBID-#{man_batch_id}", "root_bid")
|
92
92
|
r.hget("MNGBID-#{man_batch_id}", "ordered")
|
93
93
|
end
|
@@ -94,16 +94,16 @@ module CanvasSync
|
|
94
94
|
redis.hincrby(redis_key, "active_count", 0)
|
95
95
|
end
|
96
96
|
|
97
|
-
def pending_count
|
97
|
+
def pending_count(r = redis)
|
98
98
|
jobs_key = "#{redis_key}-jobs"
|
99
99
|
order = self.order || 'fifo'
|
100
100
|
case order.to_sym
|
101
101
|
when :fifo, :lifo
|
102
|
-
|
102
|
+
r.llen(jobs_key)
|
103
103
|
when :random
|
104
|
-
|
104
|
+
r.scard(jobs_key)
|
105
105
|
when :priority
|
106
|
-
|
106
|
+
r.zcard(jobs_key)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -114,9 +114,9 @@ module CanvasSync
|
|
114
114
|
# Make sure this is loaded outside of the pipeline
|
115
115
|
self.order
|
116
116
|
|
117
|
-
redis.multi do
|
117
|
+
redis.multi do |r|
|
118
118
|
r.hincrby(redis_key, "active_count", -1)
|
119
|
-
self.pending_count
|
119
|
+
self.pending_count(r)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CanvasSync
|
2
|
+
module Jobs
|
3
|
+
class SyncContentMigrationsJob < ReportStarter
|
4
|
+
# Syncs ContentMigrations
|
5
|
+
#
|
6
|
+
# Starts a report processor for the content migrations report
|
7
|
+
# (the proserv_content_migrations_csv report must be enabled)
|
8
|
+
#
|
9
|
+
# @param options [Hash]
|
10
|
+
def perform(options)
|
11
|
+
super(
|
12
|
+
"proserv_content_migrations_csv",
|
13
|
+
merge_report_params(options),
|
14
|
+
CanvasSync::Processors::ContentMigrationsProcessor.to_s,
|
15
|
+
{},
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -20,9 +20,9 @@ module CanvasSync
|
|
20
20
|
end
|
21
21
|
|
22
22
|
JobBatches::ManagedBatchJob.make_batch(jobs, ordered: false, concurrency: true) do |b|
|
23
|
-
b.description = "TermBatchJob(#{
|
23
|
+
b.description = "TermBatchJob(#{term_id}) Root"
|
24
24
|
b.context = local_context
|
25
|
-
b.on(:success, "#{self.class.to_s}.batch_finished")
|
25
|
+
b.on(:success, "#{self.class.to_s}.batch_finished") unless options[:mark_synced] == false
|
26
26
|
end
|
27
27
|
end
|
28
28
|
else
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "./report_processor"
|
2
|
+
|
3
|
+
module CanvasSync
|
4
|
+
module Processors
|
5
|
+
# Processes a content migrations report using the bulk importer.
|
6
|
+
#
|
7
|
+
# @param report_file_path [String]
|
8
|
+
# @param options [Hash]
|
9
|
+
class ContentMigrationsProcessor < ReportProcessor
|
10
|
+
def self.process(report_file_path, _options, report_id)
|
11
|
+
new(report_file_path, _options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(report_file_path, options)
|
15
|
+
do_bulk_import(report_file_path, ContentMigration, options: options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -469,3 +469,43 @@ grading_period_groups:
|
|
469
469
|
status:
|
470
470
|
database_column_name: workflow_state
|
471
471
|
type: string
|
472
|
+
|
473
|
+
content_migrations:
|
474
|
+
conflict_target: canvas_migration_id
|
475
|
+
report_columns:
|
476
|
+
canvas_migration_id:
|
477
|
+
database_column_name: canvas_id
|
478
|
+
type: integer
|
479
|
+
canvas_context_id:
|
480
|
+
database_column_name: canvas_context_id
|
481
|
+
type: integer
|
482
|
+
canvas_context_type:
|
483
|
+
database_column_name: canvas_context_type
|
484
|
+
type: string
|
485
|
+
workflow_state:
|
486
|
+
database_column_name: workflow_state
|
487
|
+
type: string
|
488
|
+
migration_settings:
|
489
|
+
database_column_name: migration_settings
|
490
|
+
type: text
|
491
|
+
started_at:
|
492
|
+
database_column_name: started_at
|
493
|
+
type: datetime
|
494
|
+
finished_at:
|
495
|
+
database_column_name: finished_at
|
496
|
+
type: datetime
|
497
|
+
progress:
|
498
|
+
database_column_name: progress
|
499
|
+
type: float
|
500
|
+
canvas_source_course_id:
|
501
|
+
database_column_name: canvas_source_course_id
|
502
|
+
type: integer
|
503
|
+
migration_type:
|
504
|
+
database_column_name: migration_type
|
505
|
+
type: string
|
506
|
+
canvas_child_subscription_id:
|
507
|
+
database_column_name: canvas_child_subscription_id
|
508
|
+
type: integer
|
509
|
+
canvas_root_account_id:
|
510
|
+
database_column_name: canvas_root_account_id
|
511
|
+
type: integer
|
data/lib/canvas_sync/version.rb
CHANGED
data/lib/canvas_sync.rb
CHANGED
@@ -44,6 +44,7 @@ module CanvasSync
|
|
44
44
|
user_observers
|
45
45
|
grading_periods
|
46
46
|
grading_period_groups
|
47
|
+
content_migrations
|
47
48
|
].freeze
|
48
49
|
|
49
50
|
SUPPORTED_TERM_SCOPE_MODELS = %w[
|
@@ -150,6 +151,7 @@ module CanvasSync
|
|
150
151
|
assignment_groups: CanvasSync::Jobs::SyncAssignmentGroupsJob,
|
151
152
|
context_modules: CanvasSync::Jobs::SyncContextModulesJob,
|
152
153
|
context_module_items: CanvasSync::Jobs::SyncContextModuleItemsJob,
|
154
|
+
content_migrations: CanvasSync::Jobs::SyncContentMigrationsJob,
|
153
155
|
}.with_indifferent_access
|
154
156
|
|
155
157
|
root_chain = base_canvas_sync_chain(**kwargs, globals: options[:global] || kwargs[:globals])
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncContentMigrationsJob do
|
4
|
+
describe "#perform" do
|
5
|
+
context "no parameters is specified" do
|
6
|
+
it "enqueues a ReportStarter for the proserv_content_migrations_csv" do
|
7
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report)
|
8
|
+
.with("self", "proserv_content_migrations_csv", { parameters: { } })
|
9
|
+
.and_return("id" => 1)
|
10
|
+
|
11
|
+
expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
|
12
|
+
|
13
|
+
CanvasSync::Jobs::SyncContentMigrationsJob.perform_now({})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "updated_after parameters is specified" do
|
18
|
+
it "enqueues a ReportStarter for the proserv_content_migrations_csv and get data from given date" do
|
19
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report)
|
20
|
+
.with("self", "proserv_content_migrations_csv", { parameters: { updated_after: 6.hours.ago.to_s } })
|
21
|
+
.and_return("id" => 1)
|
22
|
+
|
23
|
+
expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
|
24
|
+
|
25
|
+
set_batch_context(updated_after: 6.hours.ago.to_s)
|
26
|
+
CanvasSync::Jobs::SyncContentMigrationsJob.perform_now({})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CanvasSync::Processors::ContentMigrationsProcessor do
|
4
|
+
let(:subject) { CanvasSync::Processors::ContentMigrationsProcessor }
|
5
|
+
|
6
|
+
describe "#process" do
|
7
|
+
it "inserts content migrations" do
|
8
|
+
expect {
|
9
|
+
subject.process("spec/support/fixtures/reports/content_migrations.csv", {}, 1)
|
10
|
+
}.to change { ContentMigration.count }.by(2)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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 ContentMigration < ApplicationRecord
|
10
|
+
include CanvasSync::Record
|
11
|
+
include CanvasSync::Concerns::ApiSyncable
|
12
|
+
|
13
|
+
validates :canvas_id, uniqueness: true, presence: true
|
14
|
+
belongs_to :context, polymorphic: true, optional: true, primary_key: :canvas_id, foreign_key: :canvas_context_id, foreign_type: :canvas_context_type
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
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 CreateContentMigrations < ActiveRecord::Migration[5.1]
|
10
|
+
def change
|
11
|
+
create_table :content_migrations do |t|
|
12
|
+
t.bigint :canvas_id
|
13
|
+
t.bigint :canvas_context_id
|
14
|
+
t.string :canvas_context_type
|
15
|
+
t.string :workflow_state
|
16
|
+
t.text :migration_settings
|
17
|
+
t.datetime :started_at
|
18
|
+
t.datetime :finished_at
|
19
|
+
t.float :progress
|
20
|
+
t.bigint :canvas_source_course_id
|
21
|
+
t.string :migration_type
|
22
|
+
t.bigint :canvas_child_subscription_id
|
23
|
+
t.bigint :canvas_root_account_id
|
24
|
+
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
|
28
|
+
add_index :content_migrations, :canvas_id, unique: true
|
29
|
+
end
|
30
|
+
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -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:
|
13
|
+
ActiveRecord::Schema.define(version: 2022_03_08_072643) do
|
14
14
|
|
15
15
|
# These are extensions that must be enabled in order to support this database
|
16
16
|
enable_extension "plpgsql"
|
@@ -110,6 +110,24 @@ ActiveRecord::Schema.define(version: 2021_10_01_184920) do
|
|
110
110
|
t.string "batch_bid"
|
111
111
|
end
|
112
112
|
|
113
|
+
create_table "content_migrations", force: :cascade do |t|
|
114
|
+
t.bigint "canvas_id"
|
115
|
+
t.bigint "canvas_context_id"
|
116
|
+
t.string "canvas_context_type"
|
117
|
+
t.string "workflow_state"
|
118
|
+
t.text "migration_settings"
|
119
|
+
t.datetime "started_at"
|
120
|
+
t.datetime "finished_at"
|
121
|
+
t.float "progress"
|
122
|
+
t.bigint "canvas_source_course_id"
|
123
|
+
t.string "migration_type"
|
124
|
+
t.bigint "canvas_child_subscription_id"
|
125
|
+
t.bigint "canvas_root_account_id"
|
126
|
+
t.datetime "created_at", null: false
|
127
|
+
t.datetime "updated_at", null: false
|
128
|
+
t.index ["canvas_id"], name: "index_content_migrations_on_canvas_id", unique: true
|
129
|
+
end
|
130
|
+
|
113
131
|
create_table "context_module_items", force: :cascade do |t|
|
114
132
|
t.bigint "canvas_id"
|
115
133
|
t.bigint "canvas_context_module_id"
|