canvas_sync 0.10.3 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +57 -2
  3. data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +13 -0
  4. data/lib/canvas_sync.rb +43 -8
  5. data/lib/canvas_sync/api_syncable.rb +8 -0
  6. data/lib/canvas_sync/generators/templates/migrations/create_admins.rb +7 -4
  7. data/lib/canvas_sync/generators/templates/migrations/create_roles.rb +3 -4
  8. data/lib/canvas_sync/generators/templates/models/account.rb +2 -0
  9. data/lib/canvas_sync/generators/templates/models/admin.rb +4 -5
  10. data/lib/canvas_sync/generators/templates/models/role.rb +0 -4
  11. data/lib/canvas_sync/generators/templates/models/term.rb +0 -2
  12. data/lib/canvas_sync/importers/bulk_importer.rb +7 -4
  13. data/lib/canvas_sync/job.rb +24 -1
  14. data/lib/canvas_sync/jobs/fork_gather.rb +59 -0
  15. data/lib/canvas_sync/jobs/report_starter.rb +12 -1
  16. data/lib/canvas_sync/jobs/sync_admins_job.rb +9 -5
  17. data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +2 -8
  18. data/lib/canvas_sync/jobs/sync_assignments_job.rb +2 -8
  19. data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +2 -8
  20. data/lib/canvas_sync/jobs/sync_context_modules_job.rb +2 -8
  21. data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +23 -11
  22. data/lib/canvas_sync/jobs/sync_roles_job.rb +8 -5
  23. data/lib/canvas_sync/jobs/sync_simple_table_job.rb +17 -7
  24. data/lib/canvas_sync/jobs/sync_submissions_job.rb +1 -5
  25. data/lib/canvas_sync/jobs/sync_terms_job.rb +8 -2
  26. data/lib/canvas_sync/jobs/sync_users_job.rb +5 -7
  27. data/lib/canvas_sync/processors/assignment_groups_processor.rb +3 -2
  28. data/lib/canvas_sync/processors/assignments_processor.rb +3 -2
  29. data/lib/canvas_sync/processors/context_module_items_processor.rb +3 -2
  30. data/lib/canvas_sync/processors/context_modules_processor.rb +3 -2
  31. data/lib/canvas_sync/processors/normal_processor.rb +2 -1
  32. data/lib/canvas_sync/processors/provisioning_report_processor.rb +7 -2
  33. data/lib/canvas_sync/processors/submissions_processor.rb +3 -2
  34. data/lib/canvas_sync/version.rb +1 -1
  35. data/spec/canvas_sync/canvas_sync_spec.rb +17 -0
  36. data/spec/canvas_sync/jobs/fork_gather_spec.rb +73 -0
  37. data/spec/canvas_sync/jobs/job_spec.rb +39 -5
  38. data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +2 -1
  39. data/spec/canvas_sync/jobs/sync_assignment_groups_job_spec.rb +1 -1
  40. data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +2 -2
  41. data/spec/canvas_sync/jobs/sync_context_module_items_job_spec.rb +2 -2
  42. data/spec/canvas_sync/jobs/sync_context_modules_job_spec.rb +2 -2
  43. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +20 -11
  44. data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +2 -1
  45. data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +1 -0
  46. data/spec/canvas_sync/jobs/sync_submissions_job_spec.rb +1 -1
  47. data/spec/canvas_sync/jobs/sync_users_job_spec.rb +1 -1
  48. data/spec/canvas_sync/models/admins_spec.rb +3 -5
  49. data/spec/canvas_sync/models/roles_spec.rb +5 -5
  50. data/spec/canvas_sync/models/term_spec.rb +3 -3
  51. data/spec/dummy/app/models/account.rb +2 -0
  52. data/spec/dummy/app/models/admin.rb +4 -5
  53. data/spec/dummy/app/models/role.rb +0 -4
  54. data/spec/dummy/app/models/term.rb +0 -2
  55. data/spec/dummy/db/migrate/{20190702203628_create_roles.rb → 20190927204545_create_roles.rb} +3 -4
  56. data/spec/dummy/db/migrate/{20190702203629_create_admins.rb → 20190927204546_create_admins.rb} +7 -4
  57. data/spec/dummy/db/schema.rb +12 -9
  58. data/spec/dummy/db/test.sqlite3 +0 -0
  59. data/spec/dummy/log/development.log +1248 -0
  60. data/spec/dummy/log/test.log +43258 -0
  61. data/spec/factories/admin_factory.rb +0 -1
  62. data/spec/support/fake_canvas.rb +2 -2
  63. data/spec/support/fixtures/canvas_responses/roles.json +6 -0
  64. data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +3 -0
  65. data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +4 -0
  66. metadata +25 -12
@@ -12,7 +12,7 @@ module CanvasSync
12
12
  # @return [nil]
13
13
  def perform(job_chain, report_name, report_params, processor, options, allow_redownloads: false)
14
14
  account_id = options[:account_id] || job_chain[:global_options][:account_id] || "self"
15
-
15
+ options[:sync_start_time] = DateTime.now.utc.iso8601
16
16
  report_id = if allow_redownloads
17
17
  get_cached_report(job_chain, account_id, report_name, report_params)
18
18
  else
@@ -28,6 +28,17 @@ module CanvasSync
28
28
  )
29
29
  end
30
30
 
31
+ protected
32
+
33
+ def merge_report_params(job_chain, options={}, params={}, term_scope: true)
34
+ term_scope = job_chain[:global_options][:canvas_term_id] if term_scope == true
35
+ if term_scope.present?
36
+ params[:enrollment_term_id] = term_scope
37
+ end
38
+ params.merge!(options[:report_params]) if options[:report_params].present?
39
+ { parameters: params }
40
+ end
41
+
31
42
  private
32
43
 
33
44
  def get_cached_report(job_chain, account_id, report_name, report_params)
@@ -7,12 +7,16 @@ module CanvasSync
7
7
  # @param job_chain [Hash]
8
8
  # @param options [Hash]
9
9
  def perform(job_chain, _options)
10
- updated_admins = []
11
- CanvasSync.get_canvas_sync_client(job_chain[:global_options]).account_admins("self").all_pages!.each do |admin_params|
12
- admin = Admin.create_or_update(admin_params)
13
- updated_admins.push(admin.id)
10
+ updated_admin_ids = []
11
+ api_client = CanvasSync.get_canvas_sync_client(job_chain[:global_options])
12
+ CanvasSync.sync_scope(Account).find_each do |acc|
13
+ api_client.account_admins(acc.canvas_id).all_pages_each do |admin_params|
14
+ admin_params[:account_id] = acc.canvas_id
15
+ admin = update_or_create_model(Admin, admin_params)
16
+ updated_admin_ids.push(admin.id)
17
+ end
14
18
  end
15
- Admin.where.not(id: updated_admins).delete_all
19
+ Admin.where.not(id: updated_admin_ids).update_all(workflow_state: 'inactive')
16
20
  CanvasSync.invoke_next(job_chain)
17
21
  end
18
22
  end
@@ -8,17 +8,11 @@ module CanvasSync
8
8
  #
9
9
  # @param job_chain [Hash]
10
10
  # @param options [Hash]
11
- def perform(job_chain, _options)
12
- report_params = if job_chain[:global_options][:canvas_term_id].present?
13
- { "parameters[enrollment_term_id]" => job_chain[:global_options][:canvas_term_id] }
14
- else
15
- {}
16
- end
17
-
11
+ def perform(job_chain, options)
18
12
  super(
19
13
  job_chain,
20
14
  "proserv_assignment_group_export_csv",
21
- report_params,
15
+ merge_report_params(job_chain, options),
22
16
  CanvasSync::Processors::AssignmentGroupsProcessor.to_s,
23
17
  {},
24
18
  )
@@ -8,17 +8,11 @@ module CanvasSync
8
8
  #
9
9
  # @param job_chain [Hash]
10
10
  # @param options [Hash]
11
- def perform(job_chain, _options)
12
- report_params = if job_chain[:global_options][:canvas_term_id].present?
13
- { "parameters[enrollment_term_id]" => job_chain[:global_options][:canvas_term_id] }
14
- else
15
- {}
16
- end
17
-
11
+ def perform(job_chain, options)
18
12
  super(
19
13
  job_chain,
20
14
  "proserv_assignment_export_csv",
21
- report_params,
15
+ merge_report_params(job_chain, options),
22
16
  CanvasSync::Processors::AssignmentsProcessor.to_s,
23
17
  {},
24
18
  )
@@ -8,17 +8,11 @@ module CanvasSync
8
8
  #
9
9
  # @param job_chain [Hash]
10
10
  # @param options [Hash]
11
- def perform(job_chain, _options)
12
- report_params = if job_chain[:global_options][:canvas_term_id].present?
13
- { "parameters[enrollment_term_id]" => job_chain[:global_options][:canvas_term_id] }
14
- else
15
- {}
16
- end
17
-
11
+ def perform(job_chain, options)
18
12
  super(
19
13
  job_chain,
20
14
  "proserv_context_module_items_csv",
21
- report_params,
15
+ merge_report_params(job_chain, options),
22
16
  CanvasSync::Processors::ContextModuleItemsProcessor.to_s,
23
17
  {},
24
18
  )
@@ -8,17 +8,11 @@ module CanvasSync
8
8
  #
9
9
  # @param job_chain [Hash]
10
10
  # @param options [Hash]
11
- def perform(job_chain, _options)
12
- report_params = if job_chain[:global_options][:canvas_term_id].present?
13
- { "parameters[enrollment_term_id]" => job_chain[:global_options][:canvas_term_id] }
14
- else
15
- {}
16
- end
17
-
11
+ def perform(job_chain, options)
18
12
  super(
19
13
  job_chain,
20
14
  "proserv_context_modules_csv",
21
- report_params,
15
+ merge_report_params(job_chain, options),
22
16
  CanvasSync::Processors::ContextModulesProcessor.to_s,
23
17
  {},
24
18
  )
@@ -8,13 +8,23 @@ module CanvasSync
8
8
  # models to sync.
9
9
  def perform(job_chain, options)
10
10
  if options[:term_scope]
11
- Term.send(options[:term_scope]).find_each do |term|
12
- # Deep copy the job_chain so each report gets the correct term id passed into
13
- # its options with no side effects
14
- term_id = get_term_id(term)
15
- duped_job_chain = Marshal.load(Marshal.dump(job_chain))
16
- duped_job_chain[:global_options][:canvas_term_id] = term_id
17
- start_report(report_params(options, term_id), duped_job_chain, options)
11
+ sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |job_chain|
12
+ Term.send(options[:term_scope]).find_each.map do |term|
13
+ # Deep copy the job_chain so each report gets the correct term id passed into
14
+ # its options with no side effects
15
+ term_id = get_term_id(term)
16
+ duped_job_chain = Marshal.load(Marshal.dump(job_chain))
17
+ duped_job_chain[:global_options][:canvas_term_id] = term_id
18
+ {
19
+ job_chain: duped_job_chain,
20
+ params: report_params(options, term_id),
21
+ options: options,
22
+ }
23
+ end
24
+ end
25
+
26
+ sub_reports.each do |r|
27
+ start_report(r[:params], r[:job_chain], r[:options])
18
28
  end
19
29
  else
20
30
  start_report(report_params(options), job_chain, options)
@@ -35,16 +45,18 @@ module CanvasSync
35
45
 
36
46
  def report_params(options, canvas_term_id=nil)
37
47
  params = {
38
- "parameters[include_deleted]" => true
48
+ include_deleted: true,
39
49
  }
40
50
 
41
51
  options[:models].each do |model|
42
- params["parameters[#{model}]"] = true
52
+ params[model] = true
43
53
  end
44
54
 
45
- params["parameters[enrollment_term_id]"] = canvas_term_id if canvas_term_id
55
+ params[:enrollment_term_id] = canvas_term_id if canvas_term_id
56
+
57
+ params.merge!(options[:report_parameters]) if options[:report_parameters].present?
46
58
 
47
- params
59
+ { parameters: params }
48
60
  end
49
61
 
50
62
  def get_term_id(term)
@@ -7,12 +7,15 @@ module CanvasSync
7
7
  # @param job_chain [Hash]
8
8
  # @param options [Hash]
9
9
  def perform(job_chain, _options)
10
- updated_roles = []
11
- CanvasSync.get_canvas_sync_client(job_chain[:global_options]).list_roles("self").all_pages!.each do |role_params|
12
- role = Role.create_or_update(role_params)
13
- updated_roles.push(role.id)
10
+ updated_role_ids = []
11
+ api_client = CanvasSync.get_canvas_sync_client(job_chain[:global_options])
12
+ CanvasSync.sync_scope(Account).find_each do |acc|
13
+ api_client.list_roles(acc.canvas_id, state: %w[active inactive]).all_pages_each do |role_params|
14
+ role = update_or_create_model(Role, role_params)
15
+ updated_role_ids.push(role.id)
16
+ end
14
17
  end
15
- Role.where.not(id: updated_roles).delete_all
18
+ Role.where.not(id: updated_role_ids).update_all(workflow_state: 'inactive')
16
19
  CanvasSync.invoke_next(job_chain)
17
20
  end
18
21
  end
@@ -9,13 +9,23 @@ module CanvasSync
9
9
  # @param options [Hash]
10
10
  def perform(job_chain, options)
11
11
  if options[:term_scope]
12
- Term.send(options[:term_scope]).find_each do |term|
13
- # Deep copy the job_chain so each report gets the correct term id passed into
14
- # its options with no side effects
15
- term_id = get_term_id(term)
16
- duped_job_chain = Marshal.load(Marshal.dump(job_chain))
17
- duped_job_chain[:global_options][:canvas_term_id] = term_id
18
- start_report(report_params(options, term_id), duped_job_chain, options)
12
+ sub_reports = CanvasSync.fork(@job_log, job_chain, keys: [:canvas_term_id]) do |job_chain|
13
+ Term.send(options[:term_scope]).find_each.map do |term|
14
+ # Deep copy the job_chain so each report gets the correct term id passed into
15
+ # its options with no side effects
16
+ 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
19
+ {
20
+ job_chain: duped_job_chain,
21
+ params: report_params(options, term_id),
22
+ options: options,
23
+ }
24
+ end
25
+ end
26
+
27
+ sub_reports.each do |r|
28
+ start_report(r[:params], r[:job_chain], r[:options])
19
29
  end
20
30
  else
21
31
  start_report(report_params(options), job_chain, options)
@@ -9,14 +9,10 @@ module CanvasSync
9
9
  # @param job_chain [Hash]
10
10
  # @param options [Hash]
11
11
  def perform(job_chain, options)
12
- report_params = {}
13
- report_params["parameters[enrollment_term_id]"] = job_chain[:global_options][:canvas_term_id] if job_chain[:global_options][:canvas_term_id].present?
14
- report_params["parameters[include_all]"] = true if options[:include_all]
15
-
16
12
  super(
17
13
  job_chain,
18
14
  "proserv_student_submissions_csv",
19
- report_params,
15
+ merge_report_params(job_chain, options, { include_all: options[:include_all] }, {}),
20
16
  CanvasSync::Processors::SubmissionsProcessor.to_s,
21
17
  {},
22
18
  )
@@ -10,9 +10,15 @@ module CanvasSync
10
10
  def perform(job_chain, _options)
11
11
  CanvasSync.get_canvas_sync_client(job_chain[:global_options]).terms("self").all_pages!.each do |term_params|
12
12
  if job_chain[:global_options][:account_id]
13
- Term.create_or_update(term_params, job_chain[:global_options][:account_id])
13
+ # These branches are primarily to support Legacy apps
14
+ if Term.respond_to?(:create_or_update) && Term.method(:create_or_update).arity.abs == 2
15
+ Term.create_or_update(term_params, job_chain[:global_options][:account_id])
16
+ else
17
+ term_params[:account_id] |= job_chain[:global_options][:account_id]
18
+ update_or_create_model(Term, term_params)
19
+ end
14
20
  else
15
- Term.create_or_update(term_params)
21
+ update_or_create_model(Term, term_params)
16
22
  end
17
23
  end
18
24
 
@@ -1,11 +1,6 @@
1
1
  module CanvasSync
2
2
  module Jobs
3
3
  class SyncUsersJob < ReportStarter
4
- REPORT_PARAMS = {
5
- "parameters[users]" => true,
6
- "parameters[include_deleted]" => true
7
- }.freeze
8
-
9
4
  # Starts a provisioning report for just users.
10
5
  #
11
6
  # Provisioning reports do not scope users by term, so when we are
@@ -14,11 +9,14 @@ module CanvasSync
14
9
  #
15
10
  # @param job_chain [Hash]
16
11
  # @param options [Hash]
17
- def perform(job_chain, _options)
12
+ def perform(job_chain, options)
18
13
  super(
19
14
  job_chain,
20
15
  "proservices_provisioning_csv",
21
- REPORT_PARAMS,
16
+ merge_report_params(job_chain, options, {
17
+ users: true,
18
+ include_deleted: true,
19
+ }, term_scope: false),
22
20
  CanvasSync::Processors::ProvisioningReportProcessor.to_s,
23
21
  { models: ["users"] },
24
22
  )
@@ -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
@@ -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
 
@@ -83,7 +83,8 @@ module CanvasSync
83
83
  report_file_path,
84
84
  mapping[:accounts][:report_columns],
85
85
  Account,
86
- mapping[:accounts][:conflict_target].to_sym
86
+ mapping[:accounts][:conflict_target].to_sym,
87
+ import_args: @options
87
88
  )
88
89
  end
89
90
 
@@ -93,6 +94,7 @@ module CanvasSync
93
94
  mapping[:courses][:report_columns],
94
95
  Course,
95
96
  mapping[:courses][:conflict_target].to_sym,
97
+ import_args: @options
96
98
  )
97
99
  end
98
100
 
@@ -102,6 +104,7 @@ module CanvasSync
102
104
  mapping[:enrollments][:report_columns],
103
105
  Enrollment,
104
106
  mapping[:enrollments][:conflict_target].to_sym,
107
+ import_args: @options
105
108
  )
106
109
  end
107
110
 
@@ -111,6 +114,7 @@ module CanvasSync
111
114
  mapping[:sections][:report_columns],
112
115
  Section,
113
116
  mapping[:sections][:conflict_target].to_sym,
117
+ import_args: @options
114
118
  )
115
119
  end
116
120
 
@@ -120,6 +124,7 @@ module CanvasSync
120
124
  mapping[:xlist][:report_columns],
121
125
  Section,
122
126
  mapping[:xlist][:conflict_target].to_sym,
127
+ import_args: @options
123
128
  )
124
129
  end
125
130
  end