export/import question banks
refs #3396 Change-Id: I4199264bf07e145be2b3949bc4a56a37cda715b7 Reviewed-on: https://gerrit.instructure.com/3223 Tested-by: Hudson <hudson@instructure.com> Reviewed-by: Zach Wily <zach@instructure.com>
This commit is contained in:
parent
090eaf6d96
commit
31374465fe
|
@ -391,7 +391,7 @@ class AssessmentQuestion < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.process_migration(data, migration)
|
||||
question_data = {}
|
||||
question_data = {:aq_data=>{}, :qq_data=>{}}
|
||||
questions = data['assessment_questions'] ? data['assessment_questions']['assessment_questions'] : []
|
||||
questions ||= []
|
||||
to_import = migration.to_import 'quizzes'
|
||||
|
@ -425,6 +425,10 @@ class AssessmentQuestion < ActiveRecord::Base
|
|||
|
||||
banks = {}
|
||||
questions.each do |question|
|
||||
if question[:assessment_question_migration_id]
|
||||
question_data[:qq_data][question['migration_id']] = question
|
||||
next
|
||||
end
|
||||
question[:question_bank_name] = nil if question[:question_bank_name] == ''
|
||||
question[:question_bank_name] ||= bank_map[question[:migration_id]]
|
||||
question[:question_bank_name] ||= migration.question_bank_name
|
||||
|
@ -441,7 +445,7 @@ class AssessmentQuestion < ActiveRecord::Base
|
|||
end
|
||||
|
||||
question = AssessmentQuestion.import_from_migration(question, migration.context, banks[hash_id])
|
||||
question_data[question['migration_id']] = question
|
||||
question_data[:aq_data][question['migration_id']] = question
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -461,8 +465,7 @@ class AssessmentQuestion < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
context.imported_migration_items << bank if context.imported_migration_items && !context.imported_migration_items.include?(bank)
|
||||
hash[:question_text] = ImportedHtmlConverter.convert(hash[:question_text], context, true) if hash[:question_text]
|
||||
hash[:answers].each{ |answer| answer[:html] = ImportedHtmlConverter.convert(answer[:html], context, true) unless answer[:html].blank? } if hash[:answers]
|
||||
prep_for_import(hash, context)
|
||||
question_data = ActiveRecord::Base.connection.quote hash.to_yaml
|
||||
question_name = ActiveRecord::Base.connection.quote hash[:question_name]
|
||||
query = "INSERT INTO assessment_questions (name, question_data, context_id, context_type, workflow_state, created_at, updated_at, assessment_question_bank_id, migration_id)"
|
||||
|
@ -472,6 +475,11 @@ class AssessmentQuestion < ActiveRecord::Base
|
|||
hash
|
||||
end
|
||||
|
||||
def self.prep_for_import(hash, context)
|
||||
hash[:question_text] = ImportedHtmlConverter.convert(hash[:question_text], context, true) if hash[:question_text]
|
||||
hash[:answers].each{ |answer| answer[:html] = ImportedHtmlConverter.convert(answer[:html], context, true) unless answer[:html].blank? } if hash[:answers]
|
||||
end
|
||||
|
||||
named_scope :active, lambda {
|
||||
{:conditions => ['assessment_questions.workflow_state != ?', 'deleted'] }
|
||||
}
|
||||
|
|
|
@ -1129,11 +1129,20 @@ class Quiz < ActiveRecord::Base
|
|||
hash[:questions].each do |question|
|
||||
case question[:question_type]
|
||||
when "question_reference"
|
||||
if aq = question_data[question[:migration_id]]
|
||||
if qq = question_data[:qq_data][question[:migration_id]]
|
||||
if qq[:assessment_question_migration_id]
|
||||
if aq = question_data[:aq_data][qq[:assessment_question_migration_id]]
|
||||
qq['assessment_question_id'] = aq['assessment_question_id']
|
||||
AssessmentQuestion.prep_for_import(qq, context)
|
||||
QuizQuestion.import_from_migration(qq, context, item)
|
||||
else
|
||||
AssessmentQuestion.import_from_migration(qq, context)
|
||||
QuizQuestion.import_from_migration(qq, context, item)
|
||||
end
|
||||
end
|
||||
elsif aq = question_data[:aq_data][question[:migration_id]]
|
||||
aq[:points_possible] = question[:points_possible] if question[:points_possible]
|
||||
QuizQuestion.import_from_migration(aq, context, item)
|
||||
else
|
||||
#TODO: no assessment question was imported for this question...
|
||||
end
|
||||
when "question_group"
|
||||
QuizGroup.import_from_migration(question, context, item, question_data)
|
||||
|
|
|
@ -83,10 +83,20 @@ class QuizGroup < ActiveRecord::Base
|
|||
end
|
||||
item.save!
|
||||
hash[:questions].each do |question|
|
||||
if aq = question_data[question[:migration_id]]
|
||||
if qq = question_data[:qq_data][question[:migration_id]]
|
||||
if qq[:assessment_question_migration_id]
|
||||
if aq = question_data[:aq_data][qq[:assessment_question_migration_id]]
|
||||
qq['assessment_question_id'] = aq['assessment_question_id']
|
||||
AssessmentQuestion.prep_for_import(qq, context)
|
||||
QuizQuestion.import_from_migration(qq, context, quiz, item)
|
||||
else
|
||||
AssessmentQuestion.import_from_migration(qq, context)
|
||||
QuizQuestion.import_from_migration(qq, context, quiz, item)
|
||||
end
|
||||
end
|
||||
elsif aq = question_data[:aq_data][question[:migration_id]]
|
||||
aq[:points_possible] = question[:points_possible] if question[:points_possible]
|
||||
QuizQuestion.import_from_migration(aq, context, quiz, item)
|
||||
else
|
||||
#TODO: no assessment question was imported for this question...
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -127,7 +127,10 @@ class QuizQuestion < ActiveRecord::Base
|
|||
def self.import_from_migration(hash, context, quiz=nil, quiz_group=nil)
|
||||
question_data = ActiveRecord::Base.connection.quote hash.to_yaml
|
||||
query = "INSERT INTO quiz_questions (quiz_id, quiz_group_id, assessment_question_id, question_data, created_at, updated_at, migration_id)"
|
||||
query += " VALUES (#{quiz ? quiz.id : 'NULL'}, #{quiz_group ? quiz_group.id : 'NULL'}, #{hash['assessment_question_id']},#{question_data},'#{Time.now.to_s(:db)}', '#{Time.now.to_s(:db)}', '#{hash[:migration_id]}')"
|
||||
aq_id = hash['assessment_question_id'] ? hash['assessment_question_id'] : 'NULL'
|
||||
g_id = quiz_group ? quiz_group.id : 'NULL'
|
||||
q_id = quiz ? quiz.id : 'NULL'
|
||||
query += " VALUES (#{q_id}, #{g_id}, #{aq_id},#{question_data},'#{Time.now.to_s(:db)}', '#{Time.now.to_s(:db)}', '#{hash[:migration_id]}')"
|
||||
id = ActiveRecord::Base.connection.insert(query)
|
||||
hash[:quiz_question_id] = id
|
||||
hash
|
||||
|
|
|
@ -41,6 +41,17 @@ module CC
|
|||
non_cc_folder = File.join(@export_dir, ASSESSMENT_NON_CC_FOLDER)
|
||||
FileUtils::mkdir_p non_cc_folder
|
||||
|
||||
@course.assessment_question_banks.active.each do |bank|
|
||||
bank_mig_id = create_key(bank)
|
||||
|
||||
rel_path = File.join(ASSESSMENT_NON_CC_FOLDER, bank_mig_id + ".xml")
|
||||
full_path = File.join(@export_dir, rel_path)
|
||||
File.open(full_path, 'w') do |file|
|
||||
doc = Builder::XmlMarkup.new(:target=>file, :indent=>2)
|
||||
generate_bank(doc, bank, bank_mig_id)
|
||||
end
|
||||
end
|
||||
|
||||
@course.quizzes.active.each do |quiz|
|
||||
cc_qti_migration_id = create_key(quiz)
|
||||
resource_dir = File.join(@export_dir, cc_qti_migration_id)
|
||||
|
@ -160,7 +171,7 @@ module CC
|
|||
if for_cc
|
||||
add_cc_question(section_node, item)
|
||||
else
|
||||
add_question(section_node, item)
|
||||
add_quiz_question(section_node, item)
|
||||
end
|
||||
elsif item[:questions] # It's a QuizGroup
|
||||
if for_cc
|
||||
|
@ -175,6 +186,28 @@ module CC
|
|||
end # qti node
|
||||
end
|
||||
|
||||
def generate_bank(doc, bank, migration_id)
|
||||
doc.instruct!
|
||||
doc.questestinterop("xmlns" => "http://www.imsglobal.org/xsd/ims_qtiasiv1p2",
|
||||
"xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
|
||||
"xsi:schemaLocation"=> "http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd"
|
||||
) do |qti_node|
|
||||
qti_node.objectbank(
|
||||
:ident => migration_id
|
||||
) do |bank_node|
|
||||
|
||||
bank_node.qtimetadata do |meta_node|
|
||||
meta_field(meta_node, 'bank_title', bank.title)
|
||||
end # meta_node
|
||||
|
||||
bank.assessment_questions.each do |aq|
|
||||
add_question(bank_node, aq.data.with_indifferent_access)
|
||||
end
|
||||
|
||||
end # bank_node
|
||||
end # qti node
|
||||
end
|
||||
|
||||
def meta_field(node, label, entry)
|
||||
node.qtimetadatafield do |meta_node|
|
||||
meta_node.fieldlabel label
|
||||
|
@ -228,7 +261,7 @@ module CC
|
|||
|
||||
unless group[:assessment_question_bank_id]
|
||||
group[:questions].each do |question|
|
||||
add_question(section_node, question)
|
||||
add_quiz_question(section_node, question)
|
||||
end
|
||||
end
|
||||
end # section node
|
||||
|
|
|
@ -38,6 +38,28 @@ module CC
|
|||
MULTI_ANSWER_TYPES = ['matching_question',
|
||||
'multiple_dropdowns_question',
|
||||
'fill_in_multiple_blanks_question']
|
||||
|
||||
def add_ref_or_question(node, question)
|
||||
aq = nil
|
||||
unless question[:assessment_question_id].blank?
|
||||
if aq = AssessmentQuestion.find_by_id(question[:assessment_question_id])
|
||||
if aq.deleted? ||
|
||||
!aq.assessment_question_bank ||
|
||||
aq.assessment_question_bank.deleted? ||
|
||||
aq.assessment_question_bank.context_id != @course.id ||
|
||||
aq.assessment_question_bank.context_type != @course.class.to_s
|
||||
aq = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if aq
|
||||
ref = CC::CCHelper::create_key(aq)
|
||||
node.itemref(:linkrefid => ref)
|
||||
else
|
||||
add_question(node, question)
|
||||
end
|
||||
end
|
||||
|
||||
# if the question is a supported CC type it will be added
|
||||
# it it's not supported it's just skipped
|
||||
|
@ -48,8 +70,16 @@ module CC
|
|||
true
|
||||
end
|
||||
|
||||
def add_quiz_question(node, question)
|
||||
question[:is_quiz_question] = true
|
||||
add_question(node, question)
|
||||
end
|
||||
|
||||
def add_question(node, question, for_cc=false)
|
||||
question['migration_id'] = create_key("assessment_question_#{question['assessment_question_id']}")
|
||||
aq_mig_id = create_key("assessment_question_#{question['assessment_question_id']}")
|
||||
qq_mig_id = create_key("assessment_question_#{question['id']}")
|
||||
question['migration_id'] = question[:is_quiz_question] ? qq_mig_id : aq_mig_id
|
||||
|
||||
if question['question_type'] == 'missing_word_question'
|
||||
change_missing_word(question)
|
||||
end
|
||||
|
@ -67,6 +97,9 @@ module CC
|
|||
else
|
||||
meta_field(qm_node, 'question_type', question['question_type'])
|
||||
meta_field(qm_node, 'points_possible', question['points_possible'])
|
||||
if question[:is_quiz_question]
|
||||
meta_field(qm_node, 'assessment_question_identifierref', aq_mig_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end # meta data
|
||||
|
|
|
@ -50,12 +50,12 @@ def get_import_data(sub_folder, hash_name)
|
|||
end
|
||||
|
||||
def import_example_questions(context)
|
||||
question_data = {}
|
||||
question_data = {:aq_data=>{}, :qq_data=>{}}
|
||||
QUESTIONS.each do |question|
|
||||
if import_data_exists?(['vista', 'quiz'], question[0])
|
||||
q = get_import_data ['vista', 'quiz'], question[0]
|
||||
q = AssessmentQuestion.import_from_migration(q, context)
|
||||
question_data[q['migration_id']] = q
|
||||
question_data[:aq_data][q['migration_id']] = q
|
||||
end
|
||||
end
|
||||
question_data
|
||||
|
|
|
@ -85,42 +85,47 @@ class AssessmentItemConverter
|
|||
end
|
||||
|
||||
def parse_instructure_metadata
|
||||
if bank = get_node_att(@doc, 'instructureMetadata instructureField[name=question_bank]', 'value')
|
||||
@question[:question_bank_name] = bank
|
||||
end
|
||||
if bank = get_node_att(@doc, 'instructureMetadata instructureField[name=question_bank_iden]', 'value')
|
||||
@question[:question_bank_id] = bank
|
||||
end
|
||||
if score = get_node_att(@doc, 'instructureMetadata instructureField[name=max_score]', 'value')
|
||||
@question[:points_possible] = score.to_f
|
||||
end
|
||||
if score = get_node_att(@doc, 'instructureMetadata instructureField[name=points_possible]', 'value')
|
||||
@question[:points_possible] = score.to_f
|
||||
end
|
||||
if type = get_node_att(@doc, 'instructureMetadata instructureField[name=bb_question_type]', 'value')
|
||||
@migration_type = type
|
||||
case @migration_type
|
||||
when 'True/False'
|
||||
@question[:question_type] = 'true_false_question'
|
||||
when 'Short Response'
|
||||
@question[:question_type] = 'essay_question'
|
||||
when 'Fill in the Blank Plus'
|
||||
@question[:question_type] = 'fill_in_multiple_blanks_question'
|
||||
when 'WCT_FillInTheBlank'
|
||||
@question[:question_type] = 'fill_in_multiple_blanks_question'
|
||||
@question[:is_vista_fib] = true
|
||||
when 'Jumbled Sentence'
|
||||
@question[:question_type] = 'multiple_dropdowns_question'
|
||||
when 'Essay'
|
||||
@question[:question_type] = 'essay_question'
|
||||
if meta = @doc.at_css('instructureMetadata')
|
||||
if bank = get_node_att(meta, 'instructureField[name=question_bank]', 'value')
|
||||
@question[:question_bank_name] = bank
|
||||
end
|
||||
end
|
||||
if type = get_node_att(@doc, 'instructureMetadata instructureField[name=question_type]', 'value')
|
||||
@migration_type = type
|
||||
if AssessmentQuestion::ALL_QUESTION_TYPES.member?(@migration_type)
|
||||
@question[:question_type] = @migration_type
|
||||
elsif @migration_type =~ /matching/i
|
||||
@question[:question_type] = 'matching_question'
|
||||
if bank = get_node_att(meta, 'instructureField[name=question_bank_iden]', 'value')
|
||||
@question[:question_bank_id] = bank
|
||||
end
|
||||
if score = get_node_att(meta, 'instructureField[name=max_score]', 'value')
|
||||
@question[:points_possible] = score.to_f
|
||||
end
|
||||
if score = get_node_att(meta, 'instructureField[name=points_possible]', 'value')
|
||||
@question[:points_possible] = score.to_f
|
||||
end
|
||||
if ref = get_node_att(meta, 'instructureField[name=assessment_question_identifierref]', 'value')
|
||||
@question[:assessment_question_migration_id] = ref
|
||||
end
|
||||
if type = get_node_att(meta, 'instructureField[name=bb_question_type]', 'value')
|
||||
@migration_type = type
|
||||
case @migration_type
|
||||
when 'True/False'
|
||||
@question[:question_type] = 'true_false_question'
|
||||
when 'Short Response'
|
||||
@question[:question_type] = 'essay_question'
|
||||
when 'Fill in the Blank Plus'
|
||||
@question[:question_type] = 'fill_in_multiple_blanks_question'
|
||||
when 'WCT_FillInTheBlank'
|
||||
@question[:question_type] = 'fill_in_multiple_blanks_question'
|
||||
@question[:is_vista_fib] = true
|
||||
when 'Jumbled Sentence'
|
||||
@question[:question_type] = 'multiple_dropdowns_question'
|
||||
when 'Essay'
|
||||
@question[:question_type] = 'essay_question'
|
||||
end
|
||||
end
|
||||
if type = get_node_att(meta, 'instructureField[name=question_type]', 'value')
|
||||
@migration_type = type
|
||||
if AssessmentQuestion::ALL_QUESTION_TYPES.member?(@migration_type)
|
||||
@question[:question_type] = @migration_type
|
||||
elsif @migration_type =~ /matching/i
|
||||
@question[:question_type] = 'matching_question'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,13 +19,14 @@ Unknown text type: ignored mattext with texttype="text" treated as text/plain
|
|||
<assessmentItem
|
||||
xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/imsqti_v2p1.xsd" identifier="i7ee7c77592c6cd4ac58509c3e41dace8"
|
||||
xsi:schemaLocation="http://www.imsglobal.org/xsd/imsqti_v2p1 http://www.imsglobal.org/xsd/imsqti_v2p1.xsd" identifier="i27a2844e09afc2eb6e4a6bf0599bf010"
|
||||
title="Match"
|
||||
adaptive="false"
|
||||
timeDependent="false">
|
||||
<instructureMetadata>
|
||||
<instructureField name="points_possible" value="1" />
|
||||
<instructureField name="question_type" value="matching_question" />
|
||||
<instructureField name="assessment_question_identifierref" value="i7ee7c77592c6cd4ac58509c3e41dace8" />
|
||||
</instructureMetadata>
|
||||
<responseDeclaration identifier="response_1971" cardinality="single" baseType="identifier"/>
|
||||
<responseDeclaration identifier="response_338" cardinality="single" baseType="identifier"/>
|
||||
|
|
|
@ -208,7 +208,8 @@ module CanvasExpected
|
|||
:match_id=>2840,
|
||||
:text=>"4"}],
|
||||
:question_text=>"Make it stop! Please!",
|
||||
:migration_id=>"i7ee7c77592c6cd4ac58509c3e41dace8",
|
||||
:migration_id=>"i27a2844e09afc2eb6e4a6bf0599bf010",
|
||||
:assessment_question_migration_id=>"i7ee7c77592c6cd4ac58509c3e41dace8",
|
||||
:question_type=>"matching_question",
|
||||
:incorrect_comments=>"How could you get this wrong?"}
|
||||
|
||||
|
|
Loading…
Reference in New Issue