Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: instructure/ims-lti
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.2.4
Choose a base ref
...
head repository: instructure/ims-lti
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1.2.x
Choose a head ref
  • 10 commits
  • 15 files changed
  • 6 contributors

Commits on Apr 22, 2022

  1. Add support for needsAdditionalReview (#169)

    * Initial work for addsAdditionalSupport
    
    * Finish support for needsAdditionalReview
    
    * bump version
    westonkd authored Apr 22, 2022

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    3df3852 View commit details

Commits on Apr 25, 2022

  1. Add support for prioritizeNonToolGrade (#170)

    * Add support for prioritizeNonToolGrade
    
    * bump version
    westonkd authored Apr 25, 2022
    Copy the full SHA
    632c19a View commit details

Commits on Dec 12, 2022

  1. Fix content return parameter encoding (#177)

    * Add failing tests
    
    * Fix return url parameters
    pfgray authored Dec 12, 2022
    Copy the full SHA
    280eea5 View commit details

Commits on Dec 13, 2022

  1. bumping 1.2.7 version (#178)

    pfgray authored Dec 13, 2022
    Copy the full SHA
    d1c008a View commit details

Commits on Jan 3, 2023

  1. ruby 3.0 support & fix URI encoding bug

    CGI.escape() should be used here as the output is used in query params:
    URI.escape("&") is actually "&", which would mess up a query param.
    
    Also, rexml is now an external gem and needs to be explicitly stated as
    a dependency.
    
    refs INTEROP-7884
    
    Test plan:
    - Run specs on major Ruby versions (I've tested 2.4 - 3.1)
    evanbattaglia committed Jan 3, 2023
    Copy the full SHA
    ba18954 View commit details
  2. Merge pull request #180 from evanbattaglia/1.2.x

    ruby 3.0 support & fix URI encoding bug
    evanbattaglia authored Jan 3, 2023
    Copy the full SHA
    68f38c8 View commit details

Commits on Jan 10, 2023

  1. Cherry Pick Jenkins Changes from Master Branch (#185)

    * Create Jenkinsfile
    
    * fix formatting
    
    * update committer email
    
    * add publish file
    
    * update commit
    
    * build docker image to prevent file caching
    
    * only run on master merge
    
    * Add jenkins rspec matrix tests (#182)
    
    add jenkins rspec matrix tests
    
    * Add example to be used by consumer (#155)
    
    * Add ruby 3.1 to rspec matrix (#184)
    
    add ruby 3.1 to rspec matrix
    
    * fix readme conflict
    
    * update merge branch
    
    Co-authored-by: Lucas Piffer <[email protected]>
    slaughter550 and LucasPiffer authored Jan 10, 2023
    Copy the full SHA
    3d28aff View commit details

Commits on May 5, 2023

  1. Copy the full SHA
    170e470 View commit details

Commits on May 31, 2023

  1. Copy the full SHA
    caec56f View commit details

Commits on Jun 1, 2023

  1. Update Readme & Deploy Script (#189)

    * Create Jenkinsfile
    
    * fix formatting
    
    * Add example to be used by consumer (#155)
    
    * update readme and plumb version for auto-deploy
    
    ---------
    
    Co-authored-by: Lucas Piffer <[email protected]>
    slaughter550 and LucasPiffer authored Jun 1, 2023
    Copy the full SHA
    ee0bdee View commit details
22 changes: 22 additions & 0 deletions Changelog
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
2023-05-30 Version 1.2.9
* Loosen version requirement for OAuth gem

2023-01-03 Version 1.2.8
* Add Ruby 3.0 support by requiring rexml
* Fix URI encoding bug for queries with an ampersand `&`

2022-12-13 Version 1.2.7
* Fix content return parameter encoding

2022-04-26 Version 1.2.6
* Add support for prioritizeNonToolGrade
* Add support for needsAdditionalReview

2020-02-03 Version 1.2.4
* Add support for submittedAt date

2020-02-03 Version 1.2.3 -- yanked

2017-06-19 Version 1.2.2
* Explicitly require 'oauth' gem and specify version range

2017-04-13 Version 1.2.1
* Remove date field from gemspec

2017-03-08 Version 1.2.0
* Don't downcase roles

10 changes: 10 additions & 0 deletions Dockerfile.ci
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
ARG RUBY_VERSION=2.7
FROM ruby:${RUBY_VERSION}

RUN apt-get update && apt-get install -y git

RUN bash -lc "gem install bundler -v 2.2.32"

WORKDIR /usr/src/app
COPY . /usr/src/app
RUN bash -lc "bundle install"
44 changes: 44 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
pipeline {
agent { label 'docker' }

stages {
stage('Test') {
matrix {
agent { label 'docker' }
axes {
axis {
name 'RUBY_VERSION'
values '2.7', '3.0', '3.1'
}
}
stages {
stage('Build') {
steps {
timeout(10) {
sh "docker-compose build --pull --build-arg RUBY_VERSION=${RUBY_VERSION} app"
sh 'docker-compose run --rm app rspec --tag \\~slow'
}
}
}
}
}
}
stage('Deploy') {
when {
allOf {
expression { GIT_BRANCH == "1.2.x" }
}
}
steps {
lock( // only one build enters the lock
resource: "${env.JOB_NAME}" // use the job name as lock resource to make the mutual exclusion only for builds from the same branch/tag
) {
withCredentials([string(credentialsId: 'rubygems-rw', variable: 'GEM_HOST_API_KEY')]) {
sh 'docker-compose build'
sh 'docker-compose run -e GEM_HOST_API_KEY --rm app /bin/bash -lc "./bin/publish.sh"'
}
}
}
}
}
}
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -112,5 +112,18 @@ As a Tool Consumer your app will POST an OAuth-signed launch requests to TPs wit
[LTI launch data](http://www.imsglobal.org/LTI/v1p1/ltiIMGv1p1.html#_Toc319560465).
This is covered in the [LTI security model](http://www.imsglobal.org/LTI/v1p1/ltiIMGv1p1.html#_Toc319560466)

```ruby

params = { user_id: '123', lti_message_type: IMS::LTI::Models::Messages::BasicLTILaunchRequest::MESSAGE_TYPE }

header = SimpleOAuth::Header.new(:post, 'https://yoursite.com', params, consumer_key: oauth_consumer_key, consumer_secret: secret)

signed_params = header.signed_attributes.merge(params)

IMS::LTI::Services::MessageAuthenticator.new(launch_url, signed_params, secret)

```

## Contributing
Here is an example of a simple TC Sinatra app using this gem:
[LTI Tool Consumer](https://github.com/instructure/lti_tool_consumer_example)
14 changes: 14 additions & 0 deletions bin/publish.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
# shellcheck shell=bash

set -e

current_version=$(ruby -e "require '$(pwd)/lib/ims/lti/version.rb'; puts IMS::LTI::VERSION;")
existing_versions=$(gem list --exact ims-lti --remote --all | grep -o '\((.*)\)$' | tr -d '() ')

if [[ $existing_versions == *$current_version* ]]; then
echo "Gem has already been published ... skipping ..."
else
gem build ./ims-lti.gemspec
find ims-lti-*.gem | xargs gem push
fi
6 changes: 6 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile.ci
9 changes: 7 additions & 2 deletions ims-lti.gemspec
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'ims/lti/version'

Gem::Specification.new do |s|
s.name = %q{ims-lti}
s.version = "1.2.4"
s.version = IMS::LTI::VERSION

s.add_dependency 'builder', '>= 1.0', '< 4.0'
s.add_dependency 'oauth', '>= 0.4.5', '< 0.6'
s.add_dependency 'oauth', '>= 0.4.5'
s.add_dependency 'rexml'

s.add_development_dependency 'rspec', '~> 3.0', '> 3.0'

103 changes: 76 additions & 27 deletions lib/ims/lti/extensions/content.rb
Original file line number Diff line number Diff line change
@@ -96,67 +96,116 @@ def content_return_url

#generates the return url for file submissions
def file_content_return_url(url, text, content_type = nil)
url = CGI::escape(url)
text = CGI::escape(text)
content_type = CGI::escape(content_type) if content_type

return_url = "#{content_return_url}?return_type=file&url=#{url}&text=#{text}"
return_url = "#{return_url}&content_type=#{content_type}" if content_type
return_url = add_parameters(content_return_url, {
return_type: 'file',
url: url,
text: text
})

if content_type
return_url = add_parameters(return_url, {
content_type: content_type
})
end

return return_url
end

#generates the return url for url submissions
def url_content_return_url(url, title = nil, text = 'link', target = '_blank')
url = CGI::escape(url)
text = CGI::escape(text)
target = CGI::escape(target)

return_url = "#{content_return_url}?return_type=url&url=#{url}&text=#{text}&target=#{target}"
return_url = "#{return_url}&title=#{CGI::escape(title)}" if title
return_url = add_parameters(content_return_url, {
return_type: 'url',
url: url,
text: text,
target: target
})

if title
return_url = add_parameters(return_url, {
title:title
})
end

return return_url
end

#generates the return url for lti launch submissions
def lti_launch_content_return_url(url, text='link', title=nil)
url = CGI::escape(url)
text = CGI::escape(text)

return_url = "#{content_return_url}?return_type=lti_launch_url&url=#{url}&text=#{text}"
return_url = "#{return_url}&title=#{CGI::escape(title)}" if title
return_url = add_parameters(content_return_url, {
return_type: 'lti_launch_url',
url: url,
text: text
})

if title
return_url = add_parameters(return_url, {
title:title
})
end

return return_url
end

#generates the return url for image submissions
def image_content_return_url(url, width, height, alt = '')
url = CGI::escape(url)
width = CGI::escape(width.to_s)
height = CGI::escape(height.to_s)
alt = CGI::escape(alt)

"#{content_return_url}?return_type=image_url&url=#{url}&width=#{width}&height=#{height}&alt=#{alt}"
add_parameters(content_return_url, {
return_type: 'image_url',
url: url,
width: width.to_s,
height: height.to_s,
alt: alt
})
end

#generates the return url for iframe submissions
def iframe_content_return_url(url, width, height, title = nil)
url = CGI::escape(url)
width = CGI::escape(width.to_s)
height = CGI::escape(height.to_s)

return_url = "#{content_return_url}?return_type=iframe&url=#{url}&width=#{width}&height=#{height}"
return_url = "#{return_url}&title=#{CGI::escape(title)}" if title
return_url = add_parameters(content_return_url, {
return_type: 'iframe',
url: url,
width: width.to_s,
height: height.to_s
})

if title
return_url = add_parameters(return_url, {
title:title
})
end

return return_url
end

#generates the return url for oembed submissions
def oembed_content_return_url(url, endpoint)
url = CGI::escape(url)
endpoint = CGI::escape(endpoint)

"#{content_return_url}?return_type=oembed&url=#{url}&endpoint=#{endpoint}"
add_parameters(content_return_url, {
return_type: 'oembed',
url: url,
endpoint: endpoint
})
end

private

# adds parameters to a url, with consideration for
# already existing parameters
def add_parameters(url, params)
parsed = URI.parse(url)
query = if parsed.query
CGI.parse(parsed.query)
else
{}
end

query = query.merge(params)

parsed.query = URI.encode_www_form(query)
parsed.to_s
end
end

36 changes: 30 additions & 6 deletions lib/ims/lti/extensions/outcome_data.rb
Original file line number Diff line number Diff line change
@@ -69,7 +69,8 @@ def accepts_outcome_url?

# check if the consumer accepts a submitted at date as outcome data
def accepts_submitted_at?
accepted_outcome_types.member?("submitted_at")
accepted_outcome_types.member?("submitted_at") ||
@ext_params["ext_outcome_submission_submitted_at_accepted"] == "true"
end

def accepts_outcome_lti_launch_url?
@@ -80,8 +81,19 @@ def accepts_outcome_result_total_score?
!!@ext_params["outcome_result_total_score_accepted"]
end

def accepts_needs_additional_review?
@ext_params["ext_outcome_submission_needs_additional_review_accepted"] == "true"
end

def accepts_prioritize_non_tool_grade?
@ext_params["ext_outcome_submission_prioritize_non_tool_grade_accepted"] == "true"
end

# POSTs the given score to the Tool Consumer with a replaceResult and
# adds the specified data. The data hash can have the keys "text", "cdata_text", "url", "submitted_at" or "lti_launch_url"
# adds the specified data.
#
# The data hash can have the keys "text", "cdata_text", "url", "submitted_at"
# "needs_additional_review", "prioritize_non_tool_grade", or "lti_launch_url"
#
# If both cdata_text and text are sent, cdata_text will be used
#
@@ -98,7 +110,8 @@ def post_replace_result_with_data!(score = nil, data={})

# POSTs the given score to the Tool Consumer with a replaceResult and
# adds the specified data. The options hash can have the keys
# :text, :cdata_text, :url, :submitted_at, :lti_launch_url, :score, or :total_score
# :text, :cdata_text, :url, :submitted_at, :lti_launch_url, :score,
# :needs_additional_review, or :total_score
#
# If both cdata_text and text are sent, cdata_text will be used
# If both total_score and score are sent, total_score will be used
@@ -116,6 +129,8 @@ def post_extended_replace_result!(options = {})
req.outcome_text = opts[:text]
req.outcome_url = opts[:url]
req.submitted_at = opts[:submitted_at]
req.needs_additional_review = opts[:needs_additional_review]
req.prioritize_non_tool_grade = opts[:prioritize_non_tool_grade]
req.outcome_lti_launch_url = opts[:lti_launch_url]
req.total_score = opts[:total_score]
req.post_replace_result!(opts[:score])
@@ -156,7 +171,14 @@ module OutcomeRequest
include IMS::LTI::Extensions::ExtensionBase
include Base

attr_accessor :outcome_text, :outcome_url, :submitted_at, :outcome_lti_launch_url, :outcome_cdata_text, :total_score
attr_accessor :outcome_text,
:outcome_url,
:submitted_at,
:outcome_lti_launch_url,
:outcome_cdata_text,
:total_score,
:needs_additional_review,
:prioritize_non_tool_grade

def result_values(node)
super
@@ -188,7 +210,9 @@ def details(node)
super
return unless has_details_data?

node.submittedAt submitted_at
node.submittedAt submitted_at if submitted_at
node.needsAdditionalReview if needs_additional_review
node.prioritizeNonToolGrade if prioritize_non_tool_grade
end

def score
@@ -200,7 +224,7 @@ def has_result_data?
end

def has_details_data?
!!submitted_at
!!submitted_at || !!needs_additional_review || !!prioritize_non_tool_grade
end

def extention_process_xml(doc)
4 changes: 3 additions & 1 deletion lib/ims/lti/tool_provider.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'cgi'

module IMS::LTI

# Class for implementing an LTI Tool Provider
@@ -121,7 +123,7 @@ def build_return_url
messages = []
%w{lti_errormsg lti_errorlog lti_msg lti_log}.each do |m|
if message = self.send(m)
messages << "#{m}=#{URI.escape(message)}"
messages << "#{m}=#{CGI.escape(message)}"
end
end
q_string = messages.any? ? ("?" + messages.join("&")) : ''
5 changes: 5 additions & 0 deletions lib/ims/lti/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module IMS
module LTI
VERSION = '1.2.9'.freeze
end
end
Loading