RuboCop: Lint gems/plugins
Change-Id: I1b0fa3c70f655b738e94df56621e7c8b623f0cfd Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/275533 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Cody Cutrer <cody@instructure.com> Product-Review: Cody Cutrer <cody@instructure.com>
This commit is contained in:
parent
387d11d7d0
commit
cfce475310
|
@ -0,0 +1,23 @@
|
|||
inherit_from:
|
||||
../../.rubocop.yml
|
||||
|
||||
Lint:
|
||||
Severity: error
|
||||
|
||||
<%=
|
||||
|
||||
# re-set individual cops to error
|
||||
require 'yaml'
|
||||
|
||||
common_config = YAML.safe_load(File.read("../../.rubocop.common.yml"))
|
||||
|
||||
config = {}
|
||||
|
||||
common_config.each do |cop, cop_config|
|
||||
next unless cop.start_with?("Lint/")
|
||||
config[cop] = { "Severity" => "error" }
|
||||
config[cop]["AutoCorrect"] = true if cop_config["AutoCorrect"]
|
||||
end
|
||||
|
||||
config.to_yaml.sub(/^---\n/, "")
|
||||
%>
|
|
@ -26,7 +26,7 @@ module AcademicBenchmarks
|
|||
number&.prefix_enhanced
|
||||
end
|
||||
|
||||
def build_outcomes(ratings = {}, parent = nil)
|
||||
def build_outcomes(ratings = {}, _parent = nil)
|
||||
hash = {
|
||||
migration_id: guid,
|
||||
vendor_guid: guid,
|
||||
|
|
|
@ -102,8 +102,8 @@ module AccountReports
|
|||
settings = Canvas::Plugin.find(:account_reports).settings
|
||||
return REPORTS.dup unless settings
|
||||
|
||||
enabled_reports = settings.select { |report, enabled| enabled }.map(&:first)
|
||||
Hash[*REPORTS.select { |report, details| enabled_reports.include?(report) }.flatten]
|
||||
enabled_reports = settings.select { |_report, enabled| enabled }.map(&:first)
|
||||
REPORTS.select { |report, _details| enabled_reports.include?(report) }
|
||||
end
|
||||
|
||||
def self.generate_report(account_report)
|
||||
|
|
|
@ -196,10 +196,10 @@ module AccountReports
|
|||
end
|
||||
|
||||
def account_query
|
||||
accounts = root_account.all_accounts
|
||||
.select("accounts.*, pa.id AS parent_id,
|
||||
pa.sis_source_id AS parent_sis_source_id")
|
||||
.joins("INNER JOIN #{Account.quoted_table_name} AS pa ON accounts.parent_account_id=pa.id")
|
||||
root_account
|
||||
.all_accounts
|
||||
.select("accounts.*, pa.id AS parent_id, pa.sis_source_id AS parent_sis_source_id")
|
||||
.joins("INNER JOIN #{Account.quoted_table_name} AS pa ON accounts.parent_account_id=pa.id")
|
||||
end
|
||||
|
||||
def account_query_options(accounts)
|
||||
|
@ -333,7 +333,7 @@ module AccountReports
|
|||
end
|
||||
|
||||
def course_query
|
||||
courses = root_account.all_courses.preload(:account, :enrollment_term)
|
||||
root_account.all_courses.preload(:account, :enrollment_term)
|
||||
end
|
||||
|
||||
def course_query_options(courses)
|
||||
|
@ -349,7 +349,7 @@ module AccountReports
|
|||
end
|
||||
|
||||
courses = add_course_sub_account_scope(courses)
|
||||
courses = add_term_scope(courses)
|
||||
add_term_scope(courses)
|
||||
end
|
||||
|
||||
def course_row(c, course_state_sub, blueprint_map)
|
||||
|
@ -422,11 +422,12 @@ module AccountReports
|
|||
end
|
||||
|
||||
def section_query
|
||||
sections = root_account.course_sections
|
||||
.select("course_sections.*,
|
||||
root_account
|
||||
.course_sections
|
||||
.select("course_sections.*,
|
||||
rc.sis_source_id AS course_sis_id,
|
||||
ra.id AS r_account_id, ra.sis_source_id AS r_account_sis_id")
|
||||
.joins("INNER JOIN #{Course.quoted_table_name} AS rc ON course_sections.course_id = rc.id
|
||||
.joins("INNER JOIN #{Course.quoted_table_name} AS rc ON course_sections.course_id = rc.id
|
||||
INNER JOIN #{Account.quoted_table_name} AS ra ON rc.account_id = ra.id")
|
||||
end
|
||||
|
||||
|
@ -448,7 +449,7 @@ module AccountReports
|
|||
|
||||
sections = sections.where.not(course_sections: { sis_batch_id: nil }) if @created_by_sis
|
||||
sections = add_course_sub_account_scope(sections, 'rc')
|
||||
sections = add_term_scope(sections, 'rc')
|
||||
add_term_scope(sections, 'rc')
|
||||
end
|
||||
|
||||
def section_row(s)
|
||||
|
@ -580,7 +581,7 @@ module AccountReports
|
|||
.where("enrollments.type <> 'StudentViewEnrollment'")
|
||||
enrol = enrol.where.not(enrollments: { sis_batch_id: nil }) if @created_by_sis
|
||||
enrol = add_course_sub_account_scope(enrol)
|
||||
enrol = add_term_scope(enrol)
|
||||
add_term_scope(enrol)
|
||||
end
|
||||
|
||||
def enrollment_headers(include_other_roots)
|
||||
|
@ -882,7 +883,7 @@ module AccountReports
|
|||
end
|
||||
|
||||
xl = add_course_sub_account_scope(xl)
|
||||
xl = add_term_scope(xl)
|
||||
add_term_scope(xl)
|
||||
end
|
||||
|
||||
def user_observers
|
||||
|
|
|
@ -181,8 +181,6 @@ module AccountReports
|
|||
.where("enrollments.type = 'StudentEnrollment'
|
||||
AND enrollments.workflow_state = 'active'")
|
||||
|
||||
param = {}
|
||||
|
||||
if start_at
|
||||
data = data.where("enrollments.last_activity_at < ? OR enrollments.last_activity_at IS NULL", start_at)
|
||||
# Only select enrollments that have zero activity across an entire course.
|
||||
|
|
|
@ -23,7 +23,7 @@ require File.expand_path(File.dirname(__FILE__) + '/report_spec_helper')
|
|||
describe "Outcome Reports" do
|
||||
include ReportSpecHelper
|
||||
|
||||
RATING_INDEX = AccountReports::OutcomeExport::OUTCOME_EXPORT_HEADERS.find_index('ratings')
|
||||
let(:rating_index) { AccountReports::OutcomeExport::OUTCOME_EXPORT_HEADERS.find_index('ratings') }
|
||||
|
||||
describe 'outcome export' do
|
||||
def match_row(attrs)
|
||||
|
@ -50,7 +50,7 @@ describe "Outcome Reports" do
|
|||
|
||||
def n_ratings?(n)
|
||||
satisfy("have #{n} ratings") do |row|
|
||||
row.length - RATING_INDEX == 2 * n
|
||||
row.length - rating_index == 2 * n
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -289,10 +289,10 @@ describe "Outcome Reports" do
|
|||
|
||||
it 'includes all ratings' do
|
||||
expect(first_outcome).to n_ratings?(2)
|
||||
expect(first_outcome[RATING_INDEX]).to eq '3.0'
|
||||
expect(first_outcome[RATING_INDEX + 1]).to eq 'Rockin'
|
||||
expect(first_outcome[RATING_INDEX + 2]).to eq '0.0'
|
||||
expect(first_outcome[RATING_INDEX + 3]).to eq 'Lame'
|
||||
expect(first_outcome[rating_index]).to eq '3.0'
|
||||
expect(first_outcome[rating_index + 1]).to eq 'Rockin'
|
||||
expect(first_outcome[rating_index + 2]).to eq '0.0'
|
||||
expect(first_outcome[rating_index + 3]).to eq 'Lame'
|
||||
end
|
||||
|
||||
it 'includes different number of fields depending on how many ratings are present' do
|
||||
|
@ -308,19 +308,19 @@ describe "Outcome Reports" do
|
|||
}
|
||||
@root_outcome_1.save!
|
||||
expect(first_outcome).to n_ratings?(6)
|
||||
expect(first_outcome[RATING_INDEX]).to eq '10.0'
|
||||
expect(first_outcome[RATING_INDEX + 1]).to eq 'a fly'
|
||||
expect(first_outcome[RATING_INDEX + 10]).to eq '0.0'
|
||||
expect(first_outcome[RATING_INDEX + 11]).to eq 'I know'
|
||||
expect(first_outcome[RATING_INDEX + 12]).to be_nil
|
||||
expect(first_outcome[RATING_INDEX + 13]).to be_nil
|
||||
expect(first_outcome[rating_index]).to eq '10.0'
|
||||
expect(first_outcome[rating_index + 1]).to eq 'a fly'
|
||||
expect(first_outcome[rating_index + 10]).to eq '0.0'
|
||||
expect(first_outcome[rating_index + 11]).to eq 'I know'
|
||||
expect(first_outcome[rating_index + 12]).to be_nil
|
||||
expect(first_outcome[rating_index + 13]).to be_nil
|
||||
end
|
||||
|
||||
it 'exports successfully with no ratings' do
|
||||
@root_outcome_1.data = nil
|
||||
@root_outcome_1.save!
|
||||
default_count = LearningOutcome.default_rubric_criterion[:ratings].length
|
||||
expect(first_outcome.length).to eq RATING_INDEX + (default_count * 2)
|
||||
expect(first_outcome.length).to eq rating_index + (default_count * 2)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -334,7 +334,7 @@ describe "Outcome Reports" do
|
|||
end
|
||||
|
||||
it 'formats rating points' do
|
||||
expect(report[0][RATING_INDEX]).to eq '3,0'
|
||||
expect(report[0][rating_index]).to eq '3,0'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1534,7 +1534,7 @@ describe "Default Account Reports" do
|
|||
|
||||
users_report = parsed["users.csv"][1..-1].sort_by { |r| r[0] }
|
||||
expect(users_report.length).to eq 4
|
||||
expect(users_report).to eq [@user1, @user2, @user3, @user4].map { |u| expected_user(u) }
|
||||
expect(users_report).to eq([@user1, @user2, @user3, @user4].map { |u| expected_user(u) })
|
||||
end
|
||||
|
||||
it "runs the SIS Export reports with no data" do
|
||||
|
|
|
@ -23,7 +23,7 @@ module Moodle
|
|||
super(settings, "moodle")
|
||||
end
|
||||
|
||||
def export(to_export = Canvas::Migration::Migrator::SCRAPE_ALL_HASH)
|
||||
def export(_to_export = Canvas::Migration::Migrator::SCRAPE_ALL_HASH)
|
||||
unzip_archive
|
||||
migrator = Moodle2CC::Migrator.new @package_root.root_path, Dir.mktmpdir, 'format' => 'canvas', 'logger' => self
|
||||
migrator.migrate
|
||||
|
@ -65,7 +65,7 @@ module Moodle
|
|||
end
|
||||
|
||||
def add_warnings_to_map(warning_map)
|
||||
warning_map.values.each do |warnings|
|
||||
warning_map.each_value do |warnings|
|
||||
if (hashes = warnings['multiple_dropdowns_question'])
|
||||
if hashes.count > 2
|
||||
q_hash = hashes.first
|
||||
|
@ -74,10 +74,10 @@ module Moodle
|
|||
"There are %{count} Multiple Dropdowns questions in this bank that may have been imported incorrectly",
|
||||
:count => hashes.count)
|
||||
else
|
||||
hashes.each do |q_hash|
|
||||
q_hash['import_warnings'] ||= []
|
||||
q_hash['import_warnings'] << I18n.t(:moodle_dropdown_warning_title,
|
||||
"Multiple Dropdowns question may have been imported incorrectly")
|
||||
hashes.each do |q_hash2|
|
||||
q_hash2['import_warnings'] ||= []
|
||||
q_hash2['import_warnings'] << I18n.t(:moodle_dropdown_warning_title,
|
||||
"Multiple Dropdowns question may have been imported incorrectly")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -90,10 +90,10 @@ module Moodle
|
|||
"There are %{count} Formula questions in this bank that will need to have their possible answers regenerated",
|
||||
:count => hashes.count)
|
||||
else
|
||||
hashes.each do |q_hash|
|
||||
q_hash['import_warnings'] ||= []
|
||||
q_hash['import_warnings'] << I18n.t(:moodle_formula_warning_title,
|
||||
"Possible answers will need to be regenerated for Formula question")
|
||||
hashes.each do |q_hash2|
|
||||
q_hash2['import_warnings'] ||= []
|
||||
q_hash2['import_warnings'] << I18n.t(:moodle_formula_warning_title,
|
||||
"Possible answers will need to be regenerated for Formula question")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module Canvas::Plugins::Validators::QtiPluginValidator
|
||||
def self.validate(settings, plugin_setting)
|
||||
def self.validate(settings, _plugin_setting)
|
||||
settings.with_indifferent_access.slice(:enabled)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -111,7 +111,7 @@ module Qti
|
|||
next if resource_nodes.any? { |node| node['href'] == file['href'] }
|
||||
|
||||
# anything left is a file that needs to become an attachment on the context
|
||||
attachments << URI.unescape(file['href'])
|
||||
attachments << CGI.unescape(file['href'])
|
||||
end
|
||||
attachments
|
||||
end
|
||||
|
|
|
@ -205,7 +205,7 @@ module Qti
|
|||
case @migration_type
|
||||
when 'True/False'
|
||||
@question[:question_type] = 'true_false_question'
|
||||
when 'Short Response'
|
||||
when 'Short Response', "Essay"
|
||||
@question[:question_type] = 'essay_question'
|
||||
when 'Fill in the Blank Plus'
|
||||
@question[:question_type] = 'fill_in_multiple_blanks_question'
|
||||
|
@ -219,8 +219,6 @@ module Qti
|
|||
end
|
||||
when 'Jumbled Sentence'
|
||||
@question[:question_type] = 'multiple_dropdowns_question'
|
||||
when 'Essay'
|
||||
@question[:question_type] = 'essay_question'
|
||||
end
|
||||
elsif (type = get_node_att(meta, 'instructureField[name=question_type]', 'value'))
|
||||
@migration_type = type
|
||||
|
@ -309,7 +307,6 @@ module Qti
|
|||
|
||||
def self.create_instructure_question(opts)
|
||||
extend Canvas::Migration::XMLHelper
|
||||
q = nil
|
||||
manifest_node = opts[:manifest_node]
|
||||
|
||||
if manifest_node
|
||||
|
@ -322,14 +319,15 @@ module Qti
|
|||
if (type = get_node_att(manifest_node, 'instructureMetadata instructureField[name=question_type]', 'value'))
|
||||
type = type.downcase
|
||||
opts[:custom_type] ||= type
|
||||
if type == 'matching_question'
|
||||
case type
|
||||
when 'matching_question'
|
||||
opts[:interaction_type] = 'choiceinteraction'
|
||||
opts[:custom_type] = 'canvas_matching'
|
||||
elsif type == 'matching'
|
||||
when 'matching'
|
||||
opts[:custom_type] = 'respondus_matching'
|
||||
elsif type =~ /fillInMultiple|fill_in_multiple_blanks_question|fill in the blanks/i
|
||||
when /fillInMultiple|fill_in_multiple_blanks_question|fill in the blanks/i
|
||||
opts[:interaction_type] = 'fill_in_multiple_blanks_question'
|
||||
elsif type == 'multiple_dropdowns_question'
|
||||
when 'multiple_dropdowns_question'
|
||||
opts[:interaction_type] = 'multiple_dropdowns_question'
|
||||
else
|
||||
opts[:custom_type] = type
|
||||
|
@ -342,39 +340,37 @@ module Qti
|
|||
opts[:interaction_type], opts[:custom_type] = guesser.educatedly_guess_type
|
||||
end
|
||||
|
||||
case opts[:interaction_type]
|
||||
when /choiceinteraction|multiple_choice_question|multiple_answers_question|true_false_question|stupid_likert_scale_question/i
|
||||
if opts[:custom_type] and opts[:custom_type] == "matching"
|
||||
q = AssociateInteraction.new(opts)
|
||||
elsif opts[:custom_type] && opts[:custom_type] =~ /respondus_matching|canvas_matching/
|
||||
q = AssociateInteraction.new(opts)
|
||||
else
|
||||
q = ChoiceInteraction.new(opts)
|
||||
end
|
||||
when /associateinteraction|matching_question|matchinteraction/i
|
||||
q = AssociateInteraction.new(opts)
|
||||
when /extendedtextinteraction|extendedtextentryinteraction|textinteraction|essay_question|short_answer_question/i
|
||||
if opts[:custom_type] and opts[:custom_type] =~ /calculated/i
|
||||
q = CalculatedInteraction.new(opts)
|
||||
elsif opts[:custom_type] and opts[:custom_type] =~ /numeric|numerical_question/
|
||||
q = NumericInteraction.new(opts)
|
||||
else
|
||||
q = ExtendedTextInteraction.new(opts)
|
||||
end
|
||||
when /orderinteraction|ordering_question/i
|
||||
q = OrderInteraction.new(opts)
|
||||
when /fill_in_multiple_blanks_question|multiple_dropdowns_question/i
|
||||
q = FillInTheBlank.new(opts)
|
||||
when /textentryinteraction/i
|
||||
q = FillInTheBlank.new(opts)
|
||||
when nil
|
||||
q = AssessmentItemConverter.new(opts)
|
||||
else
|
||||
Canvas::Migration::logger.warn "Unknown QTI question type: #{opts[:interaction_type]}"
|
||||
q = AssessmentItemConverter.new(opts)
|
||||
end
|
||||
q = case opts[:interaction_type]
|
||||
when /choiceinteraction|multiple_choice_question|multiple_answers_question|true_false_question|stupid_likert_scale_question/i
|
||||
if opts[:custom_type] &&
|
||||
(opts[:custom_type] == "matching" ||
|
||||
opts[:custom_type] =~ /respondus_matching|canvas_matching/)
|
||||
AssociateInteraction.new(opts)
|
||||
else
|
||||
ChoiceInteraction.new(opts)
|
||||
end
|
||||
when /associateinteraction|matching_question|matchinteraction/i
|
||||
AssociateInteraction.new(opts)
|
||||
when /extendedtextinteraction|extendedtextentryinteraction|textinteraction|essay_question|short_answer_question/i
|
||||
if opts[:custom_type] && opts[:custom_type] =~ /calculated/i
|
||||
CalculatedInteraction.new(opts)
|
||||
elsif opts[:custom_type] && opts[:custom_type] =~ /numeric|numerical_question/
|
||||
NumericInteraction.new(opts)
|
||||
else
|
||||
ExtendedTextInteraction.new(opts)
|
||||
end
|
||||
when /orderinteraction|ordering_question/i
|
||||
OrderInteraction.new(opts)
|
||||
when /fill_in_multiple_blanks_question|multiple_dropdowns_question|textentryinteraction/i
|
||||
FillInTheBlank.new(opts)
|
||||
when nil
|
||||
AssessmentItemConverter.new(opts)
|
||||
else
|
||||
Canvas::Migration.logger.warn "Unknown QTI question type: #{opts[:interaction_type]}"
|
||||
AssessmentItemConverter.new(opts)
|
||||
end
|
||||
|
||||
q.create_instructure_question if q
|
||||
q&.create_instructure_question
|
||||
end
|
||||
|
||||
# Sets the actual feedback values and clears the feedback ids
|
||||
|
|
|
@ -81,15 +81,11 @@ module Qti
|
|||
end
|
||||
|
||||
def self.is_qti_2(manifest_path)
|
||||
if File.exist?(manifest_path)
|
||||
xml = Nokogiri::XML(File.open(manifest_path))
|
||||
if xml.namespaces.values.any? { |v| QTI_2_NAMESPACES.any? { |ns| v.to_s.start_with?(ns) } }
|
||||
return true
|
||||
elsif (xml.at_css('metadata schema') ? xml.at_css('metadata schema').text : '') =~ /QTIv2\./i
|
||||
return true
|
||||
end
|
||||
end
|
||||
false
|
||||
return false unless File.exist?(manifest_path)
|
||||
|
||||
xml = Nokogiri::XML(File.open(manifest_path))
|
||||
xml.namespaces.values.any? { |v| QTI_2_NAMESPACES.any? { |ns| v.to_s.start_with?(ns) } } ||
|
||||
(xml.at_css('metadata schema')&.text || '') =~ /QTIv2\./i
|
||||
end
|
||||
|
||||
def run_qti_converter
|
||||
|
|
|
@ -23,10 +23,6 @@ module Qti
|
|||
class ExtendedTextInteraction < AssessmentItemConverter
|
||||
include Canvas::Migration::XMLHelper
|
||||
|
||||
def initialize(opts)
|
||||
super(opts)
|
||||
end
|
||||
|
||||
def parse_question_data
|
||||
process_response_conditions
|
||||
if @question[:answers].present?
|
||||
|
|
|
@ -42,7 +42,7 @@ module Qti
|
|||
node.search("*").each do |subnode|
|
||||
attrs.each do |attr|
|
||||
if subnode[attr]
|
||||
val = URI.unescape(subnode[attr])
|
||||
val = CGI.unescape(subnode[attr])
|
||||
if val.start_with?(WEBCT_REL_REGEX)
|
||||
# It's from a webct package so the references may not be correct
|
||||
# Take a path like: /webct/RelativeResourceManager/Template/Imported_Resources/qti web/f11g3_r.jpg
|
||||
|
|
|
@ -28,7 +28,7 @@ module Qti
|
|||
def parse_question_data
|
||||
match_map = {}
|
||||
get_all_matches(match_map)
|
||||
if (node = @doc.at_css('correctResponse'))
|
||||
if @doc.at_css('correctResponse')
|
||||
get_correct_responses(match_map)
|
||||
else
|
||||
get_all_answers(match_map)
|
||||
|
|
|
@ -61,7 +61,7 @@ if Qti.migration_executable
|
|||
end
|
||||
|
||||
it "converts matching questions" do
|
||||
hash = get_question_hash(bb8_question_dir, 'matching', false)
|
||||
hash = get_question_hash(bb8_question_dir, 'matching', delete_answer_ids: false)
|
||||
matches = {}
|
||||
hash[:matches].each { |m| matches[m[:match_id]] = m[:text] }
|
||||
hash[:answers].each do |a|
|
||||
|
|
|
@ -63,7 +63,7 @@ if Qti.migration_executable
|
|||
end
|
||||
|
||||
it "converts matching questions where the answers are given out of order" do
|
||||
hash = get_question_hash(bb9_question_dir, 'matching2', false)
|
||||
hash = get_question_hash(bb9_question_dir, 'matching2', delete_answer_ids: false)
|
||||
matches = {}
|
||||
hash[:matches].each { |m| matches[m[:match_id]] = m[:text] }
|
||||
hash[:answers].each do |a|
|
||||
|
@ -76,12 +76,12 @@ if Qti.migration_executable
|
|||
end
|
||||
|
||||
it "converts true/false questions using identifiers, not mattext" do
|
||||
hash = get_question_hash(bb9_question_dir, 'true_false', false, :flavor => Qti::Flavors::BBLEARN)
|
||||
hash = get_question_hash(bb9_question_dir, 'true_false', delete_answer_ids: false, flavor: Qti::Flavors::BBLEARN)
|
||||
hash[:answers].each { |m| expect(m[:migration_id]).to eq m[:text].downcase }
|
||||
end
|
||||
|
||||
it "replaces negative points possible with zero" do
|
||||
hash = get_question_hash(bb9_question_dir, 'minus_one', false, :flavor => Qti::Flavors::BBLEARN)
|
||||
hash = get_question_hash(bb9_question_dir, 'minus_one', delete_answer_ids: false, flavor: Qti::Flavors::BBLEARN)
|
||||
expect(hash[:points_possible]).to eq 0.0
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,37 +20,35 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../../qti_helper')
|
||||
if Qti.migration_executable
|
||||
describe "Converting D2L QTI" do
|
||||
before do
|
||||
@opts = { :flavor => Qti::Flavors::D2L }
|
||||
end
|
||||
let(:opts) { { :flavor => Qti::Flavors::D2L } }
|
||||
|
||||
it "converts multiple choice" do
|
||||
expect(get_question_hash(d2l_question_dir, 'multiple_choice', true, @opts)).to eq D2LExpected::MULTIPLE_CHOICE
|
||||
expect(get_question_hash(d2l_question_dir, 'multiple_choice', **opts)).to eq D2LExpected::MULTIPLE_CHOICE
|
||||
end
|
||||
|
||||
it "converts true false" do
|
||||
expect(get_question_hash(d2l_question_dir, 'true_false', true, @opts)).to eq D2LExpected::TRUE_FALSE
|
||||
expect(get_question_hash(d2l_question_dir, 'true_false', **opts)).to eq D2LExpected::TRUE_FALSE
|
||||
end
|
||||
|
||||
it "converts short answer" do
|
||||
expect(get_question_hash(d2l_question_dir, 'short_answer', true, @opts)).to eq D2LExpected::SHORT_ANSWER
|
||||
expect(get_question_hash(d2l_question_dir, 'short_answer', **opts)).to eq D2LExpected::SHORT_ANSWER
|
||||
end
|
||||
|
||||
it "converts multi select" do
|
||||
expect(get_question_hash(d2l_question_dir, 'multi_select', true, @opts)).to eq D2LExpected::MULTI_SELECT
|
||||
expect(get_question_hash(d2l_question_dir, 'multi_select', **opts)).to eq D2LExpected::MULTI_SELECT
|
||||
end
|
||||
|
||||
it "converts multiple short" do
|
||||
expect(get_question_hash(d2l_question_dir, 'multiple_short', true, @opts)).to eq D2LExpected::MULTIPLE_SHORT
|
||||
expect(get_question_hash(d2l_question_dir, 'multiple_short', **opts)).to eq D2LExpected::MULTIPLE_SHORT
|
||||
end
|
||||
|
||||
it "converts fill in the blank with multiple blanks" do
|
||||
expect(get_question_hash(d2l_question_dir, 'fib', true, @opts)).to eq D2LExpected::FIB
|
||||
expect(get_question_hash(d2l_question_dir, 'fib', **opts)).to eq D2LExpected::FIB
|
||||
end
|
||||
|
||||
it "converts matching" do
|
||||
# pp get_question_hash(d2l_question_dir, 'matching', false)
|
||||
hash = get_question_hash(d2l_question_dir, 'matching', false, @opts)
|
||||
hash = get_question_hash(d2l_question_dir, 'matching', delete_answer_ids: false, **opts)
|
||||
matches = {}
|
||||
hash[:matches].each { |m| matches[m[:match_id]] = m[:text] }
|
||||
hash[:answers].each do |a|
|
||||
|
@ -63,36 +61,36 @@ if Qti.migration_executable
|
|||
end
|
||||
|
||||
it "flags ordering question as an error" do
|
||||
expect(get_question_hash(d2l_question_dir, 'ordering', true, @opts)).to eq D2LExpected::ORDERING
|
||||
expect(get_question_hash(d2l_question_dir, 'ordering', **opts)).to eq D2LExpected::ORDERING
|
||||
end
|
||||
|
||||
it "converts math question" do
|
||||
expect(get_question_hash(d2l_question_dir, 'math', true, @opts)).to eq D2LExpected::MATH
|
||||
expect(get_question_hash(d2l_question_dir, 'math', **opts)).to eq D2LExpected::MATH
|
||||
end
|
||||
|
||||
it "converts a simple math question to a numeric question" do
|
||||
expect(get_question_hash(d2l_question_dir, 'simple_math', true, @opts)).to eq D2LExpected::SIMPLE_MATH
|
||||
expect(get_question_hash(d2l_question_dir, 'simple_math', **opts)).to eq D2LExpected::SIMPLE_MATH
|
||||
end
|
||||
|
||||
it "converts long answer" do
|
||||
expect(get_question_hash(d2l_question_dir, 'long_answer', true, @opts)).to eq D2LExpected::LONG_ANSWER
|
||||
expect(get_question_hash(d2l_question_dir, 'long_answer', **opts)).to eq D2LExpected::LONG_ANSWER
|
||||
end
|
||||
|
||||
it "converts an item with a response condition with no condition" do
|
||||
expect(get_question_hash(d2l_question_dir, 'no_condition', true, @opts)).to eq D2LExpected::NO_CONDITION
|
||||
expect(get_question_hash(d2l_question_dir, 'no_condition', **opts)).to eq D2LExpected::NO_CONDITION
|
||||
end
|
||||
|
||||
it "converts the assessment into a quiz" do
|
||||
allow_any_instance_of(Qti::AssessmentTestConverter).to receive(:unique_local_id).and_return("random")
|
||||
expect(get_quiz_data(d2l_question_dir, 'assessment', @opts).last.first).to eq D2LExpected::ASSESSMENT
|
||||
expect(get_quiz_data(d2l_question_dir, 'assessment', **opts).last.first).to eq D2LExpected::ASSESSMENT
|
||||
end
|
||||
|
||||
it "converts the assessment references into a quiz" do
|
||||
expect(get_quiz_data(d2l_question_dir, 'assessment_references', @opts).last.first).to eq D2LExpected::ASSESSMENT_REFS
|
||||
expect(get_quiz_data(d2l_question_dir, 'assessment_references', **opts).last.first).to eq D2LExpected::ASSESSMENT_REFS
|
||||
end
|
||||
|
||||
it "converts text only questions" do
|
||||
expect(get_quiz_data(d2l_question_dir, 'text_only', @opts).first).to eq D2LExpected::TEXT_ONLY
|
||||
expect(get_quiz_data(d2l_question_dir, 'text_only', **opts).first).to eq D2LExpected::TEXT_ONLY
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ if Qti.migration_executable
|
|||
before(:once) do
|
||||
archive_file_path = File.join(BASE_FIXTURE_DIR, 'qti', 'qti_2_1.zip')
|
||||
unzipped_file_path = create_temp_dir!
|
||||
export_folder = create_temp_dir!
|
||||
create_temp_dir!
|
||||
exporter = Qti::Converter.new(:export_archive_path => archive_file_path, :base_download_dir => unzipped_file_path)
|
||||
exporter.export
|
||||
@course_data = exporter.course.with_indifferent_access
|
||||
|
|
|
@ -28,7 +28,7 @@ if Qti.migration_executable
|
|||
end
|
||||
|
||||
it "finds correct answer for multiple choice with zero point weights" do
|
||||
hash = get_question_hash(RESPONDUS_FIXTURE_DIR, 'zero_point_mc', false, :flavor => Qti::Flavors::RESPONDUS)
|
||||
hash = get_question_hash(RESPONDUS_FIXTURE_DIR, 'zero_point_mc', delete_answer_ids: false, flavor: Qti::Flavors::RESPONDUS)
|
||||
expect(hash[:import_error]).to eq nil
|
||||
expect(hash[:answers].first[:weight]).to eq 100
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../../qti_helper')
|
||||
if Qti.migration_executable
|
||||
describe "Converting Blackboard Vista qti" do
|
||||
KEYS_TO_IGNORE = ['is_quiz_question_bank', 'question_bank_migration_id']
|
||||
let(:keys_to_ignore) { %w[is_quiz_question_bank question_bank_migration_id] }
|
||||
|
||||
before(:once) do
|
||||
archive_file_path = File.join(BASE_FIXTURE_DIR, 'bb_vista', 'vista_archive.zip')
|
||||
|
@ -76,29 +76,29 @@ if Qti.migration_executable
|
|||
|
||||
it "converts multiple choice" do
|
||||
hash = get_question("ID_4609865476341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::MULTIPLE_CHOICE
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::MULTIPLE_CHOICE
|
||||
end
|
||||
|
||||
it "does not fail with missing response identifier" do
|
||||
expect {
|
||||
hash = get_question_hash(vista_question_dir, 'no_response_id', delete_answer_ids = true, opts = {})
|
||||
}.not_to raise_error
|
||||
expect do
|
||||
get_question_hash(vista_question_dir, 'no_response_id')
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
||||
it "converts images correctly" do
|
||||
manifest_node = get_manifest_node('true_false', :interaction_type => 'choiceInteraction')
|
||||
hash = Qti::ChoiceInteraction.create_instructure_question(:manifest_node => manifest_node, :base_dir => vista_question_dir).with_indifferent_access
|
||||
hash[:answers].each { |a| a.delete(:id) }
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::TRUE_FALSE2
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::TRUE_FALSE2
|
||||
end
|
||||
|
||||
it "converts image reference" do
|
||||
hash = get_question_hash(vista_question_dir, 'mc', delete_answer_ids = true, opts = {})
|
||||
hash = get_question_hash(vista_question_dir, 'mc')
|
||||
expect(hash[:question_text]).to match %r{\$CANVAS_OBJECT_REFERENCE\$/attachments/67320753001}
|
||||
end
|
||||
|
||||
it "converts short answer questions with multiple required answers to fimb" do
|
||||
hash = get_question_hash(vista_question_dir, 'short_to_fimb', delete_answer_ids = true, opts = {})
|
||||
hash = get_question_hash(vista_question_dir, 'short_to_fimb')
|
||||
expect(hash[:question_type]).to eq "fill_in_multiple_blanks_question"
|
||||
expect(hash[:question_text]).to include("[SA01]")
|
||||
expect(hash[:question_text]).to include("[SA02]")
|
||||
|
@ -106,22 +106,22 @@ if Qti.migration_executable
|
|||
|
||||
it "converts true/false questions" do
|
||||
hash = get_question("ID_4609865577341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::TRUE_FALSE
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::TRUE_FALSE
|
||||
end
|
||||
|
||||
it "converts multiple choice questions with multiple correct answers (multiple answer)" do
|
||||
hash = get_question("ID_4609865392341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::MULTIPLE_ANSWER
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::MULTIPLE_ANSWER
|
||||
end
|
||||
|
||||
it "converts essay questions" do
|
||||
hash = get_question("ID_4609842537341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::ESSAY
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::ESSAY
|
||||
end
|
||||
|
||||
it "converts short answer questions" do
|
||||
hash = get_question("ID_4609865550341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::SHORT_ANSWER
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::SHORT_ANSWER
|
||||
end
|
||||
|
||||
it "converts matching questions" do
|
||||
|
@ -136,7 +136,7 @@ if Qti.migration_executable
|
|||
# compare everything else without the ids
|
||||
hash[:answers].each { |a| a.delete(:id); a.delete(:match_id) }
|
||||
hash[:matches].each { |m| m.delete(:match_id) }
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::MATCHING
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::MATCHING
|
||||
end
|
||||
|
||||
it "converts the assessments into quizzes" do
|
||||
|
@ -145,27 +145,27 @@ if Qti.migration_executable
|
|||
|
||||
it "converts simple calculated questions" do
|
||||
hash = get_question("ID_4609842344341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::CALCULATED_SIMPLE
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::CALCULATED_SIMPLE
|
||||
end
|
||||
|
||||
it "converts complex calculated questions" do
|
||||
hash = get_question("ID_4609823478341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::CALCULATED_COMPLEX
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::CALCULATED_COMPLEX
|
||||
end
|
||||
|
||||
it "converts combination to multiple choice" do
|
||||
hash = get_question("ID_4609885376341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::COMBINATION
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::COMBINATION
|
||||
end
|
||||
|
||||
it "converts fill in multiple blanks questions" do
|
||||
hash = get_question("ID_4609842630341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::FILL_IN_MULTIPLE_BLANKS
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::FILL_IN_MULTIPLE_BLANKS
|
||||
end
|
||||
|
||||
it "marks jumbled sentence as not supported" do
|
||||
hash = get_question("ID_4609842882341")
|
||||
expect(hash.reject { |k, v| KEYS_TO_IGNORE.include?(k.to_s) }).to eq VistaExpected::JUMBLED_SENTENCE
|
||||
expect(hash.except(*keys_to_ignore)).to eq VistaExpected::JUMBLED_SENTENCE
|
||||
end
|
||||
|
||||
it "references associated files correctly" do
|
||||
|
|
|
@ -26,202 +26,7 @@ if Qti.migration_executable
|
|||
course_with_teacher(:active_all => true)
|
||||
end
|
||||
|
||||
it "imports duplicate files once, without munging" do
|
||||
setup_migration
|
||||
do_migration
|
||||
|
||||
expect(@course.attachments.count).to eq 2
|
||||
expect(@course.attachments.map(&:filename).sort).to eq ['header-logo.png', 'smiley.jpg']
|
||||
attachment = @course.attachments.detect { |a| a.filename == 'header-logo.png' }
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.quiz_questions.count).to eq 2
|
||||
quiz.quiz_questions.each do |q|
|
||||
text = Nokogiri::HTML5.fragment(q.question_data['question_text'])
|
||||
expect(text.css('img').first['src']).to eq "/courses/#{@course.id}/files/#{attachment.id}/preview"
|
||||
|
||||
# verify that the associated assessment_question got links translated
|
||||
aq = q.assessment_question
|
||||
text = Nokogiri::HTML5.fragment(aq.question_data['question_text'])
|
||||
expect(text.css('img').first['src']).to match %r{/assessment_questions/#{aq.id}/files/\d+/download\?verifier=\w+}
|
||||
|
||||
if aq.question_data['answers'][1]["comments_html"] =~ /\<img/
|
||||
text = Nokogiri::HTML5.fragment(aq.question_data['answers'][1]["comments_html"])
|
||||
expect(text.css('img').first['src']).to match %r{/assessment_questions/#{aq.id}/files/\d+/download\?verifier=\w+}
|
||||
end
|
||||
end
|
||||
expect(quiz.assignment).to_not be_nil
|
||||
end
|
||||
|
||||
it "brings in canvas meta data" do
|
||||
setup_migration(File.expand_path("../fixtures/qti/canvas_qti.zip", __FILE__))
|
||||
do_migration
|
||||
expect(@course.quizzes.count).to eq 1
|
||||
expect(@course.quizzes.first.description).to eq "<p>Quiz Description</p>"
|
||||
end
|
||||
|
||||
describe "applying respondus settings" do
|
||||
before do
|
||||
@copy = Tempfile.new(['spec-canvas', '.zip'])
|
||||
FileUtils.cp(fname, @copy.path)
|
||||
Zip::File.open(@copy.path) do |zf|
|
||||
zf.file.open("settings.xml", +'w') do |f|
|
||||
f.write <<-XML
|
||||
<settings>
|
||||
<setting name='hasSettings'>true</setting>
|
||||
<setting name='publishNow'>true</setting>
|
||||
</settings>
|
||||
XML
|
||||
end
|
||||
end
|
||||
setup_migration(@copy.path)
|
||||
@migration.update_migration_settings(:apply_respondus_settings_file => true)
|
||||
@migration.save!
|
||||
end
|
||||
|
||||
it "publishes as assignment on import if specified" do
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.assignment).not_to be_nil
|
||||
expect(quiz.assignment.title).to eq quiz.title
|
||||
expect(quiz.assignment).to be_published
|
||||
end
|
||||
|
||||
it "re-uses the same assignment on update" do
|
||||
do_migration
|
||||
|
||||
setup_migration(@copy.path)
|
||||
@migration.update_migration_settings(:apply_respondus_settings_file => true, :quiz_id_to_update => @course.quizzes.last.id)
|
||||
@migration.save!
|
||||
do_migration
|
||||
|
||||
expect(@course.quizzes.size).to eq 1
|
||||
expect(@course.assignments.size).to eq 1
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.assignment).not_to be_nil
|
||||
expect(quiz.assignment.title).to eq quiz.title
|
||||
expect(quiz.assignment).to be_published
|
||||
end
|
||||
|
||||
it "sets the assignment submission_type correctly" do
|
||||
do_migration
|
||||
assign = @course.assignments.last
|
||||
expect(assign.submission_types).to eq 'online_quiz'
|
||||
expect(assign.quiz.for_assignment?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it "publishes spec-canvas-1 correctly" do
|
||||
setup_migration
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.quiz_questions.size).to eq 2
|
||||
# various checks on the data
|
||||
qq = quiz.quiz_questions.first
|
||||
d = qq.question_data
|
||||
expect(d['correct_comments']).to eq "I can't believe you got that right. Awesome!"
|
||||
expect(d['correct_comments_html']).to eq "I can't <i>believe </i>you got that right. <b>Awesome!</b>"
|
||||
expect(d['incorrect_comments_html']).to eq "<b>Wrong. </b>That's a bummer."
|
||||
expect(d['points_possible']).to eq 3
|
||||
expect(d['question_name']).to eq 'q1'
|
||||
expect(d['answers'].map { |a| a['weight'] }).to eq [0, 100, 0]
|
||||
expect(d['answers'].map { |a| a['comments'] }).to eq ['nope', 'yes!', nil]
|
||||
attachment = @course.attachments.detect { |a| a.filename == 'smiley.jpg' }
|
||||
expect(d['answers'].map { |a| a['comments_html'] }).to eq [nil, %{yes! <img src="/courses/#{@course.id}/files/#{attachment.id}/preview" alt="">}, nil]
|
||||
end
|
||||
|
||||
it "imports respondus question types" do
|
||||
setup_migration(File.expand_path("../fixtures/canvas_respondus_question_types.zip", __FILE__))
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz).not_to be_available
|
||||
expect(quiz.quiz_questions.size).to eq 9
|
||||
|
||||
match_ignoring(quiz.quiz_questions.map(&:question_data), RESPONDUS_QUESTIONS, %w[id assessment_question_id match_id prepped_for_import is_quiz_question_bank question_bank_migration_id quiz_question_id])
|
||||
end
|
||||
|
||||
it "applies respondus settings" do
|
||||
setup_migration(File.expand_path("../fixtures/canvas_respondus_question_types.zip", __FILE__))
|
||||
@migration.update_migration_settings(:apply_respondus_settings_file => true)
|
||||
@migration.save!
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz).to be_available
|
||||
end
|
||||
|
||||
it "is able to import directly into an assessment question bank" do
|
||||
setup_migration(File.expand_path("../fixtures/canvas_respondus_question_types.zip", __FILE__))
|
||||
@migration.update_migration_settings(:migration_ids_to_import =>
|
||||
{ :copy => { :all_quizzes => false, :all_assessment_question_banks => true } })
|
||||
@migration.save!
|
||||
do_migration
|
||||
|
||||
expect(@course.quizzes.count).to eq 0
|
||||
qb = @course.assessment_question_banks.last
|
||||
expect(qb).to be_present
|
||||
expect(qb.assessment_questions.size).to eq 9
|
||||
data = qb.assessment_questions.map(&:question_data).sort_by! { |q| q["migration_id"] }
|
||||
match_ignoring(data, RESPONDUS_QUESTIONS, %w[id assessment_question_id match_id missing_links position prepped_for_import is_quiz_question_bank question_bank_migration_id quiz_question_id])
|
||||
end
|
||||
|
||||
def match_ignoring(a, b, ignoring = [])
|
||||
case a
|
||||
when Hash
|
||||
a_ = a.reject { |k, v| ignoring.include?(k) }
|
||||
b_ = b.reject { |k, v| ignoring.include?(k) }
|
||||
expect(a_.keys.sort).to eq b_.keys.sort
|
||||
a_.each { |k, v| match_ignoring(v, b[k], ignoring) }
|
||||
when Array
|
||||
expect(a.size).to eq b.size
|
||||
a.each_with_index do |e, i|
|
||||
match_ignoring(e.to_hash, b[i], ignoring)
|
||||
end
|
||||
when Quizzes::QuizQuestion::QuestionData
|
||||
expect(a.to_hash).to eq b
|
||||
else
|
||||
expect(a).to eq b
|
||||
end
|
||||
end
|
||||
|
||||
def fname
|
||||
File.expand_path("../fixtures/spec-canvas-1.zip", __FILE__)
|
||||
end
|
||||
|
||||
def setup_migration(zip_path = fname)
|
||||
@migration = ContentMigration.new(:context => @course,
|
||||
:user => @user)
|
||||
@migration.update_migration_settings({
|
||||
:migration_type => 'qti_converter',
|
||||
:flavor => Qti::Flavors::RESPONDUS
|
||||
})
|
||||
@migration.save!
|
||||
|
||||
@attachment = Attachment.new
|
||||
@attachment.context = @migration
|
||||
@attachment.uploaded_data = File.open(zip_path, 'rb')
|
||||
@attachment.filename = 'qti_import_test1.zip'
|
||||
@attachment.save!
|
||||
|
||||
@migration.attachment = @attachment
|
||||
@migration.save!
|
||||
end
|
||||
|
||||
def do_migration
|
||||
Canvas::Migration::Worker::QtiWorker.new(@migration.id).perform
|
||||
@migration.reload
|
||||
expect(@migration).to be_imported
|
||||
end
|
||||
|
||||
RESPONDUS_QUESTIONS =
|
||||
let(:respondus_questions) do
|
||||
[{ "position" => 1,
|
||||
"correct_comments" => "This is the correct answer feedback",
|
||||
"question_type" => "multiple_choice_question",
|
||||
|
@ -425,6 +230,202 @@ if Qti.migration_executable
|
|||
{ "match_id" => 5875, "text" => "Distractor 1" },
|
||||
{ "match_id" => 2330, "text" => "Distractor 2" }],
|
||||
"question_text" => "This is the question text." }]
|
||||
end
|
||||
|
||||
it "imports duplicate files once, without munging" do
|
||||
setup_migration
|
||||
do_migration
|
||||
|
||||
expect(@course.attachments.count).to eq 2
|
||||
expect(@course.attachments.map(&:filename).sort).to eq ['header-logo.png', 'smiley.jpg']
|
||||
attachment = @course.attachments.detect { |a| a.filename == 'header-logo.png' }
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.quiz_questions.count).to eq 2
|
||||
quiz.quiz_questions.each do |q|
|
||||
text = Nokogiri::HTML5.fragment(q.question_data['question_text'])
|
||||
expect(text.css('img').first['src']).to eq "/courses/#{@course.id}/files/#{attachment.id}/preview"
|
||||
|
||||
# verify that the associated assessment_question got links translated
|
||||
aq = q.assessment_question
|
||||
text = Nokogiri::HTML5.fragment(aq.question_data['question_text'])
|
||||
expect(text.css('img').first['src']).to match %r{/assessment_questions/#{aq.id}/files/\d+/download\?verifier=\w+}
|
||||
|
||||
if aq.question_data['answers'][1]["comments_html"]&.include?("<img")
|
||||
text = Nokogiri::HTML5.fragment(aq.question_data['answers'][1]["comments_html"])
|
||||
expect(text.css('img').first['src']).to match %r{/assessment_questions/#{aq.id}/files/\d+/download\?verifier=\w+}
|
||||
end
|
||||
end
|
||||
expect(quiz.assignment).to_not be_nil
|
||||
end
|
||||
|
||||
it "brings in canvas meta data" do
|
||||
setup_migration(File.expand_path("fixtures/qti/canvas_qti.zip", __dir__))
|
||||
do_migration
|
||||
expect(@course.quizzes.count).to eq 1
|
||||
expect(@course.quizzes.first.description).to eq "<p>Quiz Description</p>"
|
||||
end
|
||||
|
||||
describe "applying respondus settings" do
|
||||
before do
|
||||
@copy = Tempfile.new(['spec-canvas', '.zip'])
|
||||
FileUtils.cp(fname, @copy.path)
|
||||
Zip::File.open(@copy.path) do |zf|
|
||||
zf.file.open("settings.xml", +'w') do |f|
|
||||
f.write <<-XML
|
||||
<settings>
|
||||
<setting name='hasSettings'>true</setting>
|
||||
<setting name='publishNow'>true</setting>
|
||||
</settings>
|
||||
XML
|
||||
end
|
||||
end
|
||||
setup_migration(@copy.path)
|
||||
@migration.update_migration_settings(:apply_respondus_settings_file => true)
|
||||
@migration.save!
|
||||
end
|
||||
|
||||
it "publishes as assignment on import if specified" do
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.assignment).not_to be_nil
|
||||
expect(quiz.assignment.title).to eq quiz.title
|
||||
expect(quiz.assignment).to be_published
|
||||
end
|
||||
|
||||
it "re-uses the same assignment on update" do
|
||||
do_migration
|
||||
|
||||
setup_migration(@copy.path)
|
||||
@migration.update_migration_settings(:apply_respondus_settings_file => true, :quiz_id_to_update => @course.quizzes.last.id)
|
||||
@migration.save!
|
||||
do_migration
|
||||
|
||||
expect(@course.quizzes.size).to eq 1
|
||||
expect(@course.assignments.size).to eq 1
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.assignment).not_to be_nil
|
||||
expect(quiz.assignment.title).to eq quiz.title
|
||||
expect(quiz.assignment).to be_published
|
||||
end
|
||||
|
||||
it "sets the assignment submission_type correctly" do
|
||||
do_migration
|
||||
assign = @course.assignments.last
|
||||
expect(assign.submission_types).to eq 'online_quiz'
|
||||
expect(assign.quiz).to be_for_assignment
|
||||
end
|
||||
end
|
||||
|
||||
it "publishes spec-canvas-1 correctly" do
|
||||
setup_migration
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz.quiz_questions.size).to eq 2
|
||||
# various checks on the data
|
||||
qq = quiz.quiz_questions.first
|
||||
d = qq.question_data
|
||||
expect(d['correct_comments']).to eq "I can't believe you got that right. Awesome!"
|
||||
expect(d['correct_comments_html']).to eq "I can't <i>believe </i>you got that right. <b>Awesome!</b>"
|
||||
expect(d['incorrect_comments_html']).to eq "<b>Wrong. </b>That's a bummer."
|
||||
expect(d['points_possible']).to eq 3
|
||||
expect(d['question_name']).to eq 'q1'
|
||||
expect(d['answers'].map { |a| a['weight'] }).to eq [0, 100, 0]
|
||||
expect(d['answers'].map { |a| a['comments'] }).to eq ['nope', 'yes!', nil]
|
||||
attachment = @course.attachments.detect { |a| a.filename == 'smiley.jpg' }
|
||||
expect(d['answers'].map { |a| a['comments_html'] }).to eq [nil, %{yes! <img src="/courses/#{@course.id}/files/#{attachment.id}/preview" alt="">}, nil]
|
||||
end
|
||||
|
||||
it "imports respondus question types" do
|
||||
setup_migration(File.expand_path("fixtures/canvas_respondus_question_types.zip", __dir__))
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz).not_to be_available
|
||||
expect(quiz.quiz_questions.size).to eq 9
|
||||
|
||||
match_ignoring(quiz.quiz_questions.map(&:question_data), respondus_questions, %w[id assessment_question_id match_id prepped_for_import is_quiz_question_bank question_bank_migration_id quiz_question_id])
|
||||
end
|
||||
|
||||
it "applies respondus settings" do
|
||||
setup_migration(File.expand_path("fixtures/canvas_respondus_question_types.zip", __dir__))
|
||||
@migration.update_migration_settings(:apply_respondus_settings_file => true)
|
||||
@migration.save!
|
||||
do_migration
|
||||
|
||||
quiz = @course.quizzes.last
|
||||
expect(quiz).to be_present
|
||||
expect(quiz).to be_available
|
||||
end
|
||||
|
||||
it "is able to import directly into an assessment question bank" do
|
||||
setup_migration(File.expand_path("fixtures/canvas_respondus_question_types.zip", __dir__))
|
||||
@migration.update_migration_settings(:migration_ids_to_import =>
|
||||
{ :copy => { :all_quizzes => false, :all_assessment_question_banks => true } })
|
||||
@migration.save!
|
||||
do_migration
|
||||
|
||||
expect(@course.quizzes.count).to eq 0
|
||||
qb = @course.assessment_question_banks.last
|
||||
expect(qb).to be_present
|
||||
expect(qb.assessment_questions.size).to eq 9
|
||||
data = qb.assessment_questions.map(&:question_data).sort_by! { |q| q["migration_id"] }
|
||||
match_ignoring(data, respondus_questions, %w[id assessment_question_id match_id missing_links position prepped_for_import is_quiz_question_bank question_bank_migration_id quiz_question_id])
|
||||
end
|
||||
|
||||
def match_ignoring(a, b, ignoring = []) # rubocop:disable Naming/MethodParameterName
|
||||
case a
|
||||
when Hash
|
||||
a_ = a.except(*ignoring)
|
||||
b_ = b.except(*ignoring)
|
||||
expect(a_.keys.sort).to eq b_.keys.sort
|
||||
a_.each { |k, v| match_ignoring(v, b[k], ignoring) }
|
||||
when Array
|
||||
expect(a.size).to eq b.size
|
||||
a.each_with_index do |e, i|
|
||||
match_ignoring(e.to_hash, b[i], ignoring)
|
||||
end
|
||||
when Quizzes::QuizQuestion::QuestionData
|
||||
expect(a.to_hash).to eq b
|
||||
else
|
||||
expect(a).to eq b
|
||||
end
|
||||
end
|
||||
|
||||
def fname
|
||||
File.expand_path("fixtures/spec-canvas-1.zip", __dir__)
|
||||
end
|
||||
|
||||
def setup_migration(zip_path = fname)
|
||||
@migration = ContentMigration.new(:context => @course,
|
||||
:user => @user)
|
||||
@migration.update_migration_settings({
|
||||
:migration_type => 'qti_converter',
|
||||
:flavor => Qti::Flavors::RESPONDUS
|
||||
})
|
||||
@migration.save!
|
||||
|
||||
@attachment = Attachment.new
|
||||
@attachment.context = @migration
|
||||
@attachment.uploaded_data = File.open(zip_path, 'rb')
|
||||
@attachment.filename = 'qti_import_test1.zip'
|
||||
@attachment.save!
|
||||
|
||||
@migration.attachment = @attachment
|
||||
@migration.save!
|
||||
end
|
||||
|
||||
def do_migration
|
||||
Canvas::Migration::Worker::QtiWorker.new(@migration.id).perform
|
||||
@migration.reload
|
||||
expect(@migration).to be_imported
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -33,15 +33,15 @@ unless defined? BASE_FIXTURE_DIR
|
|||
end
|
||||
require 'pp'
|
||||
|
||||
def get_question_hash(dir, name, delete_answer_ids = true, opts = {})
|
||||
def get_question_hash(dir, name, delete_answer_ids: true, **opts)
|
||||
hash = get_quiz_data(dir, name, opts).first.first
|
||||
hash[:answers].each { |a| a.delete(:id) } if delete_answer_ids
|
||||
hash
|
||||
end
|
||||
|
||||
def get_quiz_data(dir, name, opts = {})
|
||||
def get_quiz_data(dir, name, **opts)
|
||||
File.open(File.join(dir, '%s.xml' % name), 'r') do |file|
|
||||
Qti.convert_xml(file.read, opts)
|
||||
Qti.convert_xml(file.read, **opts)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
inherit_from: ../../../.rubocop.yml
|
||||
|
||||
Naming:
|
||||
Enabled: false # weird SOAP names
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
module RespondusSoapEndpoint
|
||||
class Railtie < ::Rails::Engine
|
||||
initializer "respondus_soap_endpoint.canvas_plugin" do |app|
|
||||
initializer "respondus_soap_endpoint.canvas_plugin" do
|
||||
require 'respondus_soap_endpoint/plugin_validator'
|
||||
Canvas::Plugin.register :respondus_soap_endpoint, nil, {
|
||||
name: -> { t :name, 'Respondus SOAP Endpoint' },
|
||||
|
|
|
@ -54,13 +54,13 @@ module RespondusSoapEndpoint
|
|||
|
||||
protected
|
||||
|
||||
class BadAuthError < Exception; end
|
||||
class BadAuthError < RuntimeError; end
|
||||
|
||||
class NeedDelegatedAuthError < Exception; end
|
||||
class NeedDelegatedAuthError < RuntimeError; end
|
||||
|
||||
class CantReplaceError < Exception; end
|
||||
class CantReplaceError < RuntimeError; end
|
||||
|
||||
class OtherError < Exception
|
||||
class OtherError < RuntimeError
|
||||
attr_reader :errorStatus
|
||||
|
||||
def initialize(errorStatus, msg = nil)
|
||||
|
@ -96,7 +96,7 @@ module RespondusSoapEndpoint
|
|||
@verifier.generate(session)
|
||||
end
|
||||
|
||||
def load_user_with_oauth(token, domain_root_account)
|
||||
def load_user_with_oauth(token)
|
||||
token = AccessToken.authenticate(token)
|
||||
if !token.try(:user)
|
||||
raise(BadAuthError)
|
||||
|
@ -112,7 +112,7 @@ module RespondusSoapEndpoint
|
|||
domain_root_account = rack_env['canvas.domain_root_account'] || Account.default
|
||||
if userName == OAUTH_TOKEN_USERNAME
|
||||
# password is the oauth token
|
||||
return load_user_with_oauth(password, domain_root_account)
|
||||
return load_user_with_oauth(password)
|
||||
end
|
||||
|
||||
Authlogic::Session::Base.controller = AuthlogicAdapter.new(self)
|
||||
|
@ -148,8 +148,8 @@ module RespondusSoapEndpoint
|
|||
load_session(context)
|
||||
return_args = send("_#{method}", userName, password, context, *args) || []
|
||||
["Success", '', dump_session] + return_args
|
||||
rescue Exception => ex
|
||||
case ex
|
||||
rescue => e
|
||||
case e
|
||||
when NotImplementedError
|
||||
["Function not implemented"]
|
||||
when BadAuthError
|
||||
|
@ -161,24 +161,28 @@ module RespondusSoapEndpoint
|
|||
when CantReplaceError
|
||||
["Item cannot be replaced"]
|
||||
when OtherError
|
||||
[ex.errorStatus, '']
|
||||
[e.errorStatus, '']
|
||||
else
|
||||
Rails.logger.error "Error in Respondus API call: #{ex.inspect}\n#{ex.backtrace.join("\n")}"
|
||||
Rails.logger.error "Error in Respondus API call: #{e.inspect}\n#{e.backtrace.join("\n")}"
|
||||
["Server failure"]
|
||||
end
|
||||
end
|
||||
|
||||
def self.wrap_api_call(*methods)
|
||||
methods.each do |method|
|
||||
alias_method "_#{method}", method
|
||||
class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
|
||||
def #{method}(userName, password, context, *args)
|
||||
ret = nil
|
||||
ms = [Benchmark.ms { ret = make_call(:#{method}, userName, password, context, *args) }, 0.01].max
|
||||
Rails.logger.debug "Completed in \#{ms}ms | \#{ret.first.inspect} [Respondus SOAP API]\\n"
|
||||
ret
|
||||
class << self
|
||||
protected
|
||||
|
||||
def wrap_api_call(*methods)
|
||||
methods.each do |method|
|
||||
alias_method "_#{method}", method
|
||||
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
||||
def #{method}(userName, password, context, *args)
|
||||
ret = nil
|
||||
ms = [Benchmark.ms { ret = make_call(:#{method}, userName, password, context, *args) }, 0.01].max
|
||||
Rails.logger.debug "Completed in \#{ms}ms | \#{ret.first.inspect} [Respondus SOAP API]\\n"
|
||||
ret
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -198,7 +202,7 @@ module RespondusSoapEndpoint
|
|||
# context C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
# identification C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
#
|
||||
def identifyServer(userName, password, context)
|
||||
def identifyServer(_userName, _password, _context)
|
||||
return [%{
|
||||
Respondus Generic Server API
|
||||
Contract version: 1
|
||||
|
@ -219,7 +223,7 @@ Implemented for: Canvas LMS}]
|
|||
# serverStatus C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
# context C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
#
|
||||
def validateAuth(userName, password, context, institution)
|
||||
def validateAuth(_userName, _password, _context, _institution)
|
||||
# The validation happens in load_user
|
||||
[]
|
||||
end
|
||||
|
@ -239,7 +243,7 @@ Implemented for: Canvas LMS}]
|
|||
# context C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
# itemList NVPairList - {urn:RespondusAPI}NVPairList
|
||||
#
|
||||
def getServerItems(userName, password, context, itemType)
|
||||
def getServerItems(_userName, _password, _context, itemType)
|
||||
selection_state = session['selection_state'] || []
|
||||
|
||||
list = NVPairList.new
|
||||
|
@ -336,7 +340,7 @@ Implemented for: Canvas LMS}]
|
|||
# context C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
# itemID C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
#
|
||||
def publishServerItem(userName, password, context, itemType, itemName, uploadType, fileName, fileData)
|
||||
def publishServerItem(_userName, _password, _context, itemType, _itemName, uploadType, fileName, fileData)
|
||||
do_import(nil, itemType, uploadType, fileName, fileData)
|
||||
end
|
||||
|
||||
|
@ -377,7 +381,7 @@ Implemented for: Canvas LMS}]
|
|||
# serverStatus C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
# context C_String - {http://www.w3.org/2001/XMLSchema}string
|
||||
#
|
||||
def replaceServerItem(userName, password, context, itemType, itemID, uploadType, fileName, fileData)
|
||||
def replaceServerItem(_userName, _password, _context, itemType, itemID, uploadType, fileName, fileData)
|
||||
scope = get_scope(session, itemType)
|
||||
item = scope.where(id: itemID).first
|
||||
raise(CantReplaceError) unless item
|
||||
|
@ -526,7 +530,7 @@ Implemented for: Canvas LMS}]
|
|||
|
||||
ATTACHMENT_FOLDER_NAME = 'imported qti files'
|
||||
|
||||
def do_import(item, itemType, uploadType, fileName, fileData)
|
||||
def do_import(item, itemType, uploadType, _fileName, fileData)
|
||||
if fileData == "\x0" && session['pending_migration_id']
|
||||
return poll_for_completion()
|
||||
end
|
||||
|
@ -599,7 +603,7 @@ Implemented for: Canvas LMS}]
|
|||
loop do
|
||||
ret = poll_for_completion()
|
||||
if ret == ['pending']
|
||||
sleep(Setting.get('respondus_endpoint.polling_time', '2').to_f)
|
||||
sleep(Setting.get('respondus_endpoint.polling_time', '2').to_f) # rubocop:disable Lint/NoSleep
|
||||
else
|
||||
return ret
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../../../../spec/spec_hel
|
|||
require 'soap/rpc/driver'
|
||||
|
||||
class SpecStreamHandler < SOAP::StreamHandler
|
||||
def send(url, conn_data, soapaction = nil, charset = nil)
|
||||
def send(_url, conn_data, _soapaction = nil, _charset = nil)
|
||||
response = @capture_block.call(conn_data.send_string, {})
|
||||
conn_data.receive_string = response.body
|
||||
conn_data.receive_contenttype = response['Content-Type']
|
||||
|
@ -34,7 +34,7 @@ class SpecStreamHandler < SOAP::StreamHandler
|
|||
obj.send(method, *args)
|
||||
end
|
||||
|
||||
def self.create(*a)
|
||||
def self.create(*)
|
||||
new
|
||||
end
|
||||
end
|
||||
|
@ -143,20 +143,20 @@ Implemented for: Canvas LMS}
|
|||
['Institution', ''])
|
||||
expect(soap_response.first).to eq "Success"
|
||||
|
||||
status, details, context, list = soap_request('GetServerItems',
|
||||
uname, @token.full_token,
|
||||
'', ['itemType', 'course'])
|
||||
status, _details, context, list = soap_request('GetServerItems',
|
||||
uname, @token.full_token,
|
||||
'', ['itemType', 'course'])
|
||||
expect(status).to eq "Success"
|
||||
pair = list.item
|
||||
expect(pair.name).to eq "value for name"
|
||||
expect(pair.value).to eq @course.to_param
|
||||
|
||||
# verify that the respondus api session works with token auth
|
||||
status, details, context = soap_request('SelectServerItem',
|
||||
uname, @token.full_token,
|
||||
context, ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
status, _details, _context = soap_request('SelectServerItem',
|
||||
uname, @token.full_token,
|
||||
context, ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
expect(status).to eq "Success"
|
||||
end
|
||||
|
||||
|
@ -170,64 +170,63 @@ Implemented for: Canvas LMS}
|
|||
end
|
||||
|
||||
it "rejects a session created for a different user" do
|
||||
user1 = @user
|
||||
user2 = user_with_pseudonym :active_user => true,
|
||||
:username => "nobody2@example.com",
|
||||
:password => "test1234"
|
||||
user2.save!
|
||||
|
||||
status, details, context = soap_request('ValidateAuth',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'',
|
||||
['Institution', ''])
|
||||
expect(status).to eq "Success"
|
||||
status, details, context = soap_request('ValidateAuth',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context,
|
||||
['Institution', ''])
|
||||
expect(status).to eq "Success"
|
||||
status, details, context2 = soap_request('ValidateAuth',
|
||||
'nobody2@example.com', 'test1234',
|
||||
status, _details, context = soap_request('ValidateAuth',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'',
|
||||
['Institution', ''])
|
||||
expect(status).to eq "Success"
|
||||
status, details, context2 = soap_request('ValidateAuth',
|
||||
'nobody2@example.com', 'test1234',
|
||||
status, _details, context = soap_request('ValidateAuth',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context,
|
||||
['Institution', ''])
|
||||
expect(status).to eq "Success"
|
||||
status, _details, _context2 = soap_request('ValidateAuth',
|
||||
'nobody2@example.com', 'test1234',
|
||||
'',
|
||||
['Institution', ''])
|
||||
expect(status).to eq "Success"
|
||||
status, _details, _context2 = soap_request('ValidateAuth',
|
||||
'nobody2@example.com', 'test1234',
|
||||
context,
|
||||
['Institution', ''])
|
||||
expect(status).to eq "Invalid context"
|
||||
end
|
||||
|
||||
it "allows selecting a course" do
|
||||
status, details, context, list = soap_request('GetServerItems',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'', ['itemType', 'course'])
|
||||
status, _details, context, list = soap_request('GetServerItems',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'', ['itemType', 'course'])
|
||||
expect(status).to eq "Success"
|
||||
pair = list.item
|
||||
expect(pair.name).to eq "value for name"
|
||||
expect(pair.value).to eq @course.to_param
|
||||
|
||||
# select the course
|
||||
status, details, context = soap_request('SelectServerItem',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context, ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
status, _details, context = soap_request('SelectServerItem',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context, ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
expect(status).to eq "Success"
|
||||
|
||||
# list the existing quizzes
|
||||
status, details, context, list = soap_request('GetServerItems',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context, ['itemType', 'quiz'])
|
||||
status, _details, context, list = soap_request('GetServerItems',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context, ['itemType', 'quiz'])
|
||||
expect(status).to eq "Success"
|
||||
pair = list.item
|
||||
expect(pair.name).to eq "quiz1"
|
||||
expect(pair.value).to eq @quiz.to_param
|
||||
|
||||
# list the existing question banks
|
||||
status, details, context, list = soap_request('GetServerItems',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context, ['itemType', 'qdb'])
|
||||
status, _details, context, list = soap_request('GetServerItems',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
context, ['itemType', 'qdb'])
|
||||
expect(status).to eq "Success"
|
||||
pair = list.item
|
||||
expect(pair.name).to eq "questionbank1"
|
||||
|
@ -241,11 +240,11 @@ Implemented for: Canvas LMS}
|
|||
it "queues QTI quiz uploads for processing" do
|
||||
Setting.set('respondus_endpoint.polling_api', 'false')
|
||||
|
||||
status, details, context = soap_request('SelectServerItem',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'', ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
status, _details, context = soap_request('SelectServerItem',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'', ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
expect(status).to eq "Success"
|
||||
|
||||
mock_migration = ContentMigration.create!(context: @course)
|
||||
|
@ -256,7 +255,7 @@ Implemented for: Canvas LMS}
|
|||
allow(ContentMigration).to receive(:new).and_return(mock_migration)
|
||||
allow(ContentMigration).to receive(:find).with(mock_migration.id).and_return(mock_migration)
|
||||
|
||||
status, details, context, item_id = soap_request(
|
||||
status, _details, _context, item_id = soap_request(
|
||||
'PublishServerItem', 'nobody@example.com', 'asdfasdf', context,
|
||||
['itemType', 'quiz'], ['itemName', 'my quiz'], ['uploadType', 'zipPackage'],
|
||||
['fileName', 'import.zip'], ['fileData', 'pretend this is a zip file']
|
||||
|
@ -273,11 +272,11 @@ Implemented for: Canvas LMS}
|
|||
|
||||
describe "polling publish" do
|
||||
before do
|
||||
status, details, context = soap_request('SelectServerItem',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'', ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
_status, _details, context = soap_request('SelectServerItem',
|
||||
'nobody@example.com', 'asdfasdf',
|
||||
'', ['itemType', 'course'],
|
||||
['itemID', @course.to_param],
|
||||
['clearState', ''])
|
||||
@mock_migration = ContentMigration.create!(context: @course)
|
||||
def @mock_migration.export_content
|
||||
self.workflow_state = 'importing'
|
||||
|
@ -285,7 +284,7 @@ Implemented for: Canvas LMS}
|
|||
allow(ContentMigration).to receive(:new).and_return(@mock_migration)
|
||||
allow(ContentMigration).to receive(:find).with(@mock_migration.id).and_return(@mock_migration)
|
||||
|
||||
status, details, context, item_id = soap_request(
|
||||
_status, _details, context, _item_id = soap_request(
|
||||
'PublishServerItem', 'nobody@example.com', 'asdfasdf', context,
|
||||
['itemType', 'quiz'], ['itemName', 'my quiz'], ['uploadType', 'zipPackage'],
|
||||
['fileName', 'import.zip'], ['fileData', 'pretend this is a zip file']
|
||||
|
@ -294,7 +293,7 @@ Implemented for: Canvas LMS}
|
|||
end
|
||||
|
||||
it "responds immediately and allow polling for completion" do
|
||||
status, details, context, item_id = soap_request(
|
||||
status, _details, context, item_id = soap_request(
|
||||
'PublishServerItem', 'nobody@example.com', 'asdfasdf', @token,
|
||||
['itemType', 'quiz'], ['itemName', 'my quiz'], ['uploadType', 'zipPackage'],
|
||||
['fileName', 'import.zip'], ['fileData', "\x0"]
|
||||
|
@ -306,7 +305,7 @@ Implemented for: Canvas LMS}
|
|||
@mock_migration.migration_settings[:imported_assets] = ["quizzes:quiz_xyz"]
|
||||
@mock_migration.workflow_state = 'imported'
|
||||
|
||||
status, details, context, item_id = soap_request(
|
||||
status, _details, _context, item_id = soap_request(
|
||||
'PublishServerItem', 'nobody@example.com', 'asdfasdf', @token,
|
||||
['itemType', 'quiz'], ['itemName', 'my quiz'], ['uploadType', 'zipPackage'],
|
||||
['fileName', 'import.zip'], ['fileData', "\x0"]
|
||||
|
@ -319,7 +318,7 @@ Implemented for: Canvas LMS}
|
|||
@mock_migration.migration_settings[:imported_assets] = []
|
||||
@mock_migration.workflow_state = 'failed'
|
||||
|
||||
status, details, context, item_id = soap_request(
|
||||
status, _details, _context, item_id = soap_request(
|
||||
'PublishServerItem', 'nobody@example.com', 'asdfasdf', @token,
|
||||
['itemType', 'quiz'], ['itemName', 'my quiz'], ['uploadType', 'zipPackage'],
|
||||
['fileName', 'import.zip'], ['fileData', "\x0"]
|
||||
|
|
|
@ -21,7 +21,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../../../spec/apis/api_sp
|
|||
|
||||
describe 'simply_versioned' do
|
||||
before :all do
|
||||
class Woozel < ActiveRecord::Base
|
||||
class Woozel < ActiveRecord::Base # rubocop:disable Lint/ConstantDefinitionInBlock,RSpec/LeakyConstantDeclaration this needs to be a real class
|
||||
simply_versioned :explicit => true
|
||||
end
|
||||
|
||||
|
@ -206,7 +206,7 @@ describe 'simply_versioned' do
|
|||
let(:woozel) { Woozel.create!(name: 'test') }
|
||||
context "on_load" do
|
||||
let(:on_load) do
|
||||
lambda { |model, version| model.name = 'test override' }
|
||||
lambda { |model, _version| model.name = 'test override' }
|
||||
end
|
||||
before do
|
||||
woozel.simply_versioned_options[:on_load] = on_load
|
||||
|
|
Loading…
Reference in New Issue