canvas_sync 0.24.0 → 0.26.0.beta1

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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/lib/canvas_sync/concerns/ability_helper.rb +6 -2
  3. data/lib/canvas_sync/concerns/canvas_id_as_primary.rb +11 -0
  4. data/lib/canvas_sync/concerns/user/through_pseudonyms.rb +47 -0
  5. data/lib/canvas_sync/concerns/user_via_pseudonym.rb +141 -0
  6. data/lib/canvas_sync/generators/templates/migrations/create_accounts.rb +1 -1
  7. data/lib/canvas_sync/generators/templates/migrations/create_admins.rb +1 -1
  8. data/lib/canvas_sync/generators/templates/migrations/create_assignment_groups.rb +1 -1
  9. data/lib/canvas_sync/generators/templates/migrations/create_assignment_overrides.rb +1 -1
  10. data/lib/canvas_sync/generators/templates/migrations/create_assignments.rb +1 -1
  11. data/lib/canvas_sync/generators/templates/migrations/create_content_migrations.rb +1 -1
  12. data/lib/canvas_sync/generators/templates/migrations/create_context_module_items.rb +1 -1
  13. data/lib/canvas_sync/generators/templates/migrations/create_context_modules.rb +1 -1
  14. data/lib/canvas_sync/generators/templates/migrations/create_course_nicknames.rb +1 -1
  15. data/lib/canvas_sync/generators/templates/migrations/create_course_progresses.rb +1 -1
  16. data/lib/canvas_sync/generators/templates/migrations/create_courses.rb +1 -1
  17. data/lib/canvas_sync/generators/templates/migrations/create_enrollments.rb +1 -1
  18. data/lib/canvas_sync/generators/templates/migrations/create_grading_period_groups.rb +1 -1
  19. data/lib/canvas_sync/generators/templates/migrations/create_grading_periods.rb +1 -1
  20. data/lib/canvas_sync/generators/templates/migrations/create_group_memberships.rb +1 -1
  21. data/lib/canvas_sync/generators/templates/migrations/create_groups.rb +1 -1
  22. data/lib/canvas_sync/generators/templates/migrations/create_learning_outcome_results.rb +1 -1
  23. data/lib/canvas_sync/generators/templates/migrations/create_learning_outcomes.rb +1 -1
  24. data/lib/canvas_sync/generators/templates/migrations/create_pseudonyms.rb +1 -1
  25. data/lib/canvas_sync/generators/templates/migrations/create_roles.rb +1 -1
  26. data/lib/canvas_sync/generators/templates/migrations/create_rubric_assessments.rb +1 -1
  27. data/lib/canvas_sync/generators/templates/migrations/create_rubric_associations.rb +1 -1
  28. data/lib/canvas_sync/generators/templates/migrations/create_rubrics.rb +1 -1
  29. data/lib/canvas_sync/generators/templates/migrations/create_scores.rb +1 -1
  30. data/lib/canvas_sync/generators/templates/migrations/create_sections.rb +1 -1
  31. data/lib/canvas_sync/generators/templates/migrations/create_submissions.rb +1 -1
  32. data/lib/canvas_sync/generators/templates/migrations/create_terms.rb +1 -1
  33. data/lib/canvas_sync/generators/templates/migrations/create_user_observers.rb +1 -1
  34. data/lib/canvas_sync/generators/templates/migrations/create_users.rb +1 -1
  35. data/lib/canvas_sync/generators/templates/models/course_nickname.rb +1 -0
  36. data/lib/canvas_sync/generators/templates/models/course_progress.rb +1 -0
  37. data/lib/canvas_sync/generators/templates/models/pseudonym.rb +2 -0
  38. data/lib/canvas_sync/generators/templates/models/user.rb +2 -0
  39. data/lib/canvas_sync/generators/templates/models/user_observer.rb +2 -0
  40. data/lib/canvas_sync/importers/bulk_importer.rb +1 -1
  41. data/lib/canvas_sync/jobs/sync_admins_job.rb +2 -2
  42. data/lib/canvas_sync/jobs/sync_roles_job.rb +2 -2
  43. data/lib/canvas_sync/misc_helper.rb +1 -1
  44. data/lib/canvas_sync/version.rb +1 -1
  45. data/lib/canvas_sync.rb +6 -0
  46. data/spec/canvas_sync/processors/context_modules_processor_spec.rb +2 -2
  47. data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +0 -2
  48. data/spec/internal/app/models/course_nickname.rb +1 -0
  49. data/spec/internal/app/models/course_progress.rb +1 -0
  50. data/spec/internal/app/models/pseudonym.rb +2 -0
  51. data/spec/internal/app/models/user.rb +2 -0
  52. data/spec/internal/app/models/user_observer.rb +2 -0
  53. data/spec/internal/db/migrate/{20250912205136_create_users.rb → 20251029222307_create_users.rb} +1 -1
  54. data/spec/internal/db/migrate/{20250912205137_create_pseudonyms.rb → 20251029222308_create_pseudonyms.rb} +1 -1
  55. data/spec/internal/db/migrate/{20250912205138_create_courses.rb → 20251029222309_create_courses.rb} +1 -1
  56. data/spec/internal/db/migrate/{20250912205139_create_groups.rb → 20251029222310_create_groups.rb} +1 -1
  57. data/spec/internal/db/migrate/{20250912205140_create_group_memberships.rb → 20251029222311_create_group_memberships.rb} +1 -1
  58. data/spec/internal/db/migrate/{20250912205141_create_accounts.rb → 20251029222312_create_accounts.rb} +1 -1
  59. data/spec/internal/db/migrate/{20250912205142_create_terms.rb → 20251029222313_create_terms.rb} +1 -1
  60. data/spec/internal/db/migrate/{20250912205143_create_enrollments.rb → 20251029222314_create_enrollments.rb} +1 -1
  61. data/spec/internal/db/migrate/{20250912205144_create_sections.rb → 20251029222315_create_sections.rb} +1 -1
  62. data/spec/internal/db/migrate/{20250912205145_create_assignments.rb → 20251029222316_create_assignments.rb} +1 -1
  63. data/spec/internal/db/migrate/{20250912205146_create_submissions.rb → 20251029222317_create_submissions.rb} +1 -1
  64. data/spec/internal/db/migrate/{20250912205147_create_roles.rb → 20251029222318_create_roles.rb} +1 -1
  65. data/spec/internal/db/migrate/{20250912205148_create_admins.rb → 20251029222319_create_admins.rb} +1 -1
  66. data/spec/internal/db/migrate/{20250912205149_create_assignment_groups.rb → 20251029222320_create_assignment_groups.rb} +1 -1
  67. data/spec/internal/db/migrate/{20250912205150_create_context_modules.rb → 20251029222321_create_context_modules.rb} +1 -1
  68. data/spec/internal/db/migrate/{20250912205151_create_context_module_items.rb → 20251029222322_create_context_module_items.rb} +1 -1
  69. data/spec/internal/db/migrate/{20250912205153_create_grading_periods.rb → 20251029222324_create_grading_periods.rb} +1 -1
  70. data/spec/internal/db/migrate/{20250912205154_create_grading_period_groups.rb → 20251029222325_create_grading_period_groups.rb} +1 -1
  71. data/spec/internal/db/migrate/{20250912205155_create_content_migrations.rb → 20251029222326_create_content_migrations.rb} +1 -1
  72. data/spec/internal/db/migrate/{20250912205156_create_learning_outcomes.rb → 20251029222327_create_learning_outcomes.rb} +1 -1
  73. data/spec/internal/db/migrate/{20250912205157_create_learning_outcome_results.rb → 20251029222328_create_learning_outcome_results.rb} +1 -1
  74. data/spec/internal/db/migrate/{20250912205159_create_rubrics.rb → 20251029222330_create_rubrics.rb} +1 -1
  75. data/spec/internal/db/migrate/{20250912205160_create_rubric_associations.rb → 20251029222331_create_rubric_associations.rb} +1 -1
  76. data/spec/internal/db/migrate/{20250912205161_create_rubric_assessments.rb → 20251029222332_create_rubric_assessments.rb} +1 -1
  77. data/spec/internal/db/migrate/{20250912205163_create_assignment_overrides.rb → 20251029222334_create_assignment_overrides.rb} +1 -1
  78. data/spec/internal/db/migrate/{20250912205164_create_scores.rb → 20251029222335_create_scores.rb} +1 -1
  79. data/spec/internal/db/migrate/{20250912205152_create_user_observers.rb → 20251029223411_create_user_observers.rb} +1 -1
  80. data/spec/internal/db/migrate/{20250912205158_create_course_nicknames.rb → 20251029224009_create_course_nicknames.rb} +1 -1
  81. data/spec/internal/db/migrate/{20250912205162_create_course_progresses.rb → 20251029224010_create_course_progresses.rb} +1 -1
  82. metadata +62 -59
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3391d91c2c45a7bbd04099137bfc94d896b703407c71b8b04c71b0e586bd4219
4
- data.tar.gz: 581742ed82c4b5cdfcbd8d2c0c7ef2d97ab6c86833aebceeb4cd1bdab881aea1
3
+ metadata.gz: ce4d1927f18104be2a36720a8932671c3a0188a1e3a235f6929a23299a8d89c4
4
+ data.tar.gz: e8e7a15fde1156d9485026c3039e5bcbe2c4dec3c3491b61eb2f06cc1d0ea718
5
5
  SHA512:
6
- metadata.gz: 8dd6fb7e8585626f31564edd76f67227e306bc4d29449f154c197d3ef289ca69d2c7371659b4a479854e9a57f0f9c3a61e68a275370a965da0f192bb97c747e8
7
- data.tar.gz: a31a167d26a44df1837038db87d9584c5f7f0e2964f142c34f08efc353a2cb2f713cf8002df681d79237ece0540f97eb35d2ab9eef931033bc1e264d847c9e15
6
+ metadata.gz: 2b4b60b41f8b249baaef413d1f44ba17d124ba6cff5960bb0d8b7db43c28f7a5213a04b91f19650c31efb5889f1674ccb84937d33a21270f39a28cbfe0efcee1
7
+ data.tar.gz: 0a5932d0dcf129bedd5ebad761d2df9d77793ecb9ea3dcdc905b39a676f2e7da5f68e1c0bbd89b7e564ebabc92d5ee59d3722f2c73c8f7306479e3dfa5c65ee2
@@ -73,8 +73,12 @@ module CanvasSync::Concerns
73
73
  end
74
74
 
75
75
  def canvas_super_user?
76
- panda_pal_session.cache(:canvas_super_user?) do
77
- panda_pal_session.canvas_site_admin? || (panda_pal_session.canvas_account_role_labels(:root) & ["AccountAdmin", "Account Admin"]).present?
76
+ canvas_account_admin?(:root)
77
+ end
78
+
79
+ def canvas_account_admin?(account = launch_account)
80
+ panda_pal_session.cache([:canvas_account_admin?, account]) do
81
+ panda_pal_session.canvas_site_admin? || (panda_pal_session.canvas_account_role_labels(account) & ["AccountAdmin", "Account Admin"]).present?
78
82
  end
79
83
  end
80
84
 
@@ -0,0 +1,11 @@
1
+ module CanvasSync::Concerns
2
+ module CanvasIdAsPrimary
3
+ extend ActiveSupport::Concern
4
+
5
+ CanvasSync::Record.define_feature self, default: true
6
+
7
+ included do
8
+ self.primary_key = :canvas_id unless column_names.include?('id')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ module CanvasSync::Concerns
2
+ module User
3
+ module ThroughPseudonyms
4
+ extend ActiveSupport::Concern
5
+ include CanvasSync::Record
6
+
7
+ CanvasSync::Record.define_feature self, default: true
8
+
9
+ class_methods do
10
+ def has_many_via_pseudonyms(rel_name, *args, using_sis_id: false, **kwargs)
11
+ kwargs[:class_name] ||= rel_name.to_s.classify
12
+ kwargs[:primary_key] ||= using_sis_id ? :sis_id : :canvas_id
13
+
14
+ # TODO Try and guess the foreign key?
15
+ # kwargs[:foreign_key] ||= using_sis_id ? :"#{rel_name}_sis_id" : :"#{rel_name}_pseudonym_canvas_id"
16
+
17
+ through_rel = using_sis_id ? :active_pseudonyms : :all_pseudonyms
18
+
19
+ pseudo_rel = :"_user_#{rel_name}_via_pseudonym"
20
+ Pseudonym.has_many(pseudo_rel, *args, **kwargs)
21
+
22
+ class_eval <<~RUBY
23
+ has_many(:#{rel_name}, through: :#{through_rel}, source: :#{pseudo_rel}, inverse_of: :student) do
24
+ def scope_for_create(...)
25
+ # @association.reflection.inverse_of
26
+ super.tap do |scope|
27
+ user = @association.owner
28
+ scope[:#{kwargs[:foreign_key]}] = user.load_pseudonym_for_relation!(any: #{!using_sis_id}).canvas_id
29
+ end
30
+ end
31
+ end
32
+ RUBY
33
+ end
34
+ end
35
+
36
+ def load_pseudonym_for_relation!(any: false)
37
+ return @pseudonym_for_relation if defined?(@pseudonym_for_relation)
38
+
39
+ @pseudonym_for_relation = self.active_pseudonyms[0] || Pseudonym.find_by(user: self)
40
+ raise ActiveRecord::RecordNotFound, "No Pseudonym for User #{self.canvas_id}" unless @pseudonym_for_relation.present?
41
+ raise ActiveRecord::RecordNotFound, "No Active Pseudonym for User #{self.canvas_id}" unless @pseudonym_for_relation.workflow_state != "deleted" || any
42
+
43
+ @pseudonym_for_relation
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,141 @@
1
+ module CanvasSync::Concerns
2
+ module UserViaPseudonym
3
+ extend ActiveSupport::Concern
4
+
5
+ module RelationHook
6
+ extend ActiveSupport::Concern
7
+
8
+ def where!(*args)
9
+ return super unless self.respond_to?(:users_via_pseudonym)
10
+
11
+ super.tap do |q|
12
+ args.select { |a| a.is_a?(Hash) }.each do |hash|
13
+ hash.each do |key, value|
14
+ next unless users_via_pseudonym.key?(key)
15
+ q.joins!(key).references!(Arel::Nodes::SqlLiteral.new(key.to_s))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ ActiveRecord::Relation.include(RelationHook)
23
+
24
+ class RefreshUserCachesJob < CanvasSync::Job
25
+ def perform
26
+ ActiveRecord::Base.subclasses.each do |model|
27
+ next unless model.respond_to?(:update_cached_user_ids!)
28
+ model.update_cached_user_ids!
29
+ end
30
+ end
31
+ end
32
+
33
+ included do
34
+ class_hash :users_via_pseudonym
35
+ end
36
+
37
+ class_methods do
38
+ def class_hash(key)
39
+ class_eval <<~RUBY
40
+ def self.#{key}
41
+ @#{key} ||= superclass.try(:#{key})&.dup || {}
42
+ end
43
+ RUBY
44
+ end
45
+
46
+ def belongs_to_user(rel_name = :user, using_sis_id: false)
47
+ rel_name = rel_name.to_sym
48
+
49
+ pseudonym_rel_name = :"#{rel_name}_pseudonym"
50
+ if using_sis_id
51
+ belongs_to pseudonym_rel_name, -> { active }, primary_key: :sis_id, foreign_key: :"#{rel_name}_sis_id", class_name: "Pseudonym"
52
+ else
53
+ belongs_to pseudonym_rel_name, primary_key: :canvas_id, foreign_key: :"#{rel_name}_pseudonym_canvas_id", class_name: "Pseudonym"
54
+ end
55
+
56
+ config = users_via_pseudonym[rel_name] = {
57
+ user_relation: rel_name,
58
+ pseudonym_relation: pseudonym_rel_name,
59
+ by_sis_id: using_sis_id,
60
+ }
61
+
62
+ cache_column = :"#{rel_name}_cached_user_canvas_id"
63
+ if column_names.include?(cache_column.to_s)
64
+ belongs_to(rel_name, primary_key: :canvas_id, foreign_key: cache_column, class_name: "User")
65
+ config[:user_cache_column] = cache_column
66
+ else
67
+ has_one(rel_name, through: pseudonym_rel_name, source: :user)
68
+ end
69
+
70
+ class_eval <<~RUBY
71
+ def #{rel_name}=(user)
72
+ return if self.#{rel_name} == user
73
+ association(:#{pseudonym_rel_name}).writer(user&.load_pseudonym_for_relation!(any: #{!using_sis_id}))
74
+ association(:#{rel_name}).writer(user) if association(:#{rel_name}).class <= ActiveRecord::Associations::BelongsToAssociation
75
+ end
76
+
77
+ def #{pseudonym_rel_name}=(pseudonym)
78
+ return if self.#{pseudonym_rel_name} == pseudonym
79
+ association(:#{pseudonym_rel_name}).writer(pseudonym)
80
+ association(:#{rel_name}).writer(pseudonym&.user) if association(:#{rel_name}).class <= ActiveRecord::Associations::BelongsToAssociation
81
+ end
82
+ RUBY
83
+ end
84
+
85
+ def update_cached_user_ids!
86
+ cached_configs = users_via_pseudonym.values.select { |c| c[:user_cache_column].present? }
87
+ return if cached_configs.empty?
88
+
89
+ query = all
90
+
91
+ # Add JOINs
92
+ query = cached_configs.reduce(query) do |clause, config|
93
+ clause.joins(config[:pseudonym_relation]).references([ config[:pseudonym_relation], config[:user_relation] ].map { |x| Arel.sql(x.to_s) })
94
+ end
95
+
96
+ # Add OR clauses for filtering to only records with stale caches
97
+ query = cached_configs.reduce(query.where("1=0")) do |clause, config|
98
+ where_clause = query
99
+ if (updated_after = CanvasSync::JobBatches::Batch.current_context[:updated_after]).present?
100
+ where_clause = where_clause.where("#{config[:pseudonym_relation]}.updated_at >= ?", updated_after)
101
+ end
102
+ where_clause = where_clause.where("#{table_name}.#{config[:user_cache_column]} IS DISTINCT FROM #{config[:pseudonym_relation]}.canvas_user_id")
103
+ clause.or(where_clause)
104
+ end
105
+
106
+ query.in_batches do |batch|
107
+ batch = batch.to_a
108
+
109
+ cacheable_pseudonym_ids = cached_configs.map { |config| :"#{config[:pseudonym_relation]}_canvas_id" }.map { |col| batch.map(&col) }.flatten
110
+ user_id_map = Pseudonym.where(canvas_id: cacheable_pseudonym_ids).pluck(:canvas_id, :canvas_user_id).to_h
111
+
112
+ transaction do
113
+ where(primary_key => batch.map(&:id)).delete_all
114
+
115
+ cached_configs.each do |config|
116
+ batch.each do |record|
117
+ record[config[:user_cache_column]] = user_id_map[record[:"#{config[:pseudonym_relation]}_canvas_id"]]
118
+ end
119
+ end
120
+
121
+ import_results = import(
122
+ batch,
123
+ validate: false,
124
+ timestamps: false,
125
+ on_duplicate_key_ignore: true,
126
+ )
127
+
128
+ failures = import_results.failed_instances
129
+ if failures.present?
130
+ handle_duplicated_cache_failures(failures)
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ def handle_user_cache_refresh_failures(records)
137
+
138
+ end
139
+ end
140
+ end
141
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateAccounts < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :accounts do |t|
5
+ create_table :accounts, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :sis_id
8
8
  t.bigint :canvas_parent_account_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateAdmins < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :admins do |t|
5
+ create_table :admins, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :role_name
8
8
  t.bigint :canvas_account_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateAssignmentGroups < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :assignment_groups do |t|
5
+ create_table :assignment_groups, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_course_id
8
8
  t.string :name
@@ -1,6 +1,6 @@
1
1
  class CreateAssignmentOverrides < ActiveRecord::Migration[5.1]
2
2
  def change
3
- create_table :assignment_overrides do |t|
3
+ create_table :assignment_overrides, id: false do |t|
4
4
  t.bigint :canvas_id, null: false
5
5
  t.bigint :canvas_assignment_id
6
6
  t.bigint :canvas_group_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateAssignments < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :assignments do |t|
5
+ create_table :assignments, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :title
8
8
  t.text :description
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateContentMigrations < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :content_migrations do |t|
5
+ create_table :content_migrations, id: false do |t|
6
6
  t.bigint :canvas_id
7
7
  t.bigint :canvas_context_id
8
8
  t.string :canvas_context_type
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateContextModuleItems < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :context_module_items do |t|
5
+ create_table :context_module_items, id: false do |t|
6
6
  t.bigint :canvas_id
7
7
  t.bigint :canvas_context_module_id
8
8
  t.integer :position
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateContextModules < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :context_modules do |t|
5
+ create_table :context_modules, id: false do |t|
6
6
  t.bigint :canvas_id
7
7
  t.bigint :canvas_context_id
8
8
  t.string :canvas_context_type
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateCourseNicknames < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :course_nicknames do |t|
5
+ create_table :course_nicknames, id: false do |t|
6
6
  t.bigint :canvas_user_preference_value_id, null: true
7
7
  t.integer :canvas_user_id
8
8
  t.integer :canvas_course_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateCourseProgresses < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :course_progresses do |t|
5
+ create_table :course_progresses, id: false do |t|
6
6
  t.bigint :canvas_course_id, null: false
7
7
  t.bigint :canvas_user_id, null: false
8
8
  t.integer :requirement_count
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateCourses < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :courses do |t|
5
+ create_table :courses, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :sis_id
8
8
  t.string :course_code
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateEnrollments < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :enrollments do |t|
5
+ create_table :enrollments, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_course_id
8
8
  t.string :course_sis_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateGradingPeriodGroups < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :grading_period_groups do |t|
5
+ create_table :grading_period_groups, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :title
8
8
  t.boolean :weighted
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateGradingPeriods < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :grading_periods do |t|
5
+ create_table :grading_periods, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :title
8
8
  t.float :weight
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateGroupMemberships < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :group_memberships do |t|
5
+ create_table :group_memberships, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_user_id, null: false
8
8
  t.bigint :canvas_group_id, null: false
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateGroups < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :groups do |t|
5
+ create_table :groups, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :sis_id
8
8
  t.bigint :canvas_group_category_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateLearningOutcomeResults < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :learning_outcome_results do |t|
5
+ create_table :learning_outcome_results, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_context_id
8
8
  t.string :canvas_context_type
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateLearningOutcomes < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :learning_outcomes do |t|
5
+ create_table :learning_outcomes, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.integer :canvas_context_id
8
8
  t.string :canvas_context_type
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreatePseudonyms < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :pseudonyms do |t|
5
+ create_table :pseudonyms, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_user_id
8
8
  t.string :sis_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateRoles < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :roles do |t|
5
+ create_table :roles, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :label
8
8
  t.string :base_role_type
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateRubricAssessments < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :rubric_assessments do |t|
5
+ create_table :rubric_assessments, id: false do |t|
6
6
  t.bigint :canvas_id
7
7
  t.bigint :canvas_user_id
8
8
  t.bigint :canvas_rubric_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateRubricAssociations < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :rubric_associations do |t|
5
+ create_table :rubric_associations, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_rubric_id
8
8
  t.bigint :canvas_association_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateRubrics < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :rubrics do |t|
5
+ create_table :rubrics, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_user_id
8
8
  t.bigint :canvas_rubric_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateScores < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :scores do |t|
5
+ create_table :scores, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_enrollment_id, null: false
8
8
  t.bigint :canvas_assignment_group_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateSections < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :sections do |t|
5
+ create_table :sections, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :sis_id
8
8
  t.bigint :canvas_course_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateSubmissions < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :submissions do |t|
5
+ create_table :submissions, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.bigint :canvas_course_id
8
8
  t.bigint :canvas_assignment_id
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateTerms < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :terms do |t|
5
+ create_table :terms, id: false do |t|
6
6
  t.integer :canvas_id, null: false
7
7
  t.string :name
8
8
  t.datetime :start_at
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateUserObservers < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :user_observers do |t|
5
+ create_table :user_observers, id: false do |t|
6
6
  t.bigint :observing_user_id
7
7
  t.bigint :observed_user_id
8
8
  t.string :workflow_state
@@ -2,7 +2,7 @@
2
2
 
3
3
  class CreateUsers < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :users do |t|
5
+ create_table :users, id: false do |t|
6
6
  t.bigint :canvas_id, null: false
7
7
  t.string :email
8
8
  t.string :first_name
@@ -7,6 +7,7 @@ class CourseNickname < ApplicationRecord
7
7
  include CanvasSync::Concerns::ApiSyncable
8
8
 
9
9
  canvas_sync_features :defaults
10
+ self.primary_key = [:canvas_user_id, :canvas_course_id] unless column_names.include?("id")
10
11
 
11
12
  belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id, optional: true
12
13
  belongs_to :course, primary_key: :canvas_id, foreign_key: :canvas_course_id, optional: true
@@ -6,6 +6,7 @@ class CourseProgress < ApplicationRecord
6
6
  include CanvasSync::Concerns::ApiSyncable
7
7
 
8
8
  canvas_sync_features :defaults
9
+ self.primary_key = [:canvas_user_id, :canvas_course_id] unless column_names.include?("id")
9
10
 
10
11
  belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id, optional: true
11
12
  belongs_to :course, primary_key: :canvas_id, foreign_key: :canvas_course_id, optional: true
@@ -8,4 +8,6 @@ class Pseudonym < ApplicationRecord
8
8
 
9
9
  validates :canvas_id, uniqueness: true, presence: true
10
10
  belongs_to :user, primary_key: :canvas_id, foreign_key: :canvas_user_id
11
+
12
+ scope :active, -> { where(workflow_state: "active") }
11
13
  end
@@ -17,6 +17,8 @@ class User < ApplicationRecord
17
17
 
18
18
  validates :canvas_id, uniqueness: true, presence: true
19
19
  has_many :pseudonyms, primary_key: :canvas_id, foreign_key: :canvas_user_id
20
+ has_many :active_pseudonyms, ->() { active }, primary_key: :canvas_id, foreign_key: :canvas_user_id, class_name: "Pseudonym"
21
+ has_many :all_pseudonyms, primary_key: :canvas_id, foreign_key: :canvas_user_id, class_name: "Pseudonym"
20
22
  has_many :enrollments, primary_key: :canvas_id, foreign_key: :canvas_user_id
21
23
  has_many :admins, primary_key: :canvas_id, foreign_key: :canvas_user_id
22
24
  has_many :admin_roles, through: :admins, source: :role
@@ -7,6 +7,8 @@ class UserObserver < ApplicationRecord
7
7
 
8
8
  canvas_sync_features :defaults
9
9
 
10
+ self.primary_key = [:observing_user_id, :observed_user_id] unless column_names.include?("id")
11
+
10
12
  validates :canvas_id, uniqueness: true, presence: true
11
13
 
12
14
  belongs_to :observing_user, primary_key: :canvas_id, foreign_key: :observing_user_id, class_name: 'User', optional: true
@@ -150,7 +150,7 @@ module CanvasSync
150
150
  }
151
151
  global_updates.slice!(*klass.column_names.map(&:to_sym))
152
152
  if global_updates.present? && result.ids.present?
153
- klass.where(id: result.ids).update_all(global_updates)
153
+ klass.where(klass.primary_key => result.ids).update_all(global_updates)
154
154
  end
155
155
  end
156
156
 
@@ -12,10 +12,10 @@ module CanvasSync
12
12
  api_client.account_admins(acc.canvas_id).all_pages_each do |admin_params|
13
13
  admin_params[:account_id] = acc.canvas_id
14
14
  admin = update_or_create_model(Admin, admin_params)
15
- updated_admin_ids.push(admin.id)
15
+ updated_admin_ids.push(admin.canvas_id)
16
16
  end
17
17
  end
18
- Admin.where.not(id: updated_admin_ids).update_all(workflow_state: 'inactive')
18
+ Admin.where.not(canvas_id: updated_admin_ids).update_all(workflow_state: 'inactive')
19
19
  end
20
20
  end
21
21
  end
@@ -14,10 +14,10 @@ module CanvasSync
14
14
  end
15
15
  api_client.list_roles(acc.canvas_id, api_params).all_pages_each do |role_params|
16
16
  role = update_or_create_model(Role, role_params)
17
- updated_role_ids.push(role.id)
17
+ updated_role_ids.push(role.canvas_id)
18
18
  end
19
19
  end
20
- Role.where.not(id: updated_role_ids).update_all(workflow_state: 'inactive')
20
+ Role.where.not(canvas_id: updated_role_ids).update_all(workflow_state: 'inactive')
21
21
  end
22
22
  end
23
23
  end
@@ -34,7 +34,7 @@ module CanvasSync
34
34
  # TODO Support globalid
35
35
  model_class = load_constant(job[:model])
36
36
  find_by = job[:find_by]
37
- target = find_by.is_a?(Hash) ? model_class.find_by(**find_by) : model_class.find_by(id: find_by)
37
+ target = find_by.is_a?(Hash) ? model_class.find_by(**find_by) : model_class.find_by(model_class.primary_key => find_by)
38
38
  target.send(job[:method], *job_args, **job_kwargs)
39
39
  elsif job[:class]
40
40
  target = load_constant(job[:class])
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.24.0".freeze
2
+ VERSION = "0.26.0.beta1".freeze
3
3
  end
data/lib/canvas_sync.rb CHANGED
@@ -177,6 +177,8 @@ module CanvasSync
177
177
  term_scope = term_scope.to_s if term_scope
178
178
  options = options.deep_symbolize_keys!
179
179
 
180
+ given_models = models.dup
181
+
180
182
  model_job_map = {
181
183
  terms: CanvasSync::Jobs::SyncTermsJob,
182
184
  accounts: CanvasSync::Jobs::SyncAccountsJob,
@@ -255,6 +257,10 @@ module CanvasSync
255
257
  # Wrap it all up
256
258
  ###############################
257
259
 
260
+ if given_models.include?('pseudonyms')
261
+ root_chain << Concerns::UserViaPseudonym::RefreshUserCachesJob
262
+ end
263
+
258
264
  root_chain
259
265
  end
260
266