Selective Tool Profile Course Copy
fixes PLAT-2634 Test plan: * Using a course with two lti 2 tools installed * Export the course * Then selectively import the course into a new course that doesn't have the LTI 2 tools installed * Ensure that the 2 lti tools are listed in the dialog * Ensure that only the tool profiles that are checked leave warnings during the import * Do a selective course copy from the course that has the two lti 2 tools installed. * Ensure all the same stuff as above * Do selective course export via the api * Go through the export process using the following endpoint and options /api/v1/courses/:course_id/content_exports?export_type=common_cartridge&select[all_tool_profiles]=1 * Ensure that all the tool profiles in the course are exported * Go through the export process using the following endpoint and options /api/v1/courses/:course_id/content_exports?export_type=common_cartridge&select[tool_profiles][]=<id for a tool profile in the course> * Ensure that only the selected tool profile is exported Change-Id: Ib4cfbad35476369aafd8bf66214ef3efb51850e0 Reviewed-on: https://gerrit.instructure.com/116286 Reviewed-by: James Williams <jamesw@instructure.com> Reviewed-by: Nathan Mills <nathanm@instructure.com> QA-Review: August Thornton <august@instructure.com> Tested-by: Jenkins Product-Review: Karl Lloyd <karl@instructure.com>
This commit is contained in:
parent
c665297df2
commit
24c8c5e170
|
@ -92,6 +92,7 @@ define [
|
|||
discussion_topics: "icon-discussion"
|
||||
wiki_pages: "icon-note-light"
|
||||
context_external_tools: "icon-lti"
|
||||
tool_profiles: "icon-lti"
|
||||
announcements: "icon-announcement"
|
||||
calendar_events: "icon-calendar-days"
|
||||
rubrics: "icon-rubric"
|
||||
|
|
|
@ -26,6 +26,8 @@ module Importers
|
|||
tool_profiles.each do |tool_profile|
|
||||
begin
|
||||
values = tease_out_required_values!(tool_profile)
|
||||
next unless migration.import_object?('tool_profiles', tool_profile['migration_id'])
|
||||
|
||||
tool_proxies = Lti::ToolProxy.find_active_proxies_for_context_by_vendor_code_and_product_code(
|
||||
context: migration.context,
|
||||
vendor_code: values[:vendor_code],
|
||||
|
|
|
@ -27,6 +27,7 @@ module Canvas::Migration::Helpers
|
|||
['discussion_topics', -> { I18n.t('lib.canvas.migration.discussion_topics', 'Discussion Topics') }],
|
||||
['wiki_pages', -> { I18n.t('lib.canvas.migration.wikis', 'Wiki Pages') }],
|
||||
['context_external_tools', -> { I18n.t('lib.canvas.migration.external_tools', 'External Tools') }],
|
||||
['tool_profiles', -> { I18n.t('lib.canvas.migration.tool_profiles', 'Tool Profiles') }],
|
||||
['announcements', -> { I18n.t('lib.canvas.migration.announcements', 'Announcements') }],
|
||||
['calendar_events', -> { I18n.t('lib.canvas.migration.calendar_events', 'Calendar Events') }],
|
||||
['rubrics', -> { I18n.t('lib.canvas.migration.rubrics', 'Rubrics') }],
|
||||
|
@ -234,6 +235,10 @@ module Canvas::Migration::Helpers
|
|||
source.linked_learning_outcomes.active.select('learning_outcomes.id,short_description').each do |item|
|
||||
content_list << course_item_hash(type, item)
|
||||
end
|
||||
when 'tool_profiles'
|
||||
source.tool_proxies.active.select("id, name").each do |item|
|
||||
content_list << course_item_hash(type, item)
|
||||
end
|
||||
else
|
||||
if source.respond_to?(type)
|
||||
scope = source.send(type).select(:id).except(:preload)
|
||||
|
@ -272,6 +277,8 @@ module Canvas::Migration::Helpers
|
|||
count = source.discussion_topics.active.only_discussion_topics.count
|
||||
elsif type == 'learning_outcomes'
|
||||
count = source.linked_learning_outcomes.count
|
||||
elsif type == 'tool_profiles'
|
||||
count = source.tool_proxies.active.count
|
||||
elsif source.respond_to?(type) && source.send(type).respond_to?(:count)
|
||||
scope = source.send(type).except(:preload)
|
||||
if scope.klass.respond_to?(:not_deleted)
|
||||
|
|
|
@ -435,6 +435,19 @@ module MigratorHelper
|
|||
end
|
||||
end
|
||||
|
||||
if @course[:tool_profiles]
|
||||
@overview[:tool_profiles] = []
|
||||
@course[:tool_profiles].each do |tool_profile|
|
||||
title = tool_profile.dig('tool_profile', 'product_instance', 'product_info', 'product_name', 'default_value')
|
||||
next unless title
|
||||
profile = {
|
||||
migration_id: tool_profile['migration_id'],
|
||||
title: title
|
||||
}
|
||||
@overview[:tool_profiles] << profile
|
||||
end
|
||||
end
|
||||
|
||||
if @course[:learning_outcomes]
|
||||
@overview[:learning_outcomes] = []
|
||||
@course[:learning_outcomes].each do |outcome|
|
||||
|
|
|
@ -28,6 +28,7 @@ module CC::Importer::Canvas
|
|||
file_path = File.join @unzipped_file_path, file['href']
|
||||
json = JSON.parse(File.read(file_path))
|
||||
json['resource_href'] = file['href']
|
||||
json['migration_id'] = res['identifier']
|
||||
tool_profiles << json
|
||||
end
|
||||
|
||||
|
|
|
@ -20,7 +20,12 @@ module CC
|
|||
module ToolProfiles
|
||||
def create_tool_profiles
|
||||
@course.tool_proxies.active.each do |tool_proxy|
|
||||
next unless export_object?(tool_proxy)
|
||||
# This is grossness that I added until we have a proper
|
||||
# ToolProfile ActiveRecord class
|
||||
tool_proxy.define_singleton_method(:asset_string) do
|
||||
"tool_profile_#{id}"
|
||||
end
|
||||
next unless export_object?(tool_proxy, 'tool_profiles')
|
||||
migration_id = create_key(tool_proxy)
|
||||
|
||||
file_name = "#{migration_id}.json"
|
||||
|
|
|
@ -98,6 +98,14 @@ define [
|
|||
|
||||
equal nameValue, 'copy[all_assignments]', 'Adds the correct name attribute from property'
|
||||
|
||||
QUnit.module "#getIconClass",
|
||||
teardown: -> CheckboxHelper.teardown()
|
||||
|
||||
test 'returns lti icon class for tool profiles', ->
|
||||
CheckboxHelper.renderView()
|
||||
CheckboxHelper.checkboxView.model.set(type: 'tool_profiles')
|
||||
equal CheckboxHelper.checkboxView.getIconClass(), 'icon-lti'
|
||||
|
||||
QUnit.module "Sublevel Content Checkbox and Carrot Behaviors",
|
||||
setup: ->
|
||||
fakeENV.setup()
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"registration_url": "https://www.samplelaunch.com/register"
|
||||
},
|
||||
"resource_href": "href",
|
||||
"migration_id": "m_id",
|
||||
"tool_profile": {
|
||||
"lti_version": "LTI-2p0",
|
||||
"product_instance": {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"registration_url": "https://www.samplelaunch.com/register"
|
||||
},
|
||||
"resource_href": "href",
|
||||
"migration_id": "m_id",
|
||||
"tool_profile": {
|
||||
"lti_version": "LTI-2p0",
|
||||
"product_instance": {
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper.rb')
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../../../spec_helper.rb')
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../../../../lti2_course_spec_helper')
|
||||
|
||||
describe Canvas::Migration::Helpers::SelectiveContentFormatter do
|
||||
context "overview json data" do
|
||||
|
@ -26,6 +27,7 @@ describe Canvas::Migration::Helpers::SelectiveContentFormatter do
|
|||
'modules' => [{'title' => 'a1', 'migration_id' => 'a1'}],
|
||||
'wikis' => [{'title' => 'a1', 'migration_id' => 'a1'}],
|
||||
'external_tools' => [{'title' => 'a1', 'migration_id' => 'a1'}],
|
||||
'tool_profiles' => [{'title' => 'a1', 'migration_id' => 'a1'}],
|
||||
'outcomes' => [{'title' => 'a1', 'migration_id' => 'a1'}],
|
||||
'file_map' => {'oi' => {'title' => 'a1', 'migration_id' => 'a1'}},
|
||||
'assignments' => [{'title' => 'a1', 'migration_id' => 'a1'},{'title' => 'a2', 'migration_id' => 'a2', 'assignment_group_migration_id' => 'a1'}],
|
||||
|
@ -56,6 +58,7 @@ describe Canvas::Migration::Helpers::SelectiveContentFormatter do
|
|||
{:type=>"quizzes", :property=>"copy[all_quizzes]", :title=>"Quizzes", :count=>1, :sub_items_url=>"https://example.com?type=quizzes"},
|
||||
{:type=>"wiki_pages", :property=>"copy[all_wiki_pages]", :title=>"Wiki Pages", :count=>1, :sub_items_url=>"https://example.com?type=wiki_pages"},
|
||||
{:type=>"context_external_tools", :property=>"copy[all_context_external_tools]", :title=>"External Tools", :count=>1, :sub_items_url=>"https://example.com?type=context_external_tools"},
|
||||
{:type=>"tool_profiles", :property=>"copy[all_tool_profiles]", :title=>"Tool Profiles", :count=>1, :sub_items_url=>"https://example.com?type=tool_profiles"},
|
||||
{:type=>"learning_outcomes", :property=>"copy[all_learning_outcomes]", :title=>"Learning Outcomes", :count=>1},
|
||||
{:type=>"attachments", :property=>"copy[all_attachments]", :title=>"Files", :count=>1, :sub_items_url=>"https://example.com?type=attachments"}]
|
||||
end
|
||||
|
@ -171,10 +174,13 @@ describe Canvas::Migration::Helpers::SelectiveContentFormatter do
|
|||
end
|
||||
|
||||
context "course copy" do
|
||||
include_context "lti2_course_spec_helper"
|
||||
let(:formatter) { Canvas::Migration::Helpers::SelectiveContentFormatter.new(@migration) }
|
||||
|
||||
before do
|
||||
course_model
|
||||
tool_proxy.context = @course
|
||||
tool_proxy.save!
|
||||
@topic = @course.discussion_topics.create!(:message => "hi", :title => "discussion title")
|
||||
@cm = @course.context_modules.create!(:name => "some module")
|
||||
attachment_model(:context => @course, :filename => 'a5.html')
|
||||
|
@ -191,9 +197,10 @@ describe Canvas::Migration::Helpers::SelectiveContentFormatter do
|
|||
|
||||
it "should list top-level items" do
|
||||
#groups should not show up even though there are some
|
||||
expect(formatter.get_content_list).to eq [{:type=>"course_settings", :property=>"copy[all_course_settings]", :title=>"Course Settings"},
|
||||
expect(formatter.get_content_list).to match_array [{:type=>"course_settings", :property=>"copy[all_course_settings]", :title=>"Course Settings"},
|
||||
{:type=>"syllabus_body", :property=>"copy[all_syllabus_body]", :title=>"Syllabus Body"},
|
||||
{:type=>"context_modules", :property=>"copy[all_context_modules]", :title=>"Modules", :count=>1},
|
||||
{:type=>"tool_profiles", :property=>"copy[all_tool_profiles]", :title=>"Tool Profiles", :count=>1},
|
||||
{:type=>"discussion_topics", :property=>"copy[all_discussion_topics]", :title=>"Discussion Topics", :count=>1},
|
||||
{:type=>"wiki_pages", :property=>"copy[all_wiki_pages]", :title=>"Wiki Pages", :count=>1},
|
||||
{:type=>"announcements", :property=>"copy[all_announcements]", :title=>"Announcements", :count=>1},
|
||||
|
@ -236,6 +243,7 @@ describe Canvas::Migration::Helpers::SelectiveContentFormatter do
|
|||
@topic.destroy
|
||||
@course_outcome.destroy
|
||||
@account_outcome.destroy
|
||||
tool_proxy.destroy
|
||||
|
||||
@course.require_assignment_group
|
||||
@course.assignments.create!.destroy
|
|
@ -0,0 +1,78 @@
|
|||
#
|
||||
# Copyright (C) 2017 - present 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')
|
||||
|
||||
describe Canvas::Migration::MigratorHelper do
|
||||
subject do
|
||||
Class.new do
|
||||
include Canvas::Migration::MigratorHelper
|
||||
attr_accessor :course
|
||||
end
|
||||
end
|
||||
|
||||
describe "#overview" do
|
||||
context "tool profiles" do
|
||||
let(:course) do
|
||||
{
|
||||
tool_profiles: [
|
||||
{
|
||||
'tool_profile' => {
|
||||
'product_instance' => {
|
||||
'product_info' => {
|
||||
'product_name' => {
|
||||
'default_value' => 'Test Tool'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'migration_id' => 'm_id'
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns nothing if there are no tool_profiles' do
|
||||
helper = subject.new
|
||||
helper.course = {}
|
||||
helper.overview()
|
||||
expect(helper.overview[:tool_profiles]).to be_nil
|
||||
end
|
||||
|
||||
it 'returns a tool profile overview if there is a tool_profile' do
|
||||
helper = subject.new
|
||||
helper.course = course
|
||||
helper.overview()
|
||||
expect(helper.overview[:tool_profiles]).to match_array [
|
||||
{
|
||||
title: 'Test Tool',
|
||||
migration_id: 'm_id'
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
it 'returns nothing if the tool_profile data is misconfigured' do
|
||||
helper = subject.new
|
||||
course[:tool_profiles].first['tool_profile']['product_instance'] = {}
|
||||
helper.course = course
|
||||
helper.overview()
|
||||
expect(helper.overview[:tool_profiles]).to match_array []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -125,6 +125,7 @@ describe CC::Importer::Canvas::ToolProfileConverter do
|
|||
"meta" => {
|
||||
"registration_url" => "https://register.me/register"
|
||||
},
|
||||
"migration_id" => "i964fd8107ac2c2e75e9a142971693976",
|
||||
"resource_href" => "i964fd8107ac2c2e75e9a142971693976.json"
|
||||
})
|
||||
end
|
||||
|
|
|
@ -64,11 +64,18 @@ describe Importers::ToolProfileImporter do
|
|||
let(:data) { get_import_data('', 'nonmatching_tool_profiles') }
|
||||
let(:migration) { double(context: course) }
|
||||
|
||||
it 'does nothing' do
|
||||
it 'adds a warning to the migration about finding a different version' do
|
||||
tool_proxy # necessary to instantiate tool_proxy
|
||||
allow(migration).to receive(:import_object?).with(any_args).and_return(true)
|
||||
expect(migration).to receive(:add_warning).with("We found a different version of \"learn abc's\" installed for your course. If this tool fails to work as intended, try reregistering or reinstalling it.")
|
||||
Importers::ToolProfileImporter.process_migration(data, migration)
|
||||
end
|
||||
|
||||
it 'does nothing' do
|
||||
tool_proxy # necessary to instantiate tool_proxy
|
||||
allow(migration).to receive(:import_object?).with(any_args).and_return(false)
|
||||
expect { Importers::ToolProfileImporter.process_migration(data, migration) }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
context 'with tool profile and matching tool proxies' do
|
||||
|
@ -79,6 +86,7 @@ describe Importers::ToolProfileImporter do
|
|||
|
||||
it 'does nothing' do
|
||||
tool_proxy # necessary to instantiate tool_proxy
|
||||
allow(migration).to receive(:import_object?).with(any_args).and_return(true)
|
||||
expect { Importers::ToolProfileImporter.process_migration(data, migration) }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue