panda_pal 5.19.0.beta2 → 5.19.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8433b20262277ab9a0e66156b4fb2b865919cbfe73701202c163b1dd4c063c9
4
- data.tar.gz: fba4d18d40156ccf1799c33b4b2a5aed33b71c6e0e772a65df04c586f207503f
3
+ metadata.gz: d04030accc6fd45997f3e37c3c91f9bdfe77f7cf7f4898cf54e4dae47f45886e
4
+ data.tar.gz: db21a419ad8d77e68b670b292cd22bbe3432c097bd6b0663fbe8e012790ad1cf
5
5
  SHA512:
6
- metadata.gz: 33e70423978afce311e1e0d4a5eecddc17e8814e922bea12e854b1b57135cc336e1c418b6f8d0fcca061c4a25485164dab1468805639d16abd6f1c1951f7b4cb
7
- data.tar.gz: fa08843f3ad5d268203908c22725c546825102127cce6858c907a84b21e0a58561fab5f1e017b569cb95abd5e42c1715045b699b7790f899e7bbabfbf8f9693c
6
+ metadata.gz: '02434851f52dc132ceab53754675b8e3ef54bc5dc0ee6b3e74e2d24aa7d3bd023bad5bd798aa87387365d37b2fe18d66ab89525c9121c1c495433e036e7c0796'
7
+ data.tar.gz: 1d102580d5599677921de881a487ada5880e278e46e2563fd4c77bea69c96ad7fb4395411d58a8be1047af29715c9ced56895b7ddbac7c995a285f3a7f3df68f
@@ -80,6 +80,7 @@ module PandaPal
80
80
  def _parse_lti_context(context)
81
81
  context = context.to_s
82
82
  context = 'account/self' if context == 'root_account'
83
+ context = "account/#{canvas_account_id}" if context == 'org_account'
83
84
  cid, ctype = context.split(/[\.\/]/).reverse
84
85
  ctype ||= 'account'
85
86
 
@@ -89,7 +90,7 @@ module PandaPal
89
90
  # `tool:` installs one of the tools registered with PandaPal.define_tool
90
91
  # instead of the default one. In LTI 1.3 each tool is its own Developer Key,
91
92
  # tracked by an LtiRegistration rather than by this Organization's `key`.
92
- def _install_lti(host: nil, context: :root_account, version: nil, exists: :error, dedicated_deployment: false, tool: PandaPal::DEFAULT_TOOL)
93
+ def _install_lti(host: nil, context: :org_account, version: nil, exists: :error, dedicated_deployment: false, tool: PandaPal::DEFAULT_TOOL)
93
94
  outer_install = @current_lti_install
94
95
  raise "Automatically installing this LTI requires Bearcat." unless defined?(Bearcat)
95
96
 
@@ -148,28 +149,16 @@ module PandaPal
148
149
  scope_tool = existing_installs[0]
149
150
 
150
151
  # Don't need to do an update if it already exists - Settings are stored on the LTI Key instead of the installation
151
- if tool != PandaPal::DEFAULT_TOOL
152
- scope_tool ||= bearcat_client.send(:"create_#{ctype}_external_tool", cid, {
152
+ new_install = !scope_tool
153
+ scope_tool ||= _with_lti_registration_unlocked(ekey) do
154
+ bearcat_client.send(:"create_#{ctype}_external_tool", cid, {
153
155
  client_id: ekey[:id],
154
156
  })
157
+ end
155
158
 
156
- lti_registrations.find_or_create_by!(
157
- tool: tool.to_s,
158
- client_id: ekey[:id].to_s,
159
- deployment_id: (scope_tool[:deployment_id].presence&.to_s if dedicated_deployment),
160
- )
161
- elsif !scope_tool
162
- scope_tool = bearcat_client.send(:"create_#{ctype}_external_tool", cid, {
163
- client_id: ekey[:id],
164
- })
165
-
166
- new_client_id = "#{ekey[:id]}"
167
- new_client_id += "/#{scope_tool[:deployment_id]}" if dedicated_deployment
168
-
169
- self.key = new_client_id
170
- self.secret = ekey[:api_key]
171
-
172
- save! if changed?
159
+ # The default tool's key only moves with a new install; other tools always (re)register
160
+ if new_install || tool != PandaPal::DEFAULT_TOOL
161
+ _register_lti_v1p3_key(tool, ekey, deployment_id: (scope_tool[:deployment_id].presence&.to_s if dedicated_deployment))
173
162
  end
174
163
 
175
164
  @new_lti_installation = scope_tool
@@ -244,7 +233,8 @@ module PandaPal
244
233
 
245
234
  valid_redirect_uris.uniq!
246
235
 
247
- if !ekey
236
+ created = !ekey
237
+ if created
248
238
  # Create New
249
239
  ekey = bearcat_client.post("api/lti/accounts/self/developer_keys/tool_configuration", {
250
240
  developer_key: {
@@ -270,6 +260,10 @@ module PandaPal
270
260
 
271
261
  ekey = ekey[:developer_key] || ekey
272
262
 
263
+ # Record a new key right away, so a failed install is retried against
264
+ # this key instead of creating yet another one.
265
+ _register_lti_v1p3_key(tool, ekey) if created
266
+
273
267
  if ekey[:developer_key_account_binding][:workflow_state] == "off"
274
268
  bearcat_client.post("api/v1/accounts/self/developer_keys/#{ekey[:id]}/developer_key_account_bindings", {
275
269
  developer_key_account_binding: {
@@ -281,6 +275,42 @@ module PandaPal
281
275
  ekey
282
276
  end
283
277
 
278
+ # Points this Organization (default tool) or an LtiRegistration (other
279
+ # tools) at a v1.3 Developer Key.
280
+ def _register_lti_v1p3_key(tool, ekey, deployment_id: nil)
281
+ client_id = ekey[:id].to_s
282
+
283
+ if tool == PandaPal::DEFAULT_TOOL
284
+ self.key = deployment_id ? "#{client_id}/#{deployment_id}" : client_id
285
+ self.secret = ekey[:api_key] if ekey[:api_key].present?
286
+ save! if changed?
287
+ else
288
+ lti_registrations.find_or_create_by!(tool: tool.to_s, client_id: client_id, deployment_id: deployment_id)
289
+ # Drop the deployment-less placeholder recorded when the key was created
290
+ lti_registrations.where(tool: tool.to_s, client_id: client_id, deployment_id: nil).delete_all if deployment_id
291
+ end
292
+ end
293
+
294
+ # Canvas creates LTI Registrations with lock_deploying on, which blocks
295
+ # installing by client_id (when lock_lti_registrations is enabled). Unlock
296
+ # for the duration of the block, then put the lock back as it was.
297
+ def _with_lti_registration_unlocked(ekey)
298
+ registration_id = ekey[:lti_registration_id]
299
+ return yield unless registration_id.present?
300
+
301
+ registration_url = "api/v1/accounts/self/lti_registrations/#{registration_id}"
302
+ registration = bearcat_client.get(registration_url)
303
+ # Inherited registrations can only be changed by their owning account
304
+ return yield unless registration[:lock_deploying] && !registration[:inherited]
305
+
306
+ bearcat_client.put(registration_url, { lock_deploying: false })
307
+ begin
308
+ yield
309
+ ensure
310
+ bearcat_client.put(registration_url, { lock_deploying: true })
311
+ end
312
+ end
313
+
284
314
  def _find_existing_installs(context, exists: nil, &matcher)
285
315
  ctype, cid = _parse_lti_context(context)
286
316
 
@@ -363,7 +393,7 @@ module PandaPal
363
393
  end
364
394
  end
365
395
 
366
- def lti_installations(context= :root_account)
396
+ def lti_installations(context= :org_account)
367
397
  _find_existing_installs(context)
368
398
  end
369
399
 
@@ -389,7 +419,7 @@ module PandaPal
389
419
  context_path = "#{context_name}s/#{context.canvas_id}"
390
420
  else
391
421
  placement ||= "account_navigation"
392
- context_path = "accounts/#{current_organization.canvas_account_id}"
422
+ context_path = "accounts/#{canvas_account_id}"
393
423
  end
394
424
 
395
425
  if %w[global account course user].include?(placement)
@@ -1,3 +1,3 @@
1
1
  module PandaPal
2
- VERSION = '5.19.0.beta2'
2
+ VERSION = '5.19.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panda_pal
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.19.0.beta2
4
+ version: 5.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure CustomDev