Add Quizzes2 content type behind FF

closes: QUIZ-1234

test plan:
1. tests pass
2. feature is hidden behind flag and is development only
3. qa-cr

Change-Id: I602f7c41ec88f13248910bae3523420c670f134e
Reviewed-on: https://gerrit.instructure.com/102053
Tested-by: Jenkins
Reviewed-by: John Corrigan <jcorrigan@instructure.com>
QA-Review: Michael Hargiss <mhargiss@instructure.com>
Product-Review: Chris Wang <cwang@instructure.com>
This commit is contained in:
Hannah Bottalla 2017-02-14 10:58:57 -07:00
parent 4d81882f9e
commit 1a64ef0d4c
4 changed files with 149 additions and 31 deletions

View File

@ -33,13 +33,14 @@ class ContentExport < ActiveRecord::Base
has_one :job_progress, :class_name => 'Progress', :as => :context, :inverse_of => :context
#export types
COMMON_CARTRIDGE = 'common_cartridge'
COURSE_COPY = 'course_copy'
MASTER_COURSE_COPY = 'master_course_copy'
QTI = 'qti'
USER_DATA = 'user_data'
ZIP = 'zip'
# export types
COMMON_CARTRIDGE = 'common_cartridge'.freeze
COURSE_COPY = 'course_copy'.freeze
MASTER_COURSE_COPY = 'master_course_copy'.freeze
QTI = 'qti'.freeze
USER_DATA = 'user_data'.freeze
ZIP = 'zip'.freeze
QUIZZES2 = 'quizzes2'.freeze
workflow do
state :created
@ -96,18 +97,39 @@ class ContentExport < ActiveRecord::Base
export_zip(opts)
when USER_DATA
export_user_data(opts)
when QUIZZES2
return unless root_account.feature_enabled?(:quizzes2_exporter)
export_quizzes2
else
export_course(opts)
end
end
handle_asynchronously :export, :priority => Delayed::LOW_PRIORITY, :max_attempts => 1
def export_course(opts={})
def reset_and_start_job_progress
self.job_progress.try :reset!
self.job_progress.try :start!
end
def mark_exporting
self.workflow_state = 'exporting'
self.save
end
def mark_exported
self.job_progress.try :complete!
self.workflow_state = 'exported'
end
def mark_failed
self.workflow_state = 'failed'
self.job_progress.try :fail!
end
def export_course(opts={})
mark_exporting
begin
self.job_progress.try :reset!
self.job_progress.try :start!
reset_and_start_job_progress
@cc_exporter = CC::CCExporter.new(self, opts.merge({:for_course_copy => for_course_copy?}))
if @cc_exporter.export
@ -119,13 +141,11 @@ class ContentExport < ActiveRecord::Base
self.workflow_state = 'exported'
end
else
self.workflow_state = 'failed'
self.job_progress.try :fail!
mark_failed
end
rescue
add_error("Error running course export.", $!)
self.workflow_state = 'failed'
self.job_progress.try :fail!
mark_failed
ensure
self.save
epub_export.try(:mark_exported) || true
@ -133,41 +153,53 @@ class ContentExport < ActiveRecord::Base
end
def export_user_data(opts)
self.workflow_state = 'exporting'
self.save
mark_exporting
begin
self.job_progress.try :start!
if exported_attachment = Exporters::UserDataExporter.create_user_data_export(self.context)
if (exported_attachment = Exporters::UserDataExporter.create_user_data_export(self.context))
self.attachment = exported_attachment
self.progress = 100
self.job_progress.try :complete!
self.workflow_state = 'exported'
mark_exported
end
rescue
add_error("Error running user_data export.", $!)
self.workflow_state = 'failed'
self.job_progress.try :fail!
mark_failed
ensure
self.save
end
end
def export_zip(opts={})
self.workflow_state = 'exporting'
self.save
mark_exporting
begin
self.job_progress.try :start!
if attachment = Exporters::ZipExporter.create_zip_export(self, opts)
if (attachment = Exporters::ZipExporter.create_zip_export(self, opts))
self.attachment = attachment
self.progress = 100
self.job_progress.try :complete!
self.workflow_state = 'exported'
mark_exported
end
rescue
add_error("Error running zip export.", $!)
self.workflow_state = 'failed'
self.job_progress.try :fail!
mark_failed
ensure
self.save
end
end
def export_quizzes2
mark_exporting
begin
reset_and_start_job_progress
@quizzes2 = Exporters::Quizzes2Exporter.new(self)
if @quizzes2.export
self.progress = 100
mark_exported
end
rescue
add_error("Error running export to Quizzes 2.", $!)
mark_failed
ensure
self.save
end
@ -211,6 +243,10 @@ class ContentExport < ActiveRecord::Base
self.export_type == QTI
end
def quizzes2_export?
self.export_type == QUIZZES2
end
def zip_export?
self.export_type == ZIP
end
@ -314,10 +350,10 @@ class ContentExport < ActiveRecord::Base
master_migration.master_template.ensure_tag_on_export(obj)
end
return unless selective_export?
return if qti_export? || epub_export.present?
return if qti_export? || epub_export.present? || quizzes2_export?
# for integrating selective exports with external content
if type = Canvas::Migration::ExternalContent::Translator::CLASSES_TO_TYPES[obj.class]
if (type = Canvas::Migration::ExternalContent::Translator::CLASSES_TO_TYPES[obj.class])
exported_assets << "#{type}_#{obj.id}"
end
end
@ -370,6 +406,7 @@ class ContentExport < ActiveRecord::Base
scope :not_for_copy, -> { where("content_exports.export_type NOT IN (?)", [COURSE_COPY, MASTER_COURSE_COPY]) }
scope :common_cartridge, -> { where(export_type: COMMON_CARTRIDGE) }
scope :qti, -> { where(export_type: QTI) }
scope :quizzes2, -> { where(export_type: QUIZZES2) }
scope :course_copy, -> { where(export_type: COURSE_COPY) }
scope :running, -> { where(workflow_state: ['created', 'exporting']) }
scope :admin, ->(user) {

View File

@ -0,0 +1,52 @@
require 'English'
module Exporters
class Quizzes2Exporter
attr_accessor :course, :user
def initialize(content_export)
@content_export = content_export
@course = @content_export.context
@context_id = @course.id
@logger = Rails.logger
# TO-DO: initialize @quiz; we need pass in the ID of the
# quiz from the view, which is not hooked up yet
end
def build_assignment_payload
assignment_title = "Cloned Quiz" # TO-DO: Replace with quiz.title
{
assignment: {
title: assignment_title
}
}
# TO-DO: Payload should look like the example below
# {
# assignment: {
# title: "Some Name"
# resouce_link_id: "SHA from Assignment Creation"
# qti_export: {
# content_url: "Endpoint for the export"
# }
# }
# }
end
def trigger_import
build_assignment_payload
# TO-DO: Queue the Live Event here
end
def export
begin
trigger_import
rescue
add_error(I18n.t("Error running Quizzes 2 export."), $ERROR_INFO)
@logger.error $ERROR_INFO
return false
end
true
end
end
end

View File

@ -531,7 +531,16 @@ END
state: "hidden",
beta: true,
development: true
}
},
'quizzes2_exporter' =>
{
display_name: -> { I18n.t('Export to Quizzes 2 format') },
description: -> { I18n.t('Export an existing quiz to new Quizzes 2 format') },
applies_to: "RootAccount",
state: "hidden",
beta: false,
development: true,
},
)
def self.definitions

View File

@ -61,6 +61,26 @@ describe ContentExport do
end
end
context "Quizzes2 Export" do
before :once do
course = Account.default.courses.create!
course.quizzes.create!(:title => 'quiz1')
@ce = course.content_exports.create!(:export_type => ContentExport::QUIZZES2)
end
it "changes the workflow_state when :quizzes2_exporter is enabled" do
Account.default.enable_feature!(:quizzes2_exporter)
expect { @ce.export_without_send_later }.to change { @ce.workflow_state }
expect(@ce.workflow_state).to eq "exported"
end
it "fails the content export when:quizzes2_exporter is disabled" do
Account.default.disable_feature!(:quizzes2_exporter)
@ce.export_without_send_later
expect(@ce.workflow_state).to eq "created"
end
end
context "add_item_to_export" do
before :once do
course = Account.default.courses.create!