Better LTI Variable Substitution Docs

Generate LTI Variable Substitution Docs from the code
Uses YARD's plugin hooks to generate the markdown.

I couldn't find a good way to do this with YARDs builtin generation
stuff. So I hacked together. No pretty, but gets the job done.

You can update the generated markdown by running this
```
script/generate_lti_variable_subustition_markdown
```

Our yard templates, dont process markdown files like YARD is supposed
to.i Not sure why? 🤷

Fixes https://github.com/instructure/canvas-lms/issues/592

Change-Id: If0728d357dc745d81381e818ed62d087d76f0e66
Reviewed-on: https://gerrit.instructure.com/74312
Reviewed-by: Andrew Butterfield <abutterfield@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Tested-by: Jenkins
Product-Review: Brad Horrocks <bhorrocks@instructure.com>
This commit is contained in:
Brad Horrocks 2016-03-10 21:49:32 -07:00
parent 4cf628a2be
commit f51cefcc67
7 changed files with 578 additions and 34 deletions

View File

@ -22,6 +22,7 @@
<a href="<%= url_for("file.sis_csv.html") %>" class="<%= 'current' if options[:object] == 'file.sis_csv.html' %>">SIS CSV Format</a>
<h2>External Tools</h2>
<a href="<%= url_for("file.tools_intro.html") %>" class="<%= 'current' if options[:object] == 'file.tools_intro.html' %>">Introduction</a>
<a href="<%= url_for("file.tools_variable_substitutions.html") %>" class="<%= 'current' if options[:object] == 'file.tools_variable_substitutions.html' %>">Variable Substitutions</a>
<a href="<%= url_for("file.assignment_tools.html") %>" class="<%= 'current' if options[:object] == 'file.assignment_tools.html' %>">Grading</a>
<a href="<%= url_for("file.navigation_tools.html") %>" class="<%= 'current' if options[:object] == 'file.navigation_tools.html' %>">Navigation</a>
<a href="<%= url_for("file.editor_button_tools.html") %>" class="<%= 'current' if options[:object] == 'file.editor_button_tools.html' %>">Rich Editor</a>

View File

@ -1,14 +1,14 @@
External Tools Introduction
==============
Canvas, like many LMSs, supports loading external resources inline using the
Canvas, like many LMSs, supports loading external resources inline using the
<a href="http://www.imsglobal.org/lti/">IMS LTI standard</a>.
These tools can be configured on a course or account level, and
can be added to course modules or used to create custom assignments (see the
LTI Outcomes service for more information on that). Canvas supports some additional
integration points using LTI to offer a more integrated experience and to allow for
more customization of the Canvas product, even in a cloud environment. This is
accomplished by configuring additional settings on external tools used inside of
These tools can be configured on a course or account level, and
can be added to course modules or used to create custom assignments (see the
LTI Outcomes service for more information on that). Canvas supports some additional
integration points using LTI to offer a more integrated experience and to allow for
more customization of the Canvas product, even in a cloud environment. This is
accomplished by configuring additional settings on external tools used inside of
Canvas.
Because tools can be configured at any level in the system heirarchy, they can be
@ -23,69 +23,69 @@ Canvas currently supports the following types of tool extensions:
- <a href="assignment_tools.html">External tool assignments, with grades passed back from the tool to Canvas</a>
This type of integration is part of the
This type of integration is part of the
<a href="http://www.imsglobal.org/LTI/v1p1/ltiIMGv1p1.html">LTI 1.1 specification</a>,
and is important in that it allows external services to take care of things
that can be graded automatically, or outside the LMS scope.
Example use cases might include:
- Administering a timed, auto-graded coding project
- Evaluating a student's ability to correctly draw notes at different musical intervals
- Giving students credit for participating in an interactive lesson on the Civil War
- <a href="navigation_tools.html#course_navigation">Adding a link/tab to the course navigation</a>
Example use cases might include:
- Building a specialized attendance/seating chart tool
- Adding an "ebooks" link with course required reading
- Connecting to study room scheduling tool
- Linking to campus communication hub
- <a href="navigation_tools.html#account_navigation">Adding a link/tab to the account navigation</a>
Example use cases might include:
- Including outside reports in the Canvas UI
- Building helper libraries for campus-specific customizations
- Leveraging single sign-on for access to other systems, like SIS
- <a href="navigation_tools.html#user_navigation">Adding a link/tab to the user profile navigation</a>
Example use cases might include:
- Leveraging single sign-on to student portal from within Canvas
- Linking to an external user profile
- <a href="editor_button_tools.html">Adding a button to insert custom content using the rich content editor</a>
Example use cases might include:
- Embedding resources from campus video repository
- Inserting custom-designed chemistry diagrams into quiz question text
- Building integrations with new or subject-area-specialized web authoring services
- <a href="link_selection_tools.html">Selecting a link for modules or an external tool assignment</a>
Example use cases might include:
- Building and then linking to a remixed version of an online Physics textbook
- Selecting from a list of pre-built, interactive quizzes on blood vessels
- Choosing a chapter from an e-textbook to add to the "Null Hypothesis" module
### How to Configure/Import Integrated Tools
Tools extensions can be configured using LTI configuration XML as specified in the IMS
Tools extensions can be configured using LTI configuration XML as specified in the IMS
Common Cartridge specification, or using the <a href="external_tools.html">external tools
API</a>. Configuration XML contains all non-account-specific
settings (everything except the consumer key and shared secret, which must always be
entered manually). The user can retrieve the info from a standard URL that you provide
(recommended), or paste in the XML that you provide. For more information on this
API</a>. Configuration XML contains all non-account-specific
settings (everything except the consumer key and shared secret, which must always be
entered manually). The user can retrieve the info from a standard URL that you provide
(recommended), or paste in the XML that you provide. For more information on this
configuration, see the "Examples" link.
For information on how to programmatically configured external tools, so users
don't have to copy and paste URLs or XML, please see the Canvas
don't have to copy and paste URLs or XML, please see the Canvas
<a href="external_tools.html">external tools API</a>.

View File

@ -0,0 +1,26 @@
LTI Variable Substitutions
==========================
Variable substitution (aka variable expansion) is where custom variables really start to
shine. They provide a mechanism for tool providers to request that specific, contextual
information be sent across in the launch. When the tool consumer processes the launch request,
it detects requested variable substitutions and sends the appropriate data where possible.
Adding variable substitutions is exactly the same as adding custom variables, except the values
are variables instead of constants. This is denoted by prefixing the value with a $. If the
tool consumer doesn't recognize, or can't substitute, the value it will just send the variable
as if it were are regular custom variable.
This is a fairly new addition to our LTI feature set, but has allowed us to expose a lot of
data to LTI tools without asking them to go back to the Canvas API, which can be expensive
for us and them. It allows tool providers to be much more surgical when requesting user
data, and it paves the way for us to be more transparent to tool installers, by showing them
exactly what data the LTI tool will be given access to. On top of all that, variable
substitutions are generally simple to add to Canvas.
There are currently over 45 substitutions available. Many of the substitutions simply
give access to additional user and context information. An LTI tool can request things
like SIS ids, names, an avatar image, and an email address. Other variable substitutions
assist tools with accessibility (prefersHighContrast), course copy (previousCourseIds), and
masquerading users. Additionally, when we don't provide enough information or customizability
directly through LTI, tools can request everything they need to use the Canvas API for an even
richer experience.

View File

@ -0,0 +1,322 @@
LTI Variable Substitutions
==========================
Variable substitution (aka variable expansion) is where custom variables really start to
shine. They provide a mechanism for tool providers to request that specific, contextual
information be sent across in the launch. When the tool consumer processes the launch request,
it detects requested variable substitutions and sends the appropriate data where possible.
Adding variable substitutions is exactly the same as adding custom variables, except the values
are variables instead of constants. This is denoted by prefixing the value with a $. If the
tool consumer doesn't recognize, or can't substitute, the value it will just send the variable
as if it were are regular custom variable.
This is a fairly new addition to our LTI feature set, but has allowed us to expose a lot of
data to LTI tools without asking them to go back to the Canvas API, which can be expensive
for us and them. It allows tool providers to be much more surgical when requesting user
data, and it paves the way for us to be more transparent to tool installers, by showing them
exactly what data the LTI tool will be given access to. On top of all that, variable
substitutions are generally simple to add to Canvas.
There are currently over 45 substitutions available. Many of the substitutions simply
give access to additional user and context information. An LTI tool can request things
like SIS ids, names, an avatar image, and an email address. Other variable substitutions
assist tools with accessibility (prefersHighContrast), course copy (previousCourseIds), and
masquerading users. Additionally, when we don't provide enough information or customizability
directly through LTI, tools can request everything they need to use the Canvas API for an even
richer experience.
## Canvas.api.domain
returns the canvas domain for the current context. Should always be available.
```
canvas.instructure.com
```
## Canvas.api.baseUrl
returns the base URL for the current context. Should always be available.
```
https://canvas.instructure.com
```
## Canvas.api.membershipServiceUrl
Only available when launched in a course.
## Canvas.account.id
returns the account id for the current context. Should always be available.
```
1234
```
## Canvas.account.name
returns the account name for the current context. Should always be available.
```
School Name
```
## Canvas.account.sisSourceId
returns the account's sis source id for the current context. Should always be available.
## Canvas.rootAccount.id
returns the Root Account ID for the current context. Should always be available.
```
1234
```
## Canvas.rootAccount.sisSourceId
returns the root account's sis source id for the current context. Should always be available.
## Canvas.externalTool.url
returns the URL for the external tool that was launched. Only available for LTI 1.
```
http://example.url/path
```
## Canvas.css.common
returns the URL for the external tool that was launched. Should always be available.
```
http://example.url/path.css
```
## Canvas.shard.id
returns the shard id for the current context. Should always be available.
```
1234
```
## Canvas.root_account.global_id
returns the root account's global id for the current context. Should always be available.
```
123400000000123
```
## Canvas.root_account.id *[deprecated]*
returns the root account id for the current context. Should always be available.
```
1234
```
## Canvas.root_account.sisSourceId *[deprecated]*
returns the root account sis source id for the current context. Should always be available.
```
1234
```
## Canvas.course.id
returns the current course id. Only available when launched in a course.
```
1234
```
## Canvas.course.sisSourceId
returns the current course sis source id. Only available when launched in a course.
```
1234
```
## Canvas.course.startAt
returns the current course start date. Only available when launched in a course.
```
1234
```
## Canvas.term.startAt
returns the current course's term start date. Only available when launched in a course that has a term with a start date.
```
1234
```
## CourseSection.sourcedId
returns the current course section sis source id. Only available when launched in a course.
```
1234
```
## Canvas.enrollment.enrollmentState
returns the current course enrollment state. Only available when launched in a course.
```
1234
```
## Canvas.membership.roles
returns the current course membership roles. Only available when launched from a course or an account.
```
1234
```
## Canvas.membership.concludedRoles
This is a list of IMS LIS roles should have a different key. Only available when launched in a course.
## Canvas.course.previousContextIds
returns the current course enrollment state. Only available when launched in a course.
```
1234
```
## Canvas.course.previousCourseIds
returns the current course enrollment state. Only available when launched in a course.
```
1234
```
## Person.name.full
Only available when launched by a logged in user.
## Person.name.family
Only available when launched by a logged in user.
## Person.name.given
Only available when launched by a logged in user.
## Person.email.primary
Only available when launched by a logged in user.
## Person.address.timezone
Only available when launched by a logged in user.
## User.image
Only available when launched by a logged in user.
## User.id
Only available when launched by a logged in user.
## Canvas.user.id
Only available when launched by a logged in user.
## Canvas.user.prefersHighContrast
Only available when launched by a logged in user.
## Membership.role
Only available when launched by a logged in user.
## Canvas.xuser.allRoles
Should always be available.
## Canvas.user.globalId
Only available when launched by a logged in user.
## User.username
Substitutions for the primary pseudonym for the user for the account
This should hold all the SIS information for the user
This may not be the pseudonym the user is actually gingged in with. Only available when pseudonym is in use.
## Canvas.user.loginId
Only available when pseudonym is in use.
## Canvas.user.sisSourceId
Only available when pseudonym is in use.
## Canvas.user.sisIntegrationId
Only available when pseudonym is in use.
## Person.sourcedId
Only available when pseudonym is in use.
## Canvas.logoutService.url
This is the pseudonym the user is actually logged in as
it may not hold all the sis info needed in other launch substitutions.
## Canvas.masqueradingUser.id
Only available when the user is being masqueraded.
## Canvas.masqueradingUser.userId
Only available when the user is being masqueraded.
## Canvas.xapi.url
## Caliper.url
## Canvas.course.sectionIds
Only available when launched from a course.
## Canvas.course.sectionSisSourceIds
Only available when launched from a course.
## Canvas.module.id
Only available when content tag is present.
## Canvas.moduleItem.id
Only available when content tag is present.
## Canvas.assignment.id
Only available when launched as an assignment.
## Canvas.assignment.title
Only available when launched as an assignment.
## Canvas.assignment.pointsPossible
Only available when launched as an assignment.
## Canvas.assignment.unlockAt *[deprecated]*
deprecated in favor of ISO8601. Only available when launched as an assignment.
## Canvas.assignment.lockAt *[deprecated]*
deprecated in favor of ISO8601. Only available when launched as an assignment.
## Canvas.assignment.dueAt *[deprecated]*
deprecated in favor of ISO8601. Only available when launched as an assignment.
## Canvas.assignment.unlockAt.iso8601
## Canvas.assignment.lockAt.iso8601
## Canvas.assignment.dueAt.iso8601
## LtiLink.custom.url
## ToolProxyBinding.custom.url
## ToolProxy.custom.url
## ToolConsumerProfile.url
## Canvas.file.media.id
Only available when an attachment is present and it has either a media object or media entry id defined.
## Canvas.file.media.type
Only available when an attachment is present and has a media object defined.
## Canvas.file.media.duration
Only available when an attachment is present and has a media object defined.
## Canvas.file.media.size
Only available when an attachment is present and has a media object defined.
## Canvas.file.media.title
Only available when an attachment is present and has a media object defined.
## Canvas.file.usageRights.name
Only available when an attachment is present and has usage rights defined.
## Canvas.file.usageRights.url
Only available when an attachment is present and has usage rights defined.
## Canvas.file.usageRights.copyrightText
Only available when an attachment is present and has usage rights defined.

View File

@ -0,0 +1,90 @@
YARD::Templates::Engine.register_template_path Pathname.new(File.dirname(__FILE__))
class RegisterExpansionHandler < YARD::Handlers::Ruby::Base
handles method_call(:register_expansion)
namespace_only
def process
variable_substitution = statement.parameters.first.jump(:tstring_content, :ident).source
guard = (
statement.parameters[3] && statement.parameters[3].jump(:tstring_content, :ident).source.to_s
) || 'ALWAYS'
object = register YARD::CodeObjects::MethodObject.new(namespace, variable_substitution)
parse_block(statement, :owner => object)
deprecated_str = ''
deprecated_str = ' *[deprecated]*' if object.tags(:deprecated).count > 0
example_tags = object.tags(:example)
example = example_tags.count > 0 && object.tags(:example).first
example_text = ''
example_text = "\n\n#{example.text}" if example
description = if statement.comments
d = statement.comments.match(/([^@]+)@?/m)[1].strip
d = "#{d}." unless ['.', '!', '?'].include? d[-1]
d = "#{d} "
d
else
''
end
description = case guard
when 'ALWAYS'
"#{description}Should always be available."
when 'USER_GUARD'
"#{description}Only available when launched by a logged in user."
when 'USAGE_RIGHTS_GUARD'
"#{description}Only available when an attachment is present and has usage rights defined."
when 'MEDIA_OBJECT_GUARD'
"#{description}Only available when an attachment is present and has a media object defined."
when 'PSEUDONYM_GUARD'
"#{description}Only available when pseudonym is in use."
when 'ENROLLMENT_GUARD'
"#{description}Only available when launched from a course."
when 'ROLES_GUARD'
"#{description}Only available when launched from a course or an account."
when 'CONTENT_TAG_GUARD'
"#{description}Only available when content tag is present."
when 'ASSIGNMENT_GUARD'
"#{description}Only available when launched as an assignment."
when 'MEDIA_OBJECT_ID_GUARD'
"#{description}Only available when an attachment is present and it has either a media object or media entry id defined."
when 'LTI1_GUARD'
"#{description}Only available for LTI 1."
when 'MASQUERADING_GUARD'
"#{description}Only available when the user is being masqueraded."
when 'COURSE_GUARD'
"#{description}Only available when launched in a course."
when 'TERM_START_DATE_GUARD'
"#{description}Only available when launched in a course that has a term with a start date."
else
"#{description}"
end
DocWriter.append_md "## #{variable_substitution}#{deprecated_str}\n#{description}#{example_text}\n\n"
end
private
def object
@object ||= YARD::CodeObjects::ClassVariableObject.new(namespace, "LTI_Substitutions")
end
end
module DocWriter
def self.append_md(md)
markdown_file
File.write('doc/api/tools_variable_substitutions.md', md, File.size('doc/api/tools_variable_substitutions.md'), mode: 'a')
end
def self.markdown_file
@markdown_file ||= (
IO.copy_stream('doc/api/tools_variable_substitutions.head.md', 'doc/api/tools_variable_substitutions.md')
true
)
end
end

View File

@ -89,9 +89,19 @@ module Lti
end
end
# returns the canvas domain for the current context.
# @example
# ```
# canvas.instructure.com
# ```
register_expansion 'Canvas.api.domain', [],
-> { HostUrl.context_host(@root_account, @request.host) }
# returns the base URL for the current context.
# @example
# ```
# https://canvas.instructure.com
# ```
register_expansion 'Canvas.api.baseUrl', [],
-> { "#{@request.scheme}://#{HostUrl.context_host(@root_account, @request.host)}" }
@ -99,80 +109,173 @@ module Lti
-> { @controller.course_membership_service_url(@context) },
COURSE_GUARD
# returns the account id for the current context.
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.account.id', [],
-> { lti_helper.account.id }
# returns the account name for the current context.
# @example
# ```
# School Name
# ```
register_expansion 'Canvas.account.name', [],
-> { lti_helper.account.name }
# returns the account's sis source id for the current context.
register_expansion 'Canvas.account.sisSourceId', [],
-> { lti_helper.account.sis_source_id }
# returns the Root Account ID for the current context.
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.rootAccount.id', [],
-> { @root_account.id }
# returns the root account's sis source id for the current context.
register_expansion 'Canvas.rootAccount.sisSourceId', [],
-> { @root_account.sis_source_id }
# returns the URL for the external tool that was launched.
# @example
# ```
# http://example.url/path
# ```
register_expansion 'Canvas.externalTool.url', [],
-> { @controller.named_context_url(@context, :api_v1_context_external_tools_update_url,
@tool.id, include_host:true) },
LTI1_GUARD
# returns the URL for the external tool that was launched.
# @example
# ```
# http://example.url/path.css
# ```
register_expansion 'Canvas.css.common', [],
-> { URI.parse(@request.url)
.merge(@controller.view_context.stylesheet_path(@controller.css_url_for(:common))).to_s }
# returns the shard id for the current context.
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.shard.id', [],
-> { Shard.current.id }
# returns the root account's global id for the current context.
# @example
# ```
# 123400000000123
# ```
register_expansion 'Canvas.root_account.global_id', [],
-> { @root_account.global_id }
##### Deprecated Substitutions #####
# returns the root account id for the current context.
# @deprecated
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.root_account.id', [],
-> { @root_account.id }
# returns the root account sis source id for the current context.
# @deprecated
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.root_account.sisSourceId', [],
-> { @root_account.sis_source_id }
# returns the current course id.
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.course.id', [],
-> { @context.id },
COURSE_GUARD
# returns the current course sis source id.
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.course.sisSourceId', [],
-> { @context.sis_source_id },
COURSE_GUARD
# returns the current course start date.
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.course.startAt', [],
-> { @context.start_at },
COURSE_GUARD
# returns the current course's term start date.
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.term.startAt', [],
-> { @context.enrollment_term.start_at },
TERM_START_DATE_GUARD
# returns the current course section sis source id
# @example
# ```
# 1234
# ```
register_expansion 'CourseSection.sourcedId', [],
-> { @context.sis_source_id },
COURSE_GUARD
# returns the current course enrollment state
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.enrollment.enrollmentState', [],
-> { lti_helper.enrollment_state },
COURSE_GUARD
# returns the current course membership roles
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.membership.roles', [],
-> { lti_helper.current_canvas_roles },
ROLES_GUARD
#This is a list of IMS LIS roles should have a different key
# This is a list of IMS LIS roles should have a different key
register_expansion 'Canvas.membership.concludedRoles', [],
-> { lti_helper.concluded_lis_roles },
COURSE_GUARD
# returns the current course enrollment state
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.course.previousContextIds', [],
-> { lti_helper.previous_lti_context_ids },
COURSE_GUARD
# returns the current course enrollment state
# @example
# ```
# 1234
# ```
register_expansion 'Canvas.course.previousCourseIds', [],
-> { lti_helper.previous_course_ids },
COURSE_GUARD
@ -227,7 +330,6 @@ module Lti
# Substitutions for the primary pseudonym for the user for the account
# This should hold all the SIS information for the user
# This may not be the pseudonym the user is actually gingged in with
register_expansion 'User.username', [],
-> { sis_pseudonym.unique_id },
PSEUDONYM_GUARD
@ -301,17 +403,17 @@ module Lti
register_expansion 'Canvas.assignment.pointsPossible', [],
-> { @assignment.points_possible },
ASSIGNMENT_GUARD
#deprecated in favor of ISO8601
# @deprecated in favor of ISO8601
register_expansion 'Canvas.assignment.unlockAt', [],
-> { @assignment.unlock_at },
ASSIGNMENT_GUARD
#deprecated in favor of ISO8601
# @deprecated in favor of ISO8601
register_expansion 'Canvas.assignment.lockAt', [],
-> { @assignment.lock_at },
ASSIGNMENT_GUARD
#deprecated in favor of ISO8601
# @deprecated in favor of ISO8601
register_expansion 'Canvas.assignment.dueAt', [],
-> { @assignment.due_at },
ASSIGNMENT_GUARD

View File

@ -0,0 +1,3 @@
#! /bin/sh
bundle exec yardoc -n -e doc/yard_plugins/lti_variable_expansion_plugin.rb lib/lti/variable_expander.rb