panda_pal 5.18.2 → 5.19.0.beta2

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +39 -0
  3. data/app/controllers/panda_pal/lti_v1_p0_controller.rb +11 -4
  4. data/app/controllers/panda_pal/lti_v1_p3_controller.rb +17 -8
  5. data/app/lib/lti_xml/base_platform.rb +32 -18
  6. data/app/lib/lti_xml/bridge_platform.rb +2 -2
  7. data/app/lib/panda_pal/launch_url_helpers.rb +21 -14
  8. data/app/models/panda_pal/lti_registration.rb +41 -0
  9. data/app/models/panda_pal/organization.rb +2 -0
  10. data/app/models/panda_pal/platform/canvas.rb +88 -28
  11. data/app/models/panda_pal/session.rb +19 -1
  12. data/config/initializers/apartment.rb +1 -1
  13. data/db/migrate/20261006000000_create_panda_pal_lti_registrations.rb +14 -0
  14. data/db/migrate/20261006000001_add_tool_to_panda_pal_sessions.rb +5 -0
  15. data/lib/panda_pal/helpers/controller_helper.rb +20 -1
  16. data/lib/panda_pal/helpers/route_helper.rb +8 -1
  17. data/lib/panda_pal/helpers/session_replacement.rb +2 -2
  18. data/lib/panda_pal/version.rb +1 -1
  19. data/lib/panda_pal.rb +82 -10
  20. data/panda_pal.gemspec +2 -1
  21. metadata +19 -50
  22. data/spec/controllers/panda_pal/api_call_controller_spec.rb +0 -25
  23. data/spec/controllers/panda_pal/lti_v1_p0_controller_spec.rb +0 -110
  24. data/spec/controllers/panda_pal/lti_v1_p3_controller_spec.rb +0 -108
  25. data/spec/core/apartment_multidb_spec.rb +0 -166
  26. data/spec/factories/panda_pal_organizations.rb +0 -9
  27. data/spec/factories/panda_pal_sessions.rb +0 -6
  28. data/spec/internal/app/models/account.rb +0 -7
  29. data/spec/internal/app/models/admin.rb +0 -6
  30. data/spec/internal/config/database.yml +0 -18
  31. data/spec/internal/config/routes.rb +0 -5
  32. data/spec/internal/config/storage.yml +0 -3
  33. data/spec/internal/db/schema.rb +0 -30
  34. data/spec/jobs/panda_pal/jobs/grade_passback_job_spec.rb +0 -83
  35. data/spec/lib/panda_pal/ags_client_spec.rb +0 -385
  36. data/spec/lib/panda_pal/helpers/secure_headers_spec.rb +0 -77
  37. data/spec/lib/panda_pal/helpers/session_replacement_spec.rb +0 -72
  38. data/spec/models/panda_pal/api_call_spec.rb +0 -30
  39. data/spec/models/panda_pal/organization/settings_validation_spec.rb +0 -179
  40. data/spec/models/panda_pal/organization/task_scheduling_spec.rb +0 -145
  41. data/spec/models/panda_pal/organization_spec.rb +0 -50
  42. data/spec/models/panda_pal/platform_spec.rb +0 -349
  43. data/spec/models/panda_pal/session_account_roles_spec.rb +0 -182
  44. data/spec/models/panda_pal/session_spec.rb +0 -202
  45. data/spec/spec_helper.rb +0 -158
@@ -1,179 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module PandaPal
4
- PandaPal::Organization
5
- RSpec.describe OrganizationConcerns::SettingsValidation, type: :model do
6
- let!(:org) { create :panda_pal_organization }
7
-
8
- after :all do
9
- PandaPal.lti_options[:settings_structure] = nil
10
- end
11
-
12
- def set_test_settings_structure
13
- PandaPal.lti_options = {
14
- title: 'Test App',
15
- settings_structure: structure,
16
- }
17
- end
18
-
19
- RSpec.shared_examples "shared stuff" do
20
- it 'does not perform any validations if settings is not defined' do
21
- PandaPal.lti_options = {}
22
- expect(org.valid?).to be_truthy
23
- end
24
-
25
- it 'does not perform any validations if options is not defined' do
26
- PandaPal.lti_options = nil
27
- expect(org.valid?).to be_truthy
28
- end
29
-
30
- it 'does perform validations if settings_structure is defined' do
31
- set_test_settings_structure
32
- org.valid?
33
- expect(org.valid?).to be_falsey
34
- end
35
-
36
- it 'will fail if a required setting is not present' do
37
- set_test_settings_structure
38
- expect(org.valid?).to be_falsey
39
- errors = org.errors.messages[:settings]
40
- expect(errors[0]).to eq("Entry [:canvas] is required")
41
- end
42
-
43
- it 'will fail if a setting is supplied but data_type is wrong' do
44
- set_test_settings_structure
45
- org.settings = {canvas: "Dog", reports: {}}
46
- expect(org.valid?).to be_falsey
47
- errors = org.errors.messages[:settings]
48
- expect(errors[0]).to eq("Expected [:canvas] to be a Hash. Was a String")
49
- end
50
-
51
- it 'will fail if a required subsetting is missing' do
52
- set_test_settings_structure
53
- org.settings = {canvas: {base_url: 'http://'}, reports: {}}
54
- expect(org.valid?).to be_falsey
55
- errors = org.errors.messages[:settings]
56
- expect(errors[0]).to eq("Entry [:canvas][:api_token] is required")
57
- end
58
-
59
- it 'will fail if extra options are specified' do
60
- set_test_settings_structure
61
- org.settings = {canvas: {base_url: 'http://', api_token: 'TEST'}, reports: {}, unknown_option: "WHAT IS THIS?"}
62
- expect(org.valid?).to be_falsey
63
- errors = org.errors.messages[:settings]
64
- expect(errors[0]).to eq("Did not expect [:] to contain [unknown_option]")
65
- end
66
-
67
- it 'will pass if all structure is maintained' do
68
- set_test_settings_structure
69
- org.settings = {canvas: {base_url: 'http://', api_token: 'TEST'}, reports: {submissions_report_time_length: 30.minutes, max_recheck_time: 10.hours}}
70
- expect(org.valid?).to be_truthy
71
- end
72
- end
73
-
74
- context 'new settings_structure' do
75
- let!(:properties) do
76
- {
77
- canvas: {
78
- required: true,
79
- type: 'Hash',
80
- properties: {
81
- api_token: { type: 'String', required: true },
82
- base_url: { type: 'String', required: true },
83
- },
84
- },
85
- reports: {
86
- required: true,
87
- type: 'Hash',
88
- allow_additional: true,
89
- }
90
- }
91
- end
92
-
93
- let!(:structure) do
94
- {
95
- properties: properties,
96
- }
97
- end
98
-
99
- it_behaves_like("shared stuff")
100
-
101
- describe ':allow_additional' do
102
- it 'passes extra properties if allow_additional is a matching Hash' do
103
- structure[:allow_additional] = { type: 'String' }
104
- set_test_settings_structure
105
- org.settings = {canvas: {base_url: 'http://', api_token: 'TEST'}, reports: {}, unknown_option: "WHAT IS THIS?"}
106
- expect(org).to be_valid
107
- end
108
-
109
- it 'fails extra properties if allow_additional is an unmatching Hash' do
110
- structure[:allow_additional] = { type: 'Hash' }
111
- set_test_settings_structure
112
- org.settings = {canvas: {base_url: 'http://', api_token: 'TEST'}, reports: {}, unknown_option: "WHAT IS THIS?"}
113
- expect(org).not_to be_valid
114
- end
115
-
116
- it 'passes extra properties if allow_additional is a blank Hash' do
117
- structure[:allow_additional] = { }
118
- set_test_settings_structure
119
- org.settings = {canvas: {base_url: 'http://', api_token: 'TEST'}, reports: {}, unknown_option: "WHAT IS THIS?"}
120
- expect(org).to be_valid
121
- end
122
- end
123
-
124
- describe ':validate' do
125
- let!(:properties) do
126
- {
127
- blah: {
128
- type: 'String',
129
- validate: -> (v, *args) { v == 'blah' ? nil : '<path> failed validation' },
130
- }
131
- }
132
- end
133
-
134
- it 'supports a custom validation proc' do
135
- set_test_settings_structure
136
- org.settings = { blah: 'blah' }
137
- expect(org).to be_valid
138
- end
139
-
140
- it 'replaces <path> with the human readable path' do
141
- set_test_settings_structure
142
- org.settings = { blah: '' }
143
- expect(org.valid?).to be_falsey
144
- errors = org.errors.messages[:settings]
145
- expect(errors[0]).to eq("[:blah] failed validation")
146
- end
147
- end
148
- end
149
-
150
- context 'old settings_structure' do
151
- let!(:structure) do
152
- YAML.load("
153
- canvas:
154
- is_required: true
155
- data_type: Hash
156
- api_token:
157
- is_required: true
158
- data_type: String
159
- base_url:
160
- is_required: true
161
- data_type: String
162
- reports:
163
- is_required: true
164
- data_type: Hash
165
- active_term_allowance:
166
- submissions_report_time_length:
167
- is_required: false
168
- data_type: ActiveSupport::Duration
169
- recheck_wait:
170
- data_type: ActiveSupport::Duration
171
- max_recheck_time:
172
- is_required: false
173
- ").deep_symbolize_keys
174
- end
175
-
176
- it_behaves_like("shared stuff")
177
- end
178
- end
179
- end
@@ -1,145 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module PandaPal
4
- PandaPal::Organization
5
-
6
- RSpec.describe OrganizationConcerns::TaskScheduling, type: :model do
7
- let!(:organization) { create(:panda_pal_organization) }
8
- let(:schedules) { {} }
9
-
10
- before :each do
11
- Organization.instance_variable_set(:@_schedule_descriptors, nil)
12
- Organization.scheduled_task('0 0 0 * * *', :ident) { }
13
-
14
- allow(Sidekiq).to receive(:remove_schedule)
15
- allow(Sidekiq).to receive(:get_schedule) { schedules }
16
- end
17
-
18
- def descriptors
19
- Organization.instance_variable_get(:@_schedule_descriptors)
20
- end
21
-
22
- def descriptor
23
- descriptors[descriptors.keys[0]]
24
- end
25
-
26
- describe '.scheduled_task' do
27
- it 'adds to the set of descriptors' do
28
- expect(descriptors).to match(
29
- 'ident' => {
30
- :key=>"ident",
31
- :schedule=>"0 0 0 * * *",
32
- :worker=>Proc,
33
- :queue=>"default",
34
- }
35
- )
36
- end
37
- end
38
-
39
- describe '.sync_schedules' do
40
- it 'adds new schedules' do
41
- expect(Sidekiq).to receive(:set_schedule).with(/org:\w+-ident/, anything)
42
- Organization.sync_schedules
43
- end
44
-
45
- it 'removes schedules for deleted Orgs' do
46
- schedules['org:deleted_org-schedule'] = {}
47
- expect(Sidekiq).to receive(:remove_schedule).with('org:deleted_org-schedule')
48
- Organization.sync_schedules
49
- end
50
-
51
- it 'keeps schedules created from other sources' do
52
- schedules['other-schedule'] = {}
53
- expect(Sidekiq).not_to receive(:remove_schedule).with('other-schedule')
54
- Organization.sync_schedules
55
- end
56
- end
57
-
58
- describe '#generate_schedule' do
59
- it 'generates the expected schedule' do
60
- expect(organization.generate_schedule).to eq({
61
- "org:#{organization.name}-ident" => {
62
- "cron"=>"0 0 0 * * *",
63
- "queue"=>"default",
64
- "class"=>"PandaPal::OrganizationConcerns::TaskScheduling::ScheduledTaskExecutor",
65
- "args"=>[organization.name, "ident"],
66
- "enabled" => true,
67
- }
68
- })
69
- end
70
- end
71
-
72
- describe '#schedule_task_cron_time' do
73
- before :each do
74
- organization.settings = { timezone: 'America/Denver' }
75
- end
76
-
77
- it 'includes timezone if in settings' do
78
- expect(organization.send(:schedule_task_cron_time, descriptor)).to eq '0 0 0 * * * America/Denver'
79
- end
80
-
81
- it 'does not re-append timezone if already present' do
82
- descriptor[:schedule] = '1 1 1 * * * America/Chicago'
83
- expect(organization.send(:schedule_task_cron_time, descriptor)).to eq '1 1 1 * * * America/Chicago'
84
- end
85
- end
86
-
87
- describe '#sync_schedule' do
88
- it 'adds new schedules' do
89
- expect(Sidekiq).to receive(:set_schedule).with(/org:\w+-ident/, anything)
90
- organization.sync_schedule
91
- end
92
-
93
- it 'removes old jobs' do
94
- schedules["org:#{organization.name}-old_schedule"] = {}
95
- expect(Sidekiq).to receive(:remove_schedule).with("org:#{organization.name}-old_schedule")
96
- organization.sync_schedule
97
- end
98
- end
99
-
100
- describe 'SettingsValidation' do
101
- before :each do
102
- organization.settings = {}
103
- end
104
-
105
- it 'passes a valid timezone' do
106
- organization.settings[:timezone] = 'America/Denver'
107
- expect(organization).to be_valid
108
- end
109
-
110
- it 'fails an invalid timezone' do
111
- organization.settings[:timezone] = 'Timezone/Blorg'
112
- expect(organization).not_to be_valid
113
- end
114
-
115
- it 'allows [:task_schedules] entry to be missing' do
116
- expect(organization).to be_valid
117
- end
118
-
119
- it 'does not require [:task_schedules] sub-entries' do
120
- organization.settings[:task_schedules] = {}
121
- expect(organization).to be_valid
122
- end
123
-
124
- it 'allows task entry to be false' do
125
- organization.settings[:task_schedules] = { ident: false }
126
- expect(organization).to be_valid
127
- end
128
-
129
- it 'allows task entry to be a valid cron string' do
130
- organization.settings[:task_schedules] = { ident: '0 0 0 * * * America/Denver' }
131
- expect(organization).to be_valid
132
- end
133
-
134
- it 'does not allow task entry to be an invalid cron string' do
135
- organization.settings[:task_schedules] = { ident: 'blort' }
136
- expect(organization).not_to be_valid
137
- end
138
-
139
- it 'does not allow sub-entries for unknown tasks' do
140
- organization.settings[:task_schedules] = { missing_ident: '0 0 0 * * * America/Denver' }
141
- expect(organization).not_to be_valid
142
- end
143
- end
144
- end
145
- end
@@ -1,50 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module PandaPal
4
- RSpec.describe Organization, type: :model do
5
- it 'creates a schema upon creation' do
6
- expect(Apartment::Tenant).to receive(:create).and_call_original
7
- create :panda_pal_organization
8
- end
9
-
10
- it 'deletes a schema upon deletion' do
11
- expect(Apartment::Tenant).to receive(:create).and_call_original
12
- expect(Apartment::Tenant).to receive(:drop).and_call_original
13
- org = create :panda_pal_organization
14
- org.destroy
15
- end
16
-
17
- it 'does not allow the name to be changed after creation' do
18
- org = create :panda_pal_organization
19
- org.name = 'test123'
20
- expect(org.valid?).to be_falsey
21
- end
22
-
23
- it 'requires a salesforce_id' do
24
- org = build :panda_pal_organization, salesforce_id: nil
25
- expect(org.valid?).to be_falsey
26
- end
27
-
28
- it 'does not allow duplicate salesforce ids' do
29
- org = create :panda_pal_organization, salesforce_id: 'salesforce'
30
- org2 = build :panda_pal_organization, salesforce_id: 'salesforce'
31
- expect(org2.valid?).to be_falsey
32
- end
33
-
34
- it 'stores setting as an indifferent Hash' do
35
- org = create :panda_pal_organization
36
- org.update!(settings: { a: 1 })
37
-
38
- expect(Organization.last.settings).to be_a (ActiveSupport::HashWithIndifferentAccess)
39
-
40
- org.settings = {}
41
- expect(org.settings).to be_a (ActiveSupport::HashWithIndifferentAccess)
42
- end
43
-
44
- it 'stores settings' do
45
- org = create :panda_pal_organization
46
- org.update!(settings: { a: 1 })
47
- expect(Organization.last.settings[:a]).to eql(1)
48
- end
49
- end
50
- end