canvas_sync 0.27.13 → 0.27.14

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 (232) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/canvas_sync/api/v1/health_check_controller.rb +0 -0
  3. data/app/models/canvas_sync/job_log.rb +0 -0
  4. data/app/models/canvas_sync/sync_batch.rb +0 -0
  5. data/config/initializers/apartment.rb +0 -0
  6. data/config/routes.rb +0 -0
  7. data/db/migrate/20170915210836_create_canvas_sync_job_log.rb +0 -0
  8. data/db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb +0 -0
  9. data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +0 -0
  10. data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +0 -0
  11. data/db/migrate/20201030210836_add_full_sync_to_canvas_sync_sync_batch.rb +0 -0
  12. data/lib/canvas_sync/api_syncable.rb +0 -0
  13. data/lib/canvas_sync/batch_processor.rb +0 -0
  14. data/lib/canvas_sync/class_callback_executor.rb +0 -0
  15. data/lib/canvas_sync/concerns/ability_helper.rb +43 -2
  16. data/lib/canvas_sync/concerns/account/ancestry.rb +0 -0
  17. data/lib/canvas_sync/concerns/account/base.rb +0 -0
  18. data/lib/canvas_sync/concerns/api_syncable.rb +0 -0
  19. data/lib/canvas_sync/concerns/canvas_id_as_primary.rb +0 -0
  20. data/lib/canvas_sync/concerns/jit_syncing.rb +0 -0
  21. data/lib/canvas_sync/concerns/legacy_columns.rb +0 -0
  22. data/lib/canvas_sync/concerns/role/base.rb +0 -0
  23. data/lib/canvas_sync/generators/install_generator.rb +0 -0
  24. data/lib/canvas_sync/generators/install_live_events_generator.rb +0 -0
  25. data/lib/canvas_sync/generators/templates/migrations/create_accounts.rb +0 -0
  26. data/lib/canvas_sync/generators/templates/migrations/create_admins.rb +0 -0
  27. data/lib/canvas_sync/generators/templates/migrations/create_assignment_groups.rb +0 -0
  28. data/lib/canvas_sync/generators/templates/migrations/create_assignments.rb +0 -0
  29. data/lib/canvas_sync/generators/templates/migrations/create_content_migrations.rb +0 -0
  30. data/lib/canvas_sync/generators/templates/migrations/create_context_module_items.rb +0 -0
  31. data/lib/canvas_sync/generators/templates/migrations/create_context_modules.rb +0 -0
  32. data/lib/canvas_sync/generators/templates/migrations/create_course_nicknames.rb +0 -0
  33. data/lib/canvas_sync/generators/templates/migrations/create_course_progresses.rb +0 -0
  34. data/lib/canvas_sync/generators/templates/migrations/create_grading_period_groups.rb +0 -0
  35. data/lib/canvas_sync/generators/templates/migrations/create_grading_periods.rb +0 -0
  36. data/lib/canvas_sync/generators/templates/migrations/create_group_memberships.rb +0 -0
  37. data/lib/canvas_sync/generators/templates/migrations/create_groups.rb +0 -0
  38. data/lib/canvas_sync/generators/templates/migrations/create_learning_outcome_results.rb +0 -0
  39. data/lib/canvas_sync/generators/templates/migrations/create_learning_outcomes.rb +0 -0
  40. data/lib/canvas_sync/generators/templates/migrations/create_pseudonyms.rb +0 -0
  41. data/lib/canvas_sync/generators/templates/migrations/create_rubric_assessments.rb +0 -0
  42. data/lib/canvas_sync/generators/templates/migrations/create_rubric_associations.rb +0 -0
  43. data/lib/canvas_sync/generators/templates/migrations/create_rubrics.rb +0 -0
  44. data/lib/canvas_sync/generators/templates/migrations/create_sections.rb +0 -0
  45. data/lib/canvas_sync/generators/templates/migrations/create_submissions.rb +0 -0
  46. data/lib/canvas_sync/generators/templates/migrations/create_terms.rb +0 -0
  47. data/lib/canvas_sync/generators/templates/migrations/create_user_observers.rb +0 -0
  48. data/lib/canvas_sync/generators/templates/migrations/create_users.rb +0 -0
  49. data/lib/canvas_sync/generators/templates/models/content_migration.rb +0 -0
  50. data/lib/canvas_sync/generators/templates/models/course_nickname.rb +0 -0
  51. data/lib/canvas_sync/generators/templates/models/rubric.rb +0 -0
  52. data/lib/canvas_sync/generators/templates/models/rubric_assessment.rb +0 -0
  53. data/lib/canvas_sync/generators/templates/models/rubric_association.rb +0 -0
  54. data/lib/canvas_sync/generators/templates/services/live_events/assignment_event.rb +0 -0
  55. data/lib/canvas_sync/generators/templates/services/live_events/assignment_group_event.rb +0 -0
  56. data/lib/canvas_sync/generators/templates/services/live_events/course_event.rb +0 -0
  57. data/lib/canvas_sync/generators/templates/services/live_events/course_section_event.rb +0 -0
  58. data/lib/canvas_sync/generators/templates/services/live_events/enrollment_event.rb +0 -0
  59. data/lib/canvas_sync/generators/templates/services/live_events/grade_event.rb +0 -0
  60. data/lib/canvas_sync/generators/templates/services/live_events/module_event.rb +0 -0
  61. data/lib/canvas_sync/generators/templates/services/live_events/module_item_event.rb +0 -0
  62. data/lib/canvas_sync/generators/templates/services/live_events/submission_event.rb +0 -0
  63. data/lib/canvas_sync/generators/templates/services/live_events/syllabus_event.rb +0 -0
  64. data/lib/canvas_sync/generators/templates/services/live_events/user_event.rb +0 -0
  65. data/lib/canvas_sync/importers/legacy_importer.rb +0 -0
  66. data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +0 -0
  67. data/lib/canvas_sync/jobs/canvas_process_waiter.rb +0 -0
  68. data/lib/canvas_sync/jobs/sync_admins_job.rb +0 -0
  69. data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +0 -0
  70. data/lib/canvas_sync/jobs/sync_assignments_job.rb +0 -0
  71. data/lib/canvas_sync/jobs/sync_content_migrations_job.rb +0 -0
  72. data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +0 -0
  73. data/lib/canvas_sync/jobs/sync_context_modules_job.rb +0 -0
  74. data/lib/canvas_sync/jobs/sync_rubrics_job.rb +0 -0
  75. data/lib/canvas_sync/jobs/sync_simple_table_job.rb +0 -0
  76. data/lib/canvas_sync/live_events/base_handler.rb +0 -0
  77. data/lib/canvas_sync/live_events.rb +0 -0
  78. data/lib/canvas_sync/misc_helper.rb +0 -0
  79. data/lib/canvas_sync/processors/normal_processor.rb +0 -0
  80. data/lib/canvas_sync/sidekiq_job.rb +0 -0
  81. data/lib/canvas_sync/version.rb +1 -1
  82. data/spec/canvas_sync/concerns/ability_helper_spec.rb +165 -0
  83. data/spec/canvas_sync/jobs/canvas_process_waiter_spec.rb +0 -0
  84. data/spec/canvas_sync/jobs/report_starter_spec.rb +0 -0
  85. data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +0 -0
  86. data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +0 -0
  87. data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +0 -0
  88. data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +0 -0
  89. data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +0 -0
  90. data/spec/canvas_sync/live_events/live_event_sync_spec.rb +0 -0
  91. data/spec/canvas_sync/live_events/live_events_controller_spec.rb +0 -0
  92. data/spec/canvas_sync/misc_helper_spec.rb +0 -0
  93. data/spec/canvas_sync/models/accounts_spec.rb +0 -0
  94. data/spec/canvas_sync/models/admins_spec.rb +0 -0
  95. data/spec/canvas_sync/models/assignment_group_spec.rb +0 -0
  96. data/spec/canvas_sync/models/assignment_spec.rb +0 -0
  97. data/spec/canvas_sync/models/context_module_item_spec.rb +0 -0
  98. data/spec/canvas_sync/models/context_module_spec.rb +0 -0
  99. data/spec/canvas_sync/models/course_spec.rb +0 -0
  100. data/spec/canvas_sync/models/enrollment_spec.rb +0 -0
  101. data/spec/canvas_sync/models/group_membership_spec.rb +0 -0
  102. data/spec/canvas_sync/models/group_spec.rb +0 -0
  103. data/spec/canvas_sync/models/roles_spec.rb +0 -0
  104. data/spec/canvas_sync/models/section_spec.rb +0 -0
  105. data/spec/canvas_sync/models/submission_spec.rb +0 -0
  106. data/spec/canvas_sync/models/term_spec.rb +0 -0
  107. data/spec/canvas_sync/models/user_spec.rb +0 -0
  108. data/spec/canvas_sync/processors/assignment_groups_processor_spec.rb +0 -0
  109. data/spec/canvas_sync/processors/assignments_processor_spec.rb +0 -0
  110. data/spec/canvas_sync/processors/content_migrations_processor_spec.rb +0 -0
  111. data/spec/canvas_sync/processors/context_module_items_processor_spec.rb +0 -0
  112. data/spec/canvas_sync/processors/context_modules_processor_spec.rb +0 -0
  113. data/spec/canvas_sync/processors/course_completion_report_processor_spec.rb +0 -0
  114. data/spec/canvas_sync/processors/rubric_assessments_spec.rb +0 -0
  115. data/spec/canvas_sync/processors/rubric_associations_spec.rb +0 -0
  116. data/spec/canvas_sync/processors/rubrics_processor_spec.rb +0 -0
  117. data/spec/canvas_sync/processors/submissions_processor_spec.rb +0 -0
  118. data/spec/canvas_sync/services/module_event_spec.rb +0 -0
  119. data/spec/canvas_sync/services/module_item_event_spec.rb +0 -0
  120. data/spec/factories/admin_factory.rb +0 -0
  121. data/spec/factories/assignment_factory.rb +0 -0
  122. data/spec/factories/assignment_group_factory.rb +0 -0
  123. data/spec/factories/context_module_factory.rb +0 -0
  124. data/spec/factories/context_module_item_factory.rb +0 -0
  125. data/spec/factories/course_factory.rb +0 -0
  126. data/spec/factories/enrollment_factory.rb +0 -0
  127. data/spec/factories/group_factory.rb +0 -0
  128. data/spec/factories/group_membership_factory.rb +0 -0
  129. data/spec/factories/role_factory.rb +0 -0
  130. data/spec/factories/section_factory.rb +0 -0
  131. data/spec/factories/submission_factory.rb +0 -0
  132. data/spec/factories/term_factory.rb +0 -0
  133. data/spec/factories/user_factory.rb +0 -0
  134. data/spec/support/fixtures/canvas_responses/admins.json +0 -0
  135. data/spec/support/fixtures/canvas_responses/module.json +0 -0
  136. data/spec/support/fixtures/canvas_responses/module_item.json +0 -0
  137. data/spec/support/fixtures/canvas_responses/roles.json +0 -0
  138. data/spec/support/fixtures/canvas_responses/terms.json +0 -0
  139. data/spec/support/fixtures/reports/assignment_groups.csv +0 -0
  140. data/spec/support/fixtures/reports/assignments.csv +0 -0
  141. data/spec/support/fixtures/reports/content_migrations.csv +0 -0
  142. data/spec/support/fixtures/reports/context_module_items.csv +0 -0
  143. data/spec/support/fixtures/reports/context_modules.csv +0 -0
  144. data/spec/support/fixtures/reports/course_nicknames.csv +0 -0
  145. data/spec/support/fixtures/reports/course_progresses.csv +0 -0
  146. data/spec/support/fixtures/reports/course_progresses_conflict.csv +0 -0
  147. data/spec/support/fixtures/reports/grading_period_groups.csv +0 -0
  148. data/spec/support/fixtures/reports/grading_periods.csv +0 -0
  149. data/spec/support/fixtures/reports/group_memberships.csv +0 -0
  150. data/spec/support/fixtures/reports/groups.csv +0 -0
  151. data/spec/support/fixtures/reports/learning_outcome_results.csv +0 -0
  152. data/spec/support/fixtures/reports/learning_outcomes.csv +0 -0
  153. data/spec/support/fixtures/reports/provisioning_csv +0 -0
  154. data/spec/support/fixtures/reports/rubric_assessments.csv +0 -0
  155. data/spec/support/fixtures/reports/rubric_associations.csv +0 -0
  156. data/spec/support/fixtures/reports/rubrics.csv +0 -0
  157. data/spec/support/fixtures/reports/sections.csv +0 -0
  158. data/spec/support/fixtures/reports/submissions.csv +0 -0
  159. data/spec/support/fixtures/reports/user_observers.csv +0 -0
  160. data/spec/support/fixtures/reports/users.csv +0 -0
  161. data/spec/support/fixtures/reports/xlist.csv +0 -0
  162. metadata +3 -141
  163. data/spec/internal/app/models/account.rb +0 -35
  164. data/spec/internal/app/models/admin.rb +0 -35
  165. data/spec/internal/app/models/assignment.rb +0 -39
  166. data/spec/internal/app/models/assignment_group.rb +0 -31
  167. data/spec/internal/app/models/assignment_override.rb +0 -34
  168. data/spec/internal/app/models/content_migration.rb +0 -18
  169. data/spec/internal/app/models/context_module.rb +0 -69
  170. data/spec/internal/app/models/context_module_item.rb +0 -33
  171. data/spec/internal/app/models/course.rb +0 -57
  172. data/spec/internal/app/models/course_nickname.rb +0 -20
  173. data/spec/internal/app/models/course_progress.rb +0 -29
  174. data/spec/internal/app/models/enrollment.rb +0 -48
  175. data/spec/internal/app/models/grading_period.rb +0 -17
  176. data/spec/internal/app/models/grading_period_group.rb +0 -16
  177. data/spec/internal/app/models/group.rb +0 -28
  178. data/spec/internal/app/models/group_membership.rb +0 -26
  179. data/spec/internal/app/models/learning_outcome.rb +0 -30
  180. data/spec/internal/app/models/learning_outcome_result.rb +0 -54
  181. data/spec/internal/app/models/pseudonym.rb +0 -19
  182. data/spec/internal/app/models/role.rb +0 -27
  183. data/spec/internal/app/models/rubric.rb +0 -36
  184. data/spec/internal/app/models/rubric_assessment.rb +0 -23
  185. data/spec/internal/app/models/rubric_association.rb +0 -20
  186. data/spec/internal/app/models/score.rb +0 -18
  187. data/spec/internal/app/models/section.rb +0 -36
  188. data/spec/internal/app/models/submission.rb +0 -32
  189. data/spec/internal/app/models/term.rb +0 -46
  190. data/spec/internal/app/models/user.rb +0 -43
  191. data/spec/internal/app/models/user_observer.rb +0 -22
  192. data/spec/internal/app/services/live_events/assignment_event.rb +0 -43
  193. data/spec/internal/app/services/live_events/course_event.rb +0 -28
  194. data/spec/internal/app/services/live_events/course_section_event.rb +0 -28
  195. data/spec/internal/app/services/live_events/enrollment_event.rb +0 -30
  196. data/spec/internal/app/services/live_events/grade_event.rb +0 -36
  197. data/spec/internal/app/services/live_events/module_event.rb +0 -26
  198. data/spec/internal/app/services/live_events/module_item_event.rb +0 -25
  199. data/spec/internal/app/services/live_events/submission_event.rb +0 -28
  200. data/spec/internal/app/services/live_events/syllabus_event.rb +0 -31
  201. data/spec/internal/app/services/live_events/user_event.rb +0 -27
  202. data/spec/internal/db/migrate/20251029222307_create_users.rb +0 -26
  203. data/spec/internal/db/migrate/20251029222308_create_pseudonyms.rb +0 -24
  204. data/spec/internal/db/migrate/20251029222309_create_courses.rb +0 -30
  205. data/spec/internal/db/migrate/20251029222310_create_groups.rb +0 -29
  206. data/spec/internal/db/migrate/20251029222311_create_group_memberships.rb +0 -24
  207. data/spec/internal/db/migrate/20251029222312_create_accounts.rb +0 -23
  208. data/spec/internal/db/migrate/20251029222313_create_terms.rb +0 -24
  209. data/spec/internal/db/migrate/20251029222314_create_enrollments.rb +0 -31
  210. data/spec/internal/db/migrate/20251029222315_create_sections.rb +0 -27
  211. data/spec/internal/db/migrate/20251029222316_create_assignments.rb +0 -37
  212. data/spec/internal/db/migrate/20251029222317_create_submissions.rb +0 -32
  213. data/spec/internal/db/migrate/20251029222318_create_roles.rb +0 -24
  214. data/spec/internal/db/migrate/20251029222319_create_admins.rb +0 -26
  215. data/spec/internal/db/migrate/20251029222320_create_assignment_groups.rb +0 -28
  216. data/spec/internal/db/migrate/20251029222321_create_context_modules.rb +0 -28
  217. data/spec/internal/db/migrate/20251029222322_create_context_module_items.rb +0 -26
  218. data/spec/internal/db/migrate/20251029222324_create_grading_periods.rb +0 -28
  219. data/spec/internal/db/migrate/20251029222325_create_grading_period_groups.rb +0 -24
  220. data/spec/internal/db/migrate/20251029222326_create_content_migrations.rb +0 -30
  221. data/spec/internal/db/migrate/20251029222327_create_learning_outcomes.rb +0 -36
  222. data/spec/internal/db/migrate/20251029222328_create_learning_outcome_results.rb +0 -52
  223. data/spec/internal/db/migrate/20251029222330_create_rubrics.rb +0 -44
  224. data/spec/internal/db/migrate/20251029222331_create_rubric_associations.rb +0 -42
  225. data/spec/internal/db/migrate/20251029222332_create_rubric_assessments.rb +0 -37
  226. data/spec/internal/db/migrate/20251029222334_create_assignment_overrides.rb +0 -25
  227. data/spec/internal/db/migrate/20251029222335_create_scores.rb +0 -42
  228. data/spec/internal/db/migrate/20251029223411_create_user_observers.rb +0 -23
  229. data/spec/internal/db/migrate/20251029224009_create_course_nicknames.rb +0 -23
  230. data/spec/internal/db/migrate/20251029224010_create_course_progresses.rb +0 -26
  231. data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +0 -3
  232. data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 465e968a497bd2dc0bbba5d978bc37a42257122f74132e2f9d7a72c4ed7f9082
4
- data.tar.gz: 113288ee3a4bea44ba48d837f917f111e8e0bb9de2f8e43c0d5e30eb78aa0361
3
+ metadata.gz: 2d0d5545af44d472c6222d3d26833a90f795d05ce045eb029bc493b542d16799
4
+ data.tar.gz: caffe0593b173610b3a56f60459b2ba4fb8dc8d7239e018f766856f9b49cc1a1
5
5
  SHA512:
6
- metadata.gz: 2afe2d77cc726e26bdce33058d89bfd279f890dd5832c30c33575960387111f309ac15f6f2632406861cb1f3a4e34ce0ff16509612bb987f3e96974ceabc327b
7
- data.tar.gz: 3c926ea08522792eae8fd6daaafcc343888aed77b55e943d1fca08a8ddf174d01db1fc26ebe786cd613eab18dc0d9d15221a2fe739a5a46d4dda4e626e48f498
6
+ metadata.gz: e507c8517386c294feaa221a8d7b28dd82ac9b578b08bf8dfce7398b73f653f79169251768a80e3f6fecd83000b0cce99448c505178538b0700ace4596513e0f
7
+ data.tar.gz: a543d2656184f1150bbb5ff38bdaeb6a4fe2e3d18efa7b94ff1364080715ef92f12ea43ede0059c7c104f8c9878b151559fffaa3865de4555114095706fdf223
File without changes
File without changes
File without changes
data/config/routes.rb CHANGED
File without changes
File without changes
File without changes
File without changes
@@ -98,18 +98,59 @@ module CanvasSync::Concerns
98
98
  canvas_roles.where.not(base_role_type: 'AccountMembership')
99
99
  end
100
100
 
101
+ ACCOUNT_ADMIN_ROLE_LABELS = ["AccountAdmin", "Account Admin"].freeze
102
+
103
+ # True for an Admin of the Account this Tool is installed on. Note that
104
+ # `:root` is PandaPal's install-Account sense of "root" — the top of what
105
+ # this Tool can see — and not necessarily Canvas's own root Account.
101
106
  def canvas_super_user?
102
107
  canvas_account_admin?(:root)
103
108
  end
104
109
 
110
+ # True when the User administers +account+, INCLUDING by way of an Admin
111
+ # role held on an Account above it: in Canvas an Account Admin administers
112
+ # their Account and everything beneath it, so checking only the exact
113
+ # Account under-reports. Where a Tool is installed on a sub-account, that
114
+ # under-reporting inverted this check both ways — a genuine higher-level
115
+ # admin was rejected while a lower-scoped one was accepted.
105
116
  def canvas_account_admin?(account = launch_account)
106
- panda_pal_session.cache([:canvas_account_admin?, account]) do
107
- panda_pal_session.canvas_site_admin? || (panda_pal_session.canvas_account_role_labels(account) & ["AccountAdmin", "Account Admin"]).present?
117
+ # The `:inherited` cache-key segment is load-bearing, not decoration:
118
+ # #cache persists into the Session row, so sessions created before the
119
+ # traversal existed hold a cached `false` under the old key. Keying the
120
+ # new semantics separately retires those answers instead of serving
121
+ # stale denials to already-launched sessions.
122
+ panda_pal_session.cache([:canvas_account_admin?, account, :inherited]) do
123
+ panda_pal_session.canvas_site_admin? ||
124
+ (account_role_labels(account) & ACCOUNT_ADMIN_ROLE_LABELS).present?
108
125
  end
109
126
  end
110
127
 
111
128
  def canvas_user_id
112
129
  user&.canvas_id || panda_pal_session.get_lti_cust_param('canvas_user_id')
113
130
  end
131
+
132
+ private
133
+
134
+ # Feature-detected rather than version-pinned: CanvasSync deliberately
135
+ # declares no dependency on PandaPal (only this concern assumes one), so it
136
+ # cannot require >= 5.17 where `inherited:` was introduced. Detecting the
137
+ # keyword makes the upgrade order between the two gems irrelevant, instead
138
+ # of failing an authorization check with ArgumentError.
139
+ def account_role_labels(account)
140
+ if accepts_inherited_kwarg?
141
+ panda_pal_session.canvas_account_role_labels(account, inherited: true)
142
+ else
143
+ panda_pal_session.canvas_account_role_labels(account)
144
+ end
145
+ end
146
+
147
+ # `**opts` counts as support: a host app that wraps or decorates the Session
148
+ # commonly forwards keywords that way, and treating it as "too old" would
149
+ # silently drop the traversal for exactly the apps most likely to subclass.
150
+ def accepts_inherited_kwarg?
151
+ panda_pal_session.method(:canvas_account_role_labels).parameters.any? do |type, name|
152
+ type == :keyrest || ((type == :key || type == :keyreq) && name == :inherited)
153
+ end
154
+ end
114
155
  end
115
156
  end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.27.13".freeze
2
+ VERSION = "0.27.14".freeze
3
3
  end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ # Focused on what this concern contributes on top of PandaPal: that it asks for
6
+ # INHERITED role labels, and that it keys its Session-persisted cache so the
7
+ # pre-traversal answers don't outlive the change. The traversal itself belongs
8
+ # to (and is tested by) PandaPal::Session#canvas_account_role_labels.
9
+ #
10
+ # panda_pal is not in this gem's bundle, so the session is a hand-rolled double
11
+ # — which is also the only way to assert the exact call that gets made.
12
+ RSpec.describe CanvasSync::Concerns::AbilityHelper do
13
+ let(:helper_class) do
14
+ Class.new do
15
+ include CanvasSync::Concerns::AbilityHelper
16
+
17
+ attr_reader :panda_pal_session
18
+
19
+ def initialize(session)
20
+ @panda_pal_session = session
21
+ end
22
+ end
23
+ end
24
+
25
+ # Shared bookkeeping: real #cache semantics (memoised into the session under
26
+ # an arbitrary key), plus a record of every call made.
27
+ session_base = Class.new do
28
+ attr_reader :cache_keys, :label_calls
29
+
30
+ def initialize(labels: [], site_admin: false, preset_cache: {})
31
+ @labels = labels
32
+ @site_admin = site_admin
33
+ @cache = preset_cache
34
+ @cache_keys = []
35
+ @label_calls = []
36
+ end
37
+
38
+ def cache(key)
39
+ @cache_keys << key
40
+ return @cache[key] if @cache.key?(key)
41
+
42
+ @cache[key] = yield
43
+ end
44
+
45
+ def canvas_site_admin?
46
+ @site_admin
47
+ end
48
+ end
49
+
50
+ # Declared exactly as PandaPal >= 5.17 declares it, so keyword detection runs
51
+ # against a real signature rather than a catch-all that would pass for the
52
+ # wrong reason.
53
+ let(:modern_session) do
54
+ Class.new(session_base) do
55
+ def canvas_account_role_labels(account = 'self', inherited: false)
56
+ @label_calls << [account, { inherited: inherited }]
57
+ @labels
58
+ end
59
+ end
60
+ end
61
+
62
+ # PandaPal < 5.17: no keyword at all. Passing one must not reach it.
63
+ let(:legacy_session) do
64
+ Class.new(session_base) do
65
+ def canvas_account_role_labels(account = 'self')
66
+ @label_calls << [account, {}]
67
+ @labels
68
+ end
69
+ end
70
+ end
71
+
72
+ # A host app decorating the Session and forwarding keywords.
73
+ let(:forwarding_session) do
74
+ Class.new(session_base) do
75
+ def canvas_account_role_labels(account = 'self', **opts)
76
+ @label_calls << [account, opts]
77
+ @labels
78
+ end
79
+ end
80
+ end
81
+
82
+ def helper_for(klass = nil, **kwargs)
83
+ helper_class.new((klass || modern_session).new(**kwargs))
84
+ end
85
+
86
+ describe "#canvas_account_admin?" do
87
+ it "asks PandaPal for inherited role labels" do
88
+ helper = helper_for(labels: ["AccountAdmin"])
89
+
90
+ expect(helper.canvas_account_admin?(300)).to be true
91
+ expect(helper.panda_pal_session.label_calls).to eq([[300, { inherited: true }]])
92
+ end
93
+
94
+ it "accepts the human-readable \"Account Admin\" label" do
95
+ expect(helper_for(labels: ["Account Admin"]).canvas_account_admin?(300)).to be true
96
+ end
97
+
98
+ it "is false when the user holds only non-admin roles anywhere in the chain" do
99
+ expect(helper_for(labels: ["Ops", "Department Admin"]).canvas_account_admin?(300)).to be false
100
+ end
101
+
102
+ it "is true for a Canvas site admin regardless of role labels" do
103
+ expect(helper_for(labels: [], site_admin: true).canvas_account_admin?(300)).to be true
104
+ end
105
+
106
+ it "keys its cache separately from the pre-traversal answer" do
107
+ helper = helper_for(labels: ["AccountAdmin"])
108
+
109
+ helper.canvas_account_admin?(:root)
110
+
111
+ expect(helper.panda_pal_session.cache_keys).to eq([[:canvas_account_admin?, :root, :inherited]])
112
+ end
113
+
114
+ # The regression this guards: a Session launched before the traversal
115
+ # existed has `false` persisted under the OLD key. Reusing that key would
116
+ # keep denying an admin who should now pass.
117
+ it "ignores a stale pre-traversal cache entry" do
118
+ helper = helper_class.new(
119
+ modern_session.new(labels: ["AccountAdmin"], preset_cache: { [:canvas_account_admin?, :root] => false })
120
+ )
121
+
122
+ expect(helper.canvas_account_admin?(:root)).to be true
123
+ end
124
+
125
+ it "still memoises within its own key" do
126
+ helper = helper_for(labels: ["AccountAdmin"])
127
+
128
+ helper.canvas_account_admin?(:root)
129
+ helper.canvas_account_admin?(:root)
130
+
131
+ expect(helper.panda_pal_session.label_calls.size).to eq(1)
132
+ end
133
+ end
134
+
135
+ describe "#canvas_super_user?" do
136
+ it "delegates to canvas_account_admin? for the install Account" do
137
+ helper = helper_for(labels: ["AccountAdmin"])
138
+
139
+ expect(helper.canvas_super_user?).to be true
140
+ expect(helper.panda_pal_session.label_calls).to eq([[:root, { inherited: true }]])
141
+ end
142
+
143
+ it "is false for a user with no admin role above or at the install Account" do
144
+ expect(helper_for(labels: []).canvas_super_user?).to be false
145
+ end
146
+ end
147
+
148
+ # Upgrade-order safety: an app on a CanvasSync with this change but PandaPal
149
+ # < 5.17 must not blow up an authorization check with ArgumentError.
150
+ describe "keyword detection" do
151
+ it "falls back to the non-inherited call against an older PandaPal" do
152
+ helper = helper_for(legacy_session, labels: ["AccountAdmin"])
153
+
154
+ expect(helper.canvas_account_admin?(300)).to be true
155
+ expect(helper.panda_pal_session.label_calls).to eq([[300, {}]])
156
+ end
157
+
158
+ it "treats a keyword-forwarding Session as supporting inherited" do
159
+ helper = helper_for(forwarding_session, labels: ["AccountAdmin"])
160
+
161
+ expect(helper.canvas_account_admin?(300)).to be true
162
+ expect(helper.panda_pal_session.label_calls).to eq([[300, { inherited: true }]])
163
+ end
164
+ end
165
+ end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes