force navigation tabs cache to invalidate when changing external tools
fixes:PLAT-277 test plan: 1. Go to https://www.eduappcenter.com/apps/redirect 2. Enter criteria for a redirect link configuration URL 3. Access an account in Canvas 4. Add the Redirect External Tool with your configuration URL 5. Observe link is added to your Navigation per your settings 6. Attempt to edit the External Tool in Canvas with a new configuration URL you get from https://www.eduappcenter.com/apps/redirect after putting in new data 7. Observe that changes are reflected in the External Tools tab but the actual link in Navigation menus is changed Change-Id: I2b233cb89e4b446cd66b6e826ec8de894a02bfdd Reviewed-on: https://gerrit.instructure.com/33757 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Nathan Rogowski <nathan@instructure.com> Reviewed-by: Eric Berry <ericb@instructure.com> Product-Review: Nathan Mills <nathanm@instructure.com>
This commit is contained in:
parent
d7b5b7f09a
commit
079f2d60cc
|
@ -74,27 +74,27 @@ class ExternalToolsController < ApplicationController
|
|||
end
|
||||
@tools = ContextExternalTool.search_by_attribute(@tools, :name, params[:search_term])
|
||||
respond_to do |format|
|
||||
@tools = Api.paginate(@tools, self, tool_pagination_url)
|
||||
format.json {render :json => external_tools_json(@tools, @context, @current_user, session)}
|
||||
@tools = Api.paginate(@tools, self, tool_pagination_url)
|
||||
format.json { render :json => external_tools_json(@tools, @context, @current_user, session) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def homework_submissions
|
||||
if authorized_action(@context, @current_user, :read)
|
||||
@tools = ContextExternalTool.all_tools_for(@context, :user => @current_user).select(&:has_homework_submission)
|
||||
respond_to do |format|
|
||||
format.json {render :json => external_tools_json(@tools, @context, @current_user, session)}
|
||||
format.json { render :json => external_tools_json(@tools, @context, @current_user, session) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def finished
|
||||
@headers = false
|
||||
if authorized_action(@context, @current_user, :read)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def retrieve
|
||||
if authorized_action(@context, @current_user, :read)
|
||||
@tool = ContextExternalTool.find_external_tool(params[:url], @context)
|
||||
|
@ -215,7 +215,7 @@ class ExternalToolsController < ApplicationController
|
|||
end
|
||||
uri.query = {:verifier => verifier}.to_query
|
||||
|
||||
render :json => { :id => @tool.id, :name => @tool.name, :url => uri.to_s }
|
||||
render :json => {:id => @tool.id, :name => @tool.name, :url => uri.to_s}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -304,8 +304,8 @@ class ExternalToolsController < ApplicationController
|
|||
selection_type = 'editor_button' if params[:editor]
|
||||
selection_type = 'homework_submission' if params[:homework]
|
||||
|
||||
@return_url = external_content_success_url('external_tool')
|
||||
@headers = false
|
||||
@return_url = external_content_success_url('external_tool')
|
||||
@headers = false
|
||||
@tool_launch_type = 'self'
|
||||
|
||||
find_tool(params[:external_tool_id], selection_type)
|
||||
|
@ -315,12 +315,14 @@ class ExternalToolsController < ApplicationController
|
|||
def find_tool(id, selection_type)
|
||||
begin
|
||||
@tool = ContextExternalTool.find_for(id, @context, selection_type)
|
||||
rescue ActiveRecord::RecordNotFound; end
|
||||
rescue ActiveRecord::RecordNotFound;
|
||||
end
|
||||
if !@tool
|
||||
flash[:error] = t "#application.errors.invalid_external_tool_id", "Couldn't find valid settings for this tool"
|
||||
redirect_to named_context_url(@context, :context_url)
|
||||
end
|
||||
end
|
||||
|
||||
protected :find_tool
|
||||
|
||||
def render_tool(selection_type)
|
||||
|
@ -345,6 +347,7 @@ class ExternalToolsController < ApplicationController
|
|||
|
||||
render :template => 'external_tools/tool_show'
|
||||
end
|
||||
|
||||
protected :render_tool
|
||||
|
||||
# @API Create an external tool
|
||||
|
@ -511,6 +514,7 @@ class ExternalToolsController < ApplicationController
|
|||
set_tool_attributes(@tool, params[:external_tool] || params)
|
||||
respond_to do |format|
|
||||
if @tool.save
|
||||
invalidate_nav_tabs_cache(@tool)
|
||||
if api_request?
|
||||
format.json { render :json => external_tool_json(@tool, @context, @current_user, session) }
|
||||
else
|
||||
|
@ -539,6 +543,7 @@ class ExternalToolsController < ApplicationController
|
|||
respond_to do |format|
|
||||
set_tool_attributes(@tool, params[:external_tool] || params)
|
||||
if @tool.save
|
||||
invalidate_nav_tabs_cache(@tool)
|
||||
if api_request?
|
||||
format.json { render :json => external_tool_json(@tool, @context, @current_user, session) }
|
||||
else
|
||||
|
@ -565,6 +570,7 @@ class ExternalToolsController < ApplicationController
|
|||
respond_to do |format|
|
||||
if @tool.destroy
|
||||
if api_request?
|
||||
invalidate_nav_tabs_cache(@tool)
|
||||
format.json { render :json => external_tool_json(@tool, @context, @current_user, session) }
|
||||
else
|
||||
format.json { render :json => @tool.as_json(:methods => [:readable_state, :custom_fields_string], :include_root => false) }
|
||||
|
@ -575,15 +581,22 @@ class ExternalToolsController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def set_tool_attributes(tool, params)
|
||||
attrs = ContextExternalTool::EXTENSION_TYPES
|
||||
attrs += [:name, :description, :url, :icon_url, :domain, :privacy_level, :consumer_key, :shared_secret,
|
||||
:custom_fields, :custom_fields_string, :text, :config_type, :config_url, :config_xml]
|
||||
:custom_fields, :custom_fields_string, :text, :config_type, :config_url, :config_xml]
|
||||
attrs.each do |prop|
|
||||
tool.send("#{prop}=", params[prop]) if params.has_key?(prop)
|
||||
end
|
||||
end
|
||||
|
||||
def invalidate_nav_tabs_cache(tool)
|
||||
if tool.has_user_navigation || tool.has_course_navigation || tool.has_account_navigation
|
||||
Lti::NavigationCache.new(@domain_root_account).invalidate_cache_key
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -309,7 +309,7 @@ module ApplicationHelper
|
|||
@section_tabs ||= begin
|
||||
if @context
|
||||
html = []
|
||||
tabs = Rails.cache.fetch([@context, @current_user, @domain_root_account, "section_tabs_hash", I18n.locale].cache_key) do
|
||||
tabs = Rails.cache.fetch([@context, @current_user, @domain_root_account, Lti::NavigationCache.new(@domain_root_account), "section_tabs_hash", I18n.locale].cache_key) do
|
||||
if @context.respond_to?(:tabs_available) && !(tabs = @context.tabs_available(@current_user, :session => session, :root_account => @domain_root_account)).empty?
|
||||
tabs.select do |tab|
|
||||
if (tab[:id] == @context.class::TAB_COLLABORATIONS rescue false)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
# Copyright (C) 2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module Lti
|
||||
class NavigationCache
|
||||
CACHE_KEY = 'navigation_tabs_key'
|
||||
|
||||
def initialize(account)
|
||||
@account = account
|
||||
end
|
||||
|
||||
|
||||
def cache_key
|
||||
Rails.cache.fetch([@account, CACHE_KEY].cache_key) { SecureRandom.uuid }
|
||||
end
|
||||
|
||||
def invalidate_cache_key
|
||||
Rails.cache.delete([@account, CACHE_KEY].cache_key)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
|
@ -29,9 +29,9 @@ def new_valid_tool(course)
|
|||
:shared_secret => "bob")
|
||||
tool.url = "http://www.example.com/basic_lti"
|
||||
tool.resource_selection = {
|
||||
:url => "http://#{HostUrl.default_host}/selection_test",
|
||||
:selection_width => 400,
|
||||
:selection_height => 400 }
|
||||
:url => "http://#{HostUrl.default_host}/selection_test",
|
||||
:selection_width => 400,
|
||||
:selection_height => 400}
|
||||
tool.save!
|
||||
tool
|
||||
end
|
||||
|
@ -45,7 +45,7 @@ describe ExternalToolsController do
|
|||
get 'retrieve', :course_id => @course.id
|
||||
assert_unauthorized
|
||||
end
|
||||
|
||||
|
||||
it "should find tools matching by exact url" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
tool = @course.context_external_tools.new(:name => "bob", :consumer_key => "bob", :shared_secret => "bob")
|
||||
|
@ -56,7 +56,7 @@ describe ExternalToolsController do
|
|||
assigns[:tool].should == tool
|
||||
assigns[:tool_settings].should_not be_nil
|
||||
end
|
||||
|
||||
|
||||
it "should find tools matching by domain" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
tool = new_valid_tool(@course)
|
||||
|
@ -65,7 +65,7 @@ describe ExternalToolsController do
|
|||
assigns[:tool].should == tool
|
||||
assigns[:tool_settings].should_not be_nil
|
||||
end
|
||||
|
||||
|
||||
it "should redirect if no matching tools are found" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
get 'retrieve', :course_id => @course.id, :url => "http://www.example.com"
|
||||
|
@ -73,7 +73,7 @@ describe ExternalToolsController do
|
|||
flash[:error].should == "Couldn't find valid settings for this link"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "GET 'resource_selection'" do
|
||||
it "should require authentication" do
|
||||
course_with_teacher(:active_all => true)
|
||||
|
@ -168,14 +168,14 @@ describe ExternalToolsController do
|
|||
assigns[:tool_settings]['custom_canvas_enrollment_state'].should == 'inactive'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "POST 'create'" do
|
||||
it "should require authentication" do
|
||||
course_with_teacher(:active_all => true)
|
||||
post 'create', :course_id => @course.id, :format => "json"
|
||||
assert_status(401)
|
||||
end
|
||||
|
||||
|
||||
it "should accept basic configurations" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
post 'create', :course_id => @course.id, :external_tool => {:name => "tool name", :url => "http://example.com", :consumer_key => "key", :shared_secret => "secret"}, :format => "json"
|
||||
|
@ -186,7 +186,7 @@ describe ExternalToolsController do
|
|||
assigns[:tool].consumer_key.should == "key"
|
||||
assigns[:tool].shared_secret.should == "secret"
|
||||
end
|
||||
|
||||
|
||||
it "should fail on basic xml with no url or domain set" do
|
||||
rescue_action_in_public! if CANVAS_RAILS2
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
|
@ -213,7 +213,7 @@ describe ExternalToolsController do
|
|||
post 'create', :course_id => @course.id, :external_tool => {:name => "tool name", :consumer_key => "key", :shared_secret => "secret", :config_type => "by_xml", :config_xml => xml}, :format => "json"
|
||||
response.should_not be_success
|
||||
end
|
||||
|
||||
|
||||
it "should handle advanced xml configurations" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
xml = <<-XML
|
||||
|
@ -255,7 +255,7 @@ describe ExternalToolsController do
|
|||
assigns[:tool].shared_secret.should == "secret"
|
||||
assigns[:tool].has_editor_button.should be_true
|
||||
end
|
||||
|
||||
|
||||
it "should handle advanced xml configurations with no url or domain set" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
xml = <<-XML
|
||||
|
@ -297,7 +297,7 @@ describe ExternalToolsController do
|
|||
assigns[:tool].shared_secret.should == "secret"
|
||||
assigns[:tool].has_editor_button.should be_true
|
||||
end
|
||||
|
||||
|
||||
it "should fail gracefully on invalid xml configurations" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
xml = "bob"
|
||||
|
@ -315,7 +315,7 @@ describe ExternalToolsController do
|
|||
json = json_parse(response.body)
|
||||
json['errors']['config_xml'][0]['message'].should == I18n.t(:invalid_xml_syntax, 'Invalid xml syntax')
|
||||
end
|
||||
|
||||
|
||||
it "should handle advanced xml configurations by URL retrieval" do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
xml = <<-XML
|
||||
|
@ -359,7 +359,7 @@ describe ExternalToolsController do
|
|||
assigns[:tool].shared_secret.should == "secret"
|
||||
assigns[:tool].has_editor_button.should be_true
|
||||
end
|
||||
|
||||
|
||||
it "should fail gracefully on invalid URL retrieval or timeouts" do
|
||||
Net::HTTP.any_instance.stubs(:request).raises(Timeout::Error)
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
|
@ -370,6 +370,141 @@ describe ExternalToolsController do
|
|||
json = json_parse(response.body)
|
||||
json['errors']['config_url'][0]['message'].should == I18n.t(:retrieve_timeout, 'could not retrieve configuration, the server response timed out')
|
||||
end
|
||||
|
||||
|
||||
context "navigation tabs caching" do
|
||||
it "shouldn't clear the navigation tabs cache for non navigtaion tools" do
|
||||
enable_cache do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
nav_cache = Lti::NavigationCache.new(@course.root_account)
|
||||
cache_key = nav_cache.cache_key
|
||||
xml = <<-XML
|
||||
<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0" xmlns:blti="http://www.imsglobal.org/xsd/imsbasiclti_v1p0" xmlns:lticm="http://www.imsglobal.org/xsd/imslticm_v1p0" xmlns:lticp="http://www.imsglobal.org/xsd/imslticp_v1p0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">
|
||||
<blti:title>Redirect Tool</blti:title>
|
||||
<blti:description>
|
||||
Add links to external web resources that show up as navigation items in course, user or account navigation. Whatever URL you specify is loaded within the content pane when users click the link.
|
||||
</blti:description>
|
||||
<blti:launch_url>https://www.edu-apps.org/redirect</blti:launch_url>
|
||||
<blti:custom>
|
||||
<lticm:property name="url">https://</lticm:property>
|
||||
</blti:custom>
|
||||
<blti:extensions platform="canvas.instructure.com">
|
||||
<lticm:property name="icon_url">
|
||||
https://www.edu-apps.org/assets/lti_redirect_engine/redirect_icon.png
|
||||
</lticm:property>
|
||||
<lticm:property name="link_text"/>
|
||||
<lticm:property name="privacy_level">anonymous</lticm:property>
|
||||
<lticm:property name="tool_id">redirect</lticm:property>
|
||||
</blti:extensions>
|
||||
</cartridge_basiclti_link>
|
||||
XML
|
||||
post 'create', :course_id => @course.id, :external_tool => {:name => "tool name", :url => "http://example.com", :consumer_key => "key", :shared_secret => "secret", :config_type => "by_xml", :config_xml => xml}, :format => "json"
|
||||
response.should be_success
|
||||
nav_cache.cache_key.should == cache_key
|
||||
end
|
||||
end
|
||||
|
||||
it 'should clear the navigation tabs cache for course nav' do
|
||||
enable_cache do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
cache_key = Lti::NavigationCache.new(@course.root_account).cache_key
|
||||
xml = <<-XML
|
||||
<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0" xmlns:blti="http://www.imsglobal.org/xsd/imsbasiclti_v1p0" xmlns:lticm="http://www.imsglobal.org/xsd/imslticm_v1p0" xmlns:lticp="http://www.imsglobal.org/xsd/imslticp_v1p0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">
|
||||
<blti:title>Redirect Tool</blti:title>
|
||||
<blti:description>
|
||||
Add links to external web resources that show up as navigation items in course, user or account navigation. Whatever URL you specify is loaded within the content pane when users click the link.
|
||||
</blti:description>
|
||||
<blti:launch_url>https://www.edu-apps.org/redirect</blti:launch_url>
|
||||
<blti:custom>
|
||||
<lticm:property name="url">https://</lticm:property>
|
||||
</blti:custom>
|
||||
<blti:extensions platform="canvas.instructure.com">
|
||||
<lticm:options name="course_navigation">
|
||||
<lticm:property name="enabled">true</lticm:property>
|
||||
<lticm:property name="visibility">public</lticm:property>
|
||||
</lticm:options>
|
||||
<lticm:property name="icon_url">
|
||||
https://www.edu-apps.org/assets/lti_redirect_engine/redirect_icon.png
|
||||
</lticm:property>
|
||||
<lticm:property name="link_text"/>
|
||||
<lticm:property name="privacy_level">anonymous</lticm:property>
|
||||
<lticm:property name="tool_id">redirect</lticm:property>
|
||||
</blti:extensions>
|
||||
</cartridge_basiclti_link>
|
||||
XML
|
||||
post 'create', :course_id => @course.id, :external_tool => {:name => "tool name", :url => "http://example.com", :consumer_key => "key", :shared_secret => "secret", :config_type => "by_xml", :config_xml => xml}, :format => "json"
|
||||
response.should be_success
|
||||
Lti::NavigationCache.new(@course.root_account).cache_key.should_not == cache_key
|
||||
end
|
||||
end
|
||||
|
||||
it 'should clear the navigation tabs cache for account nav' do
|
||||
enable_cache do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
cache_key = Lti::NavigationCache.new(@course.root_account).cache_key
|
||||
xml = <<-XML
|
||||
<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0" xmlns:blti="http://www.imsglobal.org/xsd/imsbasiclti_v1p0" xmlns:lticm="http://www.imsglobal.org/xsd/imslticm_v1p0" xmlns:lticp="http://www.imsglobal.org/xsd/imslticp_v1p0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">
|
||||
<blti:title>Redirect Tool</blti:title>
|
||||
<blti:description>
|
||||
Add links to external web resources that show up as navigation items in course, user or account navigation. Whatever URL you specify is loaded within the content pane when users click the link.
|
||||
</blti:description>
|
||||
<blti:launch_url>https://www.edu-apps.org/redirect</blti:launch_url>
|
||||
<blti:custom>
|
||||
<lticm:property name="url">https://</lticm:property>
|
||||
</blti:custom>
|
||||
<blti:extensions platform="canvas.instructure.com">
|
||||
<lticm:options name="account_navigation">
|
||||
<lticm:property name="enabled">true</lticm:property>
|
||||
<lticm:property name="visibility">public</lticm:property>
|
||||
</lticm:options>
|
||||
<lticm:property name="icon_url">
|
||||
https://www.edu-apps.org/assets/lti_redirect_engine/redirect_icon.png
|
||||
</lticm:property>
|
||||
<lticm:property name="link_text"/>
|
||||
<lticm:property name="privacy_level">anonymous</lticm:property>
|
||||
<lticm:property name="tool_id">redirect</lticm:property>
|
||||
</blti:extensions>
|
||||
</cartridge_basiclti_link>
|
||||
XML
|
||||
post 'create', :course_id => @course.id, :external_tool => {:name => "tool name", :url => "http://example.com", :consumer_key => "key", :shared_secret => "secret", :config_type => "by_xml", :config_xml => xml}, :format => "json"
|
||||
response.should be_success
|
||||
Lti::NavigationCache.new(@course.root_account).cache_key.should_not == cache_key
|
||||
end
|
||||
end
|
||||
|
||||
it 'should clear the navigation tabs cache for user nav' do
|
||||
enable_cache do
|
||||
course_with_teacher_logged_in(:active_all => true)
|
||||
cache_key = Lti::NavigationCache.new(@course.root_account).cache_key
|
||||
xml = <<-XML
|
||||
<cartridge_basiclti_link xmlns="http://www.imsglobal.org/xsd/imslticc_v1p0" xmlns:blti="http://www.imsglobal.org/xsd/imsbasiclti_v1p0" xmlns:lticm="http://www.imsglobal.org/xsd/imslticm_v1p0" xmlns:lticp="http://www.imsglobal.org/xsd/imslticp_v1p0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imslticc_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticc_v1p0.xsd http://www.imsglobal.org/xsd/imsbasiclti_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imsbasiclti_v1p0p1.xsd http://www.imsglobal.org/xsd/imslticm_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticm_v1p0.xsd http://www.imsglobal.org/xsd/imslticp_v1p0 http://www.imsglobal.org/xsd/lti/ltiv1p0/imslticp_v1p0.xsd">
|
||||
<blti:title>Redirect Tool</blti:title>
|
||||
<blti:description>
|
||||
Add links to external web resources that show up as navigation items in course, user or account navigation. Whatever URL you specify is loaded within the content pane when users click the link.
|
||||
</blti:description>
|
||||
<blti:launch_url>https://www.edu-apps.org/redirect</blti:launch_url>
|
||||
<blti:custom>
|
||||
<lticm:property name="url">https://</lticm:property>
|
||||
</blti:custom>
|
||||
<blti:extensions platform="canvas.instructure.com">
|
||||
<lticm:options name="user_navigation">
|
||||
<lticm:property name="enabled">true</lticm:property>
|
||||
<lticm:property name="visibility">public</lticm:property>
|
||||
</lticm:options>
|
||||
<lticm:property name="icon_url">
|
||||
https://www.edu-apps.org/assets/lti_redirect_engine/redirect_icon.png
|
||||
</lticm:property>
|
||||
<lticm:property name="link_text"/>
|
||||
<lticm:property name="privacy_level">anonymous</lticm:property>
|
||||
<lticm:property name="tool_id">redirect</lticm:property>
|
||||
</blti:extensions>
|
||||
</cartridge_basiclti_link>
|
||||
XML
|
||||
post 'create', :course_id => @course.id, :external_tool => {:name => "tool name", :url => "http://example.com", :consumer_key => "key", :shared_secret => "secret", :config_type => "by_xml", :config_xml => xml}, :format => "json"
|
||||
response.should be_success
|
||||
Lti::NavigationCache.new(@course.root_account).cache_key.should_not == cache_key
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#
|
||||
# Copyright (C) 2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb')
|
||||
|
||||
module Lti
|
||||
describe NavigationCache do
|
||||
let(:account) { mock }
|
||||
subject { NavigationCache.new(account) }
|
||||
|
||||
describe "#cache_key" do
|
||||
it 'creates a new cache key' do
|
||||
enable_cache do
|
||||
uuid = SecureRandom.uuid
|
||||
SecureRandom.expects(:uuid).once.returns(uuid)
|
||||
subject.cache_key.should == uuid
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the cached result on subsequent calls' do
|
||||
enable_cache do
|
||||
uuid = SecureRandom.uuid
|
||||
SecureRandom.expects(:uuid).once.returns(uuid)
|
||||
subject.cache_key.should == uuid
|
||||
subject.cache_key.should == uuid
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "#invalidate_cache_key" do
|
||||
it 'invalidates the cache' do
|
||||
enable_cache do
|
||||
uuid = SecureRandom.uuid
|
||||
SecureRandom.expects(:uuid).twice.returns(uuid)
|
||||
subject.cache_key
|
||||
subject.invalidate_cache_key
|
||||
subject.cache_key
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue