Skip to content
Newer
Older
100644 137 lines (121 sloc) 4.82 KB
d903e9c @codekitchen initial commit of the lti outcomes service example tool
codekitchen authored Nov 30, 2011
1 begin
2 require 'rubygems'
3 rescue LoadError
4 puts "You must install rubygems to run this example"
5 raise
6 end
7
8 begin
9 require 'bundler/setup'
10 rescue LoadError
11 puts "to set up this example, run these commands:"
12 puts " gem install bundler"
13 puts " bundle install"
14 raise
15 end
16
17 require 'sinatra'
18 require 'oauth'
19 require 'oauth/request_proxy/rack_request'
20
21 # hard-coded oauth information for testing convenience
22 $oauth_key = "test"
23 $oauth_secret = "secret"
24
25 # sinatra wants to set x-frame-options by default, disable it
26 disable :protection
27 # enable sessions so we can remember the launch info between http requests, as
28 # the user takes the assessment
29 enable :sessions
30
31 # this is the entry action that Canvas (the LTI Tool Consumer) sends the
32 # browser to when launching the tool.
33 post "/assessment/start" do
34 # first we have to verify the oauth signature, to make sure this isn't an
35 # attempt to hack the planet
36 begin
37 signature = OAuth::Signature.build(request, :consumer_secret => $oauth_secret)
38 signature.verify() or raise OAuth::Unauthorized
39 rescue OAuth::Signature::UnknownSignatureMethod,
40 OAuth::Unauthorized
41 return %{unauthorized attempt. make sure you used the consumer secret "#{$oauth_secret}"}
42 end
43
44 # make sure this is an assignment tool launch, not another type of launch.
45 # only assignment tools support the outcome service, since only they appear
46 # in the Canvas gradebook.
47 unless params['lis_outcome_service_url'] && params['lis_result_sourcedid']
a422625 @codekitchen open readme in new browser window
codekitchen authored Dec 1, 2011
48 return %{It looks like this LTI tool wasn't launched as an assignment, or you are trying to take it as a teacher rather than as a a student. Make sure to set up an external tool assignment as outlined <a target="_blank" href="https://github.com/instructure/lti_example">in the README</a> for this example.}
d903e9c @codekitchen initial commit of the lti outcomes service example tool
codekitchen authored Dec 1, 2011
49 end
50
51 # store the relevant parameters from the launch into the user's session, for
52 # access during subsequent http requests.
53 # note that the name and email might be blank, if the tool wasn't configured
54 # in Canvas to provide that private information.
55 %w(lis_outcome_service_url lis_result_sourcedid lis_person_name_full lis_person_contact_email_primary).each { |v| session[v] = params[v] }
56
57 # that's it, setup is done. now send them to the assessment!
58 redirect to("/assessment")
59 end
60
61 def username
62 session['lis_person_name_full'] || 'Student'
63 end
64
65 get "/assessment" do
66 # first make sure they got here through a tool launch
67 unless session['lis_result_sourcedid']
68 return %{You need to take this assessment through Canvas.}
69 end
70
71 # now render a simple form the user will submit to "take the quiz"
72 <<-HTML
73 <html>
74 <head><title>Demo LTI Assessment Tool</title></head>
75 <body>
76 <h1>Demo LTI Assessment Tool</h1>
77 <form action="/assessment" method="post">
78 <p>Hi, #{username}. On a scale of <code>0.0</code> to <code>1.0</code>, how well would you say you did on this assessment?</p>
79 <input name='score' type='text' width='5' id='score' />
80 <input type='submit' value='Submit' />
81 <p>If you want to enter an invalid score here, you can see how Canvas will reject it.</p>
82 </form>
83 </body>
84 </html>
85 HTML
86 end
87
88 # This is the action that the form submits to with the score that the student entered.
89 # In lieu of a real assessment, that score is then just submitted back to Canvas.
90 post "/assessment" do
91 # obviously in a real tool, we're not going to let the user input their own score
92 score = params['score']
93 if !score || score.empty?
94 redirect to("/assessment")
95 end
96
97 # now post the score to canvas. Make sure to sign the POST correctly with
98 # OAuth 1.0, including the digest of the XML body. Also make sure to set the
99 # content-type to application/xml.
100 xml = %{
101 <?xml version = "1.0" encoding = "UTF-8"?>
102 <imsx_POXEnvelopeRequest xmlns = "http://www.imsglobal.org/lis/oms1p0/pox">
103 <imsx_POXHeader>
104 <imsx_POXRequestHeaderInfo>
105 <imsx_version>V1.0</imsx_version>
106 <imsx_messageIdentifier>12341234</imsx_messageIdentifier>
107 </imsx_POXRequestHeaderInfo>
108 </imsx_POXHeader>
109 <imsx_POXBody>
110 <replaceResultRequest>
111 <resultRecord>
112 <sourcedGUID>
113 <sourcedId>#{session['lis_result_sourcedid']}</sourcedId>
114 </sourcedGUID>
115 <result>
116 <resultScore>
117 <language>en</language>
118 <textString>#{score}</textString>
119 </resultScore>
120 </result>
121 </resultRecord>
122 </replaceResultRequest>
123 </imsx_POXBody>
124 </imsx_POXEnvelopeRequest>
125 }
126 consumer = OAuth::Consumer.new($oauth_key, $oauth_secret)
127 token = OAuth::AccessToken.new(consumer)
128 response = token.post(session['lis_outcome_service_url'], xml, 'Content-Type' => 'application/xml')
129
130 headers 'Content-Type' => 'text'
131 %{
132 Your score has #{response.body.match(/\bsuccess\b/) ? "been posted" : "failed in posting"} to Canvas. The response was:
133
134 #{response.body}
135 }
136 end
Something went wrong with that request. Please try again.