panda_pal 5.9.6 → 5.9.8.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/panda_pal/lti_v1_p3_controller.rb +10 -6
- data/app/models/panda_pal/session.rb +120 -2
- data/app/views/layouts/panda_pal/application.html.erb +4 -2
- data/lib/panda_pal/concerns/ability_helper.rb +34 -0
- data/lib/panda_pal/engine.rb +1 -0
- data/lib/panda_pal/version.rb +1 -1
- data/lib/panda_pal.rb +2 -0
- metadata +41 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d130670af8eb3c98ac19c8cf001e4fc69b09d4a0c2c2774537213a3b02f935d
|
4
|
+
data.tar.gz: f2294052c154c0aa7adb89ac5506c028822dc42c90e6167b77799ba9662468a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca636402af5eb76e8588a9815c3ccd6488096fb8a25f2097663386c2ab5181eb73668a97ffa108589f1760f5e1f7f44531f121f895f171b459fc54cd421e01a2
|
7
|
+
data.tar.gz: 975028818d776f606acd2a599e238229ba19292019549583b506b8a3c4bb930f61a44356a065dd52274eaa8dc5b53d7bf0112fbd53265d2a6b4bc1ddb671cf05
|
@@ -107,29 +107,33 @@ module PandaPal
|
|
107
107
|
login_redirects = params['lti_login_redirects'] || []
|
108
108
|
login_redirects << request.url
|
109
109
|
|
110
|
-
redir_url =
|
110
|
+
redir_url = apply_environment_to_url(v1p3_oidc_login_url)
|
111
111
|
|
112
|
-
if redir_url.present? && !login_redirects.include?(redir_url)
|
112
|
+
if redir_url.present? && redir_url != v1p3_oidc_login_url && !login_redirects.include?(redir_url)
|
113
113
|
@form_action = redir_url
|
114
114
|
@method = request.method.downcase
|
115
115
|
@form_data = (request.POST.presence || request.GET).merge({
|
116
116
|
lti_login_redirects: login_redirects,
|
117
|
-
})
|
117
|
+
}).with_indifferent_access
|
118
|
+
|
119
|
+
@form_data[:target_link_uri] = apply_environment_to_url(@form_data[:target_link_uri])
|
118
120
|
|
119
121
|
render action: :login
|
120
122
|
end
|
121
123
|
end
|
122
124
|
|
123
|
-
def
|
125
|
+
def apply_environment_to_url(url)
|
126
|
+
return url unless url.present?
|
127
|
+
|
124
128
|
if (canvas_env = params['canvas_environment']).present?
|
125
129
|
tdomain = PandaPal.lti_environments[:"#{canvas_env}_domain"]
|
126
130
|
|
127
131
|
if tdomain.present? && !request.url.include?(tdomain)
|
128
|
-
return
|
132
|
+
return url.gsub(PandaPal.lti_environments[:domain], tdomain)
|
129
133
|
end
|
130
134
|
end
|
131
135
|
|
132
|
-
|
136
|
+
url
|
133
137
|
end
|
134
138
|
|
135
139
|
private
|
@@ -6,15 +6,26 @@ module PandaPal
|
|
6
6
|
self.session_key ||= SecureRandom.urlsafe_base64(60)
|
7
7
|
end
|
8
8
|
|
9
|
+
def cache(key, &blk)
|
10
|
+
panda_pal_session[:cache] ||= {}
|
11
|
+
panda_pal_session[:cache][key] ||= blk.call
|
12
|
+
end
|
13
|
+
|
14
|
+
def launch_params
|
15
|
+
data[:launch_params] || {}
|
16
|
+
end
|
17
|
+
|
9
18
|
def lti_platform
|
10
19
|
return nil unless data[:lti_platform].present?
|
11
20
|
|
12
21
|
@lti_platform ||= Platform.from_serialized(data[:lti_platform])
|
13
22
|
end
|
14
23
|
|
15
|
-
def
|
16
|
-
launch_params
|
24
|
+
def lti_launch_placement
|
25
|
+
launch_params['https://www.instructure.com/placement'] || launch_params[:launch_type]
|
26
|
+
end
|
17
27
|
|
28
|
+
def custom_lti_params
|
18
29
|
# LT 1.3
|
19
30
|
custom_params = launch_params["https://purl.imsglobal.org/spec/lti/claim/custom"]
|
20
31
|
return custom_params if custom_params.present?
|
@@ -29,6 +40,113 @@ module PandaPal
|
|
29
40
|
custom_params.with_indifferent_access
|
30
41
|
end
|
31
42
|
|
43
|
+
def get_lti_cust_param(key)
|
44
|
+
nkey = key.to_s.gsub(/^custom_/, '')
|
45
|
+
|
46
|
+
launch_params.dig("https://purl.imsglobal.org/spec/lti/claim/custom", nkey) || launch_params[nkey] || launch_params["custom_#{nkey}"]
|
47
|
+
end
|
48
|
+
|
49
|
+
def canvas_role_labels
|
50
|
+
labels = get_lti_cust_param('custom_canvas_role')
|
51
|
+
labels.is_a?(String) ? labels.split(',') : []
|
52
|
+
end
|
53
|
+
|
54
|
+
def canvas_account_role_labels(account = 'self')
|
55
|
+
account = 'self' if account.to_s == "root"
|
56
|
+
account = account.canvas_id if account.respond_to?(:canvas_id)
|
57
|
+
|
58
|
+
if "::Admin".safe_constantize && ::Admin < ::ActiveRecord::Base
|
59
|
+
account = current_organization.canvas_account_id if account == 'self'
|
60
|
+
adm_query = ::Admin.where(canvas_account_id: account, workflow_state: "active")
|
61
|
+
adm_query.pluck(:role_name)
|
62
|
+
else
|
63
|
+
Rails.cache.fetch([self.class.name, "AccountAdminLinks", account, canvas_user_id], expires_in: 1.hour) do
|
64
|
+
admin_entries = canvas_sync_client.account_admins(account, user_id: [canvas_user_id])
|
65
|
+
admin_entries = admin_entries.select{|ent| ent[:workflow_state] == 'active' }
|
66
|
+
admin_entries.map{|ent| ent[:role] }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def lti_roles
|
72
|
+
@lti_roles ||= RoleStore.new(launch_params["https://purl.imsglobal.org/spec/lti/claim/roles"] || launch_params['ext_roles'] || '')
|
73
|
+
end
|
74
|
+
|
75
|
+
def canvas_site_admin?
|
76
|
+
lti_roles.system_roles.include?("sys_admin")
|
77
|
+
end
|
78
|
+
|
79
|
+
class RoleStore
|
80
|
+
ContextTypeURN = 'urn:lti:context-type:ims/lis/'.freeze
|
81
|
+
|
82
|
+
ROLE_TYPES = [
|
83
|
+
{ type: "system", urn: "urn:lti:sysrole:ims/lis/", url: "http://purl.imsglobal.org/vocab/lis/v2/system/person#" },
|
84
|
+
{ type: "institution", urn: "urn:lti:instrole:ims/lis/", url: "http://purl.imsglobal.org/vocab/lis/v2/institution/person#" },
|
85
|
+
{ type: "context", urn: "urn:lti:role:ims/lis/", url: "http://purl.imsglobal.org/vocab/lis/v2/membership#" },
|
86
|
+
]
|
87
|
+
|
88
|
+
attr_accessor :roles, :context_types, :other_roles
|
89
|
+
|
90
|
+
def initialize(roles = '')
|
91
|
+
roles = roles.split(',') if roles.is_a?(String)
|
92
|
+
@roles = roles || []
|
93
|
+
|
94
|
+
@context_types = []
|
95
|
+
@other_roles = []
|
96
|
+
@parsed_roles = HashWithIndifferentAccess.new
|
97
|
+
|
98
|
+
map_roles
|
99
|
+
end
|
100
|
+
|
101
|
+
def system_roles; @parsed_roles[:system] || []; end
|
102
|
+
def institution_roles; @parsed_roles[:institution] || []; end
|
103
|
+
def context_roles; @parsed_roles[:context] || []; end
|
104
|
+
|
105
|
+
def to_h
|
106
|
+
{
|
107
|
+
'roles' => roles,
|
108
|
+
'context_type' => context_types,
|
109
|
+
'system_roles' => system_roles,
|
110
|
+
'institution_roles' => institution_roles,
|
111
|
+
'context_roles' => context_roles
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
protected
|
116
|
+
|
117
|
+
def map_roles
|
118
|
+
roles.each do |role|
|
119
|
+
if role.downcase.include?(ContextTypeURN)
|
120
|
+
context_types << clean_role(ContextTypeURN, role)
|
121
|
+
elsif (simple_role, type = match_role(role)).present?
|
122
|
+
(@parsed_roles[type[:type]] ||= []) << simple_role
|
123
|
+
else
|
124
|
+
other_roles << role
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def match_role(role)
|
130
|
+
ROLE_TYPES.each do |rt|
|
131
|
+
# LIS V1
|
132
|
+
if role.downcase.start_with?(rt[:urn])
|
133
|
+
return clean_role(ContextTypeURN, role), rt
|
134
|
+
end
|
135
|
+
|
136
|
+
# LIS V2
|
137
|
+
if role.downcase.start_with?(rt[:url])
|
138
|
+
return role.split('#')[1].underscore, rt
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
nil
|
143
|
+
end
|
144
|
+
|
145
|
+
def clean_role(urn_prefix, role)
|
146
|
+
role.gsub(/#{Regexp.quote(urn_prefix)}/i, '').gsub('/', '').underscore
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
32
150
|
class DataSerializer
|
33
151
|
def self.load(str)
|
34
152
|
return {} unless str.present?
|
@@ -2,8 +2,10 @@
|
|
2
2
|
<html>
|
3
3
|
<head>
|
4
4
|
<title>PandaPal</title>
|
5
|
-
|
6
|
-
|
5
|
+
<% if defined? Sprockets%>
|
6
|
+
<%= stylesheet_link_tag "panda_pal/application", media: "all" %>
|
7
|
+
<%= javascript_include_tag "panda_pal/application" %>
|
8
|
+
<% end %>
|
7
9
|
<%= csrf_meta_tags %>
|
8
10
|
</head>
|
9
11
|
<body>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PandaPal::Concerns
|
4
|
+
module AbilityHelper
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# @return PandaPal::Session
|
8
|
+
def panda_pal_session
|
9
|
+
@panda_pal_session ||= begin
|
10
|
+
raise "Ability class needs to set @panda_pal_session or @controller to use this feature" unless @controller.present?
|
11
|
+
@controller.current_session
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def rails_session
|
16
|
+
@rails_session ||= begin
|
17
|
+
raise "Ability class needs to set @rails_session or @controller to use this feature" unless @controller.present?
|
18
|
+
@controller.session
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def is_lti_launch?
|
23
|
+
panda_pal_session.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def launch_params
|
27
|
+
@launch_params ||= panda_pal_session[:launch_params] || {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def canvas_site_admin?
|
31
|
+
panda_pal_session.canvas_site_admin?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/panda_pal/engine.rb
CHANGED
data/lib/panda_pal/version.rb
CHANGED
data/lib/panda_pal.rb
CHANGED
@@ -4,6 +4,8 @@ require 'panda_pal/helpers'
|
|
4
4
|
require 'oauth/request_proxy/rack_request'
|
5
5
|
require 'oauth/request_proxy/action_dispatch_request'
|
6
6
|
|
7
|
+
Dir[File.dirname(__FILE__) + "/panda_pal/concerns/**/*.rb"].each { |file| require file }
|
8
|
+
|
7
9
|
module PandaPal
|
8
10
|
class LtiNavigationInUse < StandardError;end
|
9
11
|
class NotMounted < StandardError;end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: panda_pal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.9.
|
4
|
+
version: 5.9.8.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Instructure CustomDev
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -282,7 +282,7 @@ dependencies:
|
|
282
282
|
- - '='
|
283
283
|
- !ruby/object:Gem::Version
|
284
284
|
version: 2.7.1
|
285
|
-
description:
|
285
|
+
description:
|
286
286
|
email:
|
287
287
|
- pseng@instructure.com
|
288
288
|
executables: []
|
@@ -333,6 +333,7 @@ files:
|
|
333
333
|
- db/migrate/20171205194657_remove_old_organization_settings.rb
|
334
334
|
- db/migrate/20220721095653_create_panda_pal_api_calls.rb
|
335
335
|
- lib/panda_pal.rb
|
336
|
+
- lib/panda_pal/concerns/ability_helper.rb
|
336
337
|
- lib/panda_pal/engine.rb
|
337
338
|
- lib/panda_pal/helpers.rb
|
338
339
|
- lib/panda_pal/helpers/console_helpers.rb
|
@@ -393,7 +394,7 @@ homepage: http://instructure.com
|
|
393
394
|
licenses:
|
394
395
|
- MIT
|
395
396
|
metadata: {}
|
396
|
-
post_install_message:
|
397
|
+
post_install_message:
|
397
398
|
rdoc_options: []
|
398
399
|
require_paths:
|
399
400
|
- lib
|
@@ -408,52 +409,52 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
408
409
|
- !ruby/object:Gem::Version
|
409
410
|
version: '0'
|
410
411
|
requirements: []
|
411
|
-
rubygems_version: 3.
|
412
|
-
signing_key:
|
412
|
+
rubygems_version: 3.5.4
|
413
|
+
signing_key:
|
413
414
|
specification_version: 4
|
414
415
|
summary: LTI mountable engine
|
415
416
|
test_files:
|
416
|
-
- spec/rails_helper.rb
|
417
|
-
- spec/models/panda_pal/api_call_spec.rb
|
418
|
-
- spec/models/panda_pal/organization_spec.rb
|
419
|
-
- spec/models/panda_pal/session_spec.rb
|
420
|
-
- spec/models/panda_pal/organization/settings_validation_spec.rb
|
421
|
-
- spec/models/panda_pal/organization/task_scheduling_spec.rb
|
422
417
|
- spec/controllers/panda_pal/api_call_controller_spec.rb
|
423
|
-
- spec/
|
424
|
-
- spec/dummy/db/schema.rb
|
425
|
-
- spec/dummy/public/422.html
|
426
|
-
- spec/dummy/public/favicon.ico
|
427
|
-
- spec/dummy/public/404.html
|
428
|
-
- spec/dummy/public/500.html
|
418
|
+
- spec/dummy/README.rdoc
|
429
419
|
- spec/dummy/Rakefile
|
430
|
-
- spec/dummy/app/
|
420
|
+
- spec/dummy/app/assets/javascripts/application.js
|
421
|
+
- spec/dummy/app/assets/stylesheets/application.css
|
431
422
|
- spec/dummy/app/controllers/application_controller.rb
|
432
423
|
- spec/dummy/app/helpers/application_helper.rb
|
433
|
-
- spec/dummy/app/
|
434
|
-
- spec/dummy/
|
435
|
-
- spec/dummy/
|
424
|
+
- spec/dummy/app/views/layouts/application.html.erb
|
425
|
+
- spec/dummy/bin/bundle
|
426
|
+
- spec/dummy/bin/rails
|
427
|
+
- spec/dummy/bin/rake
|
428
|
+
- spec/dummy/bin/setup
|
436
429
|
- spec/dummy/config/application.rb
|
437
|
-
- spec/dummy/config/initializers/session_store.rb
|
438
|
-
- spec/dummy/config/initializers/wrap_parameters.rb
|
439
|
-
- spec/dummy/config/initializers/inflections.rb
|
440
|
-
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
441
|
-
- spec/dummy/config/initializers/mime_types.rb
|
442
|
-
- spec/dummy/config/initializers/backtrace_silencers.rb
|
443
|
-
- spec/dummy/config/initializers/cookies_serializer.rb
|
444
|
-
- spec/dummy/config/environments/development.rb
|
445
|
-
- spec/dummy/config/environments/test.rb
|
446
|
-
- spec/dummy/config/environments/production.rb
|
447
|
-
- spec/dummy/config/database.yml
|
448
430
|
- spec/dummy/config/boot.rb
|
449
|
-
- spec/dummy/config/
|
431
|
+
- spec/dummy/config/database.yml
|
450
432
|
- spec/dummy/config/environment.rb
|
433
|
+
- spec/dummy/config/environments/development.rb
|
434
|
+
- spec/dummy/config/environments/production.rb
|
435
|
+
- spec/dummy/config/environments/test.rb
|
436
|
+
- spec/dummy/config/initializers/backtrace_silencers.rb
|
437
|
+
- spec/dummy/config/initializers/cookies_serializer.rb
|
438
|
+
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
439
|
+
- spec/dummy/config/initializers/inflections.rb
|
440
|
+
- spec/dummy/config/initializers/mime_types.rb
|
441
|
+
- spec/dummy/config/initializers/session_store.rb
|
442
|
+
- spec/dummy/config/initializers/wrap_parameters.rb
|
451
443
|
- spec/dummy/config/locales/en.yml
|
452
|
-
- spec/dummy/
|
444
|
+
- spec/dummy/config/routes.rb
|
445
|
+
- spec/dummy/config/secrets.yml
|
453
446
|
- spec/dummy/config.ru
|
454
|
-
- spec/dummy/
|
455
|
-
- spec/dummy/
|
456
|
-
- spec/dummy/
|
457
|
-
- spec/dummy/
|
447
|
+
- spec/dummy/db/schema.rb
|
448
|
+
- spec/dummy/public/404.html
|
449
|
+
- spec/dummy/public/422.html
|
450
|
+
- spec/dummy/public/500.html
|
451
|
+
- spec/dummy/public/favicon.ico
|
458
452
|
- spec/factories/panda_pal_organizations.rb
|
459
453
|
- spec/factories/panda_pal_sessions.rb
|
454
|
+
- spec/models/panda_pal/api_call_spec.rb
|
455
|
+
- spec/models/panda_pal/organization/settings_validation_spec.rb
|
456
|
+
- spec/models/panda_pal/organization/task_scheduling_spec.rb
|
457
|
+
- spec/models/panda_pal/organization_spec.rb
|
458
|
+
- spec/models/panda_pal/session_spec.rb
|
459
|
+
- spec/rails_helper.rb
|
460
|
+
- spec/spec_helper.rb
|