moodle2cc 0.2.42 → 0.2.44
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/moodle2cc/canvas_cc/models/assessment.rb +29 -20
- data/lib/moodle2cc/canvas_cc/models/question.rb +21 -15
- data/lib/moodle2cc/moodle2/models/quizzes/question.rb +23 -7
- data/lib/moodle2cc/moodle2/parsers/question_category_parser.rb +31 -21
- data/lib/moodle2cc/moodle2/parsers/question_parsers/question_parser.rb +30 -31
- data/lib/moodle2cc/moodle2/parsers/quiz_parser.rb +54 -52
- data/lib/moodle2cc/moodle2converter/question_converters/question_converter.rb +16 -12
- data/lib/moodle2cc/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8baf72f07d2a65667b1a1e8d8f62f0e87141e3c0e4cf719cb1502acefb89d70e
|
4
|
+
data.tar.gz: 3968532ffd944fb71159b2df750ad7bc5910868ade76cf94a6f95033b5274a15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d542c7bd25ccfddb029d128beb3bc6e3178087934ccf862a1488a341936b3393d6ca04899e9942d7776ed05ca739f7d7ec0b18b3154f525eec1adea4cf3d6389
|
7
|
+
data.tar.gz: 1908583476f19256292888175ed355e5d3e90b0fc2203cd4604be7bbf849885a96fa4f252263c500c8b6c0a272ffc060ebf50e70b07810557780f3bf6c1f906d
|
@@ -1,12 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Moodle2CC::CanvasCC::Models
|
2
4
|
class Assessment
|
3
|
-
META_ATTRIBUTES = [
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
META_ATTRIBUTES = %i[title
|
6
|
+
description
|
7
|
+
allowed_attempts
|
8
|
+
scoring_policy
|
9
|
+
access_code
|
10
|
+
ip_filter
|
11
|
+
shuffle_answers
|
12
|
+
time_limit
|
13
|
+
quiz_type].freeze
|
14
|
+
DATETIME_ATTRIBUTES = [:lock_at, :unlock_at].freeze
|
15
|
+
|
16
|
+
ASSESSMENT_TYPE = "imsqti_xmlv1p2/imscc_xmlv1p1/assessment"
|
17
|
+
LAR_TYPE = "associatedcontent/imscc_xmlv1p1/learning-application-resource"
|
18
|
+
ASSESSMENT_NON_CC_FOLDER = "non_cc_assessments"
|
10
19
|
|
11
20
|
attr_accessor :identifier, :workflow_state, :question_references, :items, *META_ATTRIBUTES, *DATETIME_ATTRIBUTES
|
12
21
|
|
@@ -54,14 +63,15 @@ module Moodle2CC::CanvasCC::Models
|
|
54
63
|
question = nil
|
55
64
|
group = nil
|
56
65
|
question_banks.each do |bank|
|
57
|
-
break if (question = bank.questions.detect{|q| q.original_identifier.to_s == ref[:question]})
|
58
|
-
|
66
|
+
break if (question = bank.questions.detect { |q| q.original_identifier.to_s == ref[:question] })
|
67
|
+
break if (question = bank.questions.detect { |q| q.bank_entry_id.to_s == ref[:bank_entry_id] })
|
68
|
+
break if (group = bank.question_groups.detect { |g| g.identifier.to_s == ref[:question] })
|
59
69
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
70
|
+
next unless bank.random_question_references.any? { |r| r.to_s == ref[:question] }
|
71
|
+
|
72
|
+
random_bank_counts[bank] ||= 0
|
73
|
+
random_bank_counts[bank] += 1
|
74
|
+
break
|
65
75
|
end
|
66
76
|
|
67
77
|
if question
|
@@ -83,21 +93,20 @@ module Moodle2CC::CanvasCC::Models
|
|
83
93
|
new_group = Moodle2CC::CanvasCC::Models::QuestionGroup.new
|
84
94
|
new_group.identifier = "#{@identifier}#{bank.identifier}_random_group"
|
85
95
|
new_group.selection_number = count
|
86
|
-
|
87
|
-
new_group.questions = bank.questions.map(&:dup)
|
96
|
+
new_group.questions = bank.questions.map(&:dup).map{|q| (q.identifier = "random_#{q.identifier}") && q }
|
88
97
|
child_banks = bank.find_children_banks(question_banks)
|
89
98
|
child_banks.each do |child|
|
90
|
-
new_group.questions += child.questions.map(&:dup)
|
99
|
+
new_group.questions += child.questions.map(&:dup).map{|q| (q.identifier = "random_#{q.identifier}") && q }
|
91
100
|
end
|
92
101
|
|
93
102
|
@items << new_group
|
94
103
|
end
|
95
104
|
|
96
|
-
@items.select{|i| i.is_a?(Moodle2CC::CanvasCC::Models::QuestionGroup)}.each do |group|
|
105
|
+
@items.select { |i| i.is_a?(Moodle2CC::CanvasCC::Models::QuestionGroup) }.each do |group|
|
97
106
|
group.questions.each do |q|
|
98
|
-
@items.delete_if{|i| i.respond_to?(:original_identifier) && i.original_identifier == q.original_identifier}
|
107
|
+
@items.delete_if { |i| i.respond_to?(:original_identifier) && i.original_identifier == q.original_identifier }
|
99
108
|
end
|
100
109
|
end
|
101
110
|
end
|
102
111
|
end
|
103
|
-
end
|
112
|
+
end
|
@@ -1,22 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Moodle2CC::CanvasCC::Models
|
2
4
|
class Question
|
3
|
-
QTI_META_ATTRIBUTES = [
|
4
|
-
STANDARD_QUESTION_TYPES = [
|
5
|
-
|
6
|
-
|
5
|
+
QTI_META_ATTRIBUTES = %i[question_type points_possible assessment_question_identifierref].freeze
|
6
|
+
STANDARD_QUESTION_TYPES = %w[essay_question
|
7
|
+
fill_in_multiple_blanks_question
|
8
|
+
multiple_choice_question
|
9
|
+
multiple_answers_question
|
10
|
+
short_answer_question
|
11
|
+
text_only_question
|
12
|
+
true_false_question].freeze
|
7
13
|
|
8
|
-
attr_accessor :identifier, :original_identifier, :title, :material, :answers, :general_feedback, *QTI_META_ATTRIBUTES
|
14
|
+
attr_accessor :identifier, :original_identifier, :bank_entry_id, :title, :material, :answers, :general_feedback, *QTI_META_ATTRIBUTES
|
9
15
|
|
10
16
|
@@subclasses = {}
|
11
17
|
|
12
18
|
def self.create(type)
|
13
19
|
q = if STANDARD_QUESTION_TYPES.include?(type)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
+
new
|
21
|
+
elsif (c = @@subclasses[type])
|
22
|
+
c.new
|
23
|
+
else
|
24
|
+
raise "Unknown question type: #{type}"
|
25
|
+
end
|
20
26
|
q.question_type = type
|
21
27
|
q
|
22
28
|
end
|
@@ -31,7 +37,7 @@ module Moodle2CC::CanvasCC::Models
|
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
34
|
-
require_relative
|
35
|
-
require_relative
|
36
|
-
require_relative
|
37
|
-
require_relative
|
40
|
+
require_relative "calculated_question"
|
41
|
+
require_relative "matching_question"
|
42
|
+
require_relative "multiple_dropdowns_question"
|
43
|
+
require_relative "numerical_question"
|
@@ -1,17 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Moodle2CC::Moodle2::Models::Quizzes
|
2
4
|
class Question
|
3
|
-
|
4
5
|
@@subclasses = {}
|
5
6
|
|
6
|
-
STANDARD_TYPES = [
|
7
|
+
STANDARD_TYPES = %w[description essay random shortanswer].freeze
|
7
8
|
|
8
9
|
def self.create(type)
|
9
|
-
if c = @@subclasses[type]
|
10
|
+
if (c = @@subclasses[type])
|
10
11
|
q = c.new
|
11
12
|
q.type = type
|
12
13
|
q
|
13
14
|
elsif STANDARD_TYPES.include?(type)
|
14
|
-
q =
|
15
|
+
q = new
|
15
16
|
q.type = type
|
16
17
|
q
|
17
18
|
else
|
@@ -23,11 +24,26 @@ module Moodle2CC::Moodle2::Models::Quizzes
|
|
23
24
|
@@subclasses[name] = self
|
24
25
|
end
|
25
26
|
|
26
|
-
attr_accessor :id,
|
27
|
-
:
|
27
|
+
attr_accessor :id,
|
28
|
+
:bank_entry_id,
|
29
|
+
:parent,
|
30
|
+
:name,
|
31
|
+
:question_text,
|
32
|
+
:question_text_format,
|
33
|
+
:general_feedback,
|
34
|
+
:default_mark,
|
35
|
+
:max_mark,
|
36
|
+
:penalty,
|
37
|
+
:qtype,
|
38
|
+
:length,
|
39
|
+
:stamp,
|
40
|
+
:version,
|
41
|
+
:hidden,
|
42
|
+
:answers,
|
43
|
+
:type
|
28
44
|
|
29
45
|
def initialize
|
30
46
|
@answers = []
|
31
47
|
end
|
32
48
|
end
|
33
|
-
end
|
49
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Moodle2CC::Moodle2
|
2
4
|
class Parsers::QuestionCategoryParser
|
3
5
|
include Parsers::ParserHelper
|
4
6
|
|
5
|
-
QUESTIONS_XML =
|
7
|
+
QUESTIONS_XML = "questions.xml"
|
6
8
|
|
7
9
|
def initialize(backup_dir)
|
8
10
|
@backup_dir = backup_dir
|
@@ -11,7 +13,7 @@ module Moodle2CC::Moodle2
|
|
11
13
|
def parse
|
12
14
|
File.open(File.join(@backup_dir, QUESTIONS_XML)) do |f|
|
13
15
|
root_xml = Nokogiri::XML(f)
|
14
|
-
root_xml.search(
|
16
|
+
root_xml.search("/question_categories/question_category").map { |node| question_category_parser(node) }
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
@@ -19,30 +21,38 @@ module Moodle2CC::Moodle2
|
|
19
21
|
|
20
22
|
def question_category_parser(node)
|
21
23
|
category = Models::Quizzes::QuestionCategory.new
|
22
|
-
category.id = node.at_xpath(
|
23
|
-
category.name = parse_text(node,
|
24
|
-
category.context_id = parse_text(node,
|
25
|
-
category.context_level = parse_text(node,
|
26
|
-
category.context_instance_id = parse_text(node,
|
27
|
-
category.info = parse_text(node,
|
28
|
-
category.info_format = parse_text(node,
|
29
|
-
category.stamp = parse_text(node,
|
30
|
-
category.parent = parse_text(node,
|
31
|
-
category.sort_order = parse_text(node,
|
32
|
-
|
33
|
-
category.questions += node.search(
|
24
|
+
category.id = node.at_xpath("@id").value
|
25
|
+
category.name = parse_text(node, "name")
|
26
|
+
category.context_id = parse_text(node, "contextid")
|
27
|
+
category.context_level = parse_text(node, "contextlevel")
|
28
|
+
category.context_instance_id = parse_text(node, "contextinstanceid")
|
29
|
+
category.info = parse_text(node, "info")
|
30
|
+
category.info_format = parse_text(node, "infoformat")
|
31
|
+
category.stamp = parse_text(node, "stamp")
|
32
|
+
category.parent = parse_text(node, "parent")
|
33
|
+
category.sort_order = parse_text(node, "sortorder")
|
34
|
+
|
35
|
+
category.questions += node.search("questions/question").filter_map { |question_node| question_parser(question_node) }
|
36
|
+
category.questions += node.search("question_bank_entries/question_bank_entry").map do |question_bank_entry|
|
37
|
+
question_bank_entry.search("question_version/question_versions").map do |question_versions|
|
38
|
+
question_versions.search("questions/question").map do |question_node|
|
39
|
+
bank_entry_reference = Nokogiri::XML::DocumentFragment.parse("<bank_entry_id>#{question_bank_entry.at_xpath("@id").value}</bank_entry_id>")
|
40
|
+
question_node.add_child(bank_entry_reference)
|
41
|
+
question_parser(question_node)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end.flatten.compact
|
45
|
+
|
46
|
+
category.questions = category.questions.flatten
|
34
47
|
|
35
48
|
category
|
36
49
|
end
|
37
50
|
|
38
51
|
def question_parser(node)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
nil
|
44
|
-
end
|
52
|
+
Parsers::QuestionParsers::QuestionParser.parse(node)
|
53
|
+
rescue Exception => e
|
54
|
+
Moodle2CC::OutputLogger.logger.info e.message
|
55
|
+
nil
|
45
56
|
end
|
46
|
-
|
47
57
|
end
|
48
58
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Moodle2CC::Moodle2
|
2
4
|
class Parsers::QuestionParsers::QuestionParser
|
3
5
|
include Parsers::ParserHelper
|
@@ -5,8 +7,8 @@ module Moodle2CC::Moodle2
|
|
5
7
|
@@subclasses = {}
|
6
8
|
|
7
9
|
def self.parse(node)
|
8
|
-
type = node.%(
|
9
|
-
if c = @@subclasses[type]
|
10
|
+
type = node.%("qtype").text
|
11
|
+
if (c = @@subclasses[type])
|
10
12
|
c.new.parse_question(node)
|
11
13
|
else
|
12
14
|
raise "Unknown parser type: #{type}"
|
@@ -18,37 +20,34 @@ module Moodle2CC::Moodle2
|
|
18
20
|
end
|
19
21
|
|
20
22
|
# simple question types
|
21
|
-
register_parser_type(
|
22
|
-
register_parser_type(
|
23
|
-
register_parser_type(
|
23
|
+
register_parser_type("description")
|
24
|
+
register_parser_type("essay")
|
25
|
+
register_parser_type("random")
|
24
26
|
|
25
27
|
def parse_question(node, question_type = nil)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
28
|
+
question_type ||= parse_text(node, "qtype")
|
29
|
+
question = Models::Quizzes::Question.create question_type
|
30
|
+
|
31
|
+
question.id = node.at_xpath("@id").value
|
32
|
+
question.bank_entry_id = parse_text(node, "bank_entry_id")
|
33
|
+
question.parent = parse_text(node, "parent")
|
34
|
+
question.name = parse_text(node, "name")
|
35
|
+
question.question_text = parse_text(node, "questiontext")
|
36
|
+
question.question_text_format = parse_text(node, "questiontextformat")
|
37
|
+
question.general_feedback = parse_text(node, "generalfeedback")
|
38
|
+
question.default_mark = parse_text(node, "defaultmark")
|
39
|
+
question.max_mark = parse_text(node, "maxmark")
|
40
|
+
question.penalty = parse_text(node, "penalty")
|
41
|
+
question.qtype = parse_text(node, "qtype")
|
42
|
+
question.length = parse_text(node, "length")
|
43
|
+
question.stamp = parse_text(node, "stamp")
|
44
|
+
question.version = parse_text(node, "version")
|
45
|
+
question.hidden = parse_boolean(node, "hidden")
|
46
|
+
|
47
|
+
question
|
48
|
+
rescue Exception => e
|
49
|
+
Moodle2CC::OutputLogger.logger.info e.message
|
50
|
+
nil
|
50
51
|
end
|
51
|
-
|
52
|
-
|
53
52
|
end
|
54
53
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Moodle2CC::Moodle2::Parsers
|
2
4
|
class QuizParser
|
3
5
|
include ParserHelper
|
4
6
|
|
5
|
-
QUIZ_XML =
|
6
|
-
QUIZ_MODULE_NAME =
|
7
|
+
QUIZ_XML = "quiz.xml"
|
8
|
+
QUIZ_MODULE_NAME = "quiz"
|
7
9
|
|
8
10
|
def initialize(backup_dir)
|
9
11
|
@backup_dir = backup_dir
|
@@ -21,65 +23,66 @@ module Moodle2CC::Moodle2::Parsers
|
|
21
23
|
activity_dir = File.join(@backup_dir, dir)
|
22
24
|
File.open(File.join(activity_dir, QUIZ_XML)) do |f|
|
23
25
|
xml = Nokogiri::XML(f)
|
24
|
-
quiz.id = xml.at_xpath(
|
25
|
-
quiz.module_id = xml.at_xpath(
|
26
|
-
quiz.name = parse_text(xml,
|
27
|
-
quiz.intro = parse_text(xml,
|
28
|
-
quiz.intro_format = parse_text(xml,
|
29
|
-
quiz.time_open = parse_text(xml,
|
30
|
-
quiz.time_close = parse_text(xml,
|
31
|
-
quiz.time_limit = parse_text(xml,
|
32
|
-
quiz.overdue_handling = parse_text(xml,
|
33
|
-
quiz.grace_period = parse_text(xml,
|
34
|
-
quiz.preferred_behavior = parse_text(xml,
|
35
|
-
quiz.attempts_number = parse_text(xml,
|
36
|
-
quiz.attempt_on_last = parse_text(xml,
|
37
|
-
quiz.grade_method = parse_text(xml,
|
38
|
-
quiz.decimal_points = parse_text(xml,
|
39
|
-
quiz.question_decimal_points = parse_text(xml,
|
40
|
-
quiz.review_attempt = parse_text(xml,
|
41
|
-
quiz.review_correctness = parse_text(xml,
|
42
|
-
quiz.review_marks = parse_text(xml,
|
43
|
-
quiz.review_specific_feedback = parse_text(xml,
|
44
|
-
quiz.review_general_feedback = parse_text(xml,
|
45
|
-
quiz.review_right_answer = parse_text(xml,
|
46
|
-
quiz.review_overall_feedback = parse_text(xml,
|
47
|
-
quiz.questions_per_page = parse_text(xml,
|
48
|
-
quiz.nav_method = parse_text(xml,
|
26
|
+
quiz.id = xml.at_xpath("/activity/quiz/@id").value
|
27
|
+
quiz.module_id = xml.at_xpath("/activity/@moduleid").value
|
28
|
+
quiz.name = parse_text(xml, "/activity/quiz/name")
|
29
|
+
quiz.intro = parse_text(xml, "/activity/quiz/intro")
|
30
|
+
quiz.intro_format = parse_text(xml, "/activity/quiz/introformat")
|
31
|
+
quiz.time_open = parse_text(xml, "/activity/quiz/timeopen")
|
32
|
+
quiz.time_close = parse_text(xml, "/activity/quiz/timeclose")
|
33
|
+
quiz.time_limit = parse_text(xml, "/activity/quiz/timelimit")
|
34
|
+
quiz.overdue_handling = parse_text(xml, "/activity/quiz/overduehandling")
|
35
|
+
quiz.grace_period = parse_text(xml, "/activity/quiz/graceperiod")
|
36
|
+
quiz.preferred_behavior = parse_text(xml, "/activity/quiz/preferredbehaviour")
|
37
|
+
quiz.attempts_number = parse_text(xml, "/activity/quiz/attempts_number")
|
38
|
+
quiz.attempt_on_last = parse_text(xml, "/activity/quiz/attemptonlast")
|
39
|
+
quiz.grade_method = parse_text(xml, "/activity/quiz/grademethod")
|
40
|
+
quiz.decimal_points = parse_text(xml, "/activity/quiz/decimalpoints")
|
41
|
+
quiz.question_decimal_points = parse_text(xml, "/activity/quiz/questiondecimalpoints")
|
42
|
+
quiz.review_attempt = parse_text(xml, "/activity/quiz/reviewattempt")
|
43
|
+
quiz.review_correctness = parse_text(xml, "/activity/quiz/reviewcorrectness")
|
44
|
+
quiz.review_marks = parse_text(xml, "/activity/quiz/reviewmarks")
|
45
|
+
quiz.review_specific_feedback = parse_text(xml, "/activity/quiz/reviewspecificfeedback")
|
46
|
+
quiz.review_general_feedback = parse_text(xml, "/activity/quiz/reviewgeneralfeedback")
|
47
|
+
quiz.review_right_answer = parse_text(xml, "/activity/quiz/reviewrightanswer")
|
48
|
+
quiz.review_overall_feedback = parse_text(xml, "/activity/quiz/reviewoverallfeedback")
|
49
|
+
quiz.questions_per_page = parse_text(xml, "/activity/quiz/questionsperpage")
|
50
|
+
quiz.nav_method = parse_text(xml, "/activity/quiz/navmethod")
|
49
51
|
|
50
|
-
quiz.shuffle_questions = parse_boolean(xml,
|
51
|
-
quiz.shuffle_answers = parse_boolean(xml,
|
52
|
+
quiz.shuffle_questions = parse_boolean(xml, "/activity/quiz/shufflequestions")
|
53
|
+
quiz.shuffle_answers = parse_boolean(xml, "/activity/quiz/shuffleanswers")
|
52
54
|
|
53
|
-
quiz.sum_grades = parse_text(xml,
|
54
|
-
quiz.grade = parse_text(xml,
|
55
|
-
quiz.time_created = parse_text(xml,
|
56
|
-
quiz.time_modified = parse_text(xml,
|
57
|
-
quiz.password = parse_text(xml,
|
58
|
-
quiz.subnet = parse_text(xml,
|
59
|
-
quiz.browser_security = parse_text(xml,
|
60
|
-
quiz.delay1 = parse_text(xml,
|
61
|
-
quiz.delay2 = parse_text(xml,
|
62
|
-
quiz.show_user_picture = parse_text(xml,
|
63
|
-
quiz.show_blocks = parse_text(xml,
|
55
|
+
quiz.sum_grades = parse_text(xml, "/activity/quiz/sumgrades")
|
56
|
+
quiz.grade = parse_text(xml, "/activity/quiz/grade")
|
57
|
+
quiz.time_created = parse_text(xml, "/activity/quiz/timecreated")
|
58
|
+
quiz.time_modified = parse_text(xml, "/activity/quiz/timemodified")
|
59
|
+
quiz.password = parse_text(xml, "/activity/quiz/password")
|
60
|
+
quiz.subnet = parse_text(xml, "/activity/quiz/subnet")
|
61
|
+
quiz.browser_security = parse_text(xml, "/activity/quiz/browsersecurity")
|
62
|
+
quiz.delay1 = parse_text(xml, "/activity/quiz/delay1")
|
63
|
+
quiz.delay2 = parse_text(xml, "/activity/quiz/delay2")
|
64
|
+
quiz.show_user_picture = parse_text(xml, "/activity/quiz/showuserpicture")
|
65
|
+
quiz.show_blocks = parse_text(xml, "/activity/quiz/showblocks")
|
64
66
|
|
65
|
-
xml.search(
|
67
|
+
xml.search("/activity/quiz/question_instances/question_instance").each do |node|
|
66
68
|
quiz.question_instances << {
|
67
|
-
:
|
68
|
-
:
|
69
|
+
question: parse_text(node, "question") || parse_text(node, "questionid"),
|
70
|
+
bank_entry_id: parse_text(node, "question_reference/questionbankentryid"),
|
71
|
+
grade: parse_text(node, "grade") || parse_text(node, "maxmark")
|
69
72
|
}
|
70
73
|
end
|
71
74
|
|
72
|
-
question_order = parse_text(xml,
|
75
|
+
question_order = parse_text(xml, "/activity/quiz/questions").to_s.split(",")
|
73
76
|
unless question_order.empty?
|
74
|
-
quiz.question_instances.sort_by!{|qi| question_order.index(qi[:question])}
|
77
|
+
quiz.question_instances.sort_by! { |qi| question_order.index(qi[:question]) || 0 }
|
75
78
|
end
|
76
79
|
|
77
|
-
xml.search(
|
80
|
+
xml.search("/activity/quiz/feedbacks/feedback").each do |node|
|
78
81
|
quiz.feedbacks << {
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
82
|
+
text: parse_text(node, "feedbacktext"),
|
83
|
+
format: parse_text(node, "feedbacktextformat"),
|
84
|
+
min_grade: parse_text(node, "mingrade"),
|
85
|
+
max_grade: parse_text(node, "maxgrade")
|
83
86
|
}
|
84
87
|
end
|
85
88
|
end
|
@@ -87,6 +90,5 @@ module Moodle2CC::Moodle2::Parsers
|
|
87
90
|
|
88
91
|
quiz
|
89
92
|
end
|
90
|
-
|
91
93
|
end
|
92
|
-
end
|
94
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Moodle2CC::Moodle2Converter
|
2
4
|
module QuestionConverters
|
3
5
|
class QuestionConverter
|
@@ -13,17 +15,17 @@ module Moodle2CC::Moodle2Converter
|
|
13
15
|
end
|
14
16
|
|
15
17
|
STANDARD_CONVERSIONS = {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
}
|
18
|
+
"description" => "text_only_question",
|
19
|
+
"essay" => "essay_question",
|
20
|
+
"shortanswer" => "short_answer_question"
|
21
|
+
}.freeze
|
20
22
|
|
21
23
|
def convert(moodle_question)
|
22
24
|
type = moodle_question.type
|
23
|
-
if type && c = @@subclasses[type]
|
25
|
+
if type && (c = @@subclasses[type])
|
24
26
|
c.new.convert_question(moodle_question)
|
25
|
-
elsif type && question_type = STANDARD_CONVERSIONS[type]
|
26
|
-
|
27
|
+
elsif type && (question_type = STANDARD_CONVERSIONS[type])
|
28
|
+
convert_question(moodle_question, question_type)
|
27
29
|
else
|
28
30
|
raise "Unknown converter type: #{type}"
|
29
31
|
end
|
@@ -31,29 +33,31 @@ module Moodle2CC::Moodle2Converter
|
|
31
33
|
|
32
34
|
def convert_question(moodle_question, question_type = nil)
|
33
35
|
canvas_question = create_canvas_question(question_type, moodle_question)
|
34
|
-
canvas_question.identifier = generate_unique_identifier_for(moodle_question.id,
|
36
|
+
canvas_question.identifier = generate_unique_identifier_for(moodle_question.id, "_quiz_question")
|
35
37
|
canvas_question.original_identifier = moodle_question.id
|
38
|
+
canvas_question.bank_entry_id = moodle_question.bank_entry_id
|
36
39
|
canvas_question.title = truncate_text(moodle_question.name)
|
37
40
|
canvas_question.points_possible = moodle_question.max_mark
|
38
41
|
canvas_question.general_feedback = moodle_question.general_feedback
|
39
42
|
canvas_question.answers = moodle_question.answers.map do |moodle_answer|
|
40
|
-
|
43
|
+
Moodle2CC::CanvasCC::Models::Answer.new(moodle_answer)
|
41
44
|
end
|
42
45
|
canvas_question.material = convert_question_text(moodle_question)
|
43
46
|
canvas_question
|
44
47
|
end
|
45
48
|
|
46
49
|
def convert_question_text(moodle_question)
|
47
|
-
material = moodle_question.question_text ||
|
50
|
+
material = moodle_question.question_text || ""
|
48
51
|
material = RDiscount.new(material).to_html if moodle_question.question_text_format.to_i == 4 # markdown
|
49
52
|
material
|
50
53
|
end
|
51
54
|
|
52
55
|
def create_canvas_question(question_type = nil, question = nil)
|
53
56
|
question_type ||= self.class.canvas_question_type
|
54
|
-
raise
|
57
|
+
raise "set canvas_question_type in question converter subclasses" unless question_type
|
58
|
+
|
55
59
|
Moodle2CC::CanvasCC::Models::Question.create(question_type)
|
56
60
|
end
|
57
61
|
end
|
58
62
|
end
|
59
|
-
end
|
63
|
+
end
|
data/lib/moodle2cc/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moodle2cc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.44
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Durtschi
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2024-01-30 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubyzip
|
@@ -424,7 +424,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
424
424
|
- !ruby/object:Gem::Version
|
425
425
|
version: '0'
|
426
426
|
requirements: []
|
427
|
-
rubygems_version: 3.
|
427
|
+
rubygems_version: 3.3.3
|
428
428
|
signing_key:
|
429
429
|
specification_version: 4
|
430
430
|
summary: Migrates Moodle backup ZIP to IMS Common Cartridge package
|