lti2 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lti2/version.rb +1 -1
  3. data/lti2_tc/Gemfile +14 -0
  4. data/lti2_tc/Gemfile.lock +94 -0
  5. data/lti2_tc/MIT-LICENSE +20 -0
  6. data/lti2_tc/README.rdoc +3 -0
  7. data/lti2_tc/Rakefile +34 -0
  8. data/lti2_tc/app/assets/javascripts/lti2_tc/application.js +13 -0
  9. data/lti2_tc/app/assets/stylesheets/lti2_tc/application.css +13 -0
  10. data/lti2_tc/app/controllers/lti2_tc/application_controller.rb +13 -0
  11. data/lti2_tc/app/controllers/lti2_tc/deployment_requests_controller.rb +9 -0
  12. data/lti2_tc/app/controllers/lti2_tc/tool_consumer_profiles_controller.rb +23 -0
  13. data/lti2_tc/app/controllers/lti2_tc/tool_proxies_controller.rb +8 -0
  14. data/lti2_tc/app/controllers/lti2_tc/tool_settings_controller.rb +215 -0
  15. data/lti2_tc/app/controllers/lti2_tc/tools_controller.rb +361 -0
  16. data/lti2_tc/app/models/lti2_tc/deployment_request.rb +43 -0
  17. data/lti2_tc/app/models/lti2_tc/link.rb +24 -0
  18. data/lti2_tc/app/models/lti2_tc/registry.rb +4 -0
  19. data/lti2_tc/app/models/lti2_tc/resource.rb +6 -0
  20. data/lti2_tc/app/models/lti2_tc/tool.rb +12 -0
  21. data/lti2_tc/app/models/lti2_tc/tool_consumer_profile.rb +4 -0
  22. data/lti2_tc/app/models/lti2_tc/tool_consumer_registry.rb +24 -0
  23. data/lti2_tc/app/models/lti2_tc/tool_registration.rb +83 -0
  24. data/lti2_tc/app/models/lti2_tc/tool_setting.rb +61 -0
  25. data/lti2_tc/app/services/lti2_tc/authorizer.rb +36 -0
  26. data/lti2_tc/app/services/lti2_tc/lti2_launch.rb +259 -0
  27. data/lti2_tc/app/views/layouts/lti2_tc/application.html.erb +14 -0
  28. data/lti2_tc/app/views/lti2_tc/deployment_requests/show.html.erb +2 -0
  29. data/lti2_tc/app/views/lti2_tc/tool_consumer_profiles/index.html.erb +2 -0
  30. data/lti2_tc/app/views/lti2_tc/tool_consumer_profiles/show.html.erb +2 -0
  31. data/lti2_tc/app/views/lti2_tc/tool_proxies_controller/index.html.erb +2 -0
  32. data/lti2_tc/app/views/lti2_tc/tool_settings_controller/show.html.erb +2 -0
  33. data/lti2_tc/app/views/lti2_tc/tool_settings_controller/update.html.erb +2 -0
  34. data/lti2_tc/app/views/lti2_tc/tools_controller/create.html.erb +2 -0
  35. data/lti2_tc/app/views/lti2_tc/tools_controller/show.html.erb +2 -0
  36. data/lti2_tc/bin/rails +8 -0
  37. data/lti2_tc/config/routes.rb +20 -0
  38. data/lti2_tc/db/migrate/20140826141858_create_lti2_tool_consumer_tables.rb +94 -0
  39. data/lti2_tc/db/migrate/20140826150753_create_lti2_tc_resources.rb +37 -0
  40. data/lti2_tc/db/migrate/20141027193548_insert_tool_guid.rb +5 -0
  41. data/lti2_tc/lib/lti2_tc.rb +4 -0
  42. data/lti2_tc/lib/lti2_tc/engine.rb +5 -0
  43. data/lti2_tc/lib/lti2_tc/version.rb +3 -0
  44. data/lti2_tc/lib/tasks/lti2_tc_tasks.rake +4 -0
  45. data/lti2_tc/lti2_tc.gemspec +27 -0
  46. data/lti2_tc/test/controllers/lti2_tc/deployment_requests_controller_test.rb +11 -0
  47. data/lti2_tc/test/controllers/lti2_tc/tool_consumer_profiles_controller_test.rb +16 -0
  48. data/lti2_tc/test/controllers/lti2_tc/tool_proxies_controller_controller_test.rb +11 -0
  49. data/lti2_tc/test/controllers/lti2_tc/tool_settings_controller_controller_test.rb +16 -0
  50. data/lti2_tc/test/controllers/lti2_tc/tools_controller_controller_test.rb +16 -0
  51. data/lti2_tc/test/dummy/README.rdoc +28 -0
  52. data/lti2_tc/test/dummy/Rakefile +6 -0
  53. data/lti2_tc/test/dummy/app/assets/javascripts/application.js +13 -0
  54. data/lti2_tc/test/dummy/app/assets/stylesheets/application.css +13 -0
  55. data/lti2_tc/test/dummy/app/controllers/application_controller.rb +5 -0
  56. data/lti2_tc/test/dummy/app/helpers/application_helper.rb +2 -0
  57. data/lti2_tc/test/dummy/app/views/layouts/application.html.erb +14 -0
  58. data/lti2_tc/test/dummy/bin/bundle +3 -0
  59. data/lti2_tc/test/dummy/bin/rails +4 -0
  60. data/lti2_tc/test/dummy/bin/rake +4 -0
  61. data/lti2_tc/test/dummy/config.ru +4 -0
  62. data/lti2_tc/test/dummy/config/application.rb +23 -0
  63. data/lti2_tc/test/dummy/config/boot.rb +5 -0
  64. data/lti2_tc/test/dummy/config/database.yml +39 -0
  65. data/lti2_tc/test/dummy/config/environment.rb +5 -0
  66. data/lti2_tc/test/dummy/config/environments/development.rb +29 -0
  67. data/lti2_tc/test/dummy/config/environments/production.rb +80 -0
  68. data/lti2_tc/test/dummy/config/environments/test.rb +36 -0
  69. data/lti2_tc/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  70. data/lti2_tc/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  71. data/lti2_tc/test/dummy/config/initializers/inflections.rb +16 -0
  72. data/lti2_tc/test/dummy/config/initializers/mime_types.rb +5 -0
  73. data/lti2_tc/test/dummy/config/initializers/secret_token.rb +12 -0
  74. data/lti2_tc/test/dummy/config/initializers/session_store.rb +3 -0
  75. data/lti2_tc/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  76. data/lti2_tc/test/dummy/config/locales/en.yml +23 -0
  77. data/lti2_tc/test/dummy/config/routes.rb +4 -0
  78. data/lti2_tc/test/dummy/db/database.yml +39 -0
  79. data/lti2_tc/test/dummy/db/migrate/20131121225051_create_lti2_tc_registries.lti2_tc.rb +55 -0
  80. data/lti2_tc/test/dummy/db/schema.rb +68 -0
  81. data/lti2_tc/test/dummy/public/404.html +58 -0
  82. data/lti2_tc/test/dummy/public/422.html +58 -0
  83. data/lti2_tc/test/dummy/public/500.html +57 -0
  84. data/lti2_tc/test/dummy/public/favicon.ico +0 -0
  85. data/lti2_tc/test/fixtures/lti2_tc/registries.yml +7 -0
  86. data/lti2_tc/test/helpers/lti2_tc/deployment_requests_helper_test.rb +6 -0
  87. data/lti2_tc/test/helpers/lti2_tc/tool_consumer_profiles_helper_test.rb +6 -0
  88. data/lti2_tc/test/helpers/lti2_tc/tool_proxies_controller_helper_test.rb +6 -0
  89. data/lti2_tc/test/helpers/lti2_tc/tool_settings_controller_helper_test.rb +6 -0
  90. data/lti2_tc/test/helpers/lti2_tc/tools_controller_helper_test.rb +6 -0
  91. data/lti2_tc/test/integration/navigation_test.rb +10 -0
  92. data/lti2_tc/test/lti2_tc_test.rb +7 -0
  93. data/lti2_tc/test/models/lti2_tc/registries_test.rb +9 -0
  94. data/lti2_tc/test/test_helper.rb +15 -0
  95. metadata +93 -1
@@ -0,0 +1,4 @@
1
+ module Lti2Tc
2
+ class ToolConsumerProfile < ActiveRecord::Base
3
+ end
4
+ end
@@ -0,0 +1,24 @@
1
+ module Lti2Tc
2
+ class ToolConsumerRegistry
3
+
4
+ attr_reader :tool_consumer_profile, :tc_deployment_url, :relaxed_oauth_check, :result_template,
5
+ :tool_consumer_name, :registry, :tool_consumer_profile_wrapper
6
+
7
+ def initialize
8
+ registry_entries = Registry.all
9
+ @registry = {}
10
+ registry_entries.each { |entry| @registry[entry.name] = entry.content unless entry.name == 'content' }
11
+
12
+ @tc_deployment_url = registry['tc_deployment_url']
13
+ @relaxed_oauth_check = registry['relaxed_oauth_check']
14
+ @result_template = registry['result_template']
15
+ @tool_consumer_name = registry['tool_consumer_name']
16
+
17
+ # gets tcp root and returns as a json_object (optimizes successive accesses to tcp)
18
+ tcp = Lti2Commons::JsonWrapper.new registry['tool_consumer_profile_template']
19
+ tcp.substitute_text_in_all_nodes '{', '}', registry
20
+ @tool_consumer_profile_wrapper = tcp
21
+ @tool_consumer_profile = tcp.root
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,83 @@
1
+ module Lti2Tc
2
+ class ToolRegistration
3
+ def self.remap_tool_consumer_profile( tool_consumer_profile_wrapper, tc_profile_guid )
4
+ tool_consumer_profile_wrapper.substitute_text_in_all_nodes(
5
+ '{', '}', { 'tool_consumer_profile_guid' => tc_profile_guid }
6
+ )
7
+ tool_consumer_profile_wrapper.root['guid'] = tc_profile_guid
8
+ JSON.pretty_generate( tool_consumer_profile_wrapper.root )
9
+ end
10
+
11
+ def self.register_tool( user, deployment_request, tool_consumer_profile_wrapper, tc_deployment_url )
12
+ unless deployment_request.status == 'prepared'
13
+ if deployment_request.status == 'submitted'
14
+ raise 'This deployment request has already been send to the Tool Provider'
15
+ elsif deployment_request.status == 'registered'
16
+ raise 'This deployment request has already been provisioned. Consider a Reregistration request.'
17
+ else
18
+ raise 'Invalid status for deployment request'
19
+ end
20
+ end
21
+ deployment_request.status = 'submitted'
22
+ deployment_request.save
23
+
24
+ tool_consumer_profile = Lti2Tc::ToolConsumerProfile.new
25
+ tool_consumer_profile.tc_profile = remap_tool_consumer_profile(
26
+ tool_consumer_profile_wrapper, deployment_request.tc_profile_guid
27
+ )
28
+ tool_consumer_profile.tc_profile_guid = deployment_request.tc_profile_guid
29
+ tool_consumer_profile.save
30
+
31
+ html_body = deployment_request.create_lti_message( tc_deployment_url, user.id )
32
+
33
+ html_body
34
+ end
35
+
36
+ def self.reregister_tool( user, deployment_request, tool, tool_consumer_profile,
37
+ tool_consumer_profile_wrapper, tc_deployment_url, launch_presentation_return_url )
38
+
39
+ tool_proxy = tool.get_tool_proxy
40
+ tp_base_url = tool_proxy.select('tool_profile.base_url_choice',
41
+ "selector.applies_to", "MessageHandler", 'default_base_url')
42
+ singleton_messages = tool_proxy.first_at( 'tool_profile.message' )
43
+ service_endpoint = nil
44
+ singleton_messages.each { |singleton_message|
45
+ message_types = singleton_message['message_type']
46
+ if message_types.include? 'ToolProxyReregistrationRequest'
47
+ service_endpoint = singleton_message['path']
48
+ break
49
+ end
50
+ }
51
+ raise 'No message handler found for ToolProxyRegistrationRequest' unless service_endpoint
52
+
53
+ # deployment_request = DeploymentRequest.new
54
+ deployment_request.status = 'reregistering'
55
+ deployment_request.save
56
+
57
+ # tool_consumer_profile = ToolConsumerProfile.new
58
+ current_tcp = Lti2Tc::ToolConsumerProfile.where(:tc_profile_guid => deployment_request.tc_profile_guid).first
59
+ tool_consumer_profile = current_tcp if current_tcp.present?
60
+ tool_consumer_profile.tc_profile = remap_tool_consumer_profile(
61
+ tool_consumer_profile_wrapper, deployment_request.tc_profile_guid
62
+ )
63
+ tool_consumer_profile.tc_profile_guid = deployment_request.tc_profile_guid
64
+ tool_consumer_profile.save
65
+
66
+ # convert parameters
67
+ parameters = {}
68
+ tc_base_url = tc_deployment_url
69
+ parameters['tc_profile_url'] = "#{tc_base_url}/lti2_tc/tool_consumer_profiles/#{tool_consumer_profile.tc_profile_guid}"
70
+ parameters['launch_presentation_return_url'] = launch_presentation_return_url
71
+ parameters['lti_message_type'] = 'ToolProxyReregistrationRequest'
72
+
73
+ key = tool_proxy.first_at( 'tool_proxy_guid' )
74
+ secret = tool_proxy.first_at( 'security_contract.shared_secret' )
75
+
76
+ signed_request = Signer::create_signed_request( service_endpoint, 'post', key, secret, parameters )
77
+ puts "TC Signed Request: #{signed_request.signature_base_string}"
78
+ body = MessageSupport::create_lti_message_body( service_endpoint, parameters,
79
+ Rails.application.config.wire_log, 'Reregister Tool' )
80
+ body
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,61 @@
1
+ module Lti2Tc
2
+ class ToolSetting < ActiveRecord::Base
3
+ belongs_to :scopeable, :polymorphic => true
4
+
5
+ COLLECTION_TYPES = [ :Tool, :Context, :Ltilink ]
6
+
7
+ def self.collection_index( collection_type )
8
+ COLLECTION_TYPES.find_index( collection_type.to_sym )
9
+ end
10
+
11
+ def self.create_uri( tool_id, scopeable_type, scopeable_id=nil )
12
+ tool_consumer_registry = Rails.application.config.tool_consumer_registry
13
+ result = "#{tool_consumer_registry.tc_deployment_url}/lti2_tc/tool_settings/#{tool_id}"
14
+ if scopeable_type == 'Context'
15
+ result << "/context/#{scopeable_id}"
16
+ elsif scopeable_type == 'Ltilink'
17
+ result << "/ltilink/#{scopeable_id}"
18
+ end
19
+ result
20
+ end
21
+
22
+ def self.create_reachable_uris( tool_id, scopeable_type, scopeable_id=nil )
23
+ result = {}
24
+ start_index = self.collection_index( scopeable_type )
25
+ (start_index...0).each do |index|
26
+ case index
27
+ when 0
28
+ result[:Tool] = self.create_uri( tool_id, 'Tool' )
29
+ when 1
30
+ result[:Context] = self.create_uri( tool_id, 'Context', scopeable_id )
31
+ when 2
32
+ result[:Ltilink] = self.create_uri( tool_id, 'Ltilink', scopeable_id )
33
+ link = Lti2Tc::Link.find( scopeable_id )
34
+ # for next iteration
35
+ scopeable_id = link.course.id
36
+ end
37
+ end
38
+ result
39
+ end
40
+
41
+ def self.parse_uri( path )
42
+ m = /^\/lti2_tc\/tool_settings\/(.*)\/context\/(.*)$/.match(path)
43
+ if m.present?
44
+ return [ 'Context', m[1], m[2].to_i ]
45
+ end
46
+ m = /^\/lti2_tc\/tool_settings\/(.*)\/ltilink\/(.*)$/.match(path)
47
+ if m.present?
48
+ return [ 'Ltilink', m[1], m[2].to_i ]
49
+ end
50
+ m = /^\/lti2_tc\/tool_settings\/(.*)$/.match(path)
51
+ if m.present?
52
+ return [ 'Tool', m[1], nil ]
53
+ end
54
+ return [ nil, nil, nil ]
55
+ end
56
+
57
+ def to_uri
58
+ ToolSetting.create_uri( self.tool_id, self.scopeable_type, self.scopeable_id )
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,36 @@
1
+ include Lti2Commons
2
+ include Signer
3
+ include MessageSupport
4
+ include OAuth::OAuthProxy
5
+
6
+ module Lti2Tc
7
+ class Authorizer
8
+ def self.pre_process_tenant request
9
+ rack_parameters = OAuthRequest.collect_rack_parameters request
10
+ key = rack_parameters[:oauth_consumer_key]
11
+ @tool = Lti2Tc::Tool.where( :key => key ).first
12
+ secret = @tool.secret
13
+ self.validate( request, secret )
14
+ end
15
+
16
+ def self.validate( request, secret )
17
+ # OAuth check here
18
+ tool_consumer_registry = Rails.application.config.tool_consumer_registry
19
+ unless tool_consumer_registry.relaxed_oauth_check == 'true'
20
+ request_wrapper = OAuthRequest.create_from_rack_request( request )
21
+ begin
22
+ request_wrapper.verify_signature?( secret, Rails.application.config.nonce_cache, false )
23
+ @oauth_error = false
24
+ return
25
+ rescue
26
+ # puts "Secret: #{secret}"
27
+ puts "TP Signed Request: #{request_wrapper.signature_base_string}"
28
+ @oauth_error = true
29
+ end
30
+
31
+ puts "request_wrapper: #{request_wrapper.request['parameters'].inspect}"
32
+ end
33
+ @oauth_error
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,259 @@
1
+ module Lti2Tc
2
+
3
+ class Lti2Launch
4
+
5
+ def initialize( user, link, resource, course, enrollment, return_url, &substitute_final )
6
+ @user = user
7
+ @link = link
8
+ @resource = resource
9
+ @course = course
10
+ @enrollment = enrollment
11
+ @return_url = return_url
12
+ @tool_proxy = resource.tool.get_tool_proxy
13
+ @substitute_final = substitute_final
14
+ end
15
+
16
+ def launch( open_in_external_window=true )
17
+ tool = @resource.tool
18
+ tool_name = @tool_proxy.first_at('tool_profile.product_instance.product_info.product_name.default_value')
19
+ raise "Tool #{tool_name} is currently disabled" unless tool.is_enabled
20
+
21
+ base_url = @tool_proxy.select('tool_profile.base_url_choice', 'selector.applies_to',
22
+ 'MessageHandler', 'default_base_url' )
23
+ resource_type = @resource.resource_type
24
+ resource_handler_node = @tool_proxy.search( 'tool_profile.resource_handler',
25
+ { 'resource_type' => { 'code' => resource_type } }, '@' )
26
+ resource_handler = JsonWrapper.new resource_handler_node
27
+ message = resource_handler.search( '@..message', { 'message_type' => 'basic-lti-launch-request' }, '@' )
28
+ path = message['path']
29
+ m = /(.*)\?(.*)/.match( path )
30
+ if m.present?
31
+ final_qs = '?'
32
+ parmstr = CGI.unescapeHTML( m[2] )
33
+ parm_hash = Rack::Utils::parse_query( parmstr )
34
+ parm_hash.each_pair do |k,v|
35
+ final_qs += "#{k}="
36
+ final_qs += Rack::Utils.escape( v )
37
+ final_qs += '&'
38
+ end
39
+ # conformance issue: remove trailing ampersand
40
+ final_qs = final_qs[0..final_qs.length-2] if final_qs[-1] == '&'
41
+ final_path = m[1] + final_qs
42
+ else
43
+ final_path = path
44
+ end
45
+
46
+ tp_parameters = message['parameter']
47
+ service_endpoint = base_url + final_path
48
+
49
+ if @enrollment
50
+ role = @enrollment.role
51
+ else
52
+ role = @user.role
53
+ end
54
+
55
+ tool_consumer_registry = Rails.application.config.tool_consumer_registry
56
+ tcp_wrapper = tool_consumer_registry.tool_consumer_profile_wrapper
57
+ parameters = {
58
+ 'lti_version' => @tool_proxy.first_at('lti_version'),
59
+ 'lti_message_type' => 'basic-lti-launch-request',
60
+ 'resource_link_id' => @link.id.to_s,
61
+ 'user_id' => @user.id.to_s,
62
+ 'roles' => role,
63
+ 'launch_presentation_return_url' => "#{tool_consumer_registry.tc_deployment_url}#{@return_url}",
64
+ 'launch_presentation_document_target' => 'window',
65
+
66
+ # optional
67
+ 'context_id' => @course.id.to_s,
68
+ 'launch_presentation_locale' => 'en_US',
69
+
70
+ # for conformance
71
+ 'context_label' => @course.course_label,
72
+ 'context_title' => @course.course_title,
73
+ 'lis_course_section_sourcedid' => @course.id.to_s,
74
+ 'tool_consumer_info_product_family_code' => "#{tcp_wrapper.first_at("product_instance.product_info.product_family.code")}",
75
+ 'tool_consumer_info_version' => "#{tcp_wrapper.first_at("product_instance.product_info.product_version")}",
76
+ }
77
+
78
+ if @link.is_name_permission
79
+ parameters['lis_person_sourcedid'] = @user.id.to_s
80
+ parameters['lis_person_name_given'] = @user.first_name
81
+ parameters['lis_person_name_family'] = @user.last_name
82
+ parameters['lis_person_name_full'] = "#{@user.first_name} #{@user.last_name}"
83
+ end
84
+
85
+ if @link.is_email_permission
86
+ parameters['lis_person_contact_email_primary'] = @user.email
87
+ end
88
+
89
+ if role =~ /Mentor$/
90
+ parameters['role_scope_mentor'] = url_encode_users(@user.mentor)
91
+ end
92
+
93
+ # add parameters from ToolProxy
94
+ for parameter in tp_parameters
95
+ name = parameter['name']
96
+ if parameter.has_key? 'fixed'
97
+ value = parameter['fixed']
98
+ elsif parameter.has_key? 'variable'
99
+ value = parameter['variable']
100
+ else
101
+ value = '[link-to-resolve]'
102
+ end
103
+ parameters[name] = value
104
+ end
105
+
106
+ # add parameters from Link
107
+ link_parameter_json = @link.link_parameters
108
+ if link_parameter_json
109
+ link_parameters = JSON.parse( link_parameter_json )
110
+ parameters.merge!( link_parameters )
111
+ end
112
+
113
+ # add parameters from Settings levels
114
+ settings = Lti2Tc::ToolSetting.where( :tool_id => tool.id, :scopeable_type => 'Tool' )
115
+ settings.each { |setting| parameters[setting.name] = setting.value }
116
+
117
+ settings = Lti2Tc::ToolSetting.where( :tool_id => tool.id, :scopeable_id => @course.id, :scopeable_type => 'Context' )
118
+ settings.each { |setting| parameters[setting.name] = setting.value }
119
+
120
+ settings = Lti2Tc::ToolSetting.where( :tool_id => tool.id, :scopeable_id => @link.id, :scopeable_type => 'Ltilink' )
121
+ settings.each { |setting| parameters[setting.name] = setting.value }
122
+
123
+ # auto-create result (if required) and add to reference to parameters
124
+ capabilities = resource_handler.first_at('message[0].enabled_capability')
125
+ if capabilities and capabilities.include? 'Result.autocreate'
126
+ if @link.grade_item_id
127
+ grade_result = GradeResult.where( :link_id => @link.id, :admin_user_id => @user.id ).first
128
+ # TEST ONLY
129
+ # grade_result.delete if grade_result
130
+ # grade_result = nil
131
+
132
+ unless grade_result
133
+ grade_result = GradeResult.new
134
+ grade_result.link_id = @link.id
135
+ grade_result.admin_user_id = @user.id
136
+ grade_result.save
137
+ else
138
+ # note that a nil grade_result still let's us through
139
+ unless grade_result.result.nil?
140
+ raise 'Grade result associated with this tool launch has already been filled in'
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ # perform variable substitution on all parameters
147
+ resolver = Lti2Commons::SubstitutionSupport::Resolver.new
148
+ resolver.add_resolver( 'User', @user.method(:user_resolver) )
149
+ resolver.add_resolver( 'Person', @user.method(:person_resolver) )
150
+ # now already resolved
151
+ #@course = Course.find( parameters['context_id'] )
152
+ resolver.add_resolver( 'CourseOffering', @course.method(:course_resolver) )
153
+ resolver.add_resolver( 'Result', grade_result.method(:grade_result_resolver) ) if grade_result
154
+
155
+ # This one is a bit deceptive. A TCP is usually associated with a @tool_proxy.
156
+ resolver.add_resolver( 'ToolConsumerProfile', self.method(:tool_consumer_profile_resolver) )
157
+
158
+ # Settings resolvers
159
+ resolver.add_resolver( 'ToolProxy', self.method(:tool_proxy_resolver) )
160
+ resolver.add_resolver( 'ToolProxyBinding', self.method(:tool_proxy_binding_resolver) )
161
+ resolver.add_resolver( 'LtiLink', self.method(:lti_link_resolver) )
162
+
163
+ # and resolve and normalize
164
+ final_parameters = {}
165
+ parameters.each { |k,v|
166
+ resolved_value = resolver.resolve( v )
167
+ if known_lti2_parameters.include? k or deprecated_lti_parameters.include? k
168
+ final_parameters[k] = resolved_value
169
+ else
170
+ name = 'custom_' + k
171
+ lti1_name = slugify( name )
172
+ unless name == lti1_name
173
+ final_parameters[lti1_name] = resolved_value
174
+ end
175
+ final_parameters[name] = resolved_value
176
+ end
177
+
178
+ }
179
+
180
+ subst_final_map = @substitute_final.nil? ? final_parameters : @substitute_final.call( final_parameters )
181
+
182
+ key = @resource.tool.key
183
+ secret = @resource.tool.secret
184
+
185
+ signed_request = Signer::create_signed_request( service_endpoint, 'post', key, secret, subst_final_map )
186
+ puts "TC Signed Request: #{signed_request.signature_base_string}"
187
+ puts "before"
188
+ puts Rails.application.config.wire_log.inspect
189
+ puts "after"
190
+ body = MessageSupport::create_lti_message_body( service_endpoint, subst_final_map,
191
+ Rails.application.config.wire_log, 'Lti Launch', open_in_external_window )
192
+ puts body
193
+ body
194
+ end
195
+
196
+ def deprecated_lti_parameters
197
+ [ 'context_title', 'context_label', 'resource_link_title', 'resource_link_description',
198
+ 'lis_person_name_given', 'lis_person_name_family', 'lis_person_name_full', 'lis_person_contact_email_primary',
199
+ 'user_image', 'lis_person_sourcedid', 'lis_course_offering_sourcedid', 'lis_course_section_sourcedid',
200
+ 'tool_consumer_info_product_family_code', 'tool_consumer_info_version',
201
+ 'tool_consumer_instance_name', 'tool_consumer_instance_description', 'tool_consumer_instance_url',
202
+ 'tool_consumer_instance_contact_email' ]
203
+ end
204
+
205
+ def known_lti2_parameters
206
+ [ 'lti_message_type', 'lti_version', 'user_id', 'roles', 'resource_link_id',
207
+ 'context_id', 'context_type',
208
+ 'launch_presentation_locale', 'launch_presentation_document_target', 'launch_presentation_css_url',
209
+ 'launch_presentation_width', 'launch_presentation_height', 'launch_presentation_return_url',
210
+ 'role_scope_mentor' ]
211
+ end
212
+
213
+
214
+ def tool_consumer_profile_resolver( fieldname )
215
+ if fieldname == 'url'
216
+ @tool_proxy.first_at('tool_consumer_profile')
217
+ end
218
+ end
219
+
220
+ def tool_proxy_resolver( fieldname )
221
+ if fieldname == 'custom.url'
222
+ tool_guid = @resource.tool.key
223
+ ToolSetting.create_uri( tool_guid, 'Tool' )
224
+ end
225
+ end
226
+
227
+ def tool_proxy_binding_resolver( fieldname )
228
+ if fieldname == 'custom.url'
229
+ tool_guid = @resource.tool.key
230
+ ToolSetting.create_uri( tool_guid, 'Context', @course.id )
231
+ end
232
+ end
233
+
234
+ def lti_link_resolver( fieldname )
235
+ if fieldname == 'custom.url'
236
+ tool_guid = @resource.tool.key
237
+ ToolSetting.create_uri( tool_guid, 'Ltilink', @link.id )
238
+ end
239
+ end
240
+
241
+ def slugify name
242
+ result = ''
243
+ name.each_char { |c|
244
+ result << (c =~ /\w/ ? c.downcase : '_')
245
+ }
246
+ result
247
+ end
248
+
249
+ def url_encode_users( user_list_str )
250
+ user_list = []
251
+ unless user_list_str.nil?
252
+ users = user_list_str.split(',')
253
+ users.each { |user| user_list << URI.encode( user ) }
254
+ end
255
+ user_list.join(',')
256
+ end
257
+
258
+ end
259
+ end