ims-lti 2.0.0.beta.18 → 2.0.0.beta.19

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
2
  SHA1:
3
- metadata.gz: 469b57f391256431763f04ca1187ae5a7769367a
4
- data.tar.gz: 0be379c6ea503a5503b9319aaaec4a0cc3c89f38
3
+ metadata.gz: abb31c30499a793de7682bdd02c9e1e8a71f1500
4
+ data.tar.gz: a4ed57fa69bf00c8128ec2986d47d9d3ef2c7c7b
5
5
  SHA512:
6
- metadata.gz: e16ab1448cc60ae4a895d0d21eb5f9d9a09ac65efcf211c50a84adb01fbbb43105b261e15da74fe9e9fe69b7e1a7d84f18306c5f4fe8073b527c897059e151da
7
- data.tar.gz: f5b3797ab367c341275611dfc31434673cc73c94916036d02471fe570e499f5e5cfdc343b7252da33777c72b6e4ede92d452a1977bfefd2de25aaa6a856c280b
6
+ metadata.gz: 473cafa07eada8291040ecc68b7b5ee5815914f72522576fdd442fbce7ed91bbbfed19d150a55f9178aaef3564d9ec53dce72c4a48214102b7c079c5cc2eeb6e
7
+ data.tar.gz: 70e79ca8a862600a05508314b99a281a4800600038f4e106d92bf1aebc140df14ccf1d4d6011fc2aea8ad5e6ff3b2228ffab29cef6268762a4cdf8a074be1300
@@ -3,11 +3,14 @@ require 'securerandom'
3
3
  require 'simple_oauth'
4
4
  require 'faraday'
5
5
  require 'faraday_middleware'
6
+ require 'builder'
7
+ require 'rexml/document'
6
8
 
7
9
  module IMS
8
10
  module LTI
9
11
  require_relative 'lti/models'
10
12
  require_relative 'lti/converters'
11
13
  require_relative 'lti/services'
14
+ require_relative 'lti/errors'
12
15
  end
13
16
  end
@@ -0,0 +1,5 @@
1
+ module IMS::LTI
2
+ module Errors
3
+ require_relative 'errors/invalid_lti_config_error'
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module IMS::LTI::Errors
2
+ class InvalidLTIConfigError < StandardError
3
+ end
4
+ end
@@ -10,7 +10,7 @@ module IMS::LTI::Models::Messages
10
10
  :lis_course_offering_sourcedid, :lis_course_section_sourcedid,
11
11
  :tool_consumer_info_product_family_code, :tool_consumer_info_product_family_version,
12
12
  :tool_consumer_instance_name, :tool_consumer_instance_description, :tool_consumer_instance_url,
13
- :tool_consumer_instance_contact_email
13
+ :tool_consumer_instance_contact_email, :tool_consumer_info_version
14
14
 
15
15
  MESSAGE_TYPE = 'basic-lti-launch-request'
16
16
 
@@ -1,5 +1,6 @@
1
1
  module IMS::LTI
2
2
  module Services
3
3
  require_relative 'services/tool_proxy_registration_service'
4
+ require_relative 'services/tool_config'
4
5
  end
5
6
  end
@@ -1,10 +1,12 @@
1
- class ServiceDefinition
2
- attr_reader :name, :formats, :paramater_variables
1
+ module IMS::LTI::Services
2
+ class ServiceDefinition
3
+ attr_reader :name, :formats, :paramater_variables
3
4
 
4
- def initialize(name, formats, parameter_variables = [])
5
- @name = name
6
- @formats = formats
7
- @parameter_variables = parameter_variables
8
- end
5
+ def initialize(name, formats, parameter_variables = [])
6
+ @name = name
7
+ @formats = formats
8
+ @parameter_variables = parameter_variables
9
+ end
9
10
 
10
- end
11
+ end
12
+ end
@@ -1,30 +1,32 @@
1
- class ServiceLookup
1
+ module IMS::LTI::Services
2
+ class ServiceLookup
2
3
 
3
- TOOL_SETTING_SERVICE = ServiceDefinition.new(
4
- 'ToolSettingsContainer Service',
5
- %w(application/vnd.ims.lti.v2.toolsettings+json application/vnd.ims.lti.v2.toolsettings.simple+json),
6
- %w(LtiLink.custom.url ToolProxyBinding.custom.url ToolProxy.custom.url)
7
- )
4
+ TOOL_SETTING_SERVICE = ServiceDefinition.new(
5
+ 'ToolSettingsContainer Service',
6
+ %w(application/vnd.ims.lti.v2.toolsettings+json application/vnd.ims.lti.v2.toolsettings.simple+json),
7
+ %w(LtiLink.custom.url ToolProxyBinding.custom.url ToolProxy.custom.url)
8
+ )
8
9
 
9
- TOOL_CONSUMER_PROFILE_SERVICE = ServiceDefinition.new(
10
- 'ToolConsumerProfile Service',
11
- %w(application/vnd.ims.lti.v2.toolconsumerprofile+json),
12
- []
13
- )
10
+ TOOL_CONSUMER_PROFILE_SERVICE = ServiceDefinition.new(
11
+ 'ToolConsumerProfile Service',
12
+ %w(application/vnd.ims.lti.v2.toolconsumerprofile+json),
13
+ []
14
+ )
14
15
 
15
- TOOL_PROXY_SERVICE = ServiceDefinition.new(
16
- 'ToolProxy Service',
17
- %w(application/vnd.ims.lti.v2.toolproxy+json),
18
- []
19
- )
16
+ TOOL_PROXY_SERVICE = ServiceDefinition.new(
17
+ 'ToolProxy Service',
18
+ %w(application/vnd.ims.lti.v2.toolproxy+json),
19
+ []
20
+ )
20
21
 
21
- def self.services
22
- [TOOL_SETTING_SERVICE, TOOL_CONSUMER_PROFILE_SERVICE, TOOL_PROXY_SERVICE]
23
- end
22
+ def self.services
23
+ [TOOL_SETTING_SERVICE, TOOL_CONSUMER_PROFILE_SERVICE, TOOL_PROXY_SERVICE]
24
+ end
24
25
 
25
- def self.lookup(format)
26
- services.select { |service| service.formats.include? format }
27
- end
26
+ def self.lookup(format)
27
+ services.select { |service| service.formats.include? format }
28
+ end
28
29
 
29
30
 
30
- end
31
+ end
32
+ end
@@ -0,0 +1,225 @@
1
+ module IMS::LTI::Services
2
+ # Class used to represent an LTI configuration
3
+ #
4
+ # It can create and read the Common Cartridge XML representation of LTI links
5
+ # as described here: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649689
6
+ #
7
+ # == Usage
8
+ # To generate an XML configuration:
9
+ #
10
+ # # Create a config object and set some options
11
+ # tc = IMS::LTI::Services::ToolConfig.new(:title => "Example Sinatra Tool Provider", :launch_url => url)
12
+ # tc.description = "This example LTI Tool Provider supports LIS Outcome pass-back."
13
+ #
14
+ # # generate the XML
15
+ # tc.to_xml
16
+ #
17
+ # Or to create a config object from an XML String:
18
+ #
19
+ # tc = IMS::LTI::Services::ToolConfig.create_from_xml(xml)
20
+ class ToolConfig
21
+ attr_reader :custom_params, :extensions
22
+
23
+ attr_accessor :title, :description, :launch_url, :secure_launch_url,
24
+ :icon, :secure_icon, :cartridge_bundle, :cartridge_icon,
25
+ :vendor_code, :vendor_name, :vendor_description, :vendor_url,
26
+ :vendor_contact_email, :vendor_contact_name
27
+
28
+ # Create a new ToolConfig with the given options
29
+ #
30
+ # @param opts [Hash] The initial options for the ToolConfig
31
+ def initialize(opts={})
32
+ @custom_params = opts.delete("custom_params") || {}
33
+ @extensions = opts.delete("extensions") || {}
34
+
35
+ opts.each_pair do |key, val|
36
+ self.send("#{key}=", val) if self.respond_to?("#{key}=")
37
+ end
38
+ end
39
+
40
+ # Create a ToolConfig from the given XML
41
+ #
42
+ # @param xml [String]
43
+ def self.create_from_xml(xml)
44
+ tc = ToolConfig.new
45
+ tc.process_xml(xml)
46
+
47
+ tc
48
+ end
49
+
50
+ def set_custom_param(key, val)
51
+ @custom_params[key] = val
52
+ end
53
+
54
+ def get_custom_param(key)
55
+ @custom_params[key]
56
+ end
57
+
58
+ # Set the extension parameters for a specific vendor
59
+ #
60
+ # @param ext_key [String] The identifier for the vendor-specific parameters
61
+ # @param ext_params [Hash] The parameters, this is allowed to be two-levels deep
62
+ def set_ext_params(ext_key, ext_params)
63
+ raise ArgumentError unless ext_params.is_a?(Hash)
64
+ @extensions[ext_key] = ext_params
65
+ end
66
+
67
+ def get_ext_params(ext_key)
68
+ @extensions[ext_key]
69
+ end
70
+
71
+ def set_ext_param(ext_key, param_key, val)
72
+ @extensions[ext_key] ||= {}
73
+ @extensions[ext_key][param_key] = val
74
+ end
75
+
76
+ def get_ext_param(ext_key, param_key)
77
+ @extensions[ext_key] && @extensions[ext_key][param_key]
78
+ end
79
+
80
+ # Namespaces used for parsing configuration XML
81
+ LTI_NAMESPACES = {
82
+ "xmlns" => 'http://www.imsglobal.org/xsd/imslticc_v1p0',
83
+ "blti" => 'http://www.imsglobal.org/xsd/imsbasiclti_v1p0',
84
+ "lticm" => 'http://www.imsglobal.org/xsd/imslticm_v1p0',
85
+ "lticp" => 'http://www.imsglobal.org/xsd/imslticp_v1p0',
86
+ }
87
+
88
+ # Parse tool configuration data out of the Common Cartridge LTI link XML
89
+ def process_xml(xml)
90
+ doc = REXML::Document.new xml
91
+ if root = REXML::XPath.first(doc, 'xmlns:cartridge_basiclti_link')
92
+ @title = get_node_text(root, 'blti:title')
93
+ @description = get_node_text(root, 'blti:description')
94
+ @launch_url = get_node_text(root, 'blti:launch_url')
95
+ @secure_launch_url = get_node_text(root, 'blti:secure_launch_url')
96
+ @icon = get_node_text(root, 'blti:icon')
97
+ @secure_icon = get_node_text(root, 'blti:secure_icon')
98
+ @cartridge_bundle = get_node_att(root, 'xmlns:cartridge_bundle', 'identifierref')
99
+ @cartridge_icon = get_node_att(root, 'xmlns:cartridge_icon', 'identifierref')
100
+
101
+ if vendor = REXML::XPath.first(root, 'blti:vendor')
102
+ @vendor_code = get_node_text(vendor, 'lticp:code')
103
+ @vendor_description = get_node_text(vendor, 'lticp:description')
104
+ @vendor_name = get_node_text(vendor, 'lticp:name')
105
+ @vendor_url = get_node_text(vendor, 'lticp:url')
106
+ @vendor_contact_email = get_node_text(vendor, '//lticp:contact/lticp:email')
107
+ @vendor_contact_name = get_node_text(vendor, '//lticp:contact/lticp:name')
108
+ end
109
+
110
+ if custom = REXML::XPath.first(root, 'blti:custom', LTI_NAMESPACES)
111
+ set_properties(@custom_params, custom)
112
+ end
113
+
114
+ REXML::XPath.each(root, 'blti:extensions', LTI_NAMESPACES) do |vendor_ext_node|
115
+ platform = vendor_ext_node.attributes['platform']
116
+ properties = {}
117
+ set_properties(properties, vendor_ext_node)
118
+ REXML::XPath.each(vendor_ext_node, 'lticm:options', LTI_NAMESPACES) do |options_node|
119
+ opt_name = options_node.attributes['name']
120
+ options = {}
121
+ set_properties(options, options_node)
122
+ properties[opt_name] = options
123
+ end
124
+
125
+ self.set_ext_params(platform, properties)
126
+ end
127
+
128
+ end
129
+ end
130
+
131
+ # Generate XML from the current settings
132
+ def to_xml(opts = {})
133
+ raise IMS::LTI::Errors::InvalidLTIConfigError, "A launch url is required for an LTI configuration." unless self.launch_url || self.secure_launch_url
134
+
135
+ builder = Builder::XmlMarkup.new(:indent => opts[:indent] || 0)
136
+ builder.instruct!
137
+ builder.cartridge_basiclti_link("xmlns" => "http://www.imsglobal.org/xsd/imslticc_v1p0",
138
+ "xmlns:blti" => 'http://www.imsglobal.org/xsd/imsbasiclti_v1p0',
139
+ "xmlns:lticm" => 'http://www.imsglobal.org/xsd/imslticm_v1p0',
140
+ "xmlns:lticp" => 'http://www.imsglobal.org/xsd/imslticp_v1p0',
141
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
142
+ "xsi:schemaLocation" => "http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd"
143
+ ) do |blti_node|
144
+
145
+ %w{title description launch_url secure_launch_url icon secure_icon}.each do |key|
146
+ blti_node.blti key.to_sym, self.send(key) if self.send(key)
147
+ end
148
+
149
+ vendor_keys = %w{name code description url}
150
+ if vendor_keys.any? { |k| self.send("vendor_#{k}") } || vendor_contact_email
151
+ blti_node.blti :vendor do |v_node|
152
+ vendor_keys.each do |key|
153
+ v_node.lticp key.to_sym, self.send("vendor_#{key}") if self.send("vendor_#{key}")
154
+ end
155
+ if vendor_contact_email
156
+ v_node.lticp :contact do |c_node|
157
+ c_node.lticp :name, vendor_contact_name
158
+ c_node.lticp :email, vendor_contact_email
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ if !@custom_params.empty?
165
+ blti_node.tag!("blti:custom") do |custom_node|
166
+ @custom_params.keys.sort.each do |key|
167
+ val = @custom_params[key]
168
+ custom_node.lticm :property, val, 'name' => key
169
+ end
170
+ end
171
+ end
172
+
173
+ if !@extensions.empty?
174
+ @extensions.keys.sort.each do |ext_platform|
175
+ ext_params = @extensions[ext_platform]
176
+ blti_node.blti(:extensions, :platform => ext_platform) do |ext_node|
177
+ ext_params.keys.sort.each do |key|
178
+ val = ext_params[key]
179
+ if val.is_a?(Hash)
180
+ ext_node.lticm(:options, :name => key) do |type_node|
181
+ val.keys.sort.each do |p_key|
182
+ p_val = val[p_key]
183
+ type_node.lticm :property, p_val, 'name' => p_key
184
+ end
185
+ end
186
+ else
187
+ ext_node.lticm :property, val, 'name' => key
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ blti_node.cartridge_bundle(:identifierref => @cartridge_bundle) if @cartridge_bundle
195
+ blti_node.cartridge_icon(:identifierref => @cartridge_icon) if @cartridge_icon
196
+
197
+ end
198
+ end
199
+
200
+ private
201
+
202
+ def get_node_text(node, path)
203
+ if val = REXML::XPath.first(node, path, LTI_NAMESPACES)
204
+ val.text
205
+ else
206
+ nil
207
+ end
208
+ end
209
+
210
+ def get_node_att(node, path, att)
211
+ if val = REXML::XPath.first(node, path, LTI_NAMESPACES)
212
+ val.attributes[att]
213
+ else
214
+ nil
215
+ end
216
+ end
217
+
218
+ def set_properties(hash, node)
219
+ REXML::XPath.each(node, 'lticm:property', LTI_NAMESPACES) do |prop|
220
+ hash[prop.attributes['name']] = prop.text
221
+ end
222
+ end
223
+
224
+ end
225
+ end
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: 2.0.0.beta.18
4
+ version: 2.0.0.beta.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-12 00:00:00.000000000 Z
11
+ date: 2015-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simple_oauth
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: builder
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -107,6 +121,8 @@ files:
107
121
  - lib/ims/lti.rb
108
122
  - lib/ims/lti/converters.rb
109
123
  - lib/ims/lti/converters/time_json_converter.rb
124
+ - lib/ims/lti/errors.rb
125
+ - lib/ims/lti/errors/invalid_lti_config_error.rb
110
126
  - lib/ims/lti/models.rb
111
127
  - lib/ims/lti/models/base_url_choice.rb
112
128
  - lib/ims/lti/models/base_url_selector.rb
@@ -141,6 +157,7 @@ files:
141
157
  - lib/ims/lti/services.rb
142
158
  - lib/ims/lti/services/service_definition.rb
143
159
  - lib/ims/lti/services/service_lookup.rb
160
+ - lib/ims/lti/services/tool_config.rb
144
161
  - lib/ims/lti/services/tool_proxy_registration_service.rb
145
162
  - lib/ims/lti/version.rb
146
163
  homepage: http://github.com/instructure/ims-lti