ims-lti 1.2.4 → 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 -103
- data/lib/ims.rb +3 -1
- data/lib/ims/lti.rb +6 -64
- data/lib/ims/lti/converters.rb +5 -0
- data/lib/ims/lti/converters/time_json_converter.rb +13 -0
- data/lib/ims/lti/models.rb +29 -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.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/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/services.rb +5 -0
- data/lib/ims/lti/services/message_service.rb +40 -0
- data/lib/ims/lti/version.rb +5 -0
- metadata +68 -52
- data/Changelog +0 -54
- data/LICENSE +0 -18
- data/lib/ims/lti/deprecated_role_checks.rb +0 -52
- data/lib/ims/lti/extensions.rb +0 -45
- data/lib/ims/lti/extensions/canvas.rb +0 -122
- data/lib/ims/lti/extensions/content.rb +0 -209
- data/lib/ims/lti/extensions/outcome_data.rb +0 -216
- 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 -143
@@ -1,216 +0,0 @@
|
|
1
|
-
module IMS::LTI
|
2
|
-
module Extensions
|
3
|
-
|
4
|
-
# An LTI extension that adds support for sending data back to the consumer
|
5
|
-
# in addition to the score.
|
6
|
-
#
|
7
|
-
# # Initialize TP object with OAuth creds and post parameters
|
8
|
-
# provider = IMS::LTI::ToolProvider.new(consumer_key, consumer_secret, params)
|
9
|
-
# # add extension
|
10
|
-
# provider.extend IMS::LTI::Extensions::OutcomeData::ToolProvider
|
11
|
-
#
|
12
|
-
# If the tool was launch as an outcome service and it supports the data extension
|
13
|
-
# you can POST a score to the TC.
|
14
|
-
# The POST calls all return an OutcomeResponse object which can be used to
|
15
|
-
# handle the response appropriately.
|
16
|
-
#
|
17
|
-
# # post the score to the TC, score should be a float >= 0.0 and <= 1.0
|
18
|
-
# # this returns an OutcomeResponse object
|
19
|
-
# if provider.accepts_outcome_text?
|
20
|
-
# response = provider.post_extended_replace_result!(score: score, text: "submission text")
|
21
|
-
# else
|
22
|
-
# response = provider.post_replace_result!(score)
|
23
|
-
# end
|
24
|
-
# if response.success?
|
25
|
-
# # grade write worked
|
26
|
-
# elsif response.processing?
|
27
|
-
# elsif response.unsupported?
|
28
|
-
# else
|
29
|
-
# # failed
|
30
|
-
# end
|
31
|
-
module OutcomeData
|
32
|
-
|
33
|
-
#IMS::LTI::Extensions::OutcomeData::ToolProvider
|
34
|
-
module Base
|
35
|
-
def outcome_request_extensions
|
36
|
-
super + [IMS::LTI::Extensions::OutcomeData::OutcomeRequest]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
module ToolProvider
|
41
|
-
include IMS::LTI::Extensions::ExtensionBase
|
42
|
-
include Base
|
43
|
-
|
44
|
-
# a list of the supported outcome data types
|
45
|
-
def accepted_outcome_types
|
46
|
-
return @outcome_types if @outcome_types
|
47
|
-
@outcome_types = []
|
48
|
-
if val = @ext_params["outcome_data_values_accepted"]
|
49
|
-
@outcome_types = val.split(',')
|
50
|
-
end
|
51
|
-
|
52
|
-
@outcome_types
|
53
|
-
end
|
54
|
-
|
55
|
-
# check if the outcome data extension is supported
|
56
|
-
def accepts_outcome_data?
|
57
|
-
!!@ext_params["outcome_data_values_accepted"]
|
58
|
-
end
|
59
|
-
|
60
|
-
# check if the consumer accepts text as outcome data
|
61
|
-
def accepts_outcome_text?
|
62
|
-
accepted_outcome_types.member?("text")
|
63
|
-
end
|
64
|
-
|
65
|
-
# check if the consumer accepts a url as outcome data
|
66
|
-
def accepts_outcome_url?
|
67
|
-
accepted_outcome_types.member?("url")
|
68
|
-
end
|
69
|
-
|
70
|
-
# check if the consumer accepts a submitted at date as outcome data
|
71
|
-
def accepts_submitted_at?
|
72
|
-
accepted_outcome_types.member?("submitted_at")
|
73
|
-
end
|
74
|
-
|
75
|
-
def accepts_outcome_lti_launch_url?
|
76
|
-
accepted_outcome_types.member?("lti_launch_url")
|
77
|
-
end
|
78
|
-
|
79
|
-
def accepts_outcome_result_total_score?
|
80
|
-
!!@ext_params["outcome_result_total_score_accepted"]
|
81
|
-
end
|
82
|
-
|
83
|
-
# POSTs the given score to the Tool Consumer with a replaceResult and
|
84
|
-
# adds the specified data. The data hash can have the keys "text", "cdata_text", "url", "submitted_at" or "lti_launch_url"
|
85
|
-
#
|
86
|
-
# If both cdata_text and text are sent, cdata_text will be used
|
87
|
-
#
|
88
|
-
# If score is nil, the replace result XML will not contain a resultScore node
|
89
|
-
#
|
90
|
-
# Creates a new OutcomeRequest object and stores it in @outcome_requests
|
91
|
-
#
|
92
|
-
# @return [OutcomeResponse] the response from the Tool Consumer
|
93
|
-
# @deprecated Use #post_extended_replace_result! instead
|
94
|
-
def post_replace_result_with_data!(score = nil, data={})
|
95
|
-
data[:score] = score if score
|
96
|
-
post_extended_replace_result!(data)
|
97
|
-
end
|
98
|
-
|
99
|
-
# POSTs the given score to the Tool Consumer with a replaceResult and
|
100
|
-
# adds the specified data. The options hash can have the keys
|
101
|
-
# :text, :cdata_text, :url, :submitted_at, :lti_launch_url, :score, or :total_score
|
102
|
-
#
|
103
|
-
# If both cdata_text and text are sent, cdata_text will be used
|
104
|
-
# If both total_score and score are sent, total_score will be used
|
105
|
-
# If score is nil, the replace result XML will not contain a resultScore node
|
106
|
-
#
|
107
|
-
# Creates a new OutcomeRequest object and stores it in @outcome_requests
|
108
|
-
#
|
109
|
-
# @return [OutcomeResponse] the response from the Tool Consumer
|
110
|
-
def post_extended_replace_result!(options = {})
|
111
|
-
opts = {}
|
112
|
-
options.each {|k,v| opts[k.to_sym] = v}
|
113
|
-
|
114
|
-
req = new_request
|
115
|
-
req.outcome_cdata_text = opts[:cdata_text]
|
116
|
-
req.outcome_text = opts[:text]
|
117
|
-
req.outcome_url = opts[:url]
|
118
|
-
req.submitted_at = opts[:submitted_at]
|
119
|
-
req.outcome_lti_launch_url = opts[:lti_launch_url]
|
120
|
-
req.total_score = opts[:total_score]
|
121
|
-
req.post_replace_result!(opts[:score])
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
module ToolConsumer
|
126
|
-
include IMS::LTI::Extensions::ExtensionBase
|
127
|
-
include Base
|
128
|
-
|
129
|
-
OUTCOME_DATA_TYPES = %w{text url lti_launch_url submitted_at}
|
130
|
-
|
131
|
-
# a list of the outcome data types accepted, currently only 'url', 'submitted_at' and
|
132
|
-
# 'text' are valid
|
133
|
-
#
|
134
|
-
# tc.outcome_data_values_accepted(['url', 'text'])
|
135
|
-
# tc.outcome_data_valued_accepted("url,text")
|
136
|
-
def outcome_data_values_accepted=(val)
|
137
|
-
if val.is_a? Array
|
138
|
-
val = val.join(',')
|
139
|
-
end
|
140
|
-
|
141
|
-
set_ext_param('outcome_data_values_accepted', val)
|
142
|
-
end
|
143
|
-
|
144
|
-
# a comma-separated string of the supported outcome data types
|
145
|
-
def outcome_data_values_accepted
|
146
|
-
get_ext_param('outcome_data_values_accepted')
|
147
|
-
end
|
148
|
-
|
149
|
-
# convenience method for setting support for all current outcome data types
|
150
|
-
def support_outcome_data!
|
151
|
-
self.outcome_data_values_accepted = OUTCOME_DATA_TYPES
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
module OutcomeRequest
|
156
|
-
include IMS::LTI::Extensions::ExtensionBase
|
157
|
-
include Base
|
158
|
-
|
159
|
-
attr_accessor :outcome_text, :outcome_url, :submitted_at, :outcome_lti_launch_url, :outcome_cdata_text, :total_score
|
160
|
-
|
161
|
-
def result_values(node)
|
162
|
-
super
|
163
|
-
|
164
|
-
if total_score
|
165
|
-
node.resultTotalScore do |res_total_score|
|
166
|
-
res_total_score.language "en" # 'en' represents the format of the number
|
167
|
-
res_total_score.textString total_score.to_s
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
if outcome_text || outcome_url || outcome_cdata_text || outcome_lti_launch_url
|
172
|
-
node.resultData do |res_data|
|
173
|
-
if outcome_cdata_text
|
174
|
-
res_data.text {
|
175
|
-
res_data.cdata! outcome_cdata_text
|
176
|
-
}
|
177
|
-
elsif outcome_text
|
178
|
-
res_data.text outcome_text
|
179
|
-
elsif outcome_lti_launch_url
|
180
|
-
res_data.ltiLaunchUrl outcome_lti_launch_url
|
181
|
-
end
|
182
|
-
res_data.url outcome_url if outcome_url
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def details(node)
|
188
|
-
super
|
189
|
-
return unless has_details_data?
|
190
|
-
|
191
|
-
node.submittedAt submitted_at
|
192
|
-
end
|
193
|
-
|
194
|
-
def score
|
195
|
-
total_score ? nil : @score
|
196
|
-
end
|
197
|
-
|
198
|
-
def has_result_data?
|
199
|
-
!!outcome_text || !!outcome_url || !!outcome_lti_launch_url || !!outcome_cdata_text || !!total_score || super
|
200
|
-
end
|
201
|
-
|
202
|
-
def has_details_data?
|
203
|
-
!!submitted_at
|
204
|
-
end
|
205
|
-
|
206
|
-
def extention_process_xml(doc)
|
207
|
-
super
|
208
|
-
@outcome_text = doc.get_text("//resultRecord/result/resultData/text")
|
209
|
-
@outcome_url = doc.get_text("//resultRecord/result/resultData/url")
|
210
|
-
@outcome_lti_launch_url = doc.get_text("//resultRecord/result/resultData/ltiLaunchUrl")
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
@@ -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
|