add permissions variable expansion

also keeps it undocumented for now

test plan:
* test an lti launch in a course using a variable
 in the format:

 $Canvas.membership.permissions<permission1,permission2,..>

 with a comma-separated list in between the brackets
 corresponding to course-level permissions
 (see doc/api/roles.html#method.role_overrides.show), e.g.

 $Canvas.membership.permissions<read_forum,moderate_forum>

 these are the list of permissions to check
 when the variable is expanded it should substitute it with a
 comma-separated list of permissions filtered to those
 that the user has been granted within the course

closes #PLYT-1796

Change-Id: I1c039e04318fcfe8ca5ee450e608bd3fb2affe6b
Reviewed-on: https://gerrit.instructure.com/194797
Tested-by: Jenkins
QA-Review: Nathan Mills <nathanm@instructure.com>
Product-Review: James Williams <jamesw@instructure.com>
Reviewed-by: Nathan Mills <nathanm@instructure.com>
Reviewed-by: Marc Phillips <mphillips@instructure.com>
This commit is contained in:
James Williams 2019-05-22 14:18:31 -06:00
parent 9af89f8ab5
commit bb6bd0aeac
6 changed files with 61 additions and 8 deletions

View File

@ -26,6 +26,7 @@ class RegisterExpansionHandler < YARD::Handlers::Ruby::Base
variable_substitution = statement.parameters.first.jump(:tstring_content, :ident).source variable_substitution = statement.parameters.first.jump(:tstring_content, :ident).source
object = register YARD::CodeObjects::MethodObject.new(namespace, variable_substitution) object = register YARD::CodeObjects::MethodObject.new(namespace, variable_substitution)
return if object.tags(:internal).any?
parse_block(statement, :owner => object) parse_block(statement, :owner => object)
deprecated_str = '' deprecated_str = ''

View File

@ -185,6 +185,10 @@ module Lti
concluded_course_enrollments.size > 0 ? enrollments_to_lis_roles(concluded_course_enrollments).join(',') : LtiOutbound::LTIRoles::System::NONE concluded_course_enrollments.size > 0 ? enrollments_to_lis_roles(concluded_course_enrollments).join(',') : LtiOutbound::LTIRoles::System::NONE
end end
def granted_permissions(permissions_to_check)
permissions_to_check.select{|p| @context.grants_right?(@user, p.to_sym) }.join(",")
end
def current_canvas_roles def current_canvas_roles
roles = (course_enrollments + account_enrollments).map(&:role).map(&:name).uniq roles = (course_enrollments + account_enrollments).map(&:role).map(&:name).uniq
roles = roles.map{|role| role == "AccountAdmin" ? "Account Admin" : role} # to maintain backwards compatibility roles = roles.map{|role| role == "AccountAdmin" ? "Account Admin" : role} # to maintain backwards compatibility

View File

@ -24,6 +24,7 @@ module Lti
class VariableExpander class VariableExpander
SUBSTRING_REGEX = /(?<=\${).*?(?=})/.freeze #matches only the stuff inside `${}` SUBSTRING_REGEX = /(?<=\${).*?(?=})/.freeze #matches only the stuff inside `${}`
PARAMETERS_REGEX = /^(\$.+)\<(.+)\>$/.freeze # matches key and argument
attr_reader :context, :root_account, :controller, :current_user attr_reader :context, :root_account, :controller, :current_user
@ -53,6 +54,18 @@ module Lti
self.expansions.values.select { |v| v.default_name.present? }.map(&:name) self.expansions.values.select { |v| v.default_name.present? }.map(&:name)
end end
def self.find_expansion(key)
return unless key.respond_to?(:to_sym)
if (md = key.to_s.match(PARAMETERS_REGEX))
real_key = md[1] + "<>"
if (expansion = self.expansions[real_key.to_sym])
[expansion, md[2]]
end
else
self.expansions[key.to_sym]
end
end
CONTROLLER_GUARD = -> { !!@controller } CONTROLLER_GUARD = -> { !!@controller }
COURSE_GUARD = -> { @context.is_a? Course } COURSE_GUARD = -> { @context.is_a? Course }
TERM_START_DATE_GUARD = -> { @context.is_a?(Course) && @context.enrollment_term && TERM_START_DATE_GUARD = -> { @context.is_a?(Course) && @context.enrollment_term &&
@ -97,15 +110,16 @@ module Lti
def [](key) def [](key)
k = (key[0] == '$' && key) || "$#{key}" k = (key[0] == '$' && key) || "$#{key}"
if (expansion = self.class.expansions[k.respond_to?(:to_sym) && k.to_sym]) expansion, args = self.class.find_expansion(k)
expansion.expand(self) expansion.expand(self, *args) if expansion
end
end end
def expand_variables!(var_hash) def expand_variables!(var_hash)
var_hash.update(var_hash) do |_, v| var_hash.update(var_hash) do |_, v|
if (expansion = v.respond_to?(:to_sym) && self.class.expansions[v.to_sym]) expansion, args = self.class.find_expansion(v)
expansion.expand(self) if expansion
expansion.expand(self, *args)
elsif v.respond_to?(:to_s) && v.to_s =~ SUBSTRING_REGEX elsif v.respond_to?(:to_s) && v.to_s =~ SUBSTRING_REGEX
expand_substring_variables(v) expand_substring_variables(v)
else else
@ -595,6 +609,18 @@ module Lti
-> { lti_helper.concluded_lis_roles }, -> { lti_helper.concluded_lis_roles },
COURSE_GUARD COURSE_GUARD
# Returns a comma-separated list of permissions granted to the user in the current context,
# given a comma-separated set to check using the format
# $Canvas.membership.permissions<example_permission,example_permission2,..>
# @internal
# @example
# ```
# example_permission_1,example_permission_2
# ```
register_expansion 'Canvas.membership.permissions<>', [],
-> (permissions_str) { lti_helper.granted_permissions(permissions_str.split(",")) },
ROLES_GUARD
# With respect to the current course, returns the context ids of the courses from which content has been copied (excludes cartridge imports). # With respect to the current course, returns the context ids of the courses from which content has been copied (excludes cartridge imports).
# #
# @example # @example

View File

@ -33,8 +33,12 @@ module Lti
@default_name = default_name @default_name = default_name
end end
def expand(expander) def expand(expander, *args)
expand_for?(expander) ? expander.instance_exec(&@expansion_proc) : "$#{name}" if expand_for?(expander)
expander.instance_exec(*args, &@expansion_proc)
else
"$#{name}"
end
end end
private private

View File

@ -1,3 +1,3 @@
#! /bin/sh #! /bin/sh
bundle exec yardoc --verbose --tag launch_parameter:"Launch Parameter" --tag duplicates:"Duplicates" -n -e doc/yard_plugins/lti_variable_expansion_plugin.rb lib/lti/variable_expander.rb bundle exec yardoc --verbose --tag launch_parameter:"Launch Parameter" --tag duplicates:"Duplicates" --tag internal -n -e doc/yard_plugins/lti_variable_expansion_plugin.rb lib/lti/variable_expander.rb

View File

@ -1583,6 +1583,24 @@ module Lti
expect(exp_hash[:test]).to eq 'url' expect(exp_hash[:test]).to eq 'url'
end end
end end
it 'has substitution for $Canvas.membership.permissions' do
course_with_student(:active_all => true)
exp_hash = {test: '$Canvas.membership.permissions<moderate_forum,read_forum,create_forum>'}
expander = VariableExpander.new(@course.root_account, @course, controller, current_user: @student, tool: tool)
expander.expand_variables!(exp_hash)
expect(exp_hash[:test]).to eq "read_forum,create_forum"
end
it 'substitutes $Canvas.membership.permissions inside substring' do
course_with_student(:active_all => true)
exp_hash = {test: 'string stuff: ${Canvas.membership.permissions<moderate_forum,create_forum,read_forum>}'}
expander = VariableExpander.new(@course.root_account, @course, controller, current_user: @student, tool: tool)
expander.expand_variables!(exp_hash)
expect(exp_hash[:test]).to eq "string stuff: create_forum,read_forum"
end
end end
end end
end end