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
@@ -0,0 +1,222 @@
1
+ module IMS::LTI::Models::Messages
2
+ class Message
3
+
4
+ attr_reader :message_authenticator
5
+
6
+ class << self
7
+
8
+ def required_params
9
+ supers_params('@required_params') | (@required_params || [])
10
+ end
11
+
12
+ def add_required_params(param, *params)
13
+ add_params('@required_params', param, *params)
14
+ end
15
+
16
+ def recommended_params
17
+ supers_params('@recommended_params') | (@recommended_params || [])
18
+ end
19
+
20
+ def add_recommended_params(param, *params)
21
+ add_params('@recommended_params', param, *params)
22
+ end
23
+
24
+ def optional_params
25
+ supers_params('@optional_params') | (@optional_params || [])
26
+ end
27
+
28
+ def add_optional_params(param, *params)
29
+ add_params('@optional_params', param, *params)
30
+ end
31
+
32
+ def deprecated_params
33
+ supers_params('@deprecated_params') | (@deprecated_params || [])
34
+ end
35
+
36
+ def add_deprecated_params(param, *params)
37
+ add_params('@deprecated_params', param, *params)
38
+ end
39
+
40
+ def inherited(klass)
41
+ @descendants ||= Set.new
42
+ @descendants << klass
43
+ superclass.inherited(klass) unless (self == Message)
44
+ end
45
+
46
+ def descendants
47
+ @descendants || Set.new
48
+ end
49
+
50
+ private
51
+
52
+ def add_params(instance_variable, param, *params)
53
+ instance_var = self.instance_variable_get(instance_variable) || []
54
+ instance_var |= params.unshift(param)
55
+ self.instance_variable_set(instance_variable, instance_var)
56
+ attr_accessor(params.shift, *params)
57
+ end
58
+
59
+ def parameters
60
+ required_params + recommended_params + optional_params + deprecated_params
61
+ end
62
+
63
+ def supers_params(instance_variable)
64
+ if name == "IMS::LTI::Models::Messages::Message"
65
+ []
66
+ else
67
+ (superclass.instance_variable_get(instance_variable) || []) | superclass.send(:supers_params, instance_variable)
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ MESSAGE_TYPE = "".freeze
74
+
75
+ LAUNCH_TARGET_IFRAME = 'iframe'
76
+ LAUNCH_TARGET_WINDOW = 'window'
77
+
78
+ EXTENSION_PREFIX = 'ext_'
79
+ CUSTOM_PREFIX = 'custom_'
80
+
81
+ OAUTH_KEYS = :oauth_callback, :oauth_consumer_key, :oauth_nonce, :oauth_signature, :oauth_signature_method,
82
+ :oauth_timestamp, :oauth_token, :oauth_verifier, :oauth_version
83
+
84
+ attr_accessor :launch_url, :jwt, *OAUTH_KEYS
85
+ attr_reader :unknown_params, :custom_params, :ext_params
86
+
87
+ add_required_params :lti_message_type, :lti_version
88
+
89
+ def self.generate(launch_params)
90
+ params = launch_params.key?('jwt') ? parse_jwt(jwt: launch_params['jwt']) : launch_params
91
+ klass = self.descendants.select {|d| d::MESSAGE_TYPE == params['lti_message_type']}.first
92
+ message = klass ? klass.new(params) : Message.new(params)
93
+ message.jwt = launch_params['jwt'] if launch_params.key?('jwt')
94
+ message
95
+ end
96
+
97
+ def self.parse_jwt(jwt:)
98
+ decoded_jwt = JSON::JWT.decode(jwt, :skip_verification)
99
+ params = decoded_jwt['org.imsglobal.lti.message'] || {}
100
+ custom = params.delete(:custom)
101
+ custom.each {|k,v| params["custom_#{k}"] = v }
102
+ params['consumer_key'] = decoded_jwt[:sub]
103
+ ext = params.delete(:ext)
104
+ ext.each {|k,v| params["ext_#{k}"] = v }
105
+ params
106
+ end
107
+
108
+ def initialize(attrs = {}, custom_params = {}, ext_params = {})
109
+
110
+ @custom_params = custom_params
111
+ @ext_params = ext_params
112
+ @unknown_params = {}
113
+
114
+ attrs.each do |k, v|
115
+ str_key = k.to_s
116
+ if str_key.start_with?(EXTENSION_PREFIX)
117
+ @ext_params[str_key] = v
118
+ elsif str_key.start_with?(CUSTOM_PREFIX)
119
+ @custom_params[str_key] = v
120
+ elsif !v.nil? && self.respond_to?(k.to_sym)
121
+ send(("#{k}=").to_sym, v)
122
+
123
+ else
124
+ warn "Unknown parameter #{k}"
125
+ @unknown_params[str_key] = v
126
+ end
127
+ end
128
+ end
129
+
130
+ def add_custom_params(params)
131
+ params.each {|k, v| k.to_s.start_with?('custom_') ? @custom_params[k.to_s] = v : @custom_params["custom_#{k.to_s}"] = v}
132
+ end
133
+
134
+ def get_custom_params
135
+ @custom_params.inject({}) {|hash, (k, v)| hash[k.gsub(/\Acustom_/, '')] = v; hash}
136
+ end
137
+
138
+ def get_ext_params
139
+ @ext_params.inject({}) {|hash, (k, v)| hash[k.gsub(/\Aext_/, '')] = v; hash}
140
+ end
141
+
142
+ def post_params
143
+ unknown_params.merge(@custom_params).merge(@ext_params).merge(parameters)
144
+ end
145
+
146
+ def jwt_params(private_key:, originating_domain:, algorithm: :HS256)
147
+ { 'jwt' => to_jwt(private_key: private_key, originating_domain: originating_domain, algorithm: algorithm) }
148
+ end
149
+
150
+ def signed_post_params(secret)
151
+ message_params = oauth_params.merge(post_params)
152
+ @message_authenticator = IMS::LTI::Services::MessageAuthenticator.new(launch_url, message_params, secret)
153
+ @message_authenticator.signed_params
154
+ end
155
+
156
+ def parameters
157
+ collect_attributes(self.class.send("parameters"))
158
+ end
159
+
160
+ def required_params
161
+ collect_attributes(self.class.required_params)
162
+ end
163
+
164
+ def recommended_params
165
+ collect_attributes(self.class.recommended_params)
166
+ end
167
+
168
+ def optional_params
169
+ collect_attributes(self.class.optional_params)
170
+ end
171
+
172
+ def deprecated_params
173
+ collect_attributes(self.class.deprecated_params)
174
+ end
175
+
176
+ def oauth_params
177
+ collect_attributes(OAUTH_KEYS)
178
+ end
179
+
180
+ def method_missing(meth, *args, &block)
181
+ if match = /^(custom|ext)_([^=$]*)/.match(meth)
182
+ param_type, key = match.captures
183
+ param_hash = instance_variable_get("@#{param_type}_params".to_sym)
184
+ meth =~ /=$/ ? param_hash[match.to_s] = args[0] : param_hash[match.to_s]
185
+ else
186
+ super
187
+ end
188
+ end
189
+
190
+ def to_jwt(private_key:, originating_domain:, algorithm: :HS256)
191
+ now = Time.now
192
+ exp = now + 60 * 5
193
+ ims = unknown_params.merge(parameters)
194
+ ims[:custom] = get_custom_params
195
+ ims[:ext] = get_ext_params
196
+ claim = {
197
+ iss: originating_domain,
198
+ sub: consumer_key,
199
+ aud: launch_url,
200
+ iat: now,
201
+ exp: exp,
202
+ jti: SecureRandom.uuid,
203
+ "org.imsglobal.lti.message" => ims
204
+ }
205
+ jwt = JSON::JWT.new(claim).sign(private_key, algorithm)
206
+ jwt.to_s
207
+ end
208
+
209
+ alias_attribute :consumer_key, :oauth_consumer_key
210
+
211
+ private
212
+
213
+ def collect_attributes(attributes)
214
+ attributes.inject({}) do |h, param|
215
+ value = instance_variable_get("@#{param}")
216
+ h[param.to_s] = value if value
217
+ h
218
+ end
219
+ end
220
+
221
+ end
222
+ end
@@ -0,0 +1,20 @@
1
+ module IMS::LTI::Models::Messages
2
+ class RegistrationRequest < RequestMessage
3
+
4
+ add_required_params :reg_key, :reg_password, :tc_profile_url, :launch_presentation_return_url, :tool_proxy_guid,
5
+ :tool_proxy_url
6
+
7
+
8
+ MESSAGE_TYPE = 'ToolProxyRegistrationRequest'
9
+
10
+ def initialize(attrs = {})
11
+ super(attrs)
12
+ self.lti_message_type = MESSAGE_TYPE
13
+ end
14
+
15
+ def generate_key_and_password
16
+ self.reg_key, self.reg_password = 2.times.map { SecureRandom.uuid }
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module IMS::LTI::Models::Messages
2
+ class RequestMessage < Message
3
+
4
+ add_recommended_params :user_id, :roles, :launch_presentation_document_target, :launch_presentation_width, :launch_presentation_height
5
+ add_optional_params :launch_presentation_locale, :launch_presentation_css_url
6
+
7
+ def initialize(attrs = {})
8
+ super(attrs)
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module IMS::LTI::Models::Messages
2
+ class ToolProxyUpdateRequest < RequestMessage
3
+
4
+ add_required_params :tc_profile_url, :launch_presentation_return_url
5
+
6
+
7
+ MESSAGE_TYPE = 'ToolProxyUpdateRequest'
8
+
9
+ def initialize(attrs = {})
10
+ super(attrs)
11
+ self.lti_message_type = MESSAGE_TYPE
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module IMS::LTI::Models
2
+ module Messages
3
+ require_relative 'messages/message'
4
+ require_relative 'messages/request_message'
5
+ require_relative 'messages/registration_request'
6
+ require_relative 'messages/basic_lti_launch_request'
7
+ require_relative 'messages/content_item_selection_request'
8
+ require_relative 'messages/content_item_selection'
9
+ require_relative 'messages/tool_proxy_update_request'
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ module IMS::LTI::Models
2
+ class Parameter < LTIModel
3
+
4
+ add_attributes :name, :variable, :fixed
5
+
6
+ def fixed?
7
+ !fixed.nil? && fixed.to_s.strip != ''
8
+ end
9
+
10
+ def self.process_params(parameters, lookup_hash)
11
+ [*parameters].inject({}) do |hash, param|
12
+ hash[param.name] = param.fixed? ? param.fixed : expand_variable(lookup_hash[param.variable]) || '$' + param.variable
13
+ hash
14
+ end
15
+ end
16
+
17
+ def ==(obj)
18
+ self.fixed? == obj.fixed? && self.name == obj.name && self.fixed == obj.fixed
19
+ end
20
+
21
+ private
22
+
23
+ def self.expand_variable(value)
24
+ value.respond_to?(:call) ? value.call : value
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ module IMS::LTI::Models
2
+ class ProductFamily < LTIModel
3
+ add_attributes :code
4
+ add_attribute :id, json_key: '@id'
5
+ add_attribute :vendor, relation: 'IMS::LTI::Models::Vendor'
6
+
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ module IMS::LTI::Models
2
+ class ProductInfo < LTIModel
3
+ add_attribute :product_version
4
+ add_attribute :product_family, relation: 'IMS::LTI::Models::ProductFamily'
5
+ add_attribute :description, relation: 'IMS::LTI::Models::LocalizedText'
6
+ add_attribute :product_name, relation: 'IMS::LTI::Models::LocalizedName'
7
+ add_attribute :technical_description, relation: 'IMS::LTI::Models::LocalizedText'
8
+
9
+ def create_product_name(name, key = 'product.name')
10
+ @product_name = LocalizedName.new(name, key)
11
+ end
12
+
13
+ def create_description(name, key = 'product.description')
14
+ @description = LocalizedText.new(name, key)
15
+ end
16
+
17
+ def default_description
18
+ description && description.default_value
19
+ end
20
+
21
+ def default_name
22
+ product_name && product_name.default_value
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ module IMS::LTI::Models
2
+ class ProductInstance < LTIModel
3
+ add_attributes :guid
4
+ add_attribute :product_info, relation:'IMS::LTI::Models::ProductInfo'
5
+ add_attribute :service_owner, relation:'IMS::LTI::Models::ServiceOwner'
6
+ add_attribute :service_provider, relation:'IMS::LTI::Models::ServiceProvider'
7
+ add_attribute :support, relation:'IMS::LTI::Models::Contact'
8
+
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ module IMS::LTI::Models
2
+ class ResourceHandler < LTIModel
3
+ add_attribute :resource_type, relation: 'IMS::LTI::Models::ResourceType'
4
+ add_attribute :resource_name, relation: 'IMS::LTI::Models::LocalizedName'
5
+ add_attribute :description, relation: 'IMS::LTI::Models::LocalizedText'
6
+ add_attribute :message, relation: 'IMS::LTI::Models::MessageHandler'
7
+ add_attribute :icon_info, relation: 'IMS::LTI::Models::IconInfo'
8
+
9
+ def default_name
10
+ resource_name && resource_name.default_value
11
+ end
12
+
13
+ def default_description
14
+ description && description.default_value
15
+ end
16
+
17
+ def messages
18
+ [*message]
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ module IMS::LTI::Models
2
+ class ResourceType < LTIModel
3
+ add_attribute :code
4
+
5
+ end
6
+ end
@@ -0,0 +1,30 @@
1
+ module IMS::LTI::Models
2
+ class RestService < LTIModel
3
+ TYPE = 'RestService'
4
+
5
+ add_attributes :endpoint, :format, :action
6
+ add_attribute :id, json_key:'@id'
7
+ add_attribute :type, json_key: '@type'
8
+
9
+ def initialize(attributes = {})
10
+ @type = TYPE
11
+ super(attributes)
12
+ end
13
+
14
+ def profile
15
+ RestServiceProfile.new(
16
+ service: endpoint,
17
+ action: action
18
+ )
19
+ end
20
+
21
+ def actions
22
+ [*action]
23
+ end
24
+
25
+ def formats
26
+ [*format]
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module IMS::LTI::Models
2
+ class RestServiceProfile < LTIModel
3
+ add_attributes :service, :action
4
+ add_attribute :type, json_key: '@type'
5
+
6
+ def initialize(attributes = {})
7
+ @type = "RestServiceProfile"
8
+ super(attributes)
9
+ end
10
+
11
+ def actions
12
+ [*action]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module IMS::LTI::Models
2
+ class SecurityContract < LTIModel
3
+
4
+ add_attributes :shared_secret, :tp_half_shared_secret
5
+ add_attribute :tool_service, relation: 'IMS::LTI::Models::RestServiceProfile'
6
+ add_attribute :end_user_service, relation: 'IMS::LTI::Models::RestServiceProfile'
7
+
8
+ def tool_services
9
+ [*tool_service]
10
+ end
11
+
12
+ def end_user_services
13
+ [*end_user_service]
14
+ end
15
+
16
+ def services
17
+ tool_services + end_user_services
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module IMS::LTI::Models
2
+ class SecurityProfile < LTIModel
3
+ add_attributes :security_profile_name, :digest_algorithm
4
+
5
+ def digest_algorithms
6
+ [*@digest_algorithm]
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module IMS::LTI::Models
2
+ module Serializable
3
+ def as_json(opts={})
4
+ class_name = self.class.name.gsub(/^IMS::LTI::Models/, 'IMS::LTI::Serializers') + 'Serializer'
5
+ Object.const_get(class_name).as_json(self)
6
+ end
7
+
8
+ def to_json
9
+ as_json.to_json
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ module IMS::LTI::Models
2
+ class ServiceOwner < LTIModel
3
+ add_attribute :id, json_key:'@id'
4
+ add_attribute :description, relation: 'IMS::LTI::Models::LocalizedText'
5
+ add_attribute :timestamp, json_converter:'IMS::LTI::Converters::TimeJSONConverter'
6
+ add_attribute :service_owner_name, relation: 'IMS::LTI::Models::LocalizedName'
7
+ add_attribute :support, relation:'IMS::LTI::Models::Contact'
8
+
9
+ def create_service_owner_name(name, key = 'service_owner.name')
10
+ @service_owner_name = LocalizedName.new(name, key)
11
+ end
12
+
13
+ def create_description(name, key = 'service_owner.description')
14
+ @description = LocalizedText.new(name, key)
15
+ end
16
+
17
+ def default_name
18
+ service_owner_name && service_owner_name.default_value
19
+ end
20
+
21
+ def default_description
22
+ description && description.default_value
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ module IMS::LTI::Models
2
+ class ServiceProvider < LTIModel
3
+ add_attribute :guid
4
+ add_attribute :id, json_key:'@id'
5
+ add_attribute :service_provider_name, relation:'IMS::LTI::Models::LocalizedName'
6
+ add_attribute :description, relation:'IMS::LTI::Models::LocalizedText'
7
+ add_attribute :support, relation:'IMS::LTI::Models::Contact'
8
+ add_attribute :timestamp, json_converter: 'IMS::LTI::Converters::TimeJSONConverter'
9
+
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ module IMS::LTI::Models
2
+ class ToolConsumerProfile < LTIModel
3
+
4
+ CONTEXT = "http://purl.imsglobal.org/ctx/lti/v2/ToolConsumerProfile"
5
+ TYPE = "ToolConsumerProfile"
6
+
7
+ MESSAGING_CAPABILITIES = %w(basic-lti-launch-request)
8
+ OUTCOMES_CAPABILITIES = %w(Result.autocreate)
9
+
10
+ add_attributes :lti_version, :guid, :capability_offered, :security_profile
11
+ add_attribute :id, json_key:'@id'
12
+ add_attribute :type, json_key:'@type'
13
+ add_attribute :context, json_key:'@context'
14
+ add_attribute :security_profile, relation: 'IMS::LTI::Models::SecurityProfile'
15
+ add_attribute :product_instance, relation:'IMS::LTI::Models::ProductInstance'
16
+ add_attribute :service_offered, relation: 'IMS::LTI::Models::RestService'
17
+
18
+ def initialize(attr = {})
19
+ @context = [CONTEXT]
20
+ @type = TYPE
21
+ super(attr)
22
+ end
23
+
24
+ def services_offered
25
+ [*@service_offered]
26
+ end
27
+
28
+ def capabilities_offered
29
+ [*@capability_offered]
30
+ end
31
+
32
+ def security_profiles
33
+ [*@security_profile]
34
+ end
35
+
36
+ def reregistration_capable?
37
+ @capability_offered.include?(Messages::ToolProxyUpdateRequest::MESSAGE_TYPE)
38
+ end
39
+
40
+ def security_profile_by_name(security_profile_name:)
41
+ security_profiles.find { |sp| sp.security_profile_name == security_profile_name}
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,35 @@
1
+ module IMS::LTI::Models
2
+ class ToolProfile < LTIModel
3
+ add_attributes :lti_version
4
+ add_attribute :id, json_key: '@id'
5
+ add_attribute :product_instance, relation:'IMS::LTI::Models::ProductInstance'
6
+ add_attribute :base_url_choice, relation: 'IMS::LTI::Models::BaseUrlChoice'
7
+ add_attribute :resource_handler, relation:'IMS::LTI::Models::ResourceHandler'
8
+ add_attribute :message, relation:'IMS::LTI::Models::MessageHandler'
9
+ add_attribute :service_offered, relation:'IMS::LTI::Models::RestService'
10
+ add_attribute :security_profile, relation:'IMS::LTI::Models::SecurityProfile'
11
+
12
+
13
+ def base_message_url
14
+ if base_url_choice
15
+ choice = base_url_choice.find { |choice| choice.default_message_url != '' }
16
+ choice ? choice.default_message_url : ''
17
+ else
18
+ ''
19
+ end
20
+ end
21
+
22
+ def resource_handlers
23
+ [*@resource_handler]
24
+ end
25
+
26
+ def messages
27
+ [*@message]
28
+ end
29
+
30
+ def security_profiles
31
+ [*@security_profile]
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ module IMS::LTI::Models
2
+ class ToolProxy < LTIModel
3
+ add_attributes :lti_version, :tool_proxy_guid, :custom, :custom_url, :enabled_capability, :tc_half_shared_secret
4
+ add_attribute :context, json_key:'@context'
5
+ add_attribute :type, json_key:'@type'
6
+ add_attribute :id, json_key:'@id'
7
+ add_attribute :tool_consumer_profile
8
+ add_attribute :tool_profile, relation:'IMS::LTI::Models::ToolProfile'
9
+ add_attribute :security_contract, relation:'IMS::LTI::Models::SecurityContract'
10
+
11
+ def initialize(attr = {})
12
+ @context = ['http://purl.imsglobal.org/ctx/lti/v2/ToolProxy']
13
+ super(attr)
14
+ @type = 'ToolProxy'
15
+ end
16
+
17
+ def enabled_capabilities
18
+ [*enabled_capability]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module IMS::LTI::Models
2
+ class ToolSetting < LTIModel
3
+ add_attribute :type, json_key: '@type'
4
+ add_attribute :id, json_key: '@id'
5
+ add_attributes :custom, :custom_url
6
+
7
+ TOOL_PROXY_BINDING_TYPE = 'ToolProxyBinding'
8
+ TOOL_PROXY_TYPE = 'ToolProxy'
9
+ LTI_LINK_TYPE = 'LtiLink'
10
+
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module IMS::LTI::Models
2
+ class ToolSettingContainer < LTIModel
3
+ add_attribute :context, json_key: '@context'
4
+ add_attribute :graph, json_key: '@graph', relation: 'IMS::LTI::Models::ToolSetting'
5
+
6
+ TOOL_SETTING_CONTAINER_CONTEXT = 'http://purl.imsglobal.org/ctx/lti/v2/ToolSettings'
7
+
8
+ def initialize(opts = {})
9
+ super(opts)
10
+ self.context = TOOL_SETTING_CONTAINER_CONTEXT
11
+ end
12
+
13
+ end
14
+ end