lti2 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/lib/lti2/version.rb +1 -1
  3. data/lti2_tp/Gemfile +14 -0
  4. data/lti2_tp/Gemfile.lock +94 -0
  5. data/lti2_tp/MIT-LICENSE +20 -0
  6. data/lti2_tp/README.md +77 -0
  7. data/lti2_tp/README.rdoc +3 -0
  8. data/lti2_tp/Rakefile +31 -0
  9. data/lti2_tp/app/assets/javascripts/lti2_tp/application.js +13 -0
  10. data/lti2_tp/app/assets/stylesheets/lti2_tp/application.css +13 -0
  11. data/lti2_tp/app/controllers/lti2_tp/application_controller.rb +4 -0
  12. data/lti2_tp/app/controllers/lti2_tp/registrations_controller.rb +200 -0
  13. data/lti2_tp/app/models/lti2_tp/context.rb +55 -0
  14. data/lti2_tp/app/models/lti2_tp/registration.rb +180 -0
  15. data/lti2_tp/app/models/lti2_tp/registry.rb +5 -0
  16. data/lti2_tp/app/models/lti2_tp/tool.rb +27 -0
  17. data/lti2_tp/app/models/lti2_tp/tool_deployment.rb +5 -0
  18. data/lti2_tp/app/models/lti2_tp/tool_provider_registry.rb +21 -0
  19. data/lti2_tp/app/views/layouts/lti2_tp/application.html.erb +14 -0
  20. data/lti2_tp/bin/rails +8 -0
  21. data/lti2_tp/config/initializers/lti2_tp.rb +11 -0
  22. data/lti2_tp/config/routes.rb +9 -0
  23. data/lti2_tp/db/migrate/20140826151614_create_lti2_tp_resources.rb +67 -0
  24. data/lti2_tp/lib/lti2_tp.rb +4 -0
  25. data/lti2_tp/lib/lti2_tp/engine.rb +5 -0
  26. data/lti2_tp/lib/lti2_tp/version.rb +3 -0
  27. data/lti2_tp/lib/tasks/lti2_tp_tasks.rake +4 -0
  28. data/lti2_tp/lti2_tp.gemspec +27 -0
  29. data/lti2_tp/test/dummy/README.rdoc +28 -0
  30. data/lti2_tp/test/dummy/Rakefile +6 -0
  31. data/lti2_tp/test/dummy/app/assets/javascripts/application.js +13 -0
  32. data/lti2_tp/test/dummy/app/assets/stylesheets/application.css +13 -0
  33. data/lti2_tp/test/dummy/app/controllers/application_controller.rb +5 -0
  34. data/lti2_tp/test/dummy/app/helpers/application_helper.rb +2 -0
  35. data/lti2_tp/test/dummy/app/views/layouts/application.html.erb +14 -0
  36. data/lti2_tp/test/dummy/bin/bundle +3 -0
  37. data/lti2_tp/test/dummy/bin/rails +4 -0
  38. data/lti2_tp/test/dummy/bin/rake +4 -0
  39. data/lti2_tp/test/dummy/config.ru +4 -0
  40. data/lti2_tp/test/dummy/config/application.rb +23 -0
  41. data/lti2_tp/test/dummy/config/boot.rb +5 -0
  42. data/lti2_tp/test/dummy/config/database.yml +25 -0
  43. data/lti2_tp/test/dummy/config/environment.rb +5 -0
  44. data/lti2_tp/test/dummy/config/environments/development.rb +29 -0
  45. data/lti2_tp/test/dummy/config/environments/production.rb +80 -0
  46. data/lti2_tp/test/dummy/config/environments/test.rb +36 -0
  47. data/lti2_tp/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  48. data/lti2_tp/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  49. data/lti2_tp/test/dummy/config/initializers/inflections.rb +16 -0
  50. data/lti2_tp/test/dummy/config/initializers/mime_types.rb +5 -0
  51. data/lti2_tp/test/dummy/config/initializers/secret_token.rb +12 -0
  52. data/lti2_tp/test/dummy/config/initializers/session_store.rb +3 -0
  53. data/lti2_tp/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  54. data/lti2_tp/test/dummy/config/locales/en.yml +23 -0
  55. data/lti2_tp/test/dummy/config/routes.rb +4 -0
  56. data/lti2_tp/test/dummy/db/schema.rb +63 -0
  57. data/lti2_tp/test/dummy/public/404.html +58 -0
  58. data/lti2_tp/test/dummy/public/422.html +58 -0
  59. data/lti2_tp/test/dummy/public/500.html +57 -0
  60. data/lti2_tp/test/dummy/public/favicon.ico +0 -0
  61. data/lti2_tp/test/integration/navigation_test.rb +10 -0
  62. data/lti2_tp/test/lti2_tp_test.rb +7 -0
  63. data/lti2_tp/test/test_helper.rb +15 -0
  64. metadata +62 -1
@@ -0,0 +1,55 @@
1
+ module Lti2Tp
2
+ class Context < ActiveRecord::Base
3
+
4
+ SESSION_LTI2_CONTEXT_ID = 'lti2_tc_profile.key'
5
+
6
+ class Holder
7
+ attr_accessor :lti2_context
8
+ def initialize( id=nil )
9
+ unless id.nil?
10
+ @lti2_context = Lti2Tp::Context.find_all_by_id([id]).first
11
+ end
12
+ if id.nil? || @lti2_context.blank?
13
+ @lti2_context = Lti2Tp::Context.create()
14
+ end
15
+ begin
16
+ @context_hash = JSON.load( @lti2_context.content )
17
+ rescue
18
+ @context_hash = nil
19
+ end
20
+ @context_hash ||= {}
21
+ self
22
+ end
23
+
24
+ def [] name
25
+ @context_hash[name]
26
+ end
27
+
28
+ def []= name, value
29
+ @context_hash[name] = value
30
+ @lti2_context.content = JSON.dump( @context_hash )
31
+ @lti2_context.save
32
+ end
33
+
34
+ def clear name
35
+ @context_hash.delete( name )
36
+ @lti2_context.content = JSON.dump( @context_hash )
37
+ @lti2_context.save
38
+ end
39
+ end
40
+
41
+ def self.get_holder( session )
42
+ # lazy create for holder
43
+ if session.has_key?( SESSION_LTI2_CONTEXT_ID )
44
+ result = Lti2Tp::Context::Holder.new( session[SESSION_LTI2_CONTEXT_ID] )
45
+ end
46
+ if result.blank?
47
+ result = Lti2Tp::Context::Holder.new()
48
+ end
49
+ # reassert in class new run in same browser session
50
+ session[SESSION_LTI2_CONTEXT_ID] = result.lti2_context.id
51
+ result
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,180 @@
1
+ module Lti2Tp
2
+ class Registration < ActiveRecord::Base
3
+
4
+ CORRELATION_ID = 'VND-IMS-CORRELATION-ID'
5
+ DISPOSITION = 'VND-IMS-DISPOSITION'
6
+
7
+ HTTP_CORRELATION_ID = 'HTTP_VND_IMS_CORRELATION_ID'
8
+ HTTP_DISPOSITION = 'HTTP_VND_IMS_DISPOSITION'
9
+
10
+ def create_tool_proxy tool_consumer_profile, tool_proxy_guid, disposition
11
+ tool_provider_registry = Rails.application.config.tool_provider_registry
12
+ tool_proxy = {}
13
+ # clone from provided TCP
14
+ tool_proxy['@context'] = tool_consumer_profile['@context'].clone
15
+ tool_proxy['@type'] = 'ToolProxy'
16
+ tool_proxy['@id'] = "ToolProxyProposal_at_#{Time.now.utc.iso8601}"
17
+
18
+ tool_proxy['lti_version'] = 'LTI-2p0'
19
+ tool_proxy['tool_proxy_guid'] = tool_proxy_guid if disposition == 'reregister'
20
+
21
+ tool_proxy['tool_consumer_profile'] = self.tc_profile_url
22
+ tool_proxy['tool_profile'] = JSON.load( tool_profile_json )
23
+ tool_proxy['security_contract'] = resolve_security_contract( tool_consumer_profile )
24
+
25
+ tool_proxy_wrapper = JsonWrapper.new( tool_proxy )
26
+ tool_proxy_wrapper.root
27
+ end
28
+
29
+ def get_tool_consumer_profile()
30
+ tcp_response = invoke_unsigned_service(self.tc_profile_url, 'get', {}, {}, nil, Rails.application.config.wire_log, "Get Tool Consumer Profile")
31
+ JSON.load( tcp_response.body )
32
+ end
33
+
34
+ def prepare_tool_proxy disposition, tool_proxy_guid
35
+ tool_consumer_profile = JSON.load( self.tool_consumer_profile_json )
36
+ tool_proxy = create_tool_proxy(tool_consumer_profile, tool_proxy_guid, disposition)
37
+ if tool_proxy
38
+ self.end_registration_id = UUID.generate
39
+ if disposition == 'register'
40
+ self.tool_proxy_json = tool_proxy.to_json
41
+ else
42
+ self.proposed_tool_proxy_json = tool_proxy.to_json
43
+ end
44
+ self.save!
45
+
46
+ service_offered = nil
47
+ tool_consumer_profile['service_offered'].select do |entry|
48
+ if match_services( entry['@id'] , ':ToolProxy.collection' )
49
+ service_offered = entry
50
+ break
51
+ end
52
+ end
53
+ if service_offered.nil?
54
+ status = create_status(false, nil, "No matching service definition")
55
+ return_url = self.launch_presentation_return_url + '?status=failure'
56
+ (redirect_to return_url) and return
57
+ end
58
+
59
+ (tool_proxy_response, err_code, err_msg) = register_tool_proxy service_offered, "post", disposition
60
+ unless err_code == 201
61
+ status = create_status(false, nil, "#{err_code}-#{err_msg}")
62
+ return status
63
+ end
64
+ if disposition.blank? || disposition == 'register'
65
+ # get guid from the response returned by the TC
66
+ tool_proxy['tool_proxy_guid'] = tool_proxy_response['tool_proxy_guid']
67
+
68
+
69
+ # substitute tool_proxy_guid now in the Proxy where needed
70
+ tool_proxy_wrapper = JsonWrapper.new( tool_proxy )
71
+ tool_proxy_wrapper.substitute_text_in_all_nodes( '{', '}', { 'tool_proxy_guid' => tool_proxy['tool_proxy_guid'] } )
72
+
73
+ self.tool_proxy_json = tool_proxy.to_json
74
+ self.status = disposition
75
+ self.save!
76
+
77
+ status = create_status(true, tool_proxy_wrapper.first_at('tool_proxy_guid'))
78
+ else
79
+ status = create_status(true)
80
+ end
81
+ else
82
+ status = create_status(false, nil, "Can't access ToolProxy")
83
+ end
84
+
85
+ status
86
+ end
87
+
88
+ def create_status(is_success, tool_guid=nil, message=nil)
89
+ status = "?"
90
+ if is_success
91
+ status += 'status=success&'
92
+ status += "tool_guid=#{tool_guid}&" if tool_guid.present?
93
+ else
94
+ status += 'status=failure&'
95
+ encoded_message = Rack::Utils.escape( message )
96
+ status += "lti_errormsg=#{encoded_message}&lti_errorlog=#{encoded_message}&"
97
+ end
98
+ status
99
+ end
100
+
101
+ def is_status_failure? status
102
+ status.include? "status=failure&"
103
+ end
104
+
105
+ private
106
+
107
+ def match_services( test_service, model_service )
108
+ service_name_pattern = /.*\W(\w+?\.\w+)$/
109
+ m = service_name_pattern.match( test_service )
110
+ if m.present?
111
+ test_word = m[1]
112
+ m = service_name_pattern.match( model_service )
113
+ if m.present?
114
+ model_word = m[1]
115
+ return test_word == model_word
116
+ end
117
+ end
118
+ return false
119
+ end
120
+
121
+ def register_tool_proxy service_offered, method, disposition
122
+ if disposition == 'register'
123
+ data = self.tool_proxy_json
124
+ label = 'Register'
125
+ else
126
+ data = self.proposed_tool_proxy_json
127
+ label = 'ReRegister'
128
+ end
129
+
130
+ data = JSON.pretty_generate(JSON.load(data))
131
+
132
+ # data = CGI::escape(data)
133
+ signed_request = create_signed_request \
134
+ service_offered['endpoint'],
135
+ method,
136
+ self.reg_key,
137
+ self.reg_password,
138
+ {},
139
+ data,
140
+ "application/vnd.ims.lti.v2.toolproxy+json"
141
+
142
+ puts "Register request: #{signed_request.signature_base_string}"
143
+ puts "Register secret: #{self.reg_password}"
144
+ headers = {}
145
+ (headers[CORRELATION_ID] = self.end_registration_id) if disposition == 'reregister'
146
+ response = invoke_service(signed_request, Rails.application.config.wire_log, "#{label} ToolProxy with ToolConsumer",
147
+ headers)
148
+ if response.code.between?( 200, 202 )
149
+ response_body = response.body
150
+ response_content = JSON.load( response_body ) unless response_body.strip.empty?
151
+ else
152
+ response_content = nil
153
+ end
154
+ [ response_content, response.code, response.message ]
155
+ end
156
+
157
+
158
+ def resolve_security_contract tool_consumer_profile
159
+ security_contract = {}
160
+
161
+ security_contract['shared_secret'] = SecureRandom.hex
162
+ security_contract['tool_service'] = []
163
+
164
+ services_offered = tool_consumer_profile['service_offered']
165
+ services_offered.each { |service_offered|
166
+ tool_service = {}
167
+ tool_service['@type'] = 'RestServiceProfile'
168
+ tool_service['service'] = service_offered['@id']
169
+ tool_service['action'] = service_offered['action']
170
+
171
+ # following may be wrong...check on proper construction of RestService
172
+ # tool_service['format'] = service_offered['format']
173
+ security_contract['tool_service'] << tool_service
174
+ }
175
+
176
+ security_contract
177
+ end
178
+
179
+ end
180
+ end
@@ -0,0 +1,5 @@
1
+ module Lti2Tp
2
+
3
+ class Registry < ActiveRecord::Base
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ module Lti2Tp
2
+ class Tool < ActiveRecord::Base
3
+
4
+ def get_tool_profile( tool_options=nil )
5
+ tool_provider_registry = Rails.application.config.tool_provider_registry
6
+ tool_profile = Lti2Commons::JsonWrapper.new( self.tool_profile_template )
7
+ tool_profile.substitute_text_in_all_nodes( '{', '}', tool_provider_registry.registry )
8
+
9
+ # only if tool_options, provided prune day available resource_handlers
10
+ if tool_options
11
+ resource_handlers = tool_profile.first_at('resource_handler')
12
+ resource_handlers_to_delete = []
13
+ resource_handlers.each { |resource_handler|
14
+ resource_handler_wrapper = Lti2Commons::JsonWrapper.new( resource_handler )
15
+ unless tool_options.include? resource_handler_wrapper.first_at('resource_name.default_value')
16
+ resource_handlers_to_delete << resource_handler
17
+ end
18
+ }
19
+ resource_handlers_to_delete.each { |rh|
20
+ resource_handlers.delete( rh )
21
+ }
22
+ end
23
+ tool_profile.root
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ module Lti2Tp
2
+ class ToolDeployment < ActiveRecord::Base
3
+ belongs_to :tenant
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ module Lti2Tp
2
+
3
+ class ToolProviderRegistry
4
+
5
+ attr_reader :security_contract_template, :tp_deployment_url, :relaxed_oauth_check, :result_template,
6
+ :tool_provider_name, :registry
7
+
8
+ def initialize
9
+ registry_entries = Registry.all()
10
+ @registry = {}
11
+ registry_entries.each { |entry| @registry[entry.name] = entry.content unless entry.name == 'content' }
12
+
13
+ @tp_deployment_url = registry['tp_deployment_url']
14
+ @relaxed_oauth_check = registry['relaxed_oauth_check']
15
+ @result_template = registry['result_template']
16
+ @tool_provider_name = registry['tool_provider_name']
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Lti2Tp</title>
5
+ <%= stylesheet_link_tag "lti2_tp/application", media: "all" %>
6
+ <%= javascript_include_tag "lti2_tp/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/lti2_tp/engine', __FILE__)
6
+
7
+ require 'rails/all'
8
+ require 'rails/engine/commands'
@@ -0,0 +1,11 @@
1
+ include Lti2Commons
2
+ include WireLogSupport
3
+
4
+ NONCE_TIME_TO_LIVE = 300 # seconds
5
+ Rails.application.config.nonce_cache = Cache.new :ttl => NONCE_TIME_TO_LIVE
6
+
7
+ if ActiveRecord::Base.connection.table_exists? 'lti2_tp_registries'
8
+ Rails.application.config.tool_provider_registry = Lti2Tp::ToolProviderRegistry.new
9
+ end
10
+
11
+ Rails.application.config.wire_log = WireLog.new "ToolProvider", File.expand_path("../tc_sample_app/public/wirelog.html")
@@ -0,0 +1,9 @@
1
+ Lti2Tp::Engine.routes.draw do
2
+
3
+ resources :registrations
4
+
5
+ match 'reregistrations' => 'registrations#reregister', :via => :post
6
+
7
+ match 'tool_proxies' => 'registrations#end_registration', :via => :post
8
+
9
+ end
@@ -0,0 +1,67 @@
1
+ class CreateLti2TpResources < ActiveRecord::Migration
2
+ def up
3
+ create_table :lti2_tp_registrations do |t|
4
+ t.integer :tool_id
5
+ t.integer :tenant_id
6
+ t.string :tenant_name
7
+ t.string :tenant_basename
8
+ t.string :user_id
9
+ t.string :reg_key
10
+ t.string :reg_password
11
+ t.string :tc_profile_url
12
+ t.string :launch_presentation_return_url
13
+ t.string :status
14
+ t.string :message_type
15
+ t.string :lti_version
16
+ t.string :end_registration_id
17
+ t.text :tool_consumer_profile_json
18
+ t.text :tool_profile_json
19
+ t.text :tool_proxy_json
20
+ t.text :proposed_tool_proxy_json
21
+
22
+ t.timestamps
23
+ end
24
+ execute('ALTER TABLE lti2_tp_registrations CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;')
25
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `tenant_name` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
26
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `tenant_basename` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
27
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `user_id` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
28
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `reg_key` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
29
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `reg_password` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
30
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `tc_profile_url` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
31
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `launch_presentation_return_url` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
32
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `status` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
33
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `message_type` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
34
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `lti_version` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
35
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `end_registration_id` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
36
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `tool_consumer_profile_json` TEXT CHARACTER SET utf8mb4 NULL;")
37
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `tool_profile_json` TEXT CHARACTER SET utf8mb4 NULL;")
38
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `tool_proxy_json` TEXT CHARACTER SET utf8mb4 NULL;")
39
+ execute("ALTER TABLE lti2_tp_registrations MODIFY `proposed_tool_proxy_json` TEXT CHARACTER SET utf8mb4 NULL;")
40
+
41
+ create_table :lti2_tp_registries do |t|
42
+ t.string :name
43
+ t.text :content
44
+
45
+ t.timestamps
46
+ end
47
+ execute('ALTER TABLE lti2_tp_registries CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;')
48
+ execute("ALTER TABLE lti2_tp_registries MODIFY `name` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
49
+ execute("ALTER TABLE lti2_tp_registries MODIFY `content` TEXT CHARACTER SET utf8mb4 NULL;")
50
+
51
+ create_table :lti2_tp_tools do |t|
52
+ t.string :tool_name
53
+ t.text :tool_profile_template
54
+
55
+ t.timestamps
56
+ end
57
+ execute('ALTER TABLE lti2_tp_tools CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;')
58
+ execute("ALTER TABLE lti2_tp_tools MODIFY `tool_name` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;")
59
+ execute("ALTER TABLE lti2_tp_tools MODIFY `tool_profile_template` TEXT CHARACTER SET utf8mb4 NULL;")
60
+ end
61
+
62
+ def down
63
+ drop_table :lti2_tp_registrations
64
+ drop_table :lti2_tp_registries
65
+ drop_table :lti2_tp_tools
66
+ end
67
+ end
@@ -0,0 +1,4 @@
1
+ require 'lti2_tp/engine'
2
+
3
+ module Lti2Tp
4
+ end
@@ -0,0 +1,5 @@
1
+ module Lti2Tp
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Lti2Tp
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Lti2Tp
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :lti2_tp do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,27 @@
1
+ $:.push File.expand_path( '../lib', __FILE__ )
2
+
3
+ # Maintain your gem's version:
4
+ require 'lti2_tp/version'
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+
9
+ s.name = 'lti2_tp'
10
+ s.version = Lti2Tp::VERSION
11
+ s.authors = ['John Tibbetts']
12
+ s.email = ['john.tibbetts@ingramcontent.com']
13
+ s.homepage = 'http://vitalsource.com'
14
+ s.summary = 'LTI2 Tool Provider'
15
+ s.description = 'LTI2 Tool Provider'
16
+
17
+ s.files = Dir[ '{app,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.rdoc' ]
18
+ s.test_files = Dir[ 'test/**/*' ]
19
+
20
+ s.required_ruby_version = '~> 2.0.0'
21
+
22
+ s.add_dependency 'rails', '~> 4.1.1'
23
+ s.add_dependency 'mysql2', '~> 0.3.13'
24
+
25
+ s.add_development_dependency 'sqlite3'
26
+
27
+ end