Browse files

create a simple tool consumer

  • Loading branch information...
0 parents commit 0257b0937ffb72f619936594a87c5dc966283062 @bracken bracken committed Mar 11, 2012
Showing with 236 additions and 0 deletions.
  1. +6 −0 Gemfile
  2. +11 −0 README.md
  3. +3 −0 config.ru
  4. +113 −0 tool_consumer.rb
  5. +11 −0 views/index.erb
  6. +46 −0 views/tool_config.erb
  7. +33 −0 views/tool_launch.erb
  8. +13 −0 views/tool_return.erb
6 Gemfile
@@ -0,0 +1,6 @@
+gem 'sinatra'
+gem 'ims-lti'
+
+group :development do
+ gem 'shotgun'
+end
11 README.md
@@ -0,0 +1,11 @@
+# Example LTI Tool Consumer Using imt-lti Gem
+
+This is a basic and simple LTI Tool Consumer that uses the
+[ims-lti](https://github.com/instructure/ims-lti) gem.
+To get this running in your development environment, check out the repo then:
+
+ bundle install
+ shotgun
+
+You can use this with the [example LTI Tool Provider](https://github.com/instructure/lti_tool_provider_example)
+to do some simple LTI testing.
3 config.ru
@@ -0,0 +1,3 @@
+require './tool_consumer'
+
+run Sinatra::Application
113 tool_consumer.rb
@@ -0,0 +1,113 @@
+require 'sinatra'
+require 'ims/lti'
+require 'digest/md5'
+# must include the oauth proxy object
+require 'oauth/request_proxy/rack_request'
+require 'pp'
+
+enable :sessions
+
+get '/' do
+ session['username'] = nil
+ erb :index
+end
+
+post '/set_name' do
+ session['username'] = params['username'] || 'Bob'
+ redirect to('/tool_config')
+end
+
+get '/tool_config' do
+ unless session['username']
+ redirect to('/')
+ return
+ end
+
+ @message = params['message']
+ @username = session['username']
+ erb :tool_config
+end
+
+post '/tool_launch' do
+ if %w{tool_name launch_url consumer_key consumer_secret}.any?{|k|params[k].nil? || params[k] == ''}
+ redirect to('/tool_config?message=Please%20set%20all%20values')
+ return
+ end
+
+ tc = IMS::LTI::ToolConfig.new(:title => params['tool_name'], :launch_url => params['launch_url'])
+ tc.set_custom_param('message_from_sinatra', 'hey from the sinatra example consumer')
+ @consumer = IMS::LTI::ToolConsumer.new(params['consumer_key'], params['consumer_secret'])
+ @consumer.set_config(tc)
+
+ host = request.scheme + "://" + request.host_with_port
+
+ # Set some launch data from: http://www.imsglobal.org/LTI/v1p1pd/ltiIMGv1p1pd.html#_Toc309649684
+ # Only this first one is required, the rest are recommended
+ @consumer.resource_link_id = "thisisuniquetome"
+ @consumer.launch_presentation_return_url = host + '/tool_return'
+ @consumer.lis_person_name_given = session['username']
+ @consumer.user_id = Digest::MD5.hexdigest(session['username'])
+ @consumer.roles = "learner"
+ @consumer.context_id = "bestcourseever"
+ @consumer.context_title = "Example Sinatra Tool Consumer"
+ @consumer.tool_consumer_instance_name = "Frankie"
+
+ if params['assignment']
+ @consumer.lis_outcome_service_url = host + '/grade_passback'
+ @consumer.lis_result_sourcedid = "oi"
+ end
+
+ @autolaunch = !!params['autolaunch']
+
+ erb :tool_launch
+end
+
+get '/tool_return' do
+ @error_message = params['lti_errormsg']
+ @message = params['lti_msg']
+ puts "Warning: #{params['lti_errorlog']}" if params['lti_errorlog']
+ puts "Info: #{params['lti_log']}" if params['lti_log']
+
+ erb :tool_return
+end
+
+post '/grade_passback' do
+ # Need to find the consumer key/secret to verify the post request
+ # If your return url has an identifier for a specific tool you can use that
+ # Or you can grab the consumer_key out of the HTTP_AUTHORIZATION and look up the secret
+ # Or you can parse the XML that was sent and get the lis_result_sourcedid which
+ # was set at launch time and look up the tool using that somehow.
+
+ req = IMS::LTI::OutcomeRequest.from_post_request(request)
+ sourcedid = req.lis_result_sourcedid
+
+ # todo - create some key management system
+ consumer = IMS::LTI::ToolConsumer.new('test', 'secret')
+
+ if consumer.valid_request?(request)
+ res = IMS::LTI::OutcomeResponse.new
+ res.message_ref_identifier = req.message_identifier
+ res.operation = req.operation
+ res.code_major = 'success'
+ res.severity = 'status'
+
+ if req.replace_request?
+ res.description = "Your old score of 0 has been replaced with #{req.score}"
+ elsif req.read_request?
+ res.description = "You score is 50"
+ res.score = 50
+ elsif req.delete_request?
+ res.description = "You score has been cleared"
+ else
+ res.code_major = 'unsupported'
+ res.severity = 'status'
+ res.description = "#{req.operation} is not supported"
+ end
+
+ headers 'Content-Type' => 'text/xml'
+ res.generate_response_xml
+ else
+ response['WWW-Authenticate'] = "OAuth realm=\"http://#{request.env['HTTP_HOST']}\""
+ throw(:halt, [401, "Not authorized\n"])
+ end
+end
11 views/index.erb
@@ -0,0 +1,11 @@
+<html>
+<head><title>Demo LTI Tool Consumer</title></head>
+<body>
+<p>This is an LTI Tool Consumer. Give your name and we'll get started:</p>
+
+<form action="/set_name" method="post">
+ <input name='username' type='text' id='username'/>
+ <button type='submit'>Submit</button>
+</form>
+</body>
+</html>
46 views/tool_config.erb
@@ -0,0 +1,46 @@
+<html>
+<head><title>Configure a Tool Provider</title></head>
+<body>
+<style type="text/css">
+ input {
+ width: 30em;
+ }
+</style>
+
+<h1>Tool Provider Configuration</h1>
+<p>Hey <%= @username %>, let's launch a Tool Provider!</p>
+<% if @message %>
+ <p style="color: #ff3d23;"><%= @message %></p>
+<% end %>
+<form action="/tool_launch" method="post">
+ <table>
+ <tr>
+ <td>Tool Name</td>
+ <td><input name="tool_name" type="text" value="Test Sinatra App"/></td>
+ </tr>
+ <tr>
+ <td>Consumer Key</td>
+ <td><input name="consumer_key" type="text" value="test"/></td>
+ </tr>
+ <tr>
+ <td>Consumer Secret</td>
+ <td><input name="consumer_secret" type="text" value="secret"/></td>
+ </tr>
+ <tr>
+ <td>Launch URL</td>
+ <td><input name="launch_url" type="text" value="http://localhost:9393/lti_tool"/></td>
+ </tr>
+ <tr>
+ <td>Launch as assignment</td>
+ <td><input type="checkbox" name="assignment" checked="checked"></td>
+ </tr>
+ <tr>
+ <td>Launch automatically</td>
+ <td><input type="checkbox" name="autolaunch" checked="checked"></td>
+ </tr>
+ </table>
+
+ <button type="submit">Submit</button>
+</form>
+</body>
+</html>
33 views/tool_launch.erb
@@ -0,0 +1,33 @@
+<html>
+<head><title>Launching LTI Tool</title></head>
+<body>
+<div id="ltiLaunchFormSubmitArea">
+
+ <table>
+ <tr>
+ <td colspan="2">Launch Parameters</td>
+ </tr>
+ <% @consumer.generate_launch_data.each_pair do |key, val| %>
+ <tr>
+ <td><%= key %></td>
+ <td><%= val %></td>
+ </tr>
+ <% end %>
+ </table>
+
+ <form action="<%= @consumer.launch_url %>" name="ltiLaunchForm" id="ltiLaunchForm" method="post" encType="application/x-www-form-urlencoded">
+ <% @consumer.generate_launch_data.each_pair do |key, val| %>
+ <input type="hidden" name="<%= key %>" value="<%= val %>"/>
+ <% end %>
+ <button type="submit">Launch the tool</button>
+ </form>
+
+</div>
+<% if @autolaunch %>
+ <script language="javascript">
+ document.getElementById("ltiLaunchFormSubmitArea").style.display = "none";
+ document.ltiLaunchForm.submit();
+ </script>
+<% end %>
+</body>
+</html>
13 views/tool_return.erb
@@ -0,0 +1,13 @@
+<html>
+<head><title>Return to TC</title></head>
+<body>
+ <p>Welcome back to the tool consumer demo app</p>
+ <% if @message %>
+ <p>Message from TP: <%= @message %></p>
+ <% end %>
+ <% if @error_message %>
+ <p>Error from TP: <%= @error_message %></p>
+ <% end %>
+<p><a href="/tool_config">Launch another tool</a></p>
+</body>
+</html>

0 comments on commit 0257b09

Please sign in to comment.