panda_pal 5.0.0.beta.4 → 5.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +208 -90
  3. data/app/controllers/panda_pal/lti_controller.rb +0 -18
  4. data/app/controllers/panda_pal/lti_v1_p0_controller.rb +34 -0
  5. data/app/controllers/panda_pal/lti_v1_p3_controller.rb +98 -0
  6. data/app/lib/lti_xml/base_platform.rb +4 -4
  7. data/app/lib/panda_pal/launch_url_helpers.rb +69 -0
  8. data/app/lib/panda_pal/lti_jwt_validator.rb +88 -0
  9. data/app/lib/panda_pal/misc_helper.rb +13 -0
  10. data/app/models/panda_pal/organization.rb +21 -47
  11. data/app/models/panda_pal/organization_concerns/settings_validation.rb +127 -0
  12. data/app/models/panda_pal/organization_concerns/task_scheduling.rb +204 -0
  13. data/app/models/panda_pal/platform.rb +40 -0
  14. data/app/views/panda_pal/lti_v1_p3/login.html.erb +1 -0
  15. data/app/views/panda_pal/partials/_auto_submit_form.html.erb +9 -0
  16. data/config/dev_lti_key.key +27 -0
  17. data/config/routes.rb +12 -2
  18. data/db/migrate/20160412205931_create_panda_pal_organizations.rb +1 -1
  19. data/db/migrate/20160413135653_create_panda_pal_sessions.rb +1 -1
  20. data/db/migrate/20160425130344_add_panda_pal_organization_to_session.rb +1 -1
  21. data/db/migrate/20170106165533_add_salesforce_id_to_organizations.rb +1 -1
  22. data/db/migrate/20171205183457_encrypt_organization_settings.rb +1 -1
  23. data/db/migrate/20171205194657_remove_old_organization_settings.rb +8 -3
  24. data/lib/panda_pal.rb +28 -15
  25. data/lib/panda_pal/engine.rb +8 -39
  26. data/lib/panda_pal/helpers.rb +1 -0
  27. data/lib/panda_pal/helpers/controller_helper.rb +139 -44
  28. data/lib/panda_pal/helpers/route_helper.rb +8 -8
  29. data/lib/panda_pal/helpers/secure_headers.rb +79 -0
  30. data/lib/panda_pal/version.rb +1 -1
  31. data/panda_pal.gemspec +6 -2
  32. data/spec/dummy/config/application.rb +7 -1
  33. data/spec/dummy/config/environments/development.rb +0 -14
  34. data/spec/dummy/config/environments/production.rb +0 -11
  35. data/spec/models/panda_pal/organization/settings_validation_spec.rb +175 -0
  36. data/spec/models/panda_pal/organization/task_scheduling_spec.rb +144 -0
  37. data/spec/models/panda_pal/organization_spec.rb +0 -89
  38. data/spec/spec_helper.rb +4 -0
  39. metadata +66 -10
  40. data/spec/dummy/config/initializers/assets.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 689e3885a1cc8e9ae58ed8f07e0089af4d2b82668f8a6cf9f41e053530762d5d
4
- data.tar.gz: eb7fea8c5df5b973db4dc0be811f3e5961a0e9b3efd4a012ffde72bdb36f6888
3
+ metadata.gz: c1f192b2da218022d237ff08164acd4376fc14867a40a72809050bd951fc8334
4
+ data.tar.gz: 347dd911d927eeb2326bda476bb32f5de889fe278186a6f88dd49772ce27a4a3
5
5
  SHA512:
6
- metadata.gz: 8b994a6c7a7bf474d7e38bfa36efc00d4bfb57913e684f626bf2f457615dcf37346ffed346f0937ebdf50bed19ca2875080f1b69a794358a94f4e7fcc7e518f3
7
- data.tar.gz: 399ea543b5c5765348e0ea9f11517d48b384de5939556c25e780a9d312950b5e1bdb58da931b070151c68bdb4a6e574e9844d3977a4594481346aa6c76beaba1
6
+ metadata.gz: 645ae35f8ea0c1a8b300aae27412ac5d39429bc791e62b6831c4c04c47df80e81a45c5327079b4e202c62e20f084dca346a3bc9306370fdeaface121137d31b0
7
+ data.tar.gz: 0cbf19b4b88fdc839c4598ac213681f6b86ef26809dcbf75b5cb238e848ad4919846affbabb204b326de79e881ca9f1cec0a5e400a3a792905f045f13924af77
data/README.md CHANGED
@@ -11,7 +11,12 @@ PandaPal.lti_properties = {oauth_compliant: 'true'}
11
11
  PandaPal.lti_environments = { domain: ENV['PROD_DOMAIN'], beta_domain: ENV['BETA_DOMAIN'], test_domain: ENV['TEST_DOMAIN'] }
12
12
  PandaPal.lti_custom_params = { custom_canvas_role: '$Canvas.membership.roles' }
13
13
  # :user_navigation, :course_navigation for user context and course context endpoints respectively
14
- PandaPal::stage_navigation(:account_navigation, { enabled: true, text: 'Teacher Reports', visibility: 'admins' })
14
+ PandaPal::stage_navigation(:account_navigation, {
15
+ enabled: true,
16
+ # url: :account_index, # Optional if using lti_nav
17
+ text: 'Teacher Reports',
18
+ visibility: 'admins',
19
+ })
15
20
  ```
16
21
 
17
22
  Configuration data for an installation can be set by creating a `PandaPal::Organization` record. Due to the nature of the data segregation, once created, the name of the organization should not be changed (and will raise a validation error).
@@ -28,16 +33,50 @@ Use one of these 6 options in `PandaPal.lti_options` hash.
28
33
  5. Leave this property off, and you will get the dynamic host with the root path ('http://appdomain.com/') by default.
29
34
  6. If you really do not want this property use the option `launch_url: false` for it to be left off.
30
35
 
31
- # Organization Attributes
32
- id: Primary Key
33
- name: Name of the organization. Used to on requests to select the tenant
34
- key: Key field from CanvasLMS
35
- secret: Secret field from CanvasLMS
36
- canvas_account_id: ID of the corresponding Canvas account.
37
- settings: Hash of settings for this Organization
38
- salesforce_id: ID of this organization in Salesforce
36
+ ### Task Scheduling
37
+ `PandaPal` includes an integration with `sidekiq-scheduler`. You can define tasks on an Organization class Stub like so:
38
+ ```ruby
39
+ # <your_app>/app/models/panda_pal/organization.rb
40
+ require File.expand_path('../../app/models/panda_pal/organization.rb', PandaPal::Engine.called_from)
41
+
42
+ module PandaPal
43
+ class Organization
44
+ # Will invoke CanvasSyncStarterWorker.perform_async() according to the cron schedule
45
+ scheduled_task '0 15 05 * * *', :identifier, worker: CanvasSyncStarterWorker
46
+
47
+ # Will invoke the method 'organization_method' on the Organization
48
+ scheduled_task '0 15 05 * * *', :organization_method_and_identifier
39
49
 
40
- XML for an installation can be generated by visiting /lti/config in your application.
50
+ # If you need to invoke the same method on multiple schedules
51
+ scheduled_task '0 15 05 * * *', :identifier, worker: :organization_method
52
+
53
+ # You can also use a block
54
+ scheduled_task '0 15 05 * * *', :identifier do
55
+ # Do Stuff
56
+ end
57
+
58
+ # You can use a Proc (called in the context of the Organization) to determine the schedule
59
+ scheduled_task -> { settings[:cron] }, :identifier
60
+
61
+ # You can specify a timezone. If a TZ is not coded and settings[:timezone] is present, it will be appended automatically
62
+ scheduled_task '0 15 05 * * * America/Denver', :identifier, worker: :organization_method
63
+
64
+ # Setting settings[:task_schedules][:identifier] will override the code cron schedule. Setting it to false will disable the Task
65
+ # :identifer values _must_ be unique, but can be nil, in which case they will be determined by where (lineno etc) scheduled_task is called
66
+ end
67
+ end
68
+ ```
69
+
70
+ ### Organization Attributes
71
+ `id`: Primary Key
72
+ `name`: Name of the organization. Used to on requests to select the tenant
73
+ `key`: Key field from CanvasLMS
74
+ `secret`: Secret field from CanvasLMS
75
+ `canvas_account_id`: ID of the corresponding Canvas account.
76
+ `settings`: Hash of settings for this Organization
77
+ `salesforce_id`: ID of this organization in Salesforce
78
+
79
+ XML for an installation can be generated by visiting `/lti/config` in your application.
41
80
 
42
81
  ### Routing
43
82
 
@@ -46,7 +85,7 @@ The following routes should be added to the routes.rb file of the implementing L
46
85
  ```ruby
47
86
  # config/routes.rb
48
87
  mount PandaPal::Engine, at: '/lti'
49
- lti_nav account_navigation: 'accounts#launch'
88
+ lti_nav account_navigation: 'accounts#launch' # Use lti_nav to provide a custom Launch implementation, otherwise use the url: param of stage_navigation to let PandaPal handle launch.
50
89
  root to: 'panda_pal/lti#launch'
51
90
  ```
52
91
 
@@ -81,9 +120,10 @@ It is also possible to switch tenants by implementing `around_action :switch_ten
81
120
  However, it should be noted that calling `switch_tenant` must be used in an `around_action` hook (or given a block), and is only intended to be used for LTI launches, and not subsequent requests.
82
121
 
83
122
  ### Rake tasks and jobs
84
- # Delayed Job Support has been removed. This allows each project to assess it's need to handle background jobs.
123
+ **Delayed Job Support has been removed. This allows each project to assess it's need to handle background jobs.**
124
+
85
125
  The Apartment Gem makes it so background jobs need to be run within the current tenant. If using sidekiq, there is a gem that
86
- does this automatically called apartment-sidkiq. If Delayed Jobs, see how it's done in version 1 of PandaPal.
126
+ does this automatically called `apartment-sidkiq`. If Delayed Jobs, see how it's done in version 1 of PandaPal.
87
127
 
88
128
  For rake tasks, the current tenant will be set to `public`, and thus special handling must be taken when running the task or queueing jobs as part of it.
89
129
 
@@ -125,25 +165,52 @@ Controllers will automatically have access to a number of methods that can be he
125
165
  * `save_session` - Saves the session given by `current_session` to the database.
126
166
 
127
167
  ## Sessions and `current_session`
128
- A session_key returned by `current_session` is essentially an access token, and while we can't prevent users from sharing if they're so inclined, it should still be kept hidden as much as possible (namely by not including it as a URL param at any time).
129
- A good way to pass the `session_key` if using ajax or something similar, is to define it as a header in `$.ajaxSetup`. This is particularly useful if a javascript framework such as React is being utilized.
168
+ Because of the ever-increasing security around `<iframe>`s and cookies, a custom session implementation has been rolled into `PandaPal`.
169
+ The implementation is mostly passive, but requires some changes and caveats as opposed to the native Rails implementation.
130
170
 
131
- PandaPal provides a number of ways to find a session, shown in the example below
171
+ The current session object can be accessed from any controller using `current_session`. This object isn't the actual data container (as `session` _is_ in Rails).
172
+ Session data can be accessed and modified using `current_session.data[:key]` or `current_session_data[:key]`.
132
173
 
133
- ```ruby
134
- def session_key
135
- params[:session_key] || session_key_header || flash[:session_key] || session[:session_key]
136
- end
174
+ Because cookies are unreliable, it becomes the responsibility of the LTI developer to ensure that a custom "cookie" is passed to the frontend with each response
175
+ and returned to the backend with each request, otherwise the backend won't be able to access the current session. There are a few ways to do this.
137
176
 
138
- def session_key_header
139
- if match = request.headers['Authorization'].try(:match, /token=(.+)/)
140
- match[1]
141
- end
142
- end
177
+ Generally, the method for passing the session "cookie" to the frontend looks something like:
178
+ ```html
179
+ <meta name="session_key" content="<%= current_session.session_key %>">
180
+ ```
181
+
182
+ ### Returning to the backend
183
+ The `session_key` can be passed to the backend in multiple ways:
184
+ 1. (Recommended) Via the `Authorization` Header (usually defining it as a default in your AJAX/XHR/`fetch` library):
185
+ ```http
186
+ Authorization: token=SESSION_KEY_HERE
187
+ ```
188
+ 2. Via a `session_key` parameter in a `POST` request (Useful for native HTML `<form>`s).
189
+ 3. (Used for Dev, but not highly discouraged in Prod) via a `GET`/URL Query parameter: `?session_key=SESSION_KEY_HERE`.
190
+
191
+ The `session_key` does not contain any secrets itself, so it is safe to pass to the frontend, but it is encouraged to keep it away from the
192
+ end-user as much as possible because it should not be shared.
193
+
194
+ ### Redirecting and Multi-Page Applications
195
+ Special instructions must be followed when using `link_to` or `redirect_to` to ensure that the Session is passed correctly:
196
+
197
+ Add a `session_token:` (notice the use of _`_token`_ as opposed to _`_key`_!) parameter when using `link_to` or `redirect_to`:
198
+ ```ruby
199
+ link_to "Link Name", somewhere_else_path(session_token: link_nonce)
200
+ redirect_to somewhere_else_path(session_token: link_nonce)
201
+ ```
202
+ You can also use the `redirect_with_session_to` helper, which will automatically add `organization_id:` and `session_token:` params:
203
+ ```ruby
204
+ redirect_with_session_to :somewhere_else_path, other_param: 1
143
205
  ```
206
+ For each request (not each call), `link_nonce` generates a nonce and stores it in the Session. The generated value can be used
207
+ for at-most-one future request. This means that browser back-forward navigation **will not work** (if it actually ever worked for
208
+ iframe-based LTIs in the first place).
144
209
 
145
210
  ### Persisting the session
146
- In order to reduce the number of sessions saved to the database, a session should only be saved if data has been added to it. A good way to accomplish this is to add `append_after_action :save_session, if: proc { session_changed? }` to the application_controller.rb
211
+ The session is automatically saved using an `after_action` callback. This callback is poised to run last, but if that causes issues
212
+ (eg some other callback running afterwards and needing to modify the session), `skip_after_action :auto_save_session` can be used
213
+ and a custom implementation can be supplemented.
147
214
 
148
215
  ### Session cleanup
149
216
  Over time, the sessions table will become bloated with sessions that are no longer active.
@@ -151,11 +218,6 @@ As such, `rake panda_pal:clean_sessions` should be run periodically to clean up
151
218
 
152
219
  ## Organizations and `current_organization`
153
220
  Similar to `current_session`, `current_organization` can be returned with a number of methods, shown below
154
- ```ruby
155
- def organization_key
156
- params[:oauth_consumer_key] || params[:organization_id] || current_session_data[:organization_key] || session[:organization_key]
157
- end
158
- ```
159
221
 
160
222
  ## Security
161
223
 
@@ -179,56 +241,62 @@ It can be overridden on a action-by-action basis by using `skip_before_action`.
179
241
  skip_before_action :forbid_access_if_lacking_session, only: :launch
180
242
  ```
181
243
 
182
- ### Upgrading to version 3
183
-
184
- Before upgrading save existing settings somewhere safe in case you need to
185
- restore them for whatever reason.
186
-
187
- panda_pal v3 introduces an encrypted settings hash. This should provide more security in the case where a
188
- customer may have gained access to Organization information in the database. Settings cannot be decrypted
189
- without knowing the secret decryption key. For panda_pal, we are relying on the secret_key_base to be set
190
- (typically in config/secrets.yml), if that is not available we are falling back to directly use
191
- ENV['SECRET_KEY_BASE']. For production environments, config/secrets.yml should not have a plain-text secret,
192
- it should be referencing an ENV variable. Make sure your secret is not plain-text committed to a repository!
193
-
194
- The secret key is used to encrypt / decrypt the settings hash as necessary.
195
-
196
- Before upgrading to version 3, you should confirm that the secret key is set to a consistent value (if the
197
- value is lost your settings will be hosed).
198
-
199
- You should also rollback any local encryption you have done on the settings hash. The settings hash
200
- should just be plainly visible when you upgrade to V3. Otherwise the panda_pal migrations will
201
- probably fail.
202
-
203
- Once you have upgraded your gem, you will need to run migrations. Before doing that, I would store off your
204
- unencrypted settings (just in case).
205
-
206
- `rake db:migrate`
207
-
208
- If all goes well, you should be set! Log into console, and verify that you can still access settings:
209
-
210
- `PandaPal::Organization.first.settings`
211
-
212
- should show unencrypted settings in your console.
213
-
214
- If anything goes wrong, you should be able to rollback the change:
215
-
216
- `rake db:rollback STEP=2`
217
-
218
- If you need to give up on the change, just make sure to change your gem version for panda_pal to be < 3.
244
+ ### Secure Headers
245
+ PandaPal bundles the `secure_headers` Gem and provides a default config. The PandaPal default works for really basic apps, but you may need to provide
246
+ a custom configuration. This can be done by creating a `secure_headers.rb` initializer in you App like so:
247
+ ```ruby
248
+ SecureHeaders::Configuration.default do |config|
249
+ PandaPal::SecureHeaders.apply_defaults(config) # Optional, but recommended
250
+ # ...
251
+ end
252
+ ```
219
253
 
220
- ### Validating settings in your LTI.
254
+ ## Validating settings in your LTI.
221
255
 
222
256
  You can specify a structure that you would like to have enforced for your settings.
223
257
 
224
- In your panda_pal initializer (i.e. config/initializers/panda_pal.rb or config/initializers/lti.rb)
258
+ In your panda_pal initializer (i.e. `config/initializers/panda_pal.rb` or `config/initializers/lti.rb`)
225
259
 
226
260
  You can specify options that can include a structure for your settings. If specified, PandaPal will
227
261
  enforce this structure on any new / updated organizations.
228
262
 
263
+ ```ruby
264
+ PandaPal.lti_options = {
265
+ title: 'LBS Gradebook',
266
+ settings_structure: {
267
+ allow_additional: true, # Allow additional properties that aren't included in the :properties Hash.
268
+ allow_additional: { type: 'String' }, # You can also set :allow_additional to a settings specification that will be used to validate each additional setting
269
+ validate: ->(value, spec, **kwargs) {
270
+ # kwargs currently includes:
271
+ # :errors => [An array to push errors to]
272
+ # :path => [An array representation of the current path in the settings object]
273
+
274
+ # To add errors, you may:
275
+ # Push strings to the kwargs[:errors] Array:
276
+ kwargs[:errors] << "Your error message at <path>" unless value < 10
277
+ # Or return a string or string array:
278
+ value.valid? ? nil : "Your error message at <path>" # <path> will be replaced with the actual path that the error occurred at
279
+ },
280
+ properties: {
281
+ canvas_api_token: { type: 'String', required: true, },
282
+ catalog: { # :validate, :allow_additional, :properties keys are all supported at this level as well
283
+ type: 'Hash',
284
+ required: false,
285
+ validate: -> (*args) {},
286
+ allow_additional: false,
287
+ properties: {
288
+
289
+ },
290
+ }
291
+ }
292
+ },
293
+ }
294
+ ```
295
+
296
+ #### Legacy Settings Structure:
229
297
  Here is an example options specification:
230
298
 
231
- ```
299
+ ```ruby
232
300
  PandaPal.lti_options = {
233
301
  title: 'LBS Gradebook',
234
302
  settings_structure: YAML.load("
@@ -271,9 +339,41 @@ This is determined by `PandaPal.lti_options[:platform]`.
271
339
  Set this to `platform: 'canvas.instructure.com'` (default)
272
340
  OR `platform: 'bridgeapp.com'`
273
341
 
274
- ### Safari Support
342
+ ## Development:
343
+ ### Running Specs:
344
+ Initialize the Specs DB:
345
+ `cd spec/dummy; bundle exec rake db:drop; bundle exec rake db:create; bundle exec rake db:schema:load`
346
+ Then `bundle exec rspec`
275
347
 
276
- Safari is weird, and you'll potentially run into issues getting `POST` requests to properly validate CSRF if you don't do the following:
348
+ ## Safari Support
349
+ Safari is weird (it blocks cookies in `<iframe>`s unless the site has set a cookie _outside_ of an `<iframe>` first), and you'll run into
350
+ issues with Rails-native Sessions and CSRF because of that.
351
+
352
+ This means that safari will likely refuse to send info about your rails session
353
+ back to the LTI, and the application will start up a new session each time the
354
+ browser navigates. This likely means a new session each time the LTI launches.
355
+
356
+ ### PandaPal 5
357
+ It has been a constant struggle to force safari to store and allow
358
+ access to a rails session while the application is embedded in Canvas.
359
+
360
+ As of PandaPal 5, a session cookie is no longer required by panda_pal.
361
+
362
+ See the Section on [Sessions and `current_session`](#sessions-and-current_session)
363
+
364
+ You will want to watch out for a few scenarios:
365
+ 1) Make sure you are using `redirect_with_session_to` if you need to redirect
366
+ and have your PandaPal session_key persisted server side.
367
+ 2) Use the `Authorization` header with `token={session_key}` to send your
368
+ PandaPal session info into api calls.
369
+ 3) If you use `link_to` and navigate in your LTI (apps that are not single page)
370
+ make sure you include the `link_nonce` like so:
371
+ ```ruby
372
+ link_to "Link Name", somewhere_else_path(session_token: link_nonce)
373
+ ```
374
+
375
+ ### Previous Safari Instructions
376
+ Safari is weird and you'll potentially run into issues getting `POST` requests to properly validate CSRF if you don't do the following:
277
377
 
278
378
  - Make sure you have both a `launch` controller and your normal controllers. The `launch` controller should call `before_action :validate_launch!` and then redirect
279
379
  to your other controller.
@@ -281,28 +381,47 @@ Safari is weird, and you'll potentially run into issues getting `POST` requests
281
381
 
282
382
  This will allow `PandaPal` to apply an iframe cookie fix that will allow CSRF validation to work.
283
383
 
384
+ ## Migrating Major Versions
284
385
 
285
- ### PandaPal 5
386
+ ### Upgrading to version 3
286
387
 
287
- It has been a constant struggle to force safari to store and allow
288
- access to a rails session while the application is embedded in Canvas.
388
+ Before upgrading save existing settings somewhere safe in case you need to
389
+ restore them for whatever reason.
390
+
391
+ panda_pal v3 introduces an encrypted settings hash. This should provide more security in the case where a
392
+ customer may have gained access to Organization information in the database. Settings cannot be decrypted
393
+ without knowing the secret decryption key. For panda_pal, we are relying on the secret_key_base to be set
394
+ (`typically in config/secrets.yml`), if that is not available we are falling back to directly use
395
+ `ENV['SECRET_KEY_BASE']`. For production environments, `config/secrets.yml` should not have a plain-text secret,
396
+ it should be referencing an ENV variable. Make sure your secret is not plain-text committed to a repository!
289
397
 
290
- As of PandaPal 5, a persistent session is no longer required by panda_pal.
398
+ The secret key is used to encrypt / decrypt the settings hash as necessary.
291
399
 
292
- This means that safari will likely refuse to send info about your rails session
293
- back to the LTI, and the application will start up a new session each time the
294
- browser navigates. This likely means a new session each time the LTI launches.
400
+ Before upgrading to version 3, you should confirm that the secret key is set to a consistent value (if the
401
+ value is lost your settings will be hosed).
295
402
 
296
- You will want to watch out for a few scenarios:
403
+ You should also rollback any local encryption you have done on the settings hash. The settings hash
404
+ should just be plainly visible when you upgrade to V3. Otherwise the panda_pal migrations will
405
+ probably fail.
297
406
 
298
- 1) Make sure you are using "redirect_with_session_to" if you need to redirect
299
- and have your PandaPal session_key persisted server side.
300
- 2) Use the "Authorization" header with "token={session_key}" to send your
301
- PandaPal session info into api calls.
302
- 3) If you use link_to and navigate in your LTI (apps that are not single page)
303
- make sure you include an encrypted_session_key parameter in your links.
407
+ Once you have upgraded your gem, you will need to run migrations. Before doing that, I would store off your
408
+ unencrypted settings (just in case).
304
409
 
305
- # Upgrading from PandaPal 4 to 5:
410
+ `rake db:migrate`
411
+
412
+ If all goes well, you should be set! Log into console, and verify that you can still access settings:
413
+
414
+ `PandaPal::Organization.first.settings`
415
+
416
+ should show unencrypted settings in your console.
417
+
418
+ If anything goes wrong, you should be able to rollback the change:
419
+
420
+ `rake db:rollback STEP=2`
421
+
422
+ If you need to give up on the change, just make sure to change your gem version for panda_pal to be < 3.
423
+
424
+ ### Upgrading from PandaPal 4 to 5:
306
425
 
307
426
  If your tool is setup according to a pretty standard pattern (see pace_plans,
308
427
  canvas_group_enrollment, etc), you shouldn't have to do anything to upgrade.
@@ -312,7 +431,7 @@ using "redirect_with_session_to".
312
431
 
313
432
  Here is an example launch / account controller setup, assuming an account launch.
314
433
 
315
- ```
434
+ ```ruby
316
435
  class LaunchController < ApplicationController
317
436
  # We don't verify CSRF on launch because the LTI launch is done via a POST
318
437
  # request, and Canvas wouldn't know anything about the CSRF
@@ -339,4 +458,3 @@ class AccountController < ApplicationController
339
458
  end
340
459
  end
341
460
  ```
342
-
@@ -2,23 +2,5 @@ require_dependency "panda_pal/application_controller"
2
2
 
3
3
  module PandaPal
4
4
  class LtiController < ApplicationController
5
- def tool_config
6
- if PandaPal.lti_environments.empty?
7
- render plain: 'Domains must be set in lti_environments'
8
- return
9
- end
10
- platform = PandaPal.lti_options.delete(:platform) || 'canvas.instructure.com'
11
- request_url = "#{request.scheme}://#{request.host_with_port}"
12
- case platform
13
- when 'canvas.instructure.com'
14
- xml_config = LtiXml::CanvasPlatform.new(platform, request_url, main_app)
15
- when 'bridgeapp.com'
16
- xml_config = LtiXml::BridgePlatform.new(platform, request_url, main_app)
17
- else
18
- render plain: 'platform must be set under lti_options'
19
- return
20
- end
21
- render xml: xml_config.xml
22
- end
23
5
  end
24
6
  end
@@ -0,0 +1,34 @@
1
+ require_dependency "panda_pal/application_controller"
2
+
3
+ module PandaPal
4
+ class LtiV1P0Controller < ApplicationController
5
+ def launch
6
+ current_session_data.merge!({
7
+ lti_version: 'v1p0',
8
+ lti_launch_placement: params[:launch_type],
9
+ launch_params: params.to_unsafe_h,
10
+ })
11
+
12
+ redirect_with_session_to(:"#{LaunchUrlHelpers.launch_route(params[:launch_type])}_url", route_context: main_app)
13
+ end
14
+
15
+ def tool_config
16
+ if PandaPal.lti_environments.empty?
17
+ render plain: 'Domains must be set in lti_environments'
18
+ return
19
+ end
20
+ platform = PandaPal.lti_options.delete(:platform) || 'canvas.instructure.com'
21
+ request_url = "#{request.scheme}://#{request.host_with_port}"
22
+ case platform
23
+ when 'canvas.instructure.com'
24
+ xml_config = LtiXml::CanvasPlatform.new(platform, request_url, main_app)
25
+ when 'bridgeapp.com'
26
+ xml_config = LtiXml::BridgePlatform.new(platform, request_url, main_app)
27
+ else
28
+ render plain: 'platform must be set under lti_options'
29
+ return
30
+ end
31
+ render xml: xml_config.xml
32
+ end
33
+ end
34
+ end