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:
Cody Cutrer 2021-10-08 15:29:08 -06:00
parent 387d11d7d0
commit cfce475310
28 changed files with 440 additions and 424 deletions

23
gems/plugins/.rubocop.yml Normal file
View File

@ -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/, "")
%>

View File

@ -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,

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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)

View File

@ -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|

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,4 @@
inherit_from: ../../../.rubocop.yml
Naming:
Enabled: false # weird SOAP names

View File

@ -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' },

View File

@ -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

View File

@ -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"]

View File

@ -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