ims-lti 1.2.4 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +5 -5
  2. data/Changelog.txt +0 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +25 -91
  5. data/lib/ims/lis/context_type/handles.rb +10 -0
  6. data/lib/ims/lis/context_type/urns.rb +10 -0
  7. data/lib/ims/lis/roles/context/handles.rb +60 -0
  8. data/lib/ims/lis/roles/context/urns.rb +60 -0
  9. data/lib/ims/lis/roles/institution/handles.rb +22 -0
  10. data/lib/ims/lis/roles/institution/urns.rb +22 -0
  11. data/lib/ims/lis/roles/system/handles.rb +15 -0
  12. data/lib/ims/lis/roles/system/urns.rb +15 -0
  13. data/lib/ims/lis/statuses/simple_names.rb +9 -0
  14. data/lib/ims/lis/statuses/uris.rb +9 -0
  15. data/lib/ims/lis.rb +14 -0
  16. data/lib/ims/lti/converters/time_json_converter.rb +13 -0
  17. data/lib/ims/lti/converters.rb +5 -0
  18. data/lib/ims/lti/errors/authentication_failed_error.rb +11 -0
  19. data/lib/ims/lti/errors/invalid_lti_config_error.rb +4 -0
  20. data/lib/ims/lti/errors/invalid_tool_consumer_profile.rb +4 -0
  21. data/lib/ims/lti/errors/tool_proxy_registration_error.rb +15 -0
  22. data/lib/ims/lti/errors.rb +8 -0
  23. data/lib/ims/lti/models/base_url_choice.rb +15 -0
  24. data/lib/ims/lti/models/base_url_selector.rb +5 -0
  25. data/lib/ims/lti/models/contact.rb +5 -0
  26. data/lib/ims/lti/models/content_item_container.rb +14 -0
  27. data/lib/ims/lti/models/content_item_placement.rb +20 -0
  28. data/lib/ims/lti/models/content_items/content_item.rb +32 -0
  29. data/lib/ims/lti/models/content_items/file_item.rb +15 -0
  30. data/lib/ims/lti/models/content_items/lti_link_item.rb +14 -0
  31. data/lib/ims/lti/models/content_items.rb +7 -0
  32. data/lib/ims/lti/models/icon_endpoint.rb +5 -0
  33. data/lib/ims/lti/models/icon_info.rb +6 -0
  34. data/lib/ims/lti/models/image.rb +7 -0
  35. data/lib/ims/lti/models/localized_name.rb +12 -0
  36. data/lib/ims/lti/models/localized_text.rb +12 -0
  37. data/lib/ims/lti/models/lti_model.rb +227 -0
  38. data/lib/ims/lti/models/membership_service/agent.rb +11 -0
  39. data/lib/ims/lti/models/membership_service/container.rb +11 -0
  40. data/lib/ims/lti/models/membership_service/context.rb +11 -0
  41. data/lib/ims/lti/models/membership_service/lis_membership_container.rb +13 -0
  42. data/lib/ims/lti/models/membership_service/lis_person.rb +13 -0
  43. data/lib/ims/lti/models/membership_service/membership.rb +14 -0
  44. data/lib/ims/lti/models/membership_service/organization.rb +14 -0
  45. data/lib/ims/lti/models/membership_service/page.rb +16 -0
  46. data/lib/ims/lti/models/membership_service/person.rb +13 -0
  47. data/lib/ims/lti/models/membership_service.rb +16 -0
  48. data/lib/ims/lti/models/message_handler.rb +14 -0
  49. data/lib/ims/lti/models/messages/basic_lti_launch_request.rb +24 -0
  50. data/lib/ims/lti/models/messages/content_item_selection.rb +32 -0
  51. data/lib/ims/lti/models/messages/content_item_selection_request.rb +26 -0
  52. data/lib/ims/lti/models/messages/message.rb +222 -0
  53. data/lib/ims/lti/models/messages/registration_request.rb +20 -0
  54. data/lib/ims/lti/models/messages/request_message.rb +12 -0
  55. data/lib/ims/lti/models/messages/tool_proxy_update_request.rb +15 -0
  56. data/lib/ims/lti/models/messages.rb +11 -0
  57. data/lib/ims/lti/models/parameter.rb +28 -0
  58. data/lib/ims/lti/models/product_family.rb +8 -0
  59. data/lib/ims/lti/models/product_info.rb +26 -0
  60. data/lib/ims/lti/models/product_instance.rb +10 -0
  61. data/lib/ims/lti/models/resource_handler.rb +22 -0
  62. data/lib/ims/lti/models/resource_type.rb +6 -0
  63. data/lib/ims/lti/models/rest_service.rb +30 -0
  64. data/lib/ims/lti/models/rest_service_profile.rb +15 -0
  65. data/lib/ims/lti/models/security_contract.rb +21 -0
  66. data/lib/ims/lti/models/security_profile.rb +10 -0
  67. data/lib/ims/lti/models/serializable.rb +12 -0
  68. data/lib/ims/lti/models/service_owner.rb +26 -0
  69. data/lib/ims/lti/models/service_provider.rb +11 -0
  70. data/lib/ims/lti/models/tool_consumer_profile.rb +45 -0
  71. data/lib/ims/lti/models/tool_profile.rb +35 -0
  72. data/lib/ims/lti/models/tool_proxy.rb +21 -0
  73. data/lib/ims/lti/models/tool_setting.rb +12 -0
  74. data/lib/ims/lti/models/tool_setting_container.rb +14 -0
  75. data/lib/ims/lti/models/vendor.rb +28 -0
  76. data/lib/ims/lti/models.rb +38 -0
  77. data/lib/ims/lti/serializers/base.rb +125 -0
  78. data/lib/ims/lti/serializers/membership_service/agent_serializer.rb +5 -0
  79. data/lib/ims/lti/serializers/membership_service/container_serializer.rb +6 -0
  80. data/lib/ims/lti/serializers/membership_service/context_serializer.rb +9 -0
  81. data/lib/ims/lti/serializers/membership_service/lis_membership_container_serializer.rb +9 -0
  82. data/lib/ims/lti/serializers/membership_service/lis_person_serializer.rb +11 -0
  83. data/lib/ims/lti/serializers/membership_service/membership_serializer.rb +7 -0
  84. data/lib/ims/lti/serializers/membership_service/organization_serializer.rb +8 -0
  85. data/lib/ims/lti/serializers/membership_service/page_serializer.rb +10 -0
  86. data/lib/ims/lti/serializers/membership_service/person_serializer.rb +8 -0
  87. data/lib/ims/lti/serializers/membership_service.rb +13 -0
  88. data/lib/ims/lti/serializers.rb +6 -0
  89. data/lib/ims/lti/services/authentication_service.rb +67 -0
  90. data/lib/ims/lti/services/message_authenticator.rb +80 -0
  91. data/lib/ims/lti/services/oauth2_client.rb +18 -0
  92. data/lib/ims/lti/{tool_config.rb → services/tool_config.rb} +26 -34
  93. data/lib/ims/lti/services/tool_consumer_profile_service.rb +16 -0
  94. data/lib/ims/lti/services/tool_proxy_registration_service.rb +84 -0
  95. data/lib/ims/lti/services/tool_proxy_validator.rb +182 -0
  96. data/lib/ims/lti/services.rb +11 -0
  97. data/lib/ims/lti/version.rb +5 -0
  98. data/lib/ims/lti.rb +13 -63
  99. data/lib/ims.rb +4 -1
  100. metadata +266 -44
  101. data/Changelog +0 -54
  102. data/LICENSE +0 -18
  103. data/lib/ims/lti/deprecated_role_checks.rb +0 -52
  104. data/lib/ims/lti/extensions/canvas.rb +0 -122
  105. data/lib/ims/lti/extensions/content.rb +0 -209
  106. data/lib/ims/lti/extensions/outcome_data.rb +0 -216
  107. data/lib/ims/lti/extensions.rb +0 -45
  108. data/lib/ims/lti/launch_params.rb +0 -166
  109. data/lib/ims/lti/outcome_request.rb +0 -225
  110. data/lib/ims/lti/outcome_response.rb +0 -166
  111. data/lib/ims/lti/request_validator.rb +0 -56
  112. data/lib/ims/lti/role_checks.rb +0 -101
  113. data/lib/ims/lti/tool_base.rb +0 -29
  114. data/lib/ims/lti/tool_consumer.rb +0 -86
  115. data/lib/ims/lti/tool_provider.rb +0 -143
@@ -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
@@ -1,101 +0,0 @@
1
- module IMS::LTI
2
- # Some convenience methods for the most used roles
3
- # Take care when using context_ helpers, as the context of an LTI launch
4
- # determines the meaning of that role. For example, if the context is an
5
- # institution context instead of a course context, then the short role of
6
- # "Instructor" means they are a teacher at the institution, but not necessarily
7
- # of the course you're working in.
8
- #
9
- # Also note that these only check for the base roles. So, asking context_student?
10
- # only matches `urn:lti:role:ims/lis/Learner`, not `urn:lti:role:ims/lis/Learner/NonCreditLearner`
11
- # If you make use of the more specific roles you'll need to ask specifically for those:
12
- # @tool_provider.has_exact_role?("urn:lti:role:ims/lis/Learner/NonCreditLearner")
13
- # Or you can use `has_base_role?`
14
- module RoleChecks
15
-
16
- # Check whether the Launch Parameters have a given role
17
- def has_exact_role?(role)
18
- role = role.downcase
19
- @roles && @roles.any? { |r| r.downcase == role }
20
- end
21
-
22
- # Check whether the Launch Parameters have a given role ignoring
23
- # sub roles. So asking:
24
- # @tool_provider.has_base_role?("urn:lti:role:ims/lis/Instructor/")
25
- # will return true if the role is `urn:lti:role:ims/lis/Instructor/GuestInstructor`
26
- def has_base_role?(role)
27
- role = role.downcase
28
- @roles && @roles.any? { |r| r.downcase.start_with?(role) }
29
- end
30
-
31
- # Convenience method for checking if the user is the system administrator of the TC
32
- def system_administrator?
33
- has_exact_role?('urn:lti:sysrole:ims/lis/SysAdmin') ||
34
- has_exact_role?('SysAdmin') ||
35
- has_exact_role?('urn:lti:sysrole:ims/lis/Administrator')
36
- end
37
-
38
- ### Institution-level roles
39
- # Note, these only check if the role is explicitely an institution level role
40
- # if the context of the LTI launch is the institution, the short names
41
- # will apply, and you should use the context_x? helpers.
42
-
43
- # Convenience method for checking if the user has 'student' or 'learner' roles at the institution
44
- def institution_student?
45
- has_exact_role?('urn:lti:instrole:ims/lis/Student') || has_exact_role?('urn:lti:instrole:ims/lis/Learner')
46
- end
47
-
48
- # Convenience method for checking if the user has 'Instructor' role at the institution
49
- def institution_instructor?
50
- has_exact_role?('urn:lti:instrole:ims/lis/Instructor')
51
- end
52
-
53
- # Convenience method for checking if the user has 'Administrator' role at the institution
54
- def institution_admin?
55
- has_exact_role?('urn:lti:instrole:ims/lis/Administrator')
56
- end
57
-
58
-
59
- ### Context-level roles
60
- # Note, the most common LTI context is a course, but that is not always the
61
- # case. You should be aware of the context when using these helpers.
62
- # The difference for the context_ helpers is that they check for the
63
- # short version of the roles. So `Learner` and `urn:lti:role:ims/lis/Learner`
64
- # are both valid.
65
-
66
- # Convenience method for checking if the user has 'learner' role in the current launch context
67
- def context_student?
68
- has_exact_role?('Learner') || has_exact_role?('urn:lti:role:ims/lis/Learner')
69
- end
70
-
71
- # Convenience method for checking if the user has 'instructor' role in the current launch context
72
- def context_instructor?
73
- has_exact_role?('instructor') || has_exact_role?('urn:lti:role:ims/lis/Instructor')
74
- end
75
-
76
- # Convenience method for checking if the user has 'contentdeveloper' role in the current launch context
77
- def context_content_developer?
78
- has_exact_role?('ContentDeveloper') || has_exact_role?('urn:lti:role:ims/lis/ContentDeveloper')
79
- end
80
-
81
- # Convenience method for checking if the user has 'Mentor' role in the current launch context
82
- def context_mentor?
83
- has_exact_role?('Mentor') || has_exact_role?('urn:lti:role:ims/lis/Mentor')
84
- end
85
-
86
- # Convenience method for checking if the user has 'administrator' role in the current launch context
87
- def context_admin?
88
- has_exact_role?('Administrator') || has_exact_role?('urn:lti:role:ims/lis/Administrator')
89
- end
90
-
91
- # Convenience method for checking if the user has 'TeachingAssistant' role in the current launch context
92
- def context_ta?
93
- has_exact_role?('TeachingAssistant') || has_exact_role?('urn:lti:role:ims/lis/TeachingAssistant')
94
- end
95
-
96
- # Convenience method for checking if the user has 'Observer' role in the current launch context
97
- def context_observer?
98
- has_exact_role?('Observer') || has_exact_role?('urn:lti:instrole:ims/lis/Observer')
99
- end
100
- end
101
- end
@@ -1,29 +0,0 @@
1
- module IMS::LTI
2
- class ToolBase
3
- include IMS::LTI::Extensions::Base
4
- include IMS::LTI::LaunchParams
5
- include IMS::LTI::RequestValidator
6
-
7
- # OAuth credentials
8
- attr_accessor :consumer_key, :consumer_secret
9
-
10
- def initialize(consumer_key, consumer_secret, params={})
11
- @consumer_key = consumer_key
12
- @consumer_secret = consumer_secret
13
- @custom_params = {}
14
- @ext_params = {}
15
- @non_spec_params = {}
16
- process_params(params)
17
- end
18
-
19
- # Convenience method for doing oauth signed requests to services that
20
- # aren't supported by this library
21
- def post_service_request(url, content_type, body)
22
- IMS::LTI::post_service_request(@consumer_key,
23
- @consumer_secret,
24
- url,
25
- content_type,
26
- body)
27
- end
28
- end
29
- end
@@ -1,86 +0,0 @@
1
- module IMS::LTI
2
- # Class for implementing an LTI Tool Consumer
3
- class ToolConsumer < ToolBase
4
- attr_accessor :launch_url, :timestamp, :nonce
5
-
6
- # Create a new ToolConsumer
7
- #
8
- # @param consumer_key [String] The OAuth consumer key
9
- # @param consumer_secret [String] The OAuth consumer secret
10
- # @param params [Hash] Set the launch parameters as described in LaunchParams
11
- def initialize(consumer_key, consumer_secret, params={})
12
- super(consumer_key, consumer_secret, params)
13
- @launch_url = params['launch_url']
14
- end
15
-
16
- def process_post_request(post_request)
17
- request = extend_outcome_request(OutcomeRequest.new)
18
- request.process_post_request(post_request)
19
- end
20
-
21
- # Set launch data from a ToolConfig
22
- #
23
- # @param config [ToolConfig]
24
- def set_config(config)
25
- @launch_url ||= config.secure_launch_url
26
- @launch_url ||= config.launch_url
27
- # any parameters already set will take priority
28
- @custom_params = config.custom_params.merge(@custom_params)
29
- end
30
-
31
- # Check if the required parameters for a tool launch are set
32
- def has_required_params?
33
- @consumer_key && @consumer_secret && @resource_link_id && @launch_url
34
- end
35
-
36
- # Generate the launch data including the necessary OAuth information
37
- #
38
- #
39
- def generate_launch_data
40
- raise IMS::LTI::InvalidLTIConfigError, "Not all required params set for tool launch" unless has_required_params?
41
-
42
- params = self.to_params
43
- params['lti_version'] ||= 'LTI-1p0'
44
- params['lti_message_type'] ||= 'basic-lti-launch-request'
45
- uri = URI.parse(@launch_url)
46
-
47
- if uri.port == uri.default_port
48
- host = uri.host
49
- else
50
- host = "#{uri.host}:#{uri.port}"
51
- end
52
-
53
- consumer = OAuth::Consumer.new(@consumer_key, @consumer_secret, {
54
- :site => "#{uri.scheme}://#{host}",
55
- :signature_method => "HMAC-SHA1"
56
- })
57
-
58
- path = uri.path
59
- path = '/' if path.empty?
60
- if uri.query && uri.query != ''
61
- CGI.parse(uri.query).each do |query_key, query_values|
62
- unless params[query_key]
63
- params[query_key] = query_values.first
64
- end
65
- end
66
- end
67
- options = {
68
- :scheme => 'body',
69
- :timestamp => @timestamp,
70
- :nonce => @nonce
71
- }
72
- request = consumer.create_signed_request(:post, path, nil, options, params)
73
-
74
- # the request is made by a html form in the user's browser, so we
75
- # want to revert the escapage and return the hash of post parameters ready
76
- # for embedding in a html view
77
- hash = {}
78
- request.body.split(/&/).each do |param|
79
- key, val = param.split(/=/).map { |v| CGI.unescape(v) }
80
- hash[key] = val
81
- end
82
- hash
83
- end
84
-
85
- end
86
- end