ims-lti 1.1.12 → 1.2.6

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
- SHA1:
3
- metadata.gz: 3519a3ee6fb782c4ed97fcb89652c2011a3bb602
4
- data.tar.gz: 495e959fd7bcddd71da5ead3ec88745109aae5c6
2
+ SHA256:
3
+ metadata.gz: a7fb650dcdd9fad408934d47de72f8f2e11a55605d10f23ee04944976c900cd4
4
+ data.tar.gz: 2835e4925ea33ebd4f4aac6ea8c0b47d3696a67ae548addd6f1aad5adf4f12ef
5
5
  SHA512:
6
- metadata.gz: a046a0db9890831af84705ca31d11d409ee3095b58e56e1bfd1eb458163a9856fbbff51bd7738d87a776d97bc7a88fc74b62980a64a8553437bb66592178499f
7
- data.tar.gz: ac7793788cb184c463f10e977dfac0f448c840f99ca4f9a11cc9bd1af6142d6896b9d1a1fa8419afd404b16c4ca6967315e38429cf0c17ccfb719e0273998371
6
+ metadata.gz: 98469e50f9bb313fc90facdc65c309ec286e3b71b410226d390ffa0d25b6b78ed4c1d3ca7bfec31baf27c8f949a7c83f8525dc66c313968eb8af333dd514637d
7
+ data.tar.gz: 8ab0abecf8f0f7038f91f006a1a82ddf7a3717f5532a7bfa52ba9ae2a0379fd260e6f07cdb5074cfd283ed33a4a8b692b79c99fd487aad40394586052b32733b
data/Changelog CHANGED
@@ -1,3 +1,13 @@
1
+ 2020-02-03 Version 1.2.4
2
+ * Add support for submittedAt date
3
+
4
+ 2017-03-08 Version 1.2.0
5
+ * Don't downcase roles
6
+
7
+ 2016-10-05 Version 1.1.13
8
+ * Fix Oauth::Unauthorized initialization bug
9
+ * Relax oauth dependency
10
+
1
11
  2016-06-16 Version 1.1.12
2
12
  * Add support for detecting observer role
3
13
 
data/README.md CHANGED
@@ -16,14 +16,14 @@ To require the library in your project:
16
16
  To validate the OAuth signatures you need to require the appropriate request
17
17
  proxy for your application. For example:
18
18
 
19
+ # For a Rails 5 (and 2.3) app:
20
+ require 'oauth/request_proxy/action_controller_request'
21
+
19
22
  # For a Sinatra or a Rails 3 or 4 app:
20
23
  require 'oauth/request_proxy/rack_request'
21
24
  # You also need to explicitly enable OAuth 1 support in the environment.rb or an initializer:
22
25
  OAUTH_10_SUPPORT = true
23
26
 
24
- # For a Rails 2.3 app:
25
- require 'oauth/request_proxy/action_controller_request'
26
-
27
27
  For further information see the [oauth-ruby](https://github.com/oauth-xx/oauth-ruby) project.
28
28
 
29
29
  As a quick debugging note, if you forget that step, you'll get an error like:
@@ -52,7 +52,7 @@ and it will be signed with OAuth using a key/secret that both the TP and TC shar
52
52
  This is covered in the [LTI security model](http://www.imsglobal.org/LTI/v1p1/ltiIMGv1p1.html#_Toc319560466)
53
53
 
54
54
  Here is an example of a simple TP Sinatra app using this gem:
55
- [LTI Tool Provider](https://github.com/instructure/lti_tool_provider_example)
55
+ [LTI Tool Provider](https://github.com/instructure/lti1_tool_provider_example)
56
56
 
57
57
  Once you find the `oauth_consumer_secret` based on the `oauth_consumer_key` in
58
58
  the request, you can initialize a `ToolProvider` object with them and the post parameters:
@@ -6,7 +6,7 @@ module DeprecatedRoleChecks
6
6
  # Check whether the Launch Parameters have a role
7
7
  def has_role?(role)
8
8
  role = role.downcase
9
- @roles && @roles.any?{|r| r.index(role)}
9
+ @roles && @roles.any?{|r| r.downcase.index(role)}
10
10
  end
11
11
 
12
12
  # Convenience method for checking if the user has 'learner' or 'student' role
@@ -67,6 +67,12 @@ module IMS::LTI
67
67
  accepted_outcome_types.member?("url")
68
68
  end
69
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
+ @ext_params["ext_outcome_submission_submitted_at_accepted"] == "true"
74
+ end
75
+
70
76
  def accepts_outcome_lti_launch_url?
71
77
  accepted_outcome_types.member?("lti_launch_url")
72
78
  end
@@ -75,8 +81,19 @@ module IMS::LTI
75
81
  !!@ext_params["outcome_result_total_score_accepted"]
76
82
  end
77
83
 
84
+ def accepts_needs_additional_review?
85
+ @ext_params["ext_outcome_submission_needs_additional_review_accepted"] == "true"
86
+ end
87
+
88
+ def accepts_prioritize_non_tool_grade?
89
+ @ext_params["ext_outcome_submission_prioritize_non_tool_grade_accepted"] == "true"
90
+ end
91
+
78
92
  # POSTs the given score to the Tool Consumer with a replaceResult and
79
- # adds the specified data. The data hash can have the keys "text", "cdata_text", "url", or "lti_launch_url"
93
+ # adds the specified data.
94
+ #
95
+ # The data hash can have the keys "text", "cdata_text", "url", "submitted_at"
96
+ # "needs_additional_review", "prioritize_non_tool_grade", or "lti_launch_url"
80
97
  #
81
98
  # If both cdata_text and text are sent, cdata_text will be used
82
99
  #
@@ -93,7 +110,8 @@ module IMS::LTI
93
110
 
94
111
  # POSTs the given score to the Tool Consumer with a replaceResult and
95
112
  # adds the specified data. The options hash can have the keys
96
- # :text, :cdata_text, :url, :lti_launch_url, :score, or :total_score
113
+ # :text, :cdata_text, :url, :submitted_at, :lti_launch_url, :score,
114
+ # :needs_additional_review, or :total_score
97
115
  #
98
116
  # If both cdata_text and text are sent, cdata_text will be used
99
117
  # If both total_score and score are sent, total_score will be used
@@ -110,6 +128,9 @@ module IMS::LTI
110
128
  req.outcome_cdata_text = opts[:cdata_text]
111
129
  req.outcome_text = opts[:text]
112
130
  req.outcome_url = opts[:url]
131
+ req.submitted_at = opts[:submitted_at]
132
+ req.needs_additional_review = opts[:needs_additional_review]
133
+ req.prioritize_non_tool_grade = opts[:prioritize_non_tool_grade]
113
134
  req.outcome_lti_launch_url = opts[:lti_launch_url]
114
135
  req.total_score = opts[:total_score]
115
136
  req.post_replace_result!(opts[:score])
@@ -120,9 +141,9 @@ module IMS::LTI
120
141
  include IMS::LTI::Extensions::ExtensionBase
121
142
  include Base
122
143
 
123
- OUTCOME_DATA_TYPES = %w{text url lti_launch_url}
144
+ OUTCOME_DATA_TYPES = %w{text url lti_launch_url submitted_at}
124
145
 
125
- # a list of the outcome data types accepted, currently only 'url' and
146
+ # a list of the outcome data types accepted, currently only 'url', 'submitted_at' and
126
147
  # 'text' are valid
127
148
  #
128
149
  # tc.outcome_data_values_accepted(['url', 'text'])
@@ -150,7 +171,14 @@ module IMS::LTI
150
171
  include IMS::LTI::Extensions::ExtensionBase
151
172
  include Base
152
173
 
153
- attr_accessor :outcome_text, :outcome_url, :outcome_lti_launch_url, :outcome_cdata_text, :total_score
174
+ attr_accessor :outcome_text,
175
+ :outcome_url,
176
+ :submitted_at,
177
+ :outcome_lti_launch_url,
178
+ :outcome_cdata_text,
179
+ :total_score,
180
+ :needs_additional_review,
181
+ :prioritize_non_tool_grade
154
182
 
155
183
  def result_values(node)
156
184
  super
@@ -178,6 +206,15 @@ module IMS::LTI
178
206
  end
179
207
  end
180
208
 
209
+ def details(node)
210
+ super
211
+ return unless has_details_data?
212
+
213
+ node.submittedAt submitted_at if submitted_at
214
+ node.needsAdditionalReview if needs_additional_review
215
+ node.prioritizeNonToolGrade if prioritize_non_tool_grade
216
+ end
217
+
181
218
  def score
182
219
  total_score ? nil : @score
183
220
  end
@@ -186,6 +223,10 @@ module IMS::LTI
186
223
  !!outcome_text || !!outcome_url || !!outcome_lti_launch_url || !!outcome_cdata_text || !!total_score || super
187
224
  end
188
225
 
226
+ def has_details_data?
227
+ !!submitted_at || !!needs_additional_review || !!prioritize_non_tool_grade
228
+ end
229
+
189
230
  def extention_process_xml(doc)
190
231
  super
191
232
  @outcome_text = doc.get_text("//resultRecord/result/resultData/text")
@@ -196,4 +237,4 @@ module IMS::LTI
196
237
 
197
238
  end
198
239
  end
199
- end
240
+ end
@@ -96,7 +96,7 @@ module IMS::LTI
96
96
  if roles_list.is_a?(Array)
97
97
  @roles = roles_list
98
98
  else
99
- @roles = roles_list.split(",").map(&:downcase)
99
+ @roles = roles_list.split(",")
100
100
  end
101
101
  else
102
102
  @roles = nil
@@ -148,23 +148,63 @@ module IMS::LTI
148
148
  extention_process_xml(doc)
149
149
  end
150
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
+
151
177
  private
152
-
178
+
153
179
  def extention_process_xml(doc)
154
180
  end
155
-
181
+
156
182
  def has_result_data?
157
183
  !!score
158
184
  end
159
-
185
+
186
+ def has_details_data?
187
+ false
188
+ end
189
+
160
190
  def results(node)
161
191
  return unless has_result_data?
162
-
192
+
163
193
  node.result do |res|
164
194
  result_values(res)
165
195
  end
166
196
  end
167
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
+
168
208
  def result_values(node)
169
209
  if score
170
210
  node.resultScore do |res_score|
@@ -178,29 +218,8 @@ module IMS::LTI
178
218
  @consumer_key && @consumer_secret && @lis_outcome_service_url && @lis_result_sourcedid && @operation
179
219
  end
180
220
 
181
- def generate_request_xml
182
- builder = Builder::XmlMarkup.new #(:indent=>2)
183
- builder.instruct!
184
-
185
- builder.imsx_POXEnvelopeRequest("xmlns" => "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0") do |env|
186
- env.imsx_POXHeader do |header|
187
- header.imsx_POXRequestHeaderInfo do |info|
188
- info.imsx_version "V1.0"
189
- info.imsx_messageIdentifier @message_identifier || IMS::LTI::generate_identifier
190
- end
191
- end
192
- env.imsx_POXBody do |body|
193
- body.tag!(@operation + 'Request') do |request|
194
- request.resultRecord do |record|
195
- record.sourcedGUID do |guid|
196
- guid.sourcedId @lis_result_sourcedid
197
- end
198
- results(record)
199
- end
200
- end
201
- end
202
- end
221
+ def has_request_xml_attributes?
222
+ @operation && @lis_result_sourcedid
203
223
  end
204
-
205
224
  end
206
225
  end
@@ -46,7 +46,7 @@ module IMS::LTI
46
46
  #
47
47
  class OutcomeResponse
48
48
  include IMS::LTI::Extensions::Base
49
-
49
+
50
50
  attr_accessor :request_type, :score, :message_identifier, :response_code,
51
51
  :post_response, :code_major, :severity, :description, :operation,
52
52
  :message_ref_identifier
@@ -70,7 +70,7 @@ module IMS::LTI
70
70
  response = OutcomeResponse.new
71
71
  response.process_post_response(post_response)
72
72
  end
73
-
73
+
74
74
  def process_post_response(post_response)
75
75
  self.post_response = post_response
76
76
  self.response_code = post_response.code
@@ -105,7 +105,11 @@ module IMS::LTI
105
105
 
106
106
  # Parse Outcome Response data from XML
107
107
  def process_xml(xml)
108
- doc = REXML::Document.new xml
108
+ begin
109
+ doc = REXML::Document.new xml
110
+ rescue => e
111
+ raise IMS::LTI::XMLParseError, "#{e}\nOriginal xml: '#{xml}'"
112
+ end
109
113
  @message_identifier = doc.text("//imsx_statusInfo/imsx_messageIdentifier").to_s
110
114
  @code_major = doc.text("//imsx_statusInfo/imsx_codeMajor")
111
115
  @code_major.downcase! if @code_major
@@ -18,14 +18,20 @@ module IMS::LTI
18
18
  def valid_request?(request, handle_error=true)
19
19
  begin
20
20
  @oauth_signature_validator = OAuth::Signature.build(request, :consumer_secret => @consumer_secret)
21
- @oauth_signature_validator.verify() or raise OAuth::Unauthorized
21
+ @oauth_signature_validator.verify() or raise OAuth::Unauthorized.new(request)
22
22
  true
23
- rescue OAuth::Signature::UnknownSignatureMethod, OAuth::Unauthorized
23
+ rescue OAuth::Signature::UnknownSignatureMethod
24
24
  if handle_error
25
25
  false
26
26
  else
27
27
  raise $!
28
28
  end
29
+ rescue OAuth::Unauthorized
30
+ if handle_error
31
+ false
32
+ else
33
+ raise OAuth::Unauthorized.new(request)
34
+ end
29
35
  end
30
36
  end
31
37
 
@@ -16,7 +16,7 @@ module IMS::LTI
16
16
  # Check whether the Launch Parameters have a given role
17
17
  def has_exact_role?(role)
18
18
  role = role.downcase
19
- @roles && @roles.any? { |r| r == role }
19
+ @roles && @roles.any? { |r| r.downcase == role }
20
20
  end
21
21
 
22
22
  # Check whether the Launch Parameters have a given role ignoring
@@ -25,7 +25,7 @@ module IMS::LTI
25
25
  # will return true if the role is `urn:lti:role:ims/lis/Instructor/GuestInstructor`
26
26
  def has_base_role?(role)
27
27
  role = role.downcase
28
- @roles && @roles.any? { |r| r.start_with?(role) }
28
+ @roles && @roles.any? { |r| r.downcase.start_with?(role) }
29
29
  end
30
30
 
31
31
  # Convenience method for checking if the user is the system administrator of the TC
@@ -135,9 +135,9 @@ module IMS::LTI
135
135
  :consumer_secret => @consumer_secret,
136
136
  :lis_outcome_service_url => lis_outcome_service_url,
137
137
  :lis_result_sourcedid =>lis_result_sourcedid)
138
-
138
+
139
139
  extend_outcome_request(@outcome_requests.last)
140
140
  end
141
-
141
+
142
142
  end
143
143
  end
data/lib/ims/lti.rb CHANGED
@@ -2,6 +2,7 @@ require 'oauth'
2
2
  require 'builder'
3
3
  require "rexml/document"
4
4
  require 'cgi'
5
+ require 'securerandom'
5
6
 
6
7
  module IMS # :nodoc:
7
8
 
@@ -25,13 +26,16 @@ module IMS # :nodoc:
25
26
  #
26
27
  # require 'ims/lti'
27
28
  module LTI
28
-
29
+
29
30
  # The versions of LTI this library supports
30
31
  VERSIONS = %w{1.0 1.1}
31
-
32
+
32
33
  class InvalidLTIConfigError < StandardError
33
34
  end
34
35
 
36
+ class XMLParseError < StandardError
37
+ end
38
+
35
39
  # POST a signed oauth request with the given key/secret/data
36
40
  def self.post_service_request(key, secret, url, content_type, body)
37
41
  raise IMS::LTI::InvalidLTIConfigError, "" unless key && secret
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ims-lti
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.12
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-09 00:00:00.000000000 Z
11
+ date: 2022-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: builder
@@ -16,56 +16,60 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '1.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '4.0'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '0'
29
+ version: '1.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '4.0'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: oauth
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - "~>"
37
+ - - ">="
32
38
  - !ruby/object:Gem::Version
33
39
  version: 0.4.5
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '0.6'
34
43
  type: :runtime
35
44
  prerelease: false
36
45
  version_requirements: !ruby/object:Gem::Requirement
37
46
  requirements:
38
- - - "~>"
47
+ - - ">="
39
48
  - !ruby/object:Gem::Version
40
49
  version: 0.4.5
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '0.6'
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: rspec
43
55
  requirement: !ruby/object:Gem::Requirement
44
56
  requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
57
+ - - "~>"
53
58
  - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: ruby-debug
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
59
+ version: '3.0'
60
+ - - ">"
60
61
  - !ruby/object:Gem::Version
61
- version: '0'
62
+ version: '3.0'
62
63
  type: :development
63
64
  prerelease: false
64
65
  version_requirements: !ruby/object:Gem::Requirement
65
66
  requirements:
66
- - - ">="
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.0'
70
+ - - ">"
67
71
  - !ruby/object:Gem::Version
68
- version: '0'
72
+ version: '3.0'
69
73
  description:
70
74
  email:
71
75
  executables: []
@@ -111,10 +115,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
115
  - !ruby/object:Gem::Version
112
116
  version: '0'
113
117
  requirements: []
114
- rubyforge_project:
115
- rubygems_version: 2.5.1
118
+ rubygems_version: 3.1.6
116
119
  signing_key:
117
120
  specification_version: 4
118
121
  summary: Ruby library for creating IMS LTI tool providers and consumers
119
122
  test_files: []
120
- has_rdoc: