ims-lti 1.2.9 → 2.0.0.beta.1
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 +5 -5
- data/Changelog.txt +0 -0
- data/LICENSE.txt +22 -0
- data/README.md +15 -116
- data/lib/ims/lti/converters/time_json_converter.rb +13 -0
- data/lib/ims/lti/converters.rb +5 -0
- data/lib/ims/lti/models/base_url_choice.rb +15 -0
- data/lib/ims/lti/models/base_url_selector.rb +5 -0
- data/lib/ims/lti/models/contact.rb +5 -0
- data/lib/ims/lti/models/icon_endpoint.rb +5 -0
- data/lib/ims/lti/models/icon_info.rb +6 -0
- data/lib/ims/lti/models/localized_name.rb +11 -0
- data/lib/ims/lti/models/localized_text.rb +11 -0
- data/lib/ims/lti/models/lti_model.rb +169 -0
- data/lib/ims/lti/models/message_handler.rb +6 -0
- data/lib/ims/lti/models/messages/basic_lti_launch_request.rb +8 -0
- data/lib/ims/lti/models/messages/message.rb +43 -0
- data/lib/ims/lti/models/messages/registration_request.rb +17 -0
- data/lib/ims/lti/models/messages.rb +6 -0
- data/lib/ims/lti/models/parameter.rb +5 -0
- data/lib/ims/lti/models/product_family.rb +8 -0
- data/lib/ims/lti/models/product_info.rb +19 -0
- data/lib/ims/lti/models/product_instance.rb +10 -0
- data/lib/ims/lti/models/resource_handler.rb +18 -0
- data/lib/ims/lti/models/resource_type.rb +6 -0
- data/lib/ims/lti/models/rest_service.rb +14 -0
- data/lib/ims/lti/models/rest_service_profile.rb +7 -0
- data/lib/ims/lti/models/security_contract.rb +9 -0
- data/lib/ims/lti/models/service_owner.rb +8 -0
- data/lib/ims/lti/models/service_provider.rb +11 -0
- data/lib/ims/lti/models/tool_consumer_profile.rb +20 -0
- data/lib/ims/lti/models/tool_profile.rb +22 -0
- data/lib/ims/lti/models/tool_proxy.rb +11 -0
- data/lib/ims/lti/models/vendor.rb +28 -0
- data/lib/ims/lti/models.rb +29 -0
- data/lib/ims/lti/services/message_service.rb +40 -0
- data/lib/ims/lti/services.rb +5 -0
- data/lib/ims/lti/version.rb +1 -1
- data/lib/ims/lti.rb +6 -64
- data/lib/ims.rb +3 -1
- metadata +57 -50
- data/Changelog +0 -76
- data/LICENSE +0 -18
- data/lib/ims/lti/deprecated_role_checks.rb +0 -52
- data/lib/ims/lti/extensions/canvas.rb +0 -122
- data/lib/ims/lti/extensions/content.rb +0 -258
- data/lib/ims/lti/extensions/outcome_data.rb +0 -240
- data/lib/ims/lti/extensions.rb +0 -45
- data/lib/ims/lti/launch_params.rb +0 -166
- data/lib/ims/lti/outcome_request.rb +0 -225
- data/lib/ims/lti/outcome_response.rb +0 -166
- data/lib/ims/lti/request_validator.rb +0 -56
- data/lib/ims/lti/role_checks.rb +0 -101
- data/lib/ims/lti/tool_base.rb +0 -29
- data/lib/ims/lti/tool_config.rb +0 -231
- data/lib/ims/lti/tool_consumer.rb +0 -86
- data/lib/ims/lti/tool_provider.rb +0 -145
@@ -1,166 +0,0 @@
|
|
1
|
-
module IMS::LTI
|
2
|
-
# Mixin module for managing LTI Launch Data
|
3
|
-
#
|
4
|
-
# Launch data documentation:
|
5
|
-
# http://www.imsglobal.org/lti/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684
|
6
|
-
module LaunchParams
|
7
|
-
|
8
|
-
# List of the standard launch parameters for an LTI launch
|
9
|
-
LAUNCH_DATA_PARAMETERS = %w{
|
10
|
-
accept_media_types
|
11
|
-
accept_multiple
|
12
|
-
accept_presentation_document_targets
|
13
|
-
accept_unsigned
|
14
|
-
auto_create
|
15
|
-
content_item_return_url
|
16
|
-
context_id
|
17
|
-
context_label
|
18
|
-
context_title
|
19
|
-
context_type
|
20
|
-
launch_presentation_css_url
|
21
|
-
launch_presentation_document_target
|
22
|
-
launch_presentation_height
|
23
|
-
launch_presentation_locale
|
24
|
-
launch_presentation_return_url
|
25
|
-
launch_presentation_width
|
26
|
-
lis_course_offering_sourcedid
|
27
|
-
lis_course_section_sourcedid
|
28
|
-
lis_outcome_service_url
|
29
|
-
lis_person_contact_email_primary
|
30
|
-
lis_person_name_family
|
31
|
-
lis_person_name_full
|
32
|
-
lis_person_name_given
|
33
|
-
lis_person_sourcedid
|
34
|
-
lis_result_sourcedid
|
35
|
-
lti_message_type
|
36
|
-
lti_version
|
37
|
-
oauth_callback
|
38
|
-
oauth_consumer_key
|
39
|
-
oauth_nonce
|
40
|
-
oauth_signature
|
41
|
-
oauth_signature_method
|
42
|
-
oauth_timestamp
|
43
|
-
oauth_version
|
44
|
-
resource_link_description
|
45
|
-
resource_link_id
|
46
|
-
resource_link_title
|
47
|
-
roles
|
48
|
-
role_scope_mentor
|
49
|
-
tool_consumer_info_product_family_code
|
50
|
-
tool_consumer_info_version
|
51
|
-
tool_consumer_instance_contact_email
|
52
|
-
tool_consumer_instance_description
|
53
|
-
tool_consumer_instance_guid
|
54
|
-
tool_consumer_instance_name
|
55
|
-
tool_consumer_instance_url
|
56
|
-
user_id
|
57
|
-
user_image
|
58
|
-
}
|
59
|
-
|
60
|
-
LAUNCH_DATA_PARAMETERS.each { |p| attr_accessor p }
|
61
|
-
|
62
|
-
# Hash of custom parameters, the keys will be prepended with "custom_" at launch
|
63
|
-
attr_accessor :custom_params
|
64
|
-
|
65
|
-
# Hash of extension parameters, the keys will be prepended with "ext_" at launch
|
66
|
-
attr_accessor :ext_params
|
67
|
-
|
68
|
-
# Hash of parameters to add to the launch. These keys will not be prepended
|
69
|
-
# with any value at launch
|
70
|
-
attr_accessor :non_spec_params
|
71
|
-
|
72
|
-
# Set the roles for the current launch
|
73
|
-
#
|
74
|
-
# Full list of roles can be found here:
|
75
|
-
# http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649700
|
76
|
-
#
|
77
|
-
# LIS roles include:
|
78
|
-
# * Student
|
79
|
-
# * Faculty
|
80
|
-
# * Member
|
81
|
-
# * Learner
|
82
|
-
# * Instructor
|
83
|
-
# * Mentor
|
84
|
-
# * Staff
|
85
|
-
# * Alumni
|
86
|
-
# * ProspectiveStudent
|
87
|
-
# * Guest
|
88
|
-
# * Other
|
89
|
-
# * Administrator
|
90
|
-
# * Observer
|
91
|
-
# * None
|
92
|
-
#
|
93
|
-
# @param roles_list [String,Array] An Array or comma-separated String of roles
|
94
|
-
def roles=(roles_list)
|
95
|
-
if roles_list
|
96
|
-
if roles_list.is_a?(Array)
|
97
|
-
@roles = roles_list
|
98
|
-
else
|
99
|
-
@roles = roles_list.split(",")
|
100
|
-
end
|
101
|
-
else
|
102
|
-
@roles = nil
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def set_custom_param(key, val)
|
107
|
-
@custom_params[key] = val
|
108
|
-
end
|
109
|
-
|
110
|
-
def get_custom_param(key)
|
111
|
-
@custom_params[key]
|
112
|
-
end
|
113
|
-
|
114
|
-
def set_non_spec_param(key, val)
|
115
|
-
@non_spec_params[key] = val
|
116
|
-
end
|
117
|
-
|
118
|
-
def get_non_spec_param(key)
|
119
|
-
@non_spec_params[key]
|
120
|
-
end
|
121
|
-
|
122
|
-
def set_ext_param(key, val)
|
123
|
-
@ext_params[key] = val
|
124
|
-
end
|
125
|
-
|
126
|
-
def get_ext_param(key)
|
127
|
-
@ext_params[key]
|
128
|
-
end
|
129
|
-
|
130
|
-
# Create a new Hash with all launch data. Custom/Extension keys will have the
|
131
|
-
# appropriate value prepended to the keys and the roles are set as a comma
|
132
|
-
# separated String
|
133
|
-
def to_params
|
134
|
-
params = launch_data_hash.merge(add_key_prefix(@custom_params, 'custom')).merge(add_key_prefix(@ext_params, 'ext')).merge(@non_spec_params)
|
135
|
-
params["roles"] = @roles.join(",") if @roles
|
136
|
-
params
|
137
|
-
end
|
138
|
-
|
139
|
-
# Populates the launch data from a Hash
|
140
|
-
#
|
141
|
-
# Only keys in LAUNCH_DATA_PARAMETERS and that start with 'custom_' or 'ext_'
|
142
|
-
# will be pulled from the provided Hash
|
143
|
-
def process_params(params)
|
144
|
-
params.each_pair do |key, val|
|
145
|
-
if LAUNCH_DATA_PARAMETERS.member?(key)
|
146
|
-
self.send("#{key}=", val)
|
147
|
-
elsif key =~ /\Acustom_(.+)\Z/
|
148
|
-
@custom_params[$1] = val
|
149
|
-
elsif key =~ /\Aext_(.+)\Z/
|
150
|
-
@ext_params[$1] = val
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
|
157
|
-
def launch_data_hash
|
158
|
-
LAUNCH_DATA_PARAMETERS.inject({}) { |h, k| h[k] = self.send(k) if self.send(k); h }
|
159
|
-
end
|
160
|
-
|
161
|
-
def add_key_prefix(hash, prefix)
|
162
|
-
hash.keys.inject({}) { |h, k| h["#{prefix}_#{k}"] = hash[k]; h }
|
163
|
-
end
|
164
|
-
|
165
|
-
end
|
166
|
-
end
|
@@ -1,225 +0,0 @@
|
|
1
|
-
module IMS::LTI
|
2
|
-
# Class for consuming/generating LTI Outcome Requests
|
3
|
-
#
|
4
|
-
# Outcome Request documentation: http://www.imsglobal.org/lti/v1p1pd/ltiIMGv1p1pd.html#_Toc309649691
|
5
|
-
#
|
6
|
-
# This class can be used by both Tool Providers and Tool Consumers. Each will
|
7
|
-
# use it a bit differently. The Tool Provider will use it to POST an OAuth-signed
|
8
|
-
# request to a TC. A Tool Consumer will use it to parse such a request from a TP.
|
9
|
-
#
|
10
|
-
# === Tool Provider Usage
|
11
|
-
# An OutcomeRequest will generally be created through a configured ToolProvider
|
12
|
-
# object. See the ToolProvider documentation.
|
13
|
-
#
|
14
|
-
# === Tool Consumer Usage
|
15
|
-
# When an outcome request is sent from a TP the body of the request is XML.
|
16
|
-
# This class parses that XML and provides a simple interface for accessing the
|
17
|
-
# information in the request. Typical usage would be:
|
18
|
-
#
|
19
|
-
# # create an OutcomeRequest from the request object
|
20
|
-
# req = IMS::LTI::OutcomeRequest.from_post_request(request)
|
21
|
-
#
|
22
|
-
# # access the source id to identify the user who's grade you'd like to access
|
23
|
-
# req.lis_result_sourcedid
|
24
|
-
#
|
25
|
-
# # process the request
|
26
|
-
# if req.replace_request?
|
27
|
-
# # set a new score for the user
|
28
|
-
# elsif req.read_request?
|
29
|
-
# # return the score for the user
|
30
|
-
# elsif req.delete_request?
|
31
|
-
# # clear the score for the user
|
32
|
-
# else
|
33
|
-
# # return an unsupported OutcomeResponse
|
34
|
-
# end
|
35
|
-
class OutcomeRequest < ToolBase
|
36
|
-
include IMS::LTI::Extensions::Base
|
37
|
-
|
38
|
-
REPLACE_REQUEST = 'replaceResult'
|
39
|
-
DELETE_REQUEST = 'deleteResult'
|
40
|
-
READ_REQUEST = 'readResult'
|
41
|
-
|
42
|
-
attr_accessor :operation, :score, :outcome_response, :message_identifier,
|
43
|
-
:lis_outcome_service_url, :lis_result_sourcedid,
|
44
|
-
:consumer_key, :consumer_secret, :post_request
|
45
|
-
|
46
|
-
# Create a new OutcomeRequest
|
47
|
-
#
|
48
|
-
# @param opts [Hash] initialization hash
|
49
|
-
def initialize(opts={})
|
50
|
-
opts.each_pair do |key, val|
|
51
|
-
self.send("#{key}=", val) if self.respond_to?("#{key}=")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Convenience method for creating a new OutcomeRequest from a request object
|
56
|
-
#
|
57
|
-
# req = IMS::LTI::OutcomeRequest.from_post_request(request)
|
58
|
-
def self.from_post_request(post_request)
|
59
|
-
request = OutcomeRequest.new
|
60
|
-
request.process_post_request(post_request)
|
61
|
-
end
|
62
|
-
|
63
|
-
def process_post_request(post_request)
|
64
|
-
self.post_request = post_request
|
65
|
-
if post_request.body.respond_to?(:read)
|
66
|
-
xml = post_request.body.read
|
67
|
-
post_request.body.rewind
|
68
|
-
else
|
69
|
-
xml = post_request.body
|
70
|
-
end
|
71
|
-
self.process_xml(xml)
|
72
|
-
self
|
73
|
-
end
|
74
|
-
|
75
|
-
# POSTs the given score to the Tool Consumer with a replaceResult
|
76
|
-
#
|
77
|
-
# @return [OutcomeResponse] The response from the Tool Consumer
|
78
|
-
def post_replace_result!(score)
|
79
|
-
@operation = REPLACE_REQUEST
|
80
|
-
@score = score
|
81
|
-
post_outcome_request
|
82
|
-
end
|
83
|
-
|
84
|
-
# POSTs a deleteResult to the Tool Consumer
|
85
|
-
#
|
86
|
-
# @return [OutcomeResponse] The response from the Tool Consumer
|
87
|
-
def post_delete_result!
|
88
|
-
@operation = DELETE_REQUEST
|
89
|
-
post_outcome_request
|
90
|
-
end
|
91
|
-
|
92
|
-
# POSTs a readResult to the Tool Consumer
|
93
|
-
#
|
94
|
-
# @return [OutcomeResponse] The response from the Tool Consumer
|
95
|
-
def post_read_result!
|
96
|
-
@operation = READ_REQUEST
|
97
|
-
post_outcome_request
|
98
|
-
end
|
99
|
-
|
100
|
-
# Check whether this request is a replaceResult request
|
101
|
-
def replace_request?
|
102
|
-
@operation == REPLACE_REQUEST
|
103
|
-
end
|
104
|
-
|
105
|
-
# Check whether this request is a deleteResult request
|
106
|
-
def delete_request?
|
107
|
-
@operation == DELETE_REQUEST
|
108
|
-
end
|
109
|
-
|
110
|
-
# Check whether this request is a readResult request
|
111
|
-
def read_request?
|
112
|
-
@operation == READ_REQUEST
|
113
|
-
end
|
114
|
-
|
115
|
-
# Check whether the last outcome POST was successful
|
116
|
-
def outcome_post_successful?
|
117
|
-
@outcome_response && @outcome_response.success?
|
118
|
-
end
|
119
|
-
|
120
|
-
# POST an OAuth signed request to the Tool Consumer
|
121
|
-
#
|
122
|
-
# @return [OutcomeResponse] The response from the Tool Consumer
|
123
|
-
def post_outcome_request
|
124
|
-
raise IMS::LTI::InvalidLTIConfigError, "" unless has_required_attributes?
|
125
|
-
|
126
|
-
res = post_service_request(@lis_outcome_service_url,
|
127
|
-
'application/xml',
|
128
|
-
generate_request_xml)
|
129
|
-
|
130
|
-
@outcome_response = extend_outcome_response(OutcomeResponse.new)
|
131
|
-
@outcome_response.process_post_response(res)
|
132
|
-
end
|
133
|
-
|
134
|
-
# Parse Outcome Request data from XML
|
135
|
-
def process_xml(xml)
|
136
|
-
doc = REXML::Document.new xml
|
137
|
-
@message_identifier = doc.text("//imsx_POXRequestHeaderInfo/imsx_messageIdentifier")
|
138
|
-
@lis_result_sourcedid = doc.text("//resultRecord/sourcedGUID/sourcedId")
|
139
|
-
|
140
|
-
if REXML::XPath.first(doc, "//deleteResultRequest")
|
141
|
-
@operation = DELETE_REQUEST
|
142
|
-
elsif REXML::XPath.first(doc, "//readResultRequest")
|
143
|
-
@operation = READ_REQUEST
|
144
|
-
elsif REXML::XPath.first(doc, "//replaceResultRequest")
|
145
|
-
@operation = REPLACE_REQUEST
|
146
|
-
@score = doc.get_text("//resultRecord/result/resultScore/textString")
|
147
|
-
end
|
148
|
-
extention_process_xml(doc)
|
149
|
-
end
|
150
|
-
|
151
|
-
def generate_request_xml
|
152
|
-
raise IMS::LTI::InvalidLTIConfigError, "`@operation` and `@lis_result_sourcedid` are required" unless has_request_xml_attributes?
|
153
|
-
builder = Builder::XmlMarkup.new #(:indent=>2)
|
154
|
-
builder.instruct!
|
155
|
-
|
156
|
-
builder.imsx_POXEnvelopeRequest("xmlns" => "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0") do |env|
|
157
|
-
env.imsx_POXHeader do |header|
|
158
|
-
header.imsx_POXRequestHeaderInfo do |info|
|
159
|
-
info.imsx_version "V1.0"
|
160
|
-
info.imsx_messageIdentifier @message_identifier || IMS::LTI::generate_identifier
|
161
|
-
end
|
162
|
-
end
|
163
|
-
env.imsx_POXBody do |body|
|
164
|
-
body.tag!(@operation + 'Request') do |request|
|
165
|
-
request.resultRecord do |record|
|
166
|
-
record.sourcedGUID do |guid|
|
167
|
-
guid.sourcedId @lis_result_sourcedid
|
168
|
-
end
|
169
|
-
results(record)
|
170
|
-
end
|
171
|
-
submission_details(request)
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
private
|
178
|
-
|
179
|
-
def extention_process_xml(doc)
|
180
|
-
end
|
181
|
-
|
182
|
-
def has_result_data?
|
183
|
-
!!score
|
184
|
-
end
|
185
|
-
|
186
|
-
def has_details_data?
|
187
|
-
false
|
188
|
-
end
|
189
|
-
|
190
|
-
def results(node)
|
191
|
-
return unless has_result_data?
|
192
|
-
|
193
|
-
node.result do |res|
|
194
|
-
result_values(res)
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def submission_details(request)
|
199
|
-
return unless has_details_data?
|
200
|
-
request.submissionDetails do |record|
|
201
|
-
details(record)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def details(record)
|
206
|
-
end
|
207
|
-
|
208
|
-
def result_values(node)
|
209
|
-
if score
|
210
|
-
node.resultScore do |res_score|
|
211
|
-
res_score.language "en" # 'en' represents the format of the number
|
212
|
-
res_score.textString score.to_s
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def has_required_attributes?
|
218
|
-
@consumer_key && @consumer_secret && @lis_outcome_service_url && @lis_result_sourcedid && @operation
|
219
|
-
end
|
220
|
-
|
221
|
-
def has_request_xml_attributes?
|
222
|
-
@operation && @lis_result_sourcedid
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
@@ -1,166 +0,0 @@
|
|
1
|
-
module IMS::LTI
|
2
|
-
# Class for consuming/generating LTI Outcome Responses
|
3
|
-
#
|
4
|
-
# Response documentation: http://www.imsglobal.org/lti/v1p1pd/ltiIMGv1p1pd.html#_Toc309649691
|
5
|
-
#
|
6
|
-
# Error code documentation: http://www.imsglobal.org/gws/gwsv1p0/imsgws_baseProfv1p0.html#1639667
|
7
|
-
#
|
8
|
-
# This class can be used by both Tool Providers and Tool Consumers. Each will
|
9
|
-
# use it a bit differently. The Tool Provider will use it parse the result of
|
10
|
-
# an OutcomeRequest to the Tool Consumer. A Tool Consumer will use it generate
|
11
|
-
# proper response XML to send back to a Tool Provider
|
12
|
-
#
|
13
|
-
# === Tool Provider Usage
|
14
|
-
# An OutcomeResponse will generally be created when POSTing an OutcomeRequest
|
15
|
-
# through a configured ToolProvider. See the ToolProvider documentation for
|
16
|
-
# typical usage.
|
17
|
-
#
|
18
|
-
# === Tool Consumer Usage
|
19
|
-
# When an outcome request is sent from a Tool Provider the body of the request
|
20
|
-
# is XML. This class parses that XML and provides a simple interface for
|
21
|
-
# accessing the information in the request. Typical usage would be:
|
22
|
-
#
|
23
|
-
# # create a new response and set the appropriate values
|
24
|
-
# res = IMS::LTI::OutcomeResponse.new
|
25
|
-
# res.message_ref_identifier = outcome_request.message_identifier
|
26
|
-
# res.operation = outcome_request.operation
|
27
|
-
# res.code_major = 'success'
|
28
|
-
# res.severity = 'status'
|
29
|
-
#
|
30
|
-
# # set a description (optional) and other information based on the type of response
|
31
|
-
# if outcome_request.replace_request?
|
32
|
-
# res.description = "Your old score of 0 has been replaced with #{outcome_request.score}"
|
33
|
-
# elsif outcome_request.read_request?
|
34
|
-
# res.description = "You score is 50"
|
35
|
-
# res.score = 50
|
36
|
-
# elsif outcome_request.delete_request?
|
37
|
-
# res.description = "You score has been cleared"
|
38
|
-
# else
|
39
|
-
# res.code_major = 'unsupported'
|
40
|
-
# res.severity = 'status'
|
41
|
-
# res.description = "#{outcome_request.operation} is not supported"
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# # the generated xml is returned to the Tool Provider
|
45
|
-
# res.generate_response_xml
|
46
|
-
#
|
47
|
-
class OutcomeResponse
|
48
|
-
include IMS::LTI::Extensions::Base
|
49
|
-
|
50
|
-
attr_accessor :request_type, :score, :message_identifier, :response_code,
|
51
|
-
:post_response, :code_major, :severity, :description, :operation,
|
52
|
-
:message_ref_identifier
|
53
|
-
|
54
|
-
CODE_MAJOR_CODES = %w{success processing failure unsupported}
|
55
|
-
SEVERITY_CODES = %w{status warning error}
|
56
|
-
|
57
|
-
# Create a new OutcomeResponse
|
58
|
-
#
|
59
|
-
# @param opts [Hash] initialization hash
|
60
|
-
def initialize(opts={})
|
61
|
-
opts.each_pair do |key, val|
|
62
|
-
self.send("#{key}=", val) if self.respond_to?("#{key}=")
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# Convenience method for creating a new OutcomeResponse from a response object
|
67
|
-
#
|
68
|
-
# req = IMS::LTI::OutcomeResponse.from_post_response(response)
|
69
|
-
def self.from_post_response(post_response)
|
70
|
-
response = OutcomeResponse.new
|
71
|
-
response.process_post_response(post_response)
|
72
|
-
end
|
73
|
-
|
74
|
-
def process_post_response(post_response)
|
75
|
-
self.post_response = post_response
|
76
|
-
self.response_code = post_response.code
|
77
|
-
xml = post_response.body
|
78
|
-
self.process_xml(xml)
|
79
|
-
self
|
80
|
-
end
|
81
|
-
|
82
|
-
def success?
|
83
|
-
@code_major == 'success'
|
84
|
-
end
|
85
|
-
|
86
|
-
def processing?
|
87
|
-
@code_major == 'processing'
|
88
|
-
end
|
89
|
-
|
90
|
-
def failure?
|
91
|
-
@code_major == 'failure'
|
92
|
-
end
|
93
|
-
|
94
|
-
def unsupported?
|
95
|
-
@code_major == 'unsupported'
|
96
|
-
end
|
97
|
-
|
98
|
-
def has_warning?
|
99
|
-
@severity == 'warning'
|
100
|
-
end
|
101
|
-
|
102
|
-
def has_error?
|
103
|
-
@severity == 'error'
|
104
|
-
end
|
105
|
-
|
106
|
-
# Parse Outcome Response data from XML
|
107
|
-
def process_xml(xml)
|
108
|
-
begin
|
109
|
-
doc = REXML::Document.new xml
|
110
|
-
rescue => e
|
111
|
-
raise IMS::LTI::XMLParseError, "#{e}\nOriginal xml: '#{xml}'"
|
112
|
-
end
|
113
|
-
@message_identifier = doc.text("//imsx_statusInfo/imsx_messageIdentifier").to_s
|
114
|
-
@code_major = doc.text("//imsx_statusInfo/imsx_codeMajor")
|
115
|
-
@code_major.downcase! if @code_major
|
116
|
-
@severity = doc.text("//imsx_statusInfo/imsx_severity")
|
117
|
-
@severity.downcase! if @severity
|
118
|
-
@description = doc.text("//imsx_statusInfo/imsx_description")
|
119
|
-
@description = @description.to_s if @description
|
120
|
-
@message_ref_identifier = doc.text("//imsx_statusInfo/imsx_messageRefIdentifier")
|
121
|
-
@operation = doc.text("//imsx_statusInfo/imsx_operationRefIdentifier")
|
122
|
-
@score = doc.text("//readResultResponse//resultScore/textString")
|
123
|
-
@score = @score.to_s if @score
|
124
|
-
end
|
125
|
-
|
126
|
-
# Generate XML based on the current configuration
|
127
|
-
# @return [String] The response xml
|
128
|
-
def generate_response_xml
|
129
|
-
builder = Builder::XmlMarkup.new
|
130
|
-
builder.instruct!
|
131
|
-
|
132
|
-
builder.imsx_POXEnvelopeResponse("xmlns" => "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0") do |env|
|
133
|
-
env.imsx_POXHeader do |header|
|
134
|
-
header.imsx_POXResponseHeaderInfo do |info|
|
135
|
-
info.imsx_version "V1.0"
|
136
|
-
info.imsx_messageIdentifier @message_identifier || IMS::LTI::generate_identifier
|
137
|
-
info.imsx_statusInfo do |status|
|
138
|
-
status.imsx_codeMajor @code_major
|
139
|
-
status.imsx_severity @severity
|
140
|
-
status.imsx_description @description
|
141
|
-
status.imsx_messageRefIdentifier @message_ref_identifier
|
142
|
-
status.imsx_operationRefIdentifier @operation
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end #/header
|
146
|
-
env.imsx_POXBody do |body|
|
147
|
-
unless unsupported?
|
148
|
-
if @operation == OutcomeRequest::READ_REQUEST
|
149
|
-
body.tag!(@operation + 'Response') do |request|
|
150
|
-
request.result do |res|
|
151
|
-
res.resultScore do |res_score|
|
152
|
-
res_score.language "en" # 'en' represents the format of the number
|
153
|
-
res_score.textString @score.to_s
|
154
|
-
end
|
155
|
-
end #/result
|
156
|
-
end
|
157
|
-
else
|
158
|
-
body.tag!(@operation + 'Response')
|
159
|
-
end #/operationResponse
|
160
|
-
end
|
161
|
-
end #/body
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
end
|
166
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module IMS::LTI
|
2
|
-
# A mixin for OAuth request validation
|
3
|
-
module RequestValidator
|
4
|
-
|
5
|
-
attr_reader :oauth_signature_validator
|
6
|
-
|
7
|
-
# Validates and OAuth request using the OAuth Gem - https://github.com/oauth/oauth-ruby
|
8
|
-
#
|
9
|
-
# To validate the OAuth signatures you need to require the appropriate
|
10
|
-
# request proxy for your application. For example:
|
11
|
-
#
|
12
|
-
# # For a sinatra app:
|
13
|
-
# require 'oauth/request_proxy/rack_request'
|
14
|
-
#
|
15
|
-
# # For a rails app:
|
16
|
-
# require 'oauth/request_proxy/action_controller_request'
|
17
|
-
# @return [Bool] Whether the request was valid
|
18
|
-
def valid_request?(request, handle_error=true)
|
19
|
-
begin
|
20
|
-
@oauth_signature_validator = OAuth::Signature.build(request, :consumer_secret => @consumer_secret)
|
21
|
-
@oauth_signature_validator.verify() or raise OAuth::Unauthorized.new(request)
|
22
|
-
true
|
23
|
-
rescue OAuth::Signature::UnknownSignatureMethod
|
24
|
-
if handle_error
|
25
|
-
false
|
26
|
-
else
|
27
|
-
raise $!
|
28
|
-
end
|
29
|
-
rescue OAuth::Unauthorized
|
30
|
-
if handle_error
|
31
|
-
false
|
32
|
-
else
|
33
|
-
raise OAuth::Unauthorized.new(request)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Check whether the OAuth-signed request is valid and throw error if not
|
39
|
-
#
|
40
|
-
# @return [Bool] Whether the request was valid
|
41
|
-
def valid_request!(request)
|
42
|
-
valid_request?(request, false)
|
43
|
-
end
|
44
|
-
|
45
|
-
# convenience method for getting the oauth nonce from the request
|
46
|
-
def request_oauth_nonce
|
47
|
-
@oauth_signature_validator && @oauth_signature_validator.request.oauth_nonce
|
48
|
-
end
|
49
|
-
|
50
|
-
# convenience method for getting the oauth timestamp from the request
|
51
|
-
def request_oauth_timestamp
|
52
|
-
@oauth_signature_validator && @oauth_signature_validator.request.oauth_timestamp
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|