canvas_sync 0.27.11 → 0.27.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/canvas_sync/api/v1/health_check_controller.rb +0 -0
- data/app/models/canvas_sync/job_log.rb +0 -0
- data/app/models/canvas_sync/sync_batch.rb +0 -0
- data/config/initializers/apartment.rb +0 -0
- data/config/routes.rb +0 -0
- data/db/migrate/20170915210836_create_canvas_sync_job_log.rb +0 -0
- data/db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb +0 -0
- data/db/migrate/20190916154829_add_fork_count_to_canvas_sync_job_logs.rb +0 -0
- data/db/migrate/20201018210836_create_canvas_sync_sync_batches.rb +0 -0
- data/db/migrate/20201030210836_add_full_sync_to_canvas_sync_sync_batch.rb +0 -0
- data/lib/canvas_sync/api_syncable.rb +0 -0
- data/lib/canvas_sync/batch_processor.rb +0 -0
- data/lib/canvas_sync/class_callback_executor.rb +0 -0
- data/lib/canvas_sync/concerns/ability_helper.rb +43 -2
- data/lib/canvas_sync/concerns/account/ancestry.rb +0 -0
- data/lib/canvas_sync/concerns/account/base.rb +0 -0
- data/lib/canvas_sync/concerns/api_syncable.rb +0 -0
- data/lib/canvas_sync/concerns/canvas_id_as_primary.rb +0 -0
- data/lib/canvas_sync/concerns/jit_syncing.rb +0 -0
- data/lib/canvas_sync/concerns/legacy_columns.rb +0 -0
- data/lib/canvas_sync/concerns/role/base.rb +0 -0
- data/lib/canvas_sync/generators/install_generator.rb +0 -0
- data/lib/canvas_sync/generators/install_live_events_generator.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_accounts.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_admins.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_assignment_groups.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_assignments.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_content_migrations.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_context_module_items.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_context_modules.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_course_nicknames.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_course_progresses.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_grading_period_groups.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_grading_periods.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_group_memberships.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_groups.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_learning_outcome_results.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_learning_outcomes.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_pseudonyms.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_rubric_assessments.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_rubric_associations.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_rubrics.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_sections.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_submissions.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_terms.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_user_observers.rb +0 -0
- data/lib/canvas_sync/generators/templates/migrations/create_users.rb +0 -0
- data/lib/canvas_sync/generators/templates/models/content_migration.rb +0 -0
- data/lib/canvas_sync/generators/templates/models/course_nickname.rb +0 -0
- data/lib/canvas_sync/generators/templates/models/rubric.rb +0 -0
- data/lib/canvas_sync/generators/templates/models/rubric_assessment.rb +0 -0
- data/lib/canvas_sync/generators/templates/models/rubric_association.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/assignment_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/assignment_group_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/course_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/course_section_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/enrollment_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/grade_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/module_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/module_item_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/submission_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/syllabus_event.rb +0 -0
- data/lib/canvas_sync/generators/templates/services/live_events/user_event.rb +0 -0
- data/lib/canvas_sync/importers/legacy_importer.rb +0 -0
- data/lib/canvas_sync/jobs/begin_sync_chain_job.rb +0 -0
- data/lib/canvas_sync/jobs/canvas_process_waiter.rb +0 -0
- data/lib/canvas_sync/jobs/report_starter.rb +5 -1
- data/lib/canvas_sync/jobs/report_sync_task.rb +12 -4
- data/lib/canvas_sync/jobs/sync_accounts_job.rb +2 -1
- data/lib/canvas_sync/jobs/sync_admins_job.rb +0 -0
- data/lib/canvas_sync/jobs/sync_assignment_groups_job.rb +0 -0
- data/lib/canvas_sync/jobs/sync_assignments_job.rb +0 -0
- data/lib/canvas_sync/jobs/sync_content_migrations_job.rb +0 -0
- data/lib/canvas_sync/jobs/sync_context_module_items_job.rb +0 -0
- data/lib/canvas_sync/jobs/sync_context_modules_job.rb +0 -0
- data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +1 -1
- data/lib/canvas_sync/jobs/sync_rubrics_job.rb +0 -0
- data/lib/canvas_sync/jobs/sync_simple_table_job.rb +0 -0
- data/lib/canvas_sync/live_events/base_handler.rb +0 -0
- data/lib/canvas_sync/live_events.rb +0 -0
- data/lib/canvas_sync/misc_helper.rb +0 -0
- data/lib/canvas_sync/processors/normal_processor.rb +0 -0
- data/lib/canvas_sync/sidekiq_job.rb +0 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/lib/canvas_sync.rb +66 -86
- data/spec/canvas_sync/concerns/ability_helper_spec.rb +165 -0
- data/spec/canvas_sync/jobs/begin_sync_chain_job_spec.rb +9 -3
- data/spec/canvas_sync/jobs/canvas_process_waiter_spec.rb +0 -0
- data/spec/canvas_sync/jobs/report_starter_spec.rb +0 -0
- data/spec/canvas_sync/jobs/report_sync_task_spec.rb +56 -0
- data/spec/canvas_sync/jobs/sync_accounts_job_spec.rb +41 -0
- data/spec/canvas_sync/jobs/sync_admins_job_spec.rb +0 -0
- data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +2 -2
- data/spec/canvas_sync/jobs/sync_roles_job_spec.rb +0 -0
- data/spec/canvas_sync/jobs/sync_simple_table_job_spec.rb +0 -0
- data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +0 -0
- data/spec/canvas_sync/live_events/live_event_sync_spec.rb +0 -0
- data/spec/canvas_sync/live_events/live_events_controller_spec.rb +0 -0
- data/spec/canvas_sync/misc_helper_spec.rb +0 -0
- data/spec/canvas_sync/models/accounts_spec.rb +0 -0
- data/spec/canvas_sync/models/admins_spec.rb +0 -0
- data/spec/canvas_sync/models/assignment_group_spec.rb +0 -0
- data/spec/canvas_sync/models/assignment_spec.rb +0 -0
- data/spec/canvas_sync/models/context_module_item_spec.rb +0 -0
- data/spec/canvas_sync/models/context_module_spec.rb +0 -0
- data/spec/canvas_sync/models/course_spec.rb +0 -0
- data/spec/canvas_sync/models/enrollment_spec.rb +0 -0
- data/spec/canvas_sync/models/group_membership_spec.rb +0 -0
- data/spec/canvas_sync/models/group_spec.rb +0 -0
- data/spec/canvas_sync/models/roles_spec.rb +0 -0
- data/spec/canvas_sync/models/section_spec.rb +0 -0
- data/spec/canvas_sync/models/submission_spec.rb +0 -0
- data/spec/canvas_sync/models/term_spec.rb +0 -0
- data/spec/canvas_sync/models/user_spec.rb +0 -0
- data/spec/canvas_sync/processors/assignment_groups_processor_spec.rb +0 -0
- data/spec/canvas_sync/processors/assignments_processor_spec.rb +0 -0
- data/spec/canvas_sync/processors/content_migrations_processor_spec.rb +0 -0
- data/spec/canvas_sync/processors/context_module_items_processor_spec.rb +0 -0
- data/spec/canvas_sync/processors/context_modules_processor_spec.rb +0 -0
- data/spec/canvas_sync/processors/course_completion_report_processor_spec.rb +0 -0
- data/spec/canvas_sync/processors/rubric_assessments_spec.rb +0 -0
- data/spec/canvas_sync/processors/rubric_associations_spec.rb +0 -0
- data/spec/canvas_sync/processors/rubrics_processor_spec.rb +0 -0
- data/spec/canvas_sync/processors/submissions_processor_spec.rb +0 -0
- data/spec/canvas_sync/services/module_event_spec.rb +0 -0
- data/spec/canvas_sync/services/module_item_event_spec.rb +0 -0
- data/spec/factories/admin_factory.rb +0 -0
- data/spec/factories/assignment_factory.rb +0 -0
- data/spec/factories/assignment_group_factory.rb +0 -0
- data/spec/factories/context_module_factory.rb +0 -0
- data/spec/factories/context_module_item_factory.rb +0 -0
- data/spec/factories/course_factory.rb +0 -0
- data/spec/factories/enrollment_factory.rb +0 -0
- data/spec/factories/group_factory.rb +0 -0
- data/spec/factories/group_membership_factory.rb +0 -0
- data/spec/factories/role_factory.rb +0 -0
- data/spec/factories/section_factory.rb +0 -0
- data/spec/factories/submission_factory.rb +0 -0
- data/spec/factories/term_factory.rb +0 -0
- data/spec/factories/user_factory.rb +0 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/support/fake_canvas.rb +4 -0
- data/spec/support/fixtures/canvas_responses/account.json +12 -0
- data/spec/support/fixtures/canvas_responses/admins.json +0 -0
- data/spec/support/fixtures/canvas_responses/module.json +0 -0
- data/spec/support/fixtures/canvas_responses/module_item.json +0 -0
- data/spec/support/fixtures/canvas_responses/roles.json +0 -0
- data/spec/support/fixtures/canvas_responses/terms.json +0 -0
- data/spec/support/fixtures/reports/assignment_groups.csv +0 -0
- data/spec/support/fixtures/reports/assignments.csv +0 -0
- data/spec/support/fixtures/reports/content_migrations.csv +0 -0
- data/spec/support/fixtures/reports/context_module_items.csv +0 -0
- data/spec/support/fixtures/reports/context_modules.csv +0 -0
- data/spec/support/fixtures/reports/course_nicknames.csv +0 -0
- data/spec/support/fixtures/reports/course_progresses.csv +0 -0
- data/spec/support/fixtures/reports/course_progresses_conflict.csv +0 -0
- data/spec/support/fixtures/reports/grading_period_groups.csv +0 -0
- data/spec/support/fixtures/reports/grading_periods.csv +0 -0
- data/spec/support/fixtures/reports/group_memberships.csv +0 -0
- data/spec/support/fixtures/reports/groups.csv +0 -0
- data/spec/support/fixtures/reports/learning_outcome_results.csv +0 -0
- data/spec/support/fixtures/reports/learning_outcomes.csv +0 -0
- data/spec/support/fixtures/reports/provisioning_csv +0 -0
- data/spec/support/fixtures/reports/rubric_assessments.csv +0 -0
- data/spec/support/fixtures/reports/rubric_associations.csv +0 -0
- data/spec/support/fixtures/reports/rubrics.csv +0 -0
- data/spec/support/fixtures/reports/sections.csv +0 -0
- data/spec/support/fixtures/reports/submissions.csv +0 -0
- data/spec/support/fixtures/reports/user_observers.csv +0 -0
- data/spec/support/fixtures/reports/users.csv +0 -0
- data/spec/support/fixtures/reports/xlist.csv +0 -0
- metadata +9 -143
- data/spec/internal/app/models/account.rb +0 -35
- data/spec/internal/app/models/admin.rb +0 -35
- data/spec/internal/app/models/assignment.rb +0 -39
- data/spec/internal/app/models/assignment_group.rb +0 -31
- data/spec/internal/app/models/assignment_override.rb +0 -34
- data/spec/internal/app/models/content_migration.rb +0 -18
- data/spec/internal/app/models/context_module.rb +0 -69
- data/spec/internal/app/models/context_module_item.rb +0 -33
- data/spec/internal/app/models/course.rb +0 -57
- data/spec/internal/app/models/course_nickname.rb +0 -20
- data/spec/internal/app/models/course_progress.rb +0 -29
- data/spec/internal/app/models/enrollment.rb +0 -48
- data/spec/internal/app/models/grading_period.rb +0 -17
- data/spec/internal/app/models/grading_period_group.rb +0 -16
- data/spec/internal/app/models/group.rb +0 -28
- data/spec/internal/app/models/group_membership.rb +0 -26
- data/spec/internal/app/models/learning_outcome.rb +0 -30
- data/spec/internal/app/models/learning_outcome_result.rb +0 -54
- data/spec/internal/app/models/pseudonym.rb +0 -19
- data/spec/internal/app/models/role.rb +0 -27
- data/spec/internal/app/models/rubric.rb +0 -36
- data/spec/internal/app/models/rubric_assessment.rb +0 -23
- data/spec/internal/app/models/rubric_association.rb +0 -20
- data/spec/internal/app/models/score.rb +0 -18
- data/spec/internal/app/models/section.rb +0 -36
- data/spec/internal/app/models/submission.rb +0 -32
- data/spec/internal/app/models/term.rb +0 -46
- data/spec/internal/app/models/user.rb +0 -43
- data/spec/internal/app/models/user_observer.rb +0 -22
- data/spec/internal/app/services/live_events/assignment_event.rb +0 -43
- data/spec/internal/app/services/live_events/course_event.rb +0 -28
- data/spec/internal/app/services/live_events/course_section_event.rb +0 -28
- data/spec/internal/app/services/live_events/enrollment_event.rb +0 -30
- data/spec/internal/app/services/live_events/grade_event.rb +0 -36
- data/spec/internal/app/services/live_events/module_event.rb +0 -26
- data/spec/internal/app/services/live_events/module_item_event.rb +0 -25
- data/spec/internal/app/services/live_events/submission_event.rb +0 -28
- data/spec/internal/app/services/live_events/syllabus_event.rb +0 -31
- data/spec/internal/app/services/live_events/user_event.rb +0 -27
- data/spec/internal/db/migrate/20251029222307_create_users.rb +0 -26
- data/spec/internal/db/migrate/20251029222308_create_pseudonyms.rb +0 -24
- data/spec/internal/db/migrate/20251029222309_create_courses.rb +0 -30
- data/spec/internal/db/migrate/20251029222310_create_groups.rb +0 -29
- data/spec/internal/db/migrate/20251029222311_create_group_memberships.rb +0 -24
- data/spec/internal/db/migrate/20251029222312_create_accounts.rb +0 -23
- data/spec/internal/db/migrate/20251029222313_create_terms.rb +0 -24
- data/spec/internal/db/migrate/20251029222314_create_enrollments.rb +0 -31
- data/spec/internal/db/migrate/20251029222315_create_sections.rb +0 -27
- data/spec/internal/db/migrate/20251029222316_create_assignments.rb +0 -37
- data/spec/internal/db/migrate/20251029222317_create_submissions.rb +0 -32
- data/spec/internal/db/migrate/20251029222318_create_roles.rb +0 -24
- data/spec/internal/db/migrate/20251029222319_create_admins.rb +0 -26
- data/spec/internal/db/migrate/20251029222320_create_assignment_groups.rb +0 -28
- data/spec/internal/db/migrate/20251029222321_create_context_modules.rb +0 -28
- data/spec/internal/db/migrate/20251029222322_create_context_module_items.rb +0 -26
- data/spec/internal/db/migrate/20251029222324_create_grading_periods.rb +0 -28
- data/spec/internal/db/migrate/20251029222325_create_grading_period_groups.rb +0 -24
- data/spec/internal/db/migrate/20251029222326_create_content_migrations.rb +0 -30
- data/spec/internal/db/migrate/20251029222327_create_learning_outcomes.rb +0 -36
- data/spec/internal/db/migrate/20251029222328_create_learning_outcome_results.rb +0 -52
- data/spec/internal/db/migrate/20251029222330_create_rubrics.rb +0 -44
- data/spec/internal/db/migrate/20251029222331_create_rubric_associations.rb +0 -42
- data/spec/internal/db/migrate/20251029222332_create_rubric_assessments.rb +0 -37
- data/spec/internal/db/migrate/20251029222334_create_assignment_overrides.rb +0 -25
- data/spec/internal/db/migrate/20251029222335_create_scores.rb +0 -42
- data/spec/internal/db/migrate/20251029223411_create_user_observers.rb +0 -23
- data/spec/internal/db/migrate/20251029224009_create_course_nicknames.rb +0 -23
- data/spec/internal/db/migrate/20251029224010_create_course_progresses.rb +0 -26
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +0 -3
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +0 -4
|
@@ -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
|
|
@@ -170,22 +170,28 @@ RSpec.describe CanvasSync::Jobs::BeginSyncChainJob do
|
|
|
170
170
|
end
|
|
171
171
|
|
|
172
172
|
context 'a "<weekday>/<skip weeks>" schedule (e.g. "sunday/2")' do
|
|
173
|
+
# should_full_sync? asks DateTime.now (the system zone) which weekday it is, so
|
|
174
|
+
# these travel to local noon. Midnight in any single zone lands on the adjacent
|
|
175
|
+
# day for someone, which flips the weekday and the assertion with it.
|
|
176
|
+
let(:sunday) { Time.local(2024, 1, 7, 12, 0, 0) }
|
|
177
|
+
let(:monday) { Time.local(2024, 1, 8, 12, 0, 0) }
|
|
178
|
+
|
|
173
179
|
it 'is true only on the matching weekday once the skip period has elapsed' do
|
|
174
|
-
Timecop.travel(
|
|
180
|
+
Timecop.travel(sunday) do
|
|
175
181
|
CanvasSync::SyncBatch.create!(status: 'completed', full_sync: true, batch_genre: 'default', started_at: 3.weeks.ago)
|
|
176
182
|
expect(job.should_full_sync?('sunday/2')).to eq(true)
|
|
177
183
|
end
|
|
178
184
|
end
|
|
179
185
|
|
|
180
186
|
it 'is false on the matching weekday if the skip period has not yet elapsed' do
|
|
181
|
-
Timecop.travel(
|
|
187
|
+
Timecop.travel(sunday) do
|
|
182
188
|
CanvasSync::SyncBatch.create!(status: 'completed', full_sync: true, batch_genre: 'default', started_at: 1.week.ago)
|
|
183
189
|
expect(job.should_full_sync?('sunday/2')).to eq(false)
|
|
184
190
|
end
|
|
185
191
|
end
|
|
186
192
|
|
|
187
193
|
it 'is false on a non-matching weekday even if the skip period has elapsed' do
|
|
188
|
-
Timecop.travel(
|
|
194
|
+
Timecop.travel(monday) do
|
|
189
195
|
CanvasSync::SyncBatch.create!(status: 'completed', full_sync: true, batch_genre: 'default', started_at: 3.weeks.ago)
|
|
190
196
|
expect(job.should_full_sync?('sunday/2')).to eq(false)
|
|
191
197
|
end
|
|
File without changes
|
|
File without changes
|
|
@@ -86,6 +86,30 @@ RSpec.describe CanvasSync::Jobs::ReportSyncTask do
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
describe ".from_context" do
|
|
89
|
+
# Stands in for JobBatches::ContextHash, which reads keys via #[] but routes every other Hash
|
|
90
|
+
# method through #flatten. Flattening loads (and locks down) the whole ancestor chain, so
|
|
91
|
+
# from_context has to stay on #[] - anything else costs the Batch the ability to record its
|
|
92
|
+
# own progress later in the job.
|
|
93
|
+
class FlattenTattlingContext
|
|
94
|
+
attr_reader :flatten_count
|
|
95
|
+
|
|
96
|
+
def initialize(hash)
|
|
97
|
+
@hash = hash.with_indifferent_access
|
|
98
|
+
@flatten_count = 0
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def [](key)
|
|
102
|
+
@hash[key]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def flatten
|
|
106
|
+
@flatten_count += 1
|
|
107
|
+
@hash
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
delegate_missing_to :flatten
|
|
111
|
+
end
|
|
112
|
+
|
|
89
113
|
it "reconstructs task from batch context" do
|
|
90
114
|
stub_batch_context({ canvas_term_id: 1 })
|
|
91
115
|
allow(CanvasSync::JobBatches::Batch.current).to receive(:context)
|
|
@@ -96,6 +120,38 @@ RSpec.describe CanvasSync::Jobs::ReportSyncTask do
|
|
|
96
120
|
expect(task).to be_a(SyncSpecsTask)
|
|
97
121
|
expect(task.options).to eq({ include_all: true })
|
|
98
122
|
end
|
|
123
|
+
|
|
124
|
+
it "returns nil when the context belongs to a non-report Batch" do
|
|
125
|
+
# A Batch elsewhere in the sync chain inherits a context from its parents, so the context is
|
|
126
|
+
# populated - it just has no :report_class.
|
|
127
|
+
stub_batch_context({ canvas_term_id: 1 })
|
|
128
|
+
allow(CanvasSync::JobBatches::Batch.current).to receive(:context)
|
|
129
|
+
.and_return({ sync_batch_id: 42, account_id: 'self' }.with_indifferent_access)
|
|
130
|
+
|
|
131
|
+
expect(CanvasSync::Jobs::ReportSyncTask.from_context).to be_nil
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "returns nil when there is no current Batch" do
|
|
135
|
+
allow(CanvasSync::JobBatches::Batch).to receive(:current).and_return(nil)
|
|
136
|
+
|
|
137
|
+
expect(CanvasSync::Jobs::ReportSyncTask.from_context).to be_nil
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "does not flatten the context, for a report Batch or any other" do
|
|
141
|
+
report_context = FlattenTattlingContext.new(
|
|
142
|
+
report_class: 'SyncSpecsTask', report_options: { include_all: true }
|
|
143
|
+
)
|
|
144
|
+
other_context = FlattenTattlingContext.new(sync_batch_id: 42)
|
|
145
|
+
|
|
146
|
+
[report_context, other_context].each do |context|
|
|
147
|
+
stub_batch_context({ canvas_term_id: 1 })
|
|
148
|
+
allow(CanvasSync::JobBatches::Batch.current).to receive(:context).and_return(context)
|
|
149
|
+
|
|
150
|
+
CanvasSync::Jobs::ReportSyncTask.from_context
|
|
151
|
+
|
|
152
|
+
expect(context.flatten_count).to eq(0)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
99
155
|
end
|
|
100
156
|
|
|
101
157
|
describe described_class::StarterJob do
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncAccountsJob do
|
|
4
|
+
describe '#perform' do
|
|
5
|
+
before do
|
|
6
|
+
allow(CanvasSync::Jobs::SyncAccountsJob::ReportTask).to receive(:perform_later)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'syncs the root account and then invokes the report task' do
|
|
10
|
+
expect {
|
|
11
|
+
described_class.perform_now({})
|
|
12
|
+
}.to change { Account.count }.by(1)
|
|
13
|
+
|
|
14
|
+
expect(a_request(:get, 'http://test.instructure.com/api/v1/accounts/self')).to have_been_made
|
|
15
|
+
expect(CanvasSync::Jobs::SyncAccountsJob::ReportTask).to have_received(:perform_later).with({})
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'uses account_id from the options when present' do
|
|
19
|
+
described_class.perform_now({ account_id: 42 })
|
|
20
|
+
|
|
21
|
+
expect(a_request(:get, 'http://test.instructure.com/api/v1/accounts/42')).to have_been_made
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'falls back to account_id from the batch context' do
|
|
25
|
+
set_batch_context(account_id: 7)
|
|
26
|
+
|
|
27
|
+
described_class.perform_now({})
|
|
28
|
+
|
|
29
|
+
expect(a_request(:get, 'http://test.instructure.com/api/v1/accounts/7')).to have_been_made
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'skips the root account sync when root_account is false' do
|
|
33
|
+
expect {
|
|
34
|
+
described_class.perform_now({ root_account: false })
|
|
35
|
+
}.not_to change { Account.count }
|
|
36
|
+
|
|
37
|
+
expect(a_request(:get, %r{/api/v1/accounts/})).not_to have_been_made
|
|
38
|
+
expect(CanvasSync::Jobs::SyncAccountsJob::ReportTask).to have_received(:perform_later)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
File without changes
|
|
@@ -17,7 +17,7 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
|
|
|
17
17
|
'courses' => true,
|
|
18
18
|
enrollment_term_id: term.canvas_id,
|
|
19
19
|
}
|
|
20
|
-
})
|
|
20
|
+
}.with_indifferent_access)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -33,7 +33,7 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
|
|
|
33
33
|
'users' => true,
|
|
34
34
|
'courses' => true,
|
|
35
35
|
}
|
|
36
|
-
})
|
|
36
|
+
}.with_indifferent_access)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
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
|
data/spec/spec_helper.rb
CHANGED
|
@@ -78,7 +78,9 @@ def open_canvas_fixture(name)
|
|
|
78
78
|
JSON.parse(data)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
# Mirrors the host-app hook CanvasSync.get_canvas_sync_client calls. It passes an
|
|
82
|
+
# account ID when one is configured, so this has to accept an optional argument.
|
|
83
|
+
def canvas_sync_client(account_id = nil)
|
|
82
84
|
Bearcat::Client.new(token: 'cool-token', prefix: 'http://test.instructure.com')
|
|
83
85
|
end
|
|
84
86
|
|
data/spec/support/fake_canvas.rb
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": 1,
|
|
3
|
+
"name": "Test Root Account",
|
|
4
|
+
"workflow_state": "active",
|
|
5
|
+
"parent_account_id": null,
|
|
6
|
+
"root_account_id": null,
|
|
7
|
+
"uuid": "abcDEF1234567890abcDEF1234567890abcDEF12",
|
|
8
|
+
"default_storage_quota_mb": 500,
|
|
9
|
+
"default_user_storage_quota_mb": 50,
|
|
10
|
+
"default_group_storage_quota_mb": 50,
|
|
11
|
+
"default_time_zone": "America/Denver"
|
|
12
|
+
}
|
|
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
|