canvas_sync 0.17.40 → 0.17.42

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 252aa98d20ca9456416bab466fdbfc5bcfe5d7626a8462002a66034c5aa8e168
4
- data.tar.gz: da8257b9f54f1840b19661982a712c51a2e720e5defecdd2080b1ecd3d2962f7
3
+ metadata.gz: 6637b97dd9b51f6d3babe9b022904d9e77b1c886e62707fb857db5caba909fc3
4
+ data.tar.gz: 1bfa80e171b9b92b12ebad2fdc732b558e59fe9271175ce7d1dd2680a81e2b0c
5
5
  SHA512:
6
- metadata.gz: 247383e570fe4b9f89640bfee466ba616bd845e299c03fef240e14c45fbc9d2cd5558d3ea09bc8a80bb8d8a6d451ed7f6fa5f162ef93d0764f3e4fb9ea022c62
7
- data.tar.gz: d470874db2a8008a5be3bafbae07161fd79ec931eb7c98414fd233bccb4778bb5a4054337aa2c677c00a5e51c17e13dd69a7eb6759c2e30f817bac7817318ed7
6
+ metadata.gz: 0af624f526294b480e6b24814ab9156f3970056160eb59e0aafdd9af2849984ef34668099cce16f978257b6311c5fbfe69e2fe9e0bfd52224034c7e8018afbfc
7
+ data.tar.gz: 2d2d89dc832f3cb4d901641f00c930f929ca410f86b2890689909f43fea3fb29d56584fa72c5871382101d946ff7d50fde3d044375ae03d1b8de230bba13788b
@@ -28,7 +28,7 @@ module CanvasSync::Concerns
28
28
  @model = model
29
29
  @map_def = map_def
30
30
  @map_def[:conflict_target] ||= []
31
- @map_def[:report_columns] ||= {}
31
+ @map_def[:columns] ||= {}
32
32
  end
33
33
 
34
34
  def self.normalize_model_name(model)
@@ -50,9 +50,9 @@ module CanvasSync::Concerns
50
50
  legacy[:report_columns][lct][:database_column_name]
51
51
  end
52
52
 
53
- m[:report_columns] = {}
53
+ m[:columns] = {}
54
54
  legacy[:report_columns].each do |rcol, opts|
55
- m[:report_columns][opts[:database_column_name]] = opts.except(:database_column_name).merge!(
55
+ m[:columns][opts[:database_column_name]] = opts.except(:database_column_name).merge!(
56
56
  report_column: rcol,
57
57
  ).freeze
58
58
  end
@@ -84,23 +84,23 @@ module CanvasSync::Concerns
84
84
  end
85
85
 
86
86
  def reset_links
87
- @map_def[:report_columns] = {}.with_indifferent_access
87
+ @map_def[:columns] = {}.with_indifferent_access
88
88
  end
89
89
 
90
90
  def unlink_column(key)
91
- @map_def[:report_columns].delete(key)
91
+ @map_def[:columns].delete(key)
92
92
  end
93
93
 
94
94
  def link_column(m, type: nil, &blk)
95
95
  if m.is_a?(Hash)
96
96
  raise "Hash should have exactly 1 entry" if m && m.count != 1
97
- @map_def[:report_columns][m.values[0]] = {
97
+ @map_def[:columns][m.values[0]] = {
98
98
  report_column: m.keys[0],
99
99
  type: type,
100
100
  transform: blk,
101
101
  }
102
102
  elsif m.is_a?(Symbol)
103
- @map_def[:report_columns][m] = {
103
+ @map_def[:columns][m] = {
104
104
  report_column: m,
105
105
  type: type,
106
106
  transform: blk,
@@ -5,9 +5,10 @@ module CanvasSync
5
5
  class Engine < ::Rails::Engine
6
6
  isolate_namespace CanvasSync
7
7
 
8
- initializer "canvas_sync.serialze_symbols" do |app|
8
+ initializer "canvas_sync.safe_yaml_classes" do |app|
9
9
  app.config.active_record.yaml_column_permitted_classes ||= []
10
- app.config.active_record.yaml_column_permitted_classes |= [Symbol]
10
+ app.config.active_record.yaml_column_permitted_classes |= [Symbol, ActiveSupport::HashWithIndifferentAccess]
11
+ ActiveRecord::Base.yaml_column_permitted_classes |= app.config.active_record.yaml_column_permitted_classes
11
12
  rescue
12
13
  end
13
14
 
@@ -40,12 +41,14 @@ module CanvasSync
40
41
 
41
42
  require 'panda_pal'
42
43
 
43
- def canvas_sync_client(account_id = nil)
44
- Bearcat::Client.new(
45
- prefix: current_organization.canvas_url,
46
- token: current_organization.canvas_api_token,
47
- master_rate_limit: (Rails.env.production? && !!defined?(Redis) && ENV['REDIS_URL'].present?),
48
- )
44
+ class ::Object
45
+ def canvas_sync_client(account_id = nil)
46
+ Bearcat::Client.new(
47
+ prefix: current_organization.canvas_url,
48
+ token: current_organization.canvas_api_token,
49
+ master_rate_limit: (Rails.env.production? && !!defined?(Redis) && ENV['REDIS_URL'].present?),
50
+ )
51
+ end
49
52
  end
50
53
  rescue LoadError
51
54
  end
@@ -157,13 +157,13 @@ module CanvasSync
157
157
  let_close!
158
158
  end
159
159
  else
160
- redis.hset(@bidkey, 'keep_open', true)
160
+ redis.hset(@bidkey, 'keep_open', "true")
161
161
  end
162
162
  end
163
163
 
164
164
  def let_close!
165
165
  _, failed, pending, children, complete, success = redis.multi do |r|
166
- r.hset(@bidkey, 'keep_open', false)
166
+ r.hset(@bidkey, 'keep_open', "false")
167
167
 
168
168
  r.scard("BID-#{bid}-failed")
169
169
  r.hincrby("BID-#{bid}", "pending", 0)
@@ -333,7 +333,7 @@ module CanvasSync
333
333
  opts = {"bid" => bid, "event" => event}
334
334
  should_schedule_batch = callback_args.present? && !callback_params.present?
335
335
  already_processed = redis do |r|
336
- SCHEDULE_CALLBACK.call(r, [batch_key], [event.to_s, should_schedule_batch, BID_EXPIRE_TTL])
336
+ SCHEDULE_CALLBACK.call(r, [batch_key], [event.to_s, should_schedule_batch.to_s, BID_EXPIRE_TTL])
337
337
  end
338
338
 
339
339
  return if already_processed == 'true'
@@ -6,6 +6,10 @@ module CanvasSync
6
6
  def perform(chain_definition, globals = {})
7
7
  @globals = globals
8
8
 
9
+ if globals[:updated_after] == nil && Rails.env.development?
10
+ globals[:updated_after] = false
11
+ end
12
+
9
13
  if globals[:updated_after] == false
10
14
  globals[:updated_after] = nil
11
15
  elsif !globals[:updated_after].present? || globals[:updated_after] == true
@@ -0,0 +1,73 @@
1
+ module CanvasSync::Jobs
2
+ class CanvasProcessWaiter < ActiveJob::Base
3
+ # rubocop:disable Metrics/PerceivedComplexity
4
+ def perform(progress_url, next_job, kwargs = {})
5
+ kwargs = kwargs.symbolize_keys
6
+
7
+ response = canvas_sync_client.get(progress_url)
8
+ status = kwargs[:status_key].present? ? response[kwargs[:status_key]] : response['workflow_state'] || response['status']
9
+
10
+ if %w[completed complete].include? status
11
+ InvokeCallbackWorker.perform_later(build_next_job(next_job, kwargs, response)) if next_job
12
+ elsif %w[failed error].include? status
13
+ if kwargs[:on_failure].is_a?(Hash)
14
+ InvokeCallbackWorker.perform_later(build_next_job(kwargs[:on_failure], kwargs, response))
15
+ else
16
+ Rails.logger.error("Progress #{progress_url} failed")
17
+ end
18
+ else # if status == 'queued' || status == 'running'
19
+ interval = kwargs[:interval] || (Rails.env.development? ? 3 : 60)
20
+ CanvasProcessWaiter.set(wait: interval).perform_later(progress_url, next_job, kwargs)
21
+ end
22
+ end
23
+ # rubocop:enable Metrics/PerceivedComplexity
24
+
25
+ def build_next_job(job, kwargs, response)
26
+ job = job.symbolize_keys
27
+ if kwargs[:progress_as].present?
28
+ job[:kwargs] ||= {}
29
+ job[:kwargs][kwargs[:progress_as].to_sym] = response
30
+ end
31
+ job
32
+ end
33
+
34
+ # This is a separate job so that, if it fails and a retry is triggered, it doesn't query the API needlessly
35
+ class InvokeCallbackWorker < ActiveJob::Base
36
+ # rubocop:disable Metrics/PerceivedComplexity
37
+ def perform(job)
38
+ job = job.symbolize_keys
39
+
40
+ params = job[:args] || []
41
+ params << job[:kwargs].symbolize_keys if job[:kwargs]
42
+ # params[-1] = params[-1].symbolize_keys if params[-1].is_a?(Hash)
43
+
44
+ if job[:model]
45
+ model_class = load_constant(job[:model])
46
+ find_by = job[:find_by]
47
+ target = find_by.is_a?(Hash) ? model_class.find_by(find_by) : model_class.find_by(id: find_by)
48
+ target.send(job[:method], *params)
49
+ elsif job[:class]
50
+ target = load_constant(job[:class])
51
+ target.send(job[:method], *params)
52
+ elsif job[:instance_of]
53
+ target = load_constant(job[:instance_of]).new
54
+ target.send(job[:method], *params)
55
+ elsif job[:job]
56
+ job_class = load_constant(job[:job])
57
+ job_class = job_class.set(job[:options]) if job[:options].present?
58
+ if job_class < ActiveJob::Base
59
+ job_class.perform_later(*params)
60
+ else
61
+ job_class.perform_async(*params)
62
+ end
63
+ end
64
+ end
65
+ # rubocop:enable Metrics/PerceivedComplexity
66
+
67
+ def load_constant(const)
68
+ const = const.constantize if const.is_a?(String)
69
+ const
70
+ end
71
+ end
72
+ end
73
+ end
@@ -8,6 +8,10 @@ module CanvasSync
8
8
  COMPILATION_TIMEOUT = 1.hour
9
9
  MAX_TRIES = 3
10
10
 
11
+ class FatalReportError < ::RuntimeError; end
12
+
13
+ discard_on FatalReportError
14
+
11
15
  # @param report_name [Hash] e.g., 'provisioning_csv'
12
16
  # @param report_id [Integer]
13
17
  # @param processor [String] a stringified report processor class name
@@ -36,21 +40,21 @@ module CanvasSync
36
40
  Rails.logger.error(message)
37
41
  if failed_attempts >= max_tries
38
42
  Rails.logger.error("This report has failed #{failed_attempts} times. Giving up.")
39
- raise message
43
+ raise FatalReportError, message
40
44
  else
41
45
  restart_report(options, report_name, processor, checker_context)
42
46
  end
43
47
  else
44
48
  report_timeout = parse_timeout(options[:report_timeout] || batch_context[:report_timeout] || REPORT_TIMEOUT)
45
49
  if timeout_met?(options[:sync_start_time], report_timeout)
46
- raise "Report appears to be stuck #{report_name}##{report_id}"
50
+ raise FatalReportError, "Report appears to be stuck #{report_name}##{report_id}"
47
51
  end
48
52
 
49
53
  if report_status["status"].downcase == 'compiling'
50
54
  checker_context['compiling_since'] ||= DateTime.now.iso8601
51
55
  compilation_timeout = parse_timeout(options[:report_compilation_timeout] || batch_context[:report_compilation_timeout] || COMPILATION_TIMEOUT)
52
56
  if timeout_met?(checker_context['compiling_since'], compilation_timeout)
53
- raise "Report appears to be stuck #{report_name}##{report_id}"
57
+ raise FatalReportError, "Report appears to be stuck #{report_name}##{report_id}"
54
58
  end
55
59
  end
56
60
 
@@ -26,7 +26,7 @@ module CanvasSync
26
26
  def download(report_name, report_url)
27
27
  Dir.mktmpdir do |dir|
28
28
  file_path = "#{dir}/#{report_name}"
29
- IO.copy_stream(open(report_url), file_path)
29
+ IO.copy_stream(URI.open(report_url), file_path)
30
30
  yield file_path
31
31
  end
32
32
  end
@@ -35,7 +35,11 @@ module CanvasSync
35
35
 
36
36
  protected
37
37
 
38
- def merge_report_params(options, params={}, term_scope: true)
38
+ # Ruby 3 changed how kwargs are handled. _kw_placeholder allows for backwards compatibility
39
+ # In Ruby 2, merge_report_params(options, params) would parse as merge_report_params(options, params={}, **params) (wtf?), so
40
+ # merge_report_params(options, params, {}) is used. That doesn't work in Ruby 3.
41
+ # In order to maintain compatibility with 2 and with any apps, this oddness is needed
42
+ def merge_report_params(options, params={}, _kw_placeholder=nil, term_scope: true)
39
43
  term_scope = options[:canvas_term_id] || batch_context[:canvas_term_id] if term_scope == true
40
44
  if term_scope.present?
41
45
  params[:enrollment_term_id] = term_scope
@@ -10,12 +10,22 @@ module CanvasSync
10
10
  options[:models].each do |model|
11
11
  # group_membership is the only model param that is singular :(
12
12
  model = 'group_membership' if model == 'group_memberships'
13
+
13
14
  params[model] = true
14
15
  end
15
16
 
17
+ merged_params = merge_report_params(options, params, {}).with_indifferent_access
18
+
19
+ # Make sure the report also checks last_activity_at when checking updated_at
20
+ if options[:models].include?("enrollments")
21
+ if (%w[last_activity_at total_activity_time] & Enrollment.get_sync_mapping[:columns].keys).present? && merged_params.dig(:parameters, :include_last_activity) == nil
22
+ merged_params[:parameters][:include_last_activity] = true
23
+ end
24
+ end
25
+
16
26
  super(
17
27
  "proservices_provisioning_csv",
18
- merge_report_params(options, params, {}),
28
+ merged_params,
19
29
  CanvasSync::Processors::ProvisioningReportProcessor.to_s,
20
30
  options,
21
31
  )
@@ -16,10 +16,9 @@ module CanvasSync
16
16
  m = mapping[options[:mapping].to_sym]
17
17
  CanvasSync::Importers::BulkImporter.import(
18
18
  report_file_path,
19
- m[:report_columns],
19
+ m[:columns],
20
20
  options[:klass].constantize,
21
21
  m[:conflict_target],
22
- import_args: options
23
22
  )
24
23
  end
25
24
  end
@@ -16,7 +16,7 @@ module CanvasSync
16
16
  m = mapping_for(model, mapping_key)
17
17
  CanvasSync::Importers::BulkImporter.import(
18
18
  report_file_path,
19
- m[:report_columns],
19
+ m[:columns],
20
20
  model,
21
21
  m[:conflict_target],
22
22
  import_args: options,
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.17.40".freeze
2
+ VERSION = "0.17.42".freeze
3
3
  end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CanvasSync::Jobs::CanvasProcessWaiter do
4
+ let!(:worker) { CanvasSync::Jobs::CanvasProcessWaiter.new }
5
+
6
+ describe 'perform' do
7
+ it 'queues a InvokeCallbackWorker when complete' do
8
+ job = {
9
+ args: [1, 2],
10
+ kwargs: { progress: anything },
11
+ }
12
+ allow_any_instance_of(Bearcat::Client).to receive(:get).and_return('workflow_state' => 'completed')
13
+ expect(CanvasSync::Jobs::CanvasProcessWaiter::InvokeCallbackWorker).to receive(:perform_later).with(job)
14
+ worker.perform('/blah/', job)
15
+ end
16
+
17
+ it 'invokes the on_failure callback if failed' do
18
+ job = {
19
+ args: [1, 2],
20
+ kwargs: { progress: anything },
21
+ }
22
+ allow_any_instance_of(Bearcat::Client).to receive(:get).and_return('workflow_state' => 'failed')
23
+ expect(CanvasSync::Jobs::CanvasProcessWaiter::InvokeCallbackWorker).to receive(:perform_later).with(job)
24
+ worker.perform('/blah/', nil, on_failure: job)
25
+ end
26
+
27
+ it 're-enqueues if incomplete' do
28
+ ActiveJob::Base.queue_adapter = :test
29
+ allow_any_instance_of(Bearcat::Client).to receive(:get).and_return('workflow_state' => 'pending')
30
+ worker.perform('/blah/', nil, interval: 13)
31
+ expect(CanvasSync::Jobs::CanvasProcessWaiter).to have_been_enqueued.once.with('/blah/', nil, interval: 13)
32
+ end
33
+ end
34
+
35
+ describe 'InvokeCallbackWorker' do
36
+ let!(:worker) { CanvasSync::Jobs::CanvasProcessWaiter::InvokeCallbackWorker.new }
37
+
38
+ with_model :Model do
39
+ table
40
+ model do
41
+ def wait_callback(*args); end
42
+
43
+ def self.wait_callback(*args); end
44
+ end
45
+ end
46
+
47
+ class CPW_TestWorker
48
+ extend Sidekiq::Worker
49
+ end
50
+
51
+ it 'schedules a given job' do
52
+ expect(CPW_TestWorker).to receive(:perform_async)
53
+ worker.perform(
54
+ job: 'CPW_TestWorker',
55
+ args: [1, 2],
56
+ )
57
+ end
58
+
59
+ it 'invokes a model method' do
60
+ model = Model.create!
61
+ expect(Model).to receive(:find_by).with(id: model.id).and_return(model)
62
+ expect(model).to receive(:wait_callback).with(1, 2, a: 3, b: 4)
63
+ worker.perform(
64
+ model: Model.to_s,
65
+ find_by: { id: model.id },
66
+ method: :wait_callback,
67
+ args: [1, 2],
68
+ kwargs: { a: 3, b: 4 },
69
+ )
70
+ end
71
+
72
+ it 'invokes a class method' do
73
+ expect(Model).to receive(:wait_callback).with(1, 2, a: 3, b: 4)
74
+ worker.perform(
75
+ class: Model.to_s,
76
+ method: :wait_callback,
77
+ args: [1, 2],
78
+ kwargs: { a: 3, b: 4 },
79
+ )
80
+ end
81
+ end
82
+ end
@@ -2260,3 +2260,196 @@ Migrating to CreateUsers (20220926221926)
2260
2260
   (1.2ms) COMMIT
2261
2261
   (0.2ms) SELECT pg_advisory_unlock(1438354376499275445)
2262
2262
   (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
2263
+  (1.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
2264
+  (0.8ms) SELECT "ar_internal_metadata"."value" FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 [["key", "environment"]]
2265
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
2266
+  (0.2ms) SELECT "ar_internal_metadata"."value" FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 [["key", "environment"]]
2267
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
2268
+  (0.2ms) SELECT "ar_internal_metadata"."value" FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 [["key", "environment"]]
2269
+  (48.4ms) DROP DATABASE IF EXISTS "canvas_sync_development"
2270
+  (49.8ms) DROP DATABASE IF EXISTS "canvas_sync_test"
2271
+  (133.7ms) CREATE DATABASE "canvas_sync_development" ENCODING = 'unicode'
2272
+  (105.4ms) CREATE DATABASE "canvas_sync_test" ENCODING = 'unicode'
2273
+  (11.6ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL PRIMARY KEY)
2274
+  (8.8ms) CREATE TABLE "ar_internal_metadata" ("key" character varying NOT NULL PRIMARY KEY, "value" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2275
+  (0.1ms) SELECT pg_try_advisory_lock(1438354376499275445)
2276
+  (0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
2277
+ Migrating to CreateCanvasSyncJobLog (20170915210836)
2278
+  (0.2ms) BEGIN
2279
+  (8.8ms) CREATE TABLE "canvas_sync_job_logs" ("id" serial NOT NULL PRIMARY KEY, "started_at" timestamp, "completed_at" timestamp, "exception" character varying, "backtrace" text, "job_class" character varying, "status" character varying, "metadata" text, "job_arguments" text, "created_at" timestamp, "updated_at" timestamp)
2280
+ ActiveRecord::SchemaMigration Create (0.5ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20170915210836"]]
2281
+  (1.2ms) COMMIT
2282
+ Migrating to AddJobIdToCanvasSyncJobLogs (20180725155729)
2283
+  (0.2ms) BEGIN
2284
+  (0.4ms) ALTER TABLE "canvas_sync_job_logs" ADD "job_id" character varying
2285
+  (3.9ms) CREATE INDEX "index_canvas_sync_job_logs_on_job_id" ON "canvas_sync_job_logs" ("job_id")
2286
+ ActiveRecord::SchemaMigration Create (0.5ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20180725155729"]]
2287
+  (1.3ms) COMMIT
2288
+ Migrating to CreateCourses (20190702203621)
2289
+  (0.2ms) BEGIN
2290
+  (10.3ms) CREATE TABLE "courses" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "sis_id" character varying, "course_code" character varying, "name" character varying, "workflow_state" character varying, "canvas_account_id" integer, "canvas_term_id" integer, "start_at" timestamp, "end_at" timestamp, "grading_standard_id" bigint, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2291
+  (5.4ms) CREATE UNIQUE INDEX "index_courses_on_canvas_id" ON "courses" ("canvas_id")
2292
+ ActiveRecord::SchemaMigration Create (0.5ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203621"]]
2293
+  (1.2ms) COMMIT
2294
+ Migrating to CreateAccounts (20190702203622)
2295
+  (0.2ms) BEGIN
2296
+  (9.6ms) CREATE TABLE "accounts" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "sis_id" character varying, "canvas_parent_account_id" bigint, "sis_parent_account_id" character varying, "name" character varying, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2297
+  (4.0ms) CREATE UNIQUE INDEX "index_accounts_on_canvas_id" ON "accounts" ("canvas_id")
2298
+ ActiveRecord::SchemaMigration Create (0.5ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203622"]]
2299
+  (1.3ms) COMMIT
2300
+ Migrating to CreateTerms (20190702203623)
2301
+  (0.3ms) BEGIN
2302
+  (8.1ms) CREATE TABLE "terms" ("id" bigserial primary key, "canvas_id" integer NOT NULL, "name" character varying, "start_at" timestamp, "end_at" timestamp, "workflow_state" character varying, "grading_period_group_id" integer, "sis_id" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2303
+  (4.1ms) CREATE UNIQUE INDEX "index_terms_on_canvas_id" ON "terms" ("canvas_id")
2304
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203623"]]
2305
+  (1.2ms) COMMIT
2306
+ Migrating to CreateEnrollments (20190702203624)
2307
+  (0.2ms) BEGIN
2308
+  (9.2ms) CREATE TABLE "enrollments" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "canvas_course_id" bigint, "course_sis_id" character varying, "canvas_user_id" bigint, "user_sis_id" character varying, "role" character varying, "canvas_role_id" integer, "canvas_section_id" bigint, "workflow_state" character varying, "base_role_type" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2309
+  (3.8ms) CREATE UNIQUE INDEX "index_enrollments_on_canvas_id" ON "enrollments" ("canvas_id")
2310
+  (3.8ms) CREATE INDEX "index_enrollments_on_canvas_course_id" ON "enrollments" ("canvas_course_id")
2311
+  (4.1ms) CREATE INDEX "index_enrollments_on_canvas_user_id" ON "enrollments" ("canvas_user_id")
2312
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203624"]]
2313
+  (1.2ms) COMMIT
2314
+ Migrating to CreateSections (20190702203625)
2315
+  (0.2ms) BEGIN
2316
+  (9.7ms) CREATE TABLE "sections" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "sis_id" character varying, "canvas_course_id" bigint, "canvas_nonxlist_course_id" bigint, "name" character varying, "workflow_state" character varying, "start_at" timestamp, "end_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2317
+  (4.0ms) CREATE UNIQUE INDEX "index_sections_on_canvas_id" ON "sections" ("canvas_id")
2318
+  (3.6ms) CREATE INDEX "index_sections_on_canvas_course_id" ON "sections" ("canvas_course_id")
2319
+ ActiveRecord::SchemaMigration Create (0.5ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203625"]]
2320
+  (1.3ms) COMMIT
2321
+ Migrating to CreateAssignments (20190702203626)
2322
+  (0.3ms) BEGIN
2323
+  (9.0ms) CREATE TABLE "assignments" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "title" character varying, "description" text, "due_at" timestamp, "unlock_at" timestamp, "lock_at" timestamp, "points_possible" float, "min_score" float, "max_score" float, "mastery_score" float, "grading_type" character varying, "submission_types" character varying, "workflow_state" character varying, "canvas_context_id" integer, "canvas_context_type" character varying, "canvas_assignment_group_id" integer, "canvas_grading_scheme_id" integer, "canvas_grading_standard_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2324
+  (3.8ms) CREATE UNIQUE INDEX "index_assignments_on_canvas_id" ON "assignments" ("canvas_id")
2325
+  (3.9ms) CREATE INDEX "index_assignments_on_canvas_context_id_and_canvas_context_type" ON "assignments" ("canvas_context_id", "canvas_context_type")
2326
+ ActiveRecord::SchemaMigration Create (0.3ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203626"]]
2327
+  (1.3ms) COMMIT
2328
+ Migrating to CreateSubmissions (20190702203627)
2329
+  (0.2ms) BEGIN
2330
+  (9.0ms) CREATE TABLE "submissions" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "canvas_course_id" bigint, "canvas_assignment_id" bigint, "canvas_user_id" bigint, "submitted_at" timestamp, "due_at" timestamp, "graded_at" timestamp, "score" float, "points_possible" float, "excused" boolean, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2331
+  (3.9ms) CREATE UNIQUE INDEX "index_submissions_on_canvas_id" ON "submissions" ("canvas_id")
2332
+  (3.7ms) CREATE INDEX "index_submissions_on_canvas_assignment_id" ON "submissions" ("canvas_assignment_id")
2333
+  (3.9ms) CREATE INDEX "index_submissions_on_canvas_course_id" ON "submissions" ("canvas_course_id")
2334
+  (3.9ms) CREATE INDEX "index_submissions_on_canvas_user_id" ON "submissions" ("canvas_user_id")
2335
+ ActiveRecord::SchemaMigration Create (0.3ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203627"]]
2336
+  (1.2ms) COMMIT
2337
+ Migrating to CreateAssignmentGroups (20190702203630)
2338
+  (0.2ms) BEGIN
2339
+  (9.0ms) CREATE TABLE "assignment_groups" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "canvas_course_id" bigint, "name" character varying, "rules" text, "position" integer, "group_weight" float, "workflow_state" character varying, "canvas_created_at" timestamp, "canvas_updated_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2340
+  (3.8ms) CREATE UNIQUE INDEX "index_assignment_groups_on_canvas_id" ON "assignment_groups" ("canvas_id")
2341
+  (3.9ms) CREATE INDEX "index_assignment_groups_on_canvas_course_id" ON "assignment_groups" ("canvas_course_id")
2342
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203630"]]
2343
+  (1.3ms) COMMIT
2344
+ Migrating to CreateContextModules (20190702203631)
2345
+  (0.2ms) BEGIN
2346
+  (10.4ms) CREATE TABLE "context_modules" ("id" bigserial primary key, "canvas_id" bigint, "canvas_context_id" bigint, "canvas_context_type" character varying, "position" integer, "name" character varying, "workflow_state" character varying, "deleted_at" timestamp, "unlock_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2347
+  (4.1ms) CREATE UNIQUE INDEX "index_context_modules_on_canvas_id" ON "context_modules" ("canvas_id")
2348
+  (3.8ms) CREATE INDEX "index_context_modules_on_context" ON "context_modules" ("canvas_context_id", "canvas_context_type")
2349
+ ActiveRecord::SchemaMigration Create (0.3ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203631"]]
2350
+  (1.3ms) COMMIT
2351
+ Migrating to CreateContextModuleItems (20190702203632)
2352
+  (0.2ms) BEGIN
2353
+  (10.0ms) CREATE TABLE "context_module_items" ("id" bigserial primary key, "canvas_id" bigint, "canvas_context_module_id" bigint, "position" integer, "canvas_content_id" bigint, "canvas_content_type" character varying, "canvas_assignment_id" bigint, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2354
+  (3.8ms) CREATE UNIQUE INDEX "index_context_module_items_on_canvas_id" ON "context_module_items" ("canvas_id")
2355
+  (3.9ms) CREATE INDEX "index_context_module_items_on_canvas_context_module_id" ON "context_module_items" ("canvas_context_module_id")
2356
+ ActiveRecord::SchemaMigration Create (0.5ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190702203632"]]
2357
+  (1.5ms) COMMIT
2358
+ Migrating to AddForkCountToCanvasSyncJobLogs (20190916154829)
2359
+  (0.3ms) BEGIN
2360
+  (0.4ms) ALTER TABLE "canvas_sync_job_logs" ADD "fork_count" integer
2361
+ ActiveRecord::SchemaMigration Create (0.3ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190916154829"]]
2362
+  (1.0ms) COMMIT
2363
+ Migrating to CreateRoles (20190927204545)
2364
+  (0.1ms) BEGIN
2365
+  (8.8ms) CREATE TABLE "roles" ("id" bigserial primary key, "canvas_id" integer NOT NULL, "label" character varying, "base_role_type" character varying, "canvas_account_id" integer, "workflow_state" character varying, "permissions" json, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2366
+  (3.6ms) CREATE UNIQUE INDEX "index_roles_on_canvas_id" ON "roles" ("canvas_id")
2367
+  (3.8ms) CREATE INDEX "index_roles_on_canvas_account_id" ON "roles" ("canvas_account_id")
2368
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190927204545"]]
2369
+  (1.4ms) COMMIT
2370
+ Migrating to CreateAdmins (20190927204546)
2371
+  (0.2ms) BEGIN
2372
+  (8.5ms) CREATE TABLE "admins" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "role_name" character varying, "canvas_account_id" bigint, "canvas_role_id" bigint, "canvas_user_id" bigint, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2373
+  (3.9ms) CREATE UNIQUE INDEX "index_admins_on_canvas_id" ON "admins" ("canvas_id")
2374
+  (3.6ms) CREATE INDEX "index_admins_on_canvas_role_id" ON "admins" ("canvas_role_id")
2375
+  (4.1ms) CREATE INDEX "index_admins_on_canvas_user_id" ON "admins" ("canvas_user_id")
2376
+  (3.7ms) CREATE INDEX "index_admins_on_canvas_account_id" ON "admins" ("canvas_account_id")
2377
+ ActiveRecord::SchemaMigration Create (0.6ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20190927204546"]]
2378
+  (1.5ms) COMMIT
2379
+ Migrating to CreateGroups (20200415171620)
2380
+  (0.3ms) BEGIN
2381
+  (9.3ms) CREATE TABLE "groups" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "sis_id" character varying, "canvas_group_category_id" bigint, "group_category_sis_id" character varying, "canvas_account_id" bigint, "canvas_course_id" bigint, "name" character varying, "workflow_state" character varying, "context_id" bigint, "context_type" character varying, "max_membership" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2382
+  (3.8ms) CREATE UNIQUE INDEX "index_groups_on_canvas_id" ON "groups" ("canvas_id")
2383
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20200415171620"]]
2384
+  (1.4ms) COMMIT
2385
+ Migrating to CreateGroupMemberships (20200416214248)
2386
+  (0.2ms) BEGIN
2387
+  (14.1ms) CREATE TABLE "group_memberships" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "canvas_user_id" bigint NOT NULL, "canvas_group_id" bigint NOT NULL, "group_sis_id" character varying, "user_sis_id" character varying, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2388
+  (3.6ms) CREATE UNIQUE INDEX "index_group_memberships_on_canvas_id" ON "group_memberships" ("canvas_id")
2389
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20200416214248"]]
2390
+  (1.7ms) COMMIT
2391
+ Migrating to CreatePseudonyms (20201016181346)
2392
+  (0.3ms) BEGIN
2393
+  (9.1ms) CREATE TABLE "pseudonyms" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "canvas_user_id" bigint, "sis_id" character varying, "unique_id" character varying, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2394
+  (3.9ms) CREATE UNIQUE INDEX "index_pseudonyms_on_canvas_id" ON "pseudonyms" ("canvas_id")
2395
+  (3.6ms) CREATE INDEX "index_pseudonyms_on_canvas_user_id" ON "pseudonyms" ("canvas_user_id")
2396
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20201016181346"]]
2397
+  (1.3ms) COMMIT
2398
+ Migrating to CreateCanvasSyncSyncBatches (20201018210836)
2399
+  (0.2ms) BEGIN
2400
+  (8.7ms) CREATE TABLE "canvas_sync_sync_batches" ("id" serial NOT NULL PRIMARY KEY, "started_at" timestamp, "completed_at" timestamp, "status" character varying, "created_at" timestamp, "updated_at" timestamp)
2401
+ ActiveRecord::SchemaMigration Create (0.3ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20201018210836"]]
2402
+  (1.2ms) COMMIT
2403
+ Migrating to AddFullSyncToCanvasSyncSyncBatch (20201030210836)
2404
+  (0.2ms) BEGIN
2405
+  (0.6ms) ALTER TABLE "canvas_sync_sync_batches" ADD "full_sync" boolean DEFAULT FALSE
2406
+  (0.5ms) ALTER TABLE "canvas_sync_sync_batches" ADD "batch_genre" character varying
2407
+  (0.7ms) ALTER TABLE "canvas_sync_sync_batches" ADD "batch_bid" character varying
2408
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20201030210836"]]
2409
+  (1.5ms) COMMIT
2410
+ Migrating to CreateUserObservers (20210907233329)
2411
+  (0.2ms) BEGIN
2412
+  (9.8ms) CREATE TABLE "user_observers" ("id" bigserial primary key, "observing_user_id" bigint, "observed_user_id" bigint, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2413
+  (4.1ms) CREATE UNIQUE INDEX "index_user_observers_on_observed_user_id_and_observing_user_id" ON "user_observers" ("observed_user_id", "observing_user_id")
2414
+  (4.0ms) CREATE INDEX "index_user_observers_on_observing_user_id" ON "user_observers" ("observing_user_id")
2415
+  (3.9ms) CREATE INDEX "index_user_observers_on_observed_user_id" ON "user_observers" ("observed_user_id")
2416
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20210907233329"]]
2417
+  (1.4ms) COMMIT
2418
+ Migrating to CreateGradingPeriods (20210907233330)
2419
+  (0.3ms) BEGIN
2420
+  (9.8ms) CREATE TABLE "grading_periods" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "title" character varying, "weight" float, "start_date" timestamp, "end_date" timestamp, "close_date" timestamp, "canvas_grading_period_group_id" bigint, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2421
+  (4.3ms) CREATE UNIQUE INDEX "index_grading_periods_on_canvas_id" ON "grading_periods" ("canvas_id")
2422
+  (4.0ms) CREATE INDEX "index_grading_periods_on_canvas_grading_period_group_id" ON "grading_periods" ("canvas_grading_period_group_id")
2423
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20210907233330"]]
2424
+  (1.3ms) COMMIT
2425
+ Migrating to CreateGradingPeriodGroups (20211001184920)
2426
+  (0.3ms) BEGIN
2427
+  (10.1ms) CREATE TABLE "grading_period_groups" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "title" character varying, "weighted" boolean, "display_totals_for_all_grading_periods" boolean, "workflow_state" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2428
+  (4.0ms) CREATE UNIQUE INDEX "index_grading_period_groups_on_canvas_id" ON "grading_period_groups" ("canvas_id")
2429
+ ActiveRecord::SchemaMigration Create (0.6ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20211001184920"]]
2430
+  (1.2ms) COMMIT
2431
+ Migrating to CreateContentMigrations (20220308072643)
2432
+  (0.2ms) BEGIN
2433
+  (10.7ms) CREATE TABLE "content_migrations" ("id" bigserial primary key, "canvas_id" bigint, "canvas_context_id" bigint, "canvas_context_type" character varying, "workflow_state" character varying, "migration_settings" text, "started_at" timestamp, "finished_at" timestamp, "progress" float, "canvas_source_course_id" bigint, "migration_type" character varying, "canvas_child_subscription_id" bigint, "canvas_root_account_id" bigint, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2434
+  (4.1ms) CREATE UNIQUE INDEX "index_content_migrations_on_canvas_id" ON "content_migrations" ("canvas_id")
2435
+ ActiveRecord::SchemaMigration Create (0.7ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20220308072643"]]
2436
+  (1.5ms) COMMIT
2437
+ Migrating to CreateLearningOutcomes (20220712210559)
2438
+  (0.3ms) BEGIN
2439
+  (10.5ms) CREATE TABLE "learning_outcomes" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "canvas_context_id" integer, "canvas_context_type" character varying, "name" character varying, "friendly_name" character varying, "workflow_state" character varying, "canvas_created_at" timestamp, "canvas_updated_at" timestamp, "migration_id" character varying, "vendor_guid" character varying, "low_grade" character varying, "high_grade" character varying, "calculation_method" character varying, "calculation_int" character varying, "outcome_import_id" integer, "root_account_ids" integer[] DEFAULT '{}', "description" text, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2440
+  (4.0ms) CREATE UNIQUE INDEX "index_learning_outcomes_on_canvas_id" ON "learning_outcomes" ("canvas_id")
2441
+  (3.9ms) CREATE INDEX "index_learning_outcomes_on_context" ON "learning_outcomes" ("canvas_context_id", "canvas_context_type")
2442
+ ActiveRecord::SchemaMigration Create (0.5ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20220712210559"]]
2443
+  (1.4ms) COMMIT
2444
+ Migrating to CreateUsers (20220926221926)
2445
+  (0.3ms) BEGIN
2446
+  (9.6ms) CREATE TABLE "users" ("id" bigserial primary key, "canvas_id" bigint NOT NULL, "email" character varying, "first_name" character varying, "last_name" character varying, "workflow_state" character varying, "login_id" character varying, "name" character varying, "sortable_name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
2447
+  (4.0ms) CREATE UNIQUE INDEX "index_users_on_canvas_id" ON "users" ("canvas_id")
2448
+ ActiveRecord::SchemaMigration Create (0.4ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) RETURNING "version" [["version", "20220926221926"]]
2449
+  (1.4ms) COMMIT
2450
+ ActiveRecord::InternalMetadata Load (0.5ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2 [["key", "environment"], ["LIMIT", 1]]
2451
+  (0.4ms) BEGIN
2452
+ ActiveRecord::InternalMetadata Create (0.6ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "key" [["key", "environment"], ["value", "development"], ["created_at", "2022-12-12 21:35:40.947063"], ["updated_at", "2022-12-12 21:35:40.947063"]]
2453
+  (1.3ms) COMMIT
2454
+  (0.3ms) SELECT pg_advisory_unlock(1438354376499275445)
2455
+  (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC