exclude grading schemes/assignment groups in selective assignment export

test plan:
 0. have a course containing an assignment with a custom grading scheme
    and named assignment group. also a graded discussion topic in a
    different assignment group with a different grading scheme, and
    a published quiz in a third assignment group.
 1. copy the course. the destination course should copy the assignment
    groups and grading schemes and associate them with the copied objects
    correctly.
 2. repeat step 1, but do a selective course copy, and select the
    assignment, quiz, and topic specifically. you should get the
    same result as in step 1.
 3. use the content exports API to selectively export the three objects
    e.g.,
      select[assignments][]=X&select[quizzes][]=Y&select[discussion_topics][]=Z
    import this package into a new course. the three objects should be
    there, but should not have custom assignment groups or grading
    schemes.

fixes CNVS-14820

Change-Id: I871771284b4a3bbd3695a99a6f2af613d76a8ebf
Reviewed-on: https://gerrit.instructure.com/39914
Tested-by: Jenkins <jenkins@instructure.com>
QA-Review: Clare Strong <clare@instructure.com>
Reviewed-by: James Williams  <jamesw@instructure.com>
Product-Review: Jeremy Stanley <jeremy@instructure.com>
This commit is contained in:
Jeremy Stanley 2014-08-25 10:49:53 -06:00
parent 4792a97aff
commit d518b6f131
9 changed files with 175 additions and 33 deletions

View File

@ -36,7 +36,12 @@ module CC
"xsi:schemaLocation"=> "#{CCHelper::CANVAS_NAMESPACE} #{CCHelper::XSD_URI}"
) do |groups_node|
@course.assignment_groups.active.each do |group|
next unless export_object?(group) || group.assignments.any?{|a| export_object?(a)}
add_item_to_export(group) if for_course_copy && !export_object?(group) && group.assignments.any? do |a|
export_object?(a) ||
a.quiz && export_object?(a.quiz) ||
a.discussion_topic && export_object?(a.discussion_topic)
end
next unless export_object?(group)
migration_id = CCHelper.create_key(group)
groups_node.assignmentGroup(:identifier=>migration_id) do |group_node|
group_node.title group.name

View File

@ -73,7 +73,7 @@ module CC
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation"=> "#{CCHelper::ASSIGNMENT_NAMESPACE} #{CCHelper::ASSIGNMENT_XSD_URI}"
) do |a|
AssignmentResources.create_cc_assignment(a, assignment, migration_id)
AssignmentResources.create_cc_assignment(a, assignment, migration_id, @manifest)
end
end
@ -108,7 +108,7 @@ module CC
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation"=> "#{CCHelper::CANVAS_NAMESPACE} #{CCHelper::XSD_URI}"
) do |a|
AssignmentResources.create_canvas_assignment(a, assignment)
AssignmentResources.create_canvas_assignment(a, assignment, @manifest)
end
assignment_file.close
@ -128,7 +128,7 @@ module CC
"online_upload" => "file"
}.freeze
def self.create_cc_assignment(node, assignment, migration_id)
def self.create_cc_assignment(node, assignment, migration_id, manifest = nil)
node.title(assignment.title)
node.text(assignment.description, texttype: 'text/html')
if assignment.points_possible
@ -149,20 +149,20 @@ module CC
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation"=> "#{CCHelper::CANVAS_NAMESPACE} #{CCHelper::XSD_URI}"
) do |a|
AssignmentResources.create_canvas_assignment(a, assignment)
AssignmentResources.create_canvas_assignment(a, assignment, manifest)
end
end
end
def self.create_canvas_assignment(node, assignment)
def self.create_canvas_assignment(node, assignment, manifest = nil)
node.title assignment.title
node.due_at CCHelper::ims_datetime(assignment.due_at) if assignment.due_at
node.lock_at CCHelper::ims_datetime(assignment.lock_at) if assignment.lock_at
node.unlock_at CCHelper::ims_datetime(assignment.unlock_at) if assignment.unlock_at
node.all_day_date CCHelper::ims_date(assignment.all_day_date) if assignment.all_day_date
node.peer_reviews_due_at CCHelper::ims_datetime(assignment.peer_reviews_due_at) if assignment.peer_reviews_due_at
node.assignment_group_identifierref CCHelper.create_key(assignment.assignment_group)
node.grading_standard_identifierref CCHelper.create_key(assignment.grading_standard) if assignment.grading_standard
node.assignment_group_identifierref CCHelper.create_key(assignment.assignment_group) if assignment.assignment_group && (!manifest || manifest.export_object?(assignment.assignment_group))
node.grading_standard_identifierref CCHelper.create_key(assignment.grading_standard) if assignment.grading_standard && (!manifest || manifest.export_object?(assignment.grading_standard))
node.workflow_state assignment.workflow_state
if assignment.rubric
assoc = assignment.rubric_association

View File

@ -19,14 +19,16 @@ module CC
module GradingStandards
def add_referenced_grading_standards
@course.assignments.active.where('grading_standard_id IS NOT NULL').each do |assignment|
next unless export_object?(assignment)
next unless export_object?(assignment) ||
assignment.quiz && export_object?(assignment.quiz) ||
assignment.discussion_topic && export_object?(assignment.discussion_topic)
gs = assignment.grading_standard
add_item_to_export(gs) if gs && gs.context_type == 'Course' && gs.context_id == @course.id
end
end
def create_grading_standards(document=nil)
add_referenced_grading_standards
add_referenced_grading_standards if for_course_copy
standards_to_copy = (@course.grading_standards.to_a + [@course.grading_standard]).compact.uniq(&:id).select{|s| export_object?(s)}
return nil unless standards_to_copy.size > 0

View File

@ -196,7 +196,7 @@ module CC
if quiz.assignment && !quiz.assignment.deleted?
assignment_migration_id = CCHelper.create_key(quiz.assignment)
doc.assignment(:identifier=>assignment_migration_id) do |a|
AssignmentResources.create_canvas_assignment(a, quiz.assignment)
AssignmentResources.create_canvas_assignment(a, quiz.assignment, @manifest)
end
end
if quiz.assignment_group_id

View File

@ -123,7 +123,7 @@ module CC
if topic.assignment && !topic.assignment.deleted?
assignment_migration_id = CCHelper.create_key(topic.assignment)
doc.assignment(:identifier=>assignment_migration_id) do |a|
AssignmentResources.create_canvas_assignment(a, topic.assignment)
AssignmentResources.create_canvas_assignment(a, topic.assignment, @manifest)
end
end
end

View File

@ -54,6 +54,29 @@ describe ContentMigration do
to_assign.assignment_group.should == @copy_to.assignment_groups.find_by_migration_id(mig_id(g))
end
it "should link assignments to assignment groups on complete export" do
g = @copy_from.assignment_groups.create!(:name => "group")
from_assign = @copy_from.assignments.create!(:title => "some assignment", :assignment_group_id => g.id)
run_export_and_import
to_assign = @copy_to.assignments.find_by_migration_id(mig_id(from_assign))
to_assign.assignment_group.should == @copy_to.assignment_groups.find_by_migration_id(mig_id(g))
end
it "should not link assignments to assignment groups on selective export" do
g = @copy_from.assignment_groups.create!(:name => "group")
from_assign = @copy_from.assignments.create!(:title => "some assignment", :assignment_group_id => g.id)
# test that we neither export nor reference the assignment group
unrelated_group = @copy_to.assignment_groups.create! name: 'unrelated group with coincidentally matching migration id'
unrelated_group.update_attribute :migration_id, mig_id(g)
run_export_and_import do |export|
export.selected_content = { 'assignments' => { mig_id(from_assign) => "1" } }
end
to_assign = @copy_to.assignments.find_by_migration_id(mig_id(from_assign))
to_assign.assignment_group.should_not == unrelated_group
unrelated_group.reload.name.should_not eql g.name
end
it "should copy assignment attributes" do
assignment_model(:course => @copy_from, :points_possible => 40, :submission_types => 'file_upload', :grading_type => 'points')
@assignment.turnitin_enabled = true
@ -313,6 +336,31 @@ describe ContentMigration do
@copy_to.grading_standards.map(&:title).should eql %w(Two)
@copy_to.assignments.first.grading_standard.title.should eql 'Two'
end
it "should copy referenced grading standards in complete export" do
gs = make_grading_standard(@copy_from, title: 'GS')
assign = @copy_from.assignments.build
assign.grading_standard = gs
assign.save!
run_export_and_import
@copy_to.assignments.first.grading_standard.title.should eql gs.title
end
it "should not copy referenced grading standards in selective export" do
gs = make_grading_standard(@copy_from, title: 'One')
assign = @copy_from.assignments.build
assign.grading_standard = gs
assign.save!
# test that we neither export nor reference the grading standard
unrelated_grading_standard = make_grading_standard(@copy_to, title: 'unrelated grading standard with coincidentally matching migration id')
unrelated_grading_standard.update_attribute :migration_id, mig_id(gs)
run_export_and_import do |export|
export.selected_content = { 'assignments' => { mig_id(assign) => "1" } }
end
@copy_to.assignments.count.should eql 1
@copy_to.assignments.first.grading_standard.should be_nil
unrelated_grading_standard.reload.title.should_not eql gs.title
end
end
end
end

View File

@ -4,6 +4,15 @@ describe ContentMigration do
context "course copy discussions" do
include_examples "course copy"
def graded_discussion_topic
@topic = @copy_from.discussion_topics.build(:title => "topic")
@assignment = @copy_from.assignments.build(:submission_types => 'discussion_topic', :title => @topic.title)
@assignment.infer_times
@assignment.saved_by = :discussion_topic
@topic.assignment = @assignment
@topic.save
end
it "should copy discussion topic attributes" do
topic = @copy_from.discussion_topics.create!(:title => "topic", :message => "<p>bloop</p>",
:pinned => true, :discussion_type => "threaded",
@ -25,25 +34,20 @@ describe ContentMigration do
end
it "should copy a discussion topic when assignment is selected" do
topic = @copy_from.discussion_topics.build(:title => "topic")
assignment = @copy_from.assignments.build(:submission_types => 'discussion_topic', :title => topic.title)
assignment.infer_times
assignment.saved_by = :discussion_topic
topic.assignment = assignment
topic.save
graded_discussion_topic
# Should not fail if the destination has a group
@copy_to.groups.create!(:name => 'some random group of people')
@cm.copy_options = {
:assignments => {mig_id(assignment) => "1"},
:discussion_topics => {mig_id(topic) => "0"},
:assignments => {mig_id(@assignment) => "1"},
:discussion_topics => {mig_id(@topic) => "0"},
}
@cm.save!
run_course_copy
@copy_to.discussion_topics.find_by_migration_id(mig_id(topic)).should_not be_nil
@copy_to.discussion_topics.find_by_migration_id(mig_id(@topic)).should_not be_nil
end
it "should properly copy selected delayed announcements" do
@ -74,22 +78,56 @@ describe ContentMigration do
end
it "should not copy deleted assignment attached to topic" do
topic = @copy_from.discussion_topics.build(:title => "topic")
assignment = @copy_from.assignments.build(:submission_types => 'discussion_topic', :title => topic.title)
assignment.infer_times
assignment.saved_by = :discussion_topic
topic.assignment = assignment
topic.save!
assignment.workflow_state = 'deleted'
assignment.save!
graded_discussion_topic
@assignment.workflow_state = 'deleted'
@assignment.save!
topic.reload
topic.active?.should == true
@topic.reload
@topic.active?.should == true
run_course_copy
@copy_to.discussion_topics.find_by_migration_id(mig_id(topic)).should_not be_nil
@copy_to.assignments.find_by_migration_id(mig_id(assignment)).should be_nil
@copy_to.discussion_topics.find_by_migration_id(mig_id(@topic)).should_not be_nil
@copy_to.assignments.find_by_migration_id(mig_id(@assignment)).should be_nil
end
it "should copy the assignment group and grading standard in selective copy" do
graded_discussion_topic
gs = make_grading_standard(@copy_from, title: 'One')
group = @copy_from.assignment_groups.create!(:name => "new group")
@assignment.assignment_group = group
@assignment.grading_standard = gs
@assignment.save!
@cm.copy_options = { 'everything' => '0', 'discussion_topics' => { mig_id(@topic) => "1" } }
run_course_copy
new_topic = @copy_to.discussion_topics.find_by_migration_id(mig_id(@topic))
new_topic.assignment.should be_present
new_topic.assignment.assignment_group.migration_id.should eql mig_id(group)
new_topic.assignment.grading_standard.migration_id.should eql mig_id(gs)
end
it "should not copy the assignment group and grading standard in selective export" do
graded_discussion_topic
gs = make_grading_standard(@copy_from, title: 'One')
group = @copy_from.assignment_groups.create!(:name => "new group")
@assignment.assignment_group = group
@assignment.grading_standard = gs
@assignment.save!
# test that we neither export nor reference the grading standard and assignment group
decoy_gs = make_grading_standard(@copy_to, title: 'decoy')
decoy_gs.update_attribute :migration_id, mig_id(gs)
decoy_ag = @copy_to.assignment_groups.create! name: 'decoy'
decoy_ag.update_attribute :migration_id, mig_id(group)
run_export_and_import do |export|
export.selected_content = { 'discussion_topics' => { mig_id(@topic) => "1" } }
end
new_topic = @copy_to.discussion_topics.find_by_migration_id(mig_id(@topic))
new_topic.assignment.should be_present
new_topic.assignment.grading_standard.should be_nil
new_topic.assignment.assignment_group.migration_id.should_not eql mig_id(@group)
decoy_gs.reload.title.should_not eql gs.title
decoy_ag.reload.name.should_not eql group.name
end
end
end

View File

@ -33,6 +33,26 @@ shared_examples_for "course copy" do
@copy_to.reload
end
def run_export_and_import
export = @copy_from.content_exports.build
export.export_type = ContentExport::COMMON_CARTRIDGE
export.user = @teacher
yield(export) if block_given?
export.save
export.export_course
export.workflow_state.should == 'exported'
export.attachment_id.should_not be_nil
@cm.set_default_settings
@cm.migration_type = 'canvas_cartridge_importer'
worker = Canvas::Migration::Worker::CCWorker.new
@cm.attachment_id = export.attachment_id
@cm.skip_job_progress = true
worker.perform(@cm)
@cm.workflow_state.should == 'imported'
@copy_to.reload
end
def make_grading_standard(context, opts = {})
gs = context.grading_standards.new
gs.title = opts[:title] || "Standard eh"

View File

@ -580,5 +580,34 @@ equation: <img class="equation_image" title="Log_216" src="/equation_images/Log_
qq2.assessment_question_id.should == aqb2.assessment_questions.first.id
qq2.question_data['points_possible'].should == qq.question_data['points_possible']
end
it "should copy the assignment group in selective copy" do
pending unless Qti.qti_enabled?
group = @copy_from.assignment_groups.create!(:name => "new group")
quiz = @copy_from.quizzes.create(:title => "asmnt", :quiz_type => "assignment", :assignment_group_id => group.id)
quiz.publish!
@cm.copy_options = { 'everything' => '0', 'quizzes' => { mig_id(quiz) => "1" } }
run_course_copy
dest_quiz = @copy_to.quizzes.find_by_migration_id mig_id(quiz)
dest_quiz.assignment_group.migration_id.should eql mig_id(group)
end
it "should not copy the assignment group in selective export" do
pending unless Qti.qti_enabled?
group = @copy_from.assignment_groups.create!(:name => "new group")
quiz = @copy_from.quizzes.create(:title => "asmnt", :quiz_type => "assignment", :assignment_group_id => group.id)
quiz.publish!
# test that we neither export nor reference the assignment group
decoy_assignment_group = @copy_to.assignment_groups.create!(:name => "decoy")
decoy_assignment_group.update_attribute(:migration_id, mig_id(group))
run_export_and_import do |export|
export.selected_content = { 'quizzes' => { mig_id(quiz) => "1" } }
end
dest_quiz = @copy_to.quizzes.find_by_migration_id mig_id(quiz)
dest_quiz.assignment_group.migration_id.should_not eql decoy_assignment_group
decoy_assignment_group.reload.name.should_not eql group.name
end
end
end