ams_migration 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +9 -0
  3. data/README.md +33 -0
  4. data/lib/ams_migration/canvas/converter/classic_quiz/calculated.rb +33 -0
  5. data/lib/ams_migration/canvas/converter/classic_quiz/classic_question.rb +114 -0
  6. data/lib/ams_migration/canvas/converter/classic_quiz/essay.rb +36 -0
  7. data/lib/ams_migration/canvas/converter/classic_quiz/file_upload.rb +35 -0
  8. data/lib/ams_migration/canvas/converter/classic_quiz/fill_in_blank.rb +63 -0
  9. data/lib/ams_migration/canvas/converter/classic_quiz/fill_in_multiple_blanks.rb +111 -0
  10. data/lib/ams_migration/canvas/converter/classic_quiz/matching.rb +66 -0
  11. data/lib/ams_migration/canvas/converter/classic_quiz/multiple_answer.rb +27 -0
  12. data/lib/ams_migration/canvas/converter/classic_quiz/multiple_choice.rb +57 -0
  13. data/lib/ams_migration/canvas/converter/classic_quiz/multiple_dropdown.rb +126 -0
  14. data/lib/ams_migration/canvas/converter/classic_quiz/numerical.rb +89 -0
  15. data/lib/ams_migration/canvas/converter/classic_quiz/text.rb +28 -0
  16. data/lib/ams_migration/canvas/converter/classic_quiz/true_false.rb +14 -0
  17. data/lib/ams_migration/canvas/converter/classic_quiz/unknown.rb +31 -0
  18. data/lib/ams_migration/canvas/converter/new_quiz/categorization.rb +108 -0
  19. data/lib/ams_migration/canvas/converter/new_quiz/essay.rb +78 -0
  20. data/lib/ams_migration/canvas/converter/new_quiz/file_upload.rb +33 -0
  21. data/lib/ams_migration/canvas/converter/new_quiz/fill_in_blank.rb +180 -0
  22. data/lib/ams_migration/canvas/converter/new_quiz/formula.rb +33 -0
  23. data/lib/ams_migration/canvas/converter/new_quiz/hotspot.rb +166 -0
  24. data/lib/ams_migration/canvas/converter/new_quiz/matching.rb +85 -0
  25. data/lib/ams_migration/canvas/converter/new_quiz/multiple_answer.rb +28 -0
  26. data/lib/ams_migration/canvas/converter/new_quiz/multiple_choice.rb +70 -0
  27. data/lib/ams_migration/canvas/converter/new_quiz/new_question.rb +133 -0
  28. data/lib/ams_migration/canvas/converter/new_quiz/numerical.rb +117 -0
  29. data/lib/ams_migration/canvas/converter/new_quiz/ordering.rb +68 -0
  30. data/lib/ams_migration/canvas/converter/new_quiz/stimulus.rb +35 -0
  31. data/lib/ams_migration/canvas/converter/new_quiz/true_false.rb +33 -0
  32. data/lib/ams_migration/canvas/converter/new_quiz/unknown.rb +30 -0
  33. data/lib/ams_migration/canvas/converter/question_type.rb +30 -0
  34. data/lib/ams_migration/services/README.md +26 -0
  35. data/lib/ams_migration/services/data_provider.rb +26 -0
  36. data/lib/ams_migration/services/learnosity_bank_cleaner.rb +44 -0
  37. data/lib/ams_migration/services/learnosity_data_api_client.rb +135 -0
  38. data/lib/ams_migration/services/learnosity_sink.rb +190 -0
  39. data/lib/ams_migration/services/migration_service.rb +37 -0
  40. data/lib/ams_migration/services/new_quiz_learnosity_transformer.rb +115 -0
  41. data/lib/ams_migration/version.rb +3 -0
  42. data/lib/ams_migration.rb +45 -0
  43. data/lib/factories/classic_quiz_item_converter_factory.rb +43 -0
  44. data/lib/factories/new_quiz_item_converter_factory.rb +76 -0
  45. data/spec/fixtures/sample_data/classic_quiz/calculated.json +24 -0
  46. data/spec/fixtures/sample_data/classic_quiz/essay.json +24 -0
  47. data/spec/fixtures/sample_data/classic_quiz/file_upload.json +24 -0
  48. data/spec/fixtures/sample_data/classic_quiz/fill_in_bank.json +24 -0
  49. data/spec/fixtures/sample_data/classic_quiz/fill_in_blank.json +53 -0
  50. data/spec/fixtures/sample_data/classic_quiz/fill_in_multiple_blanks.json +57 -0
  51. data/spec/fixtures/sample_data/classic_quiz/matching.json +107 -0
  52. data/spec/fixtures/sample_data/classic_quiz/multiple_answer.json +48 -0
  53. data/spec/fixtures/sample_data/classic_quiz/multiple_choice.json +56 -0
  54. data/spec/fixtures/sample_data/classic_quiz/multiple_dropdown.json +73 -0
  55. data/spec/fixtures/sample_data/classic_quiz/numerical.json +55 -0
  56. data/spec/fixtures/sample_data/classic_quiz/text.json +24 -0
  57. data/spec/fixtures/sample_data/classic_quiz/true_false.json +39 -0
  58. data/spec/fixtures/sample_data/classic_quiz/unknown.json +24 -0
  59. data/spec/fixtures/sample_data/new_quiz/bank_entry_item.json +5 -0
  60. data/spec/fixtures/sample_data/new_quiz/bank_item.json +11 -0
  61. data/spec/fixtures/sample_data/new_quiz/categorization.json +135 -0
  62. data/spec/fixtures/sample_data/new_quiz/essay.json +40 -0
  63. data/spec/fixtures/sample_data/new_quiz/file_upload.json +30 -0
  64. data/spec/fixtures/sample_data/new_quiz/fill_in_blank_association.json +162 -0
  65. data/spec/fixtures/sample_data/new_quiz/fill_in_blank_dropdown.json +180 -0
  66. data/spec/fixtures/sample_data/new_quiz/fill_in_blank_math.json +45 -0
  67. data/spec/fixtures/sample_data/new_quiz/fill_in_blank_mixed.json +188 -0
  68. data/spec/fixtures/sample_data/new_quiz/fill_in_blank_text.json +140 -0
  69. data/spec/fixtures/sample_data/new_quiz/formula.json +51 -0
  70. data/spec/fixtures/sample_data/new_quiz/hotspot_oval.json +38 -0
  71. data/spec/fixtures/sample_data/new_quiz/hotspot_polygon.json +66 -0
  72. data/spec/fixtures/sample_data/new_quiz/hotspot_square.json +38 -0
  73. data/spec/fixtures/sample_data/new_quiz/matching.json +88 -0
  74. data/spec/fixtures/sample_data/new_quiz/multiple_answer.json +57 -0
  75. data/spec/fixtures/sample_data/new_quiz/multiple_choice.json +66 -0
  76. data/spec/fixtures/sample_data/new_quiz/multiple_choice_math.json +55 -0
  77. data/spec/fixtures/sample_data/new_quiz/numerical.json +64 -0
  78. data/spec/fixtures/sample_data/new_quiz/ordering.json +60 -0
  79. data/spec/fixtures/sample_data/new_quiz/stimulus.json +17 -0
  80. data/spec/fixtures/sample_data/new_quiz/true_false.json +27 -0
  81. data/spec/fixtures/sample_data/new_quiz/unknown.json +14 -0
  82. data/spec/lib/ams_migration/services/learnosity_sink_spec.rb +198 -0
  83. data/spec/lib/canvas/converter/classic_quiz/calculated_spec.rb +26 -0
  84. data/spec/lib/canvas/converter/classic_quiz/essay_spec.rb +26 -0
  85. data/spec/lib/canvas/converter/classic_quiz/file_upload_spec.rb +23 -0
  86. data/spec/lib/canvas/converter/classic_quiz/fill_in_blank_spec.rb +30 -0
  87. data/spec/lib/canvas/converter/classic_quiz/fill_in_multiple_blanks_spec.rb +33 -0
  88. data/spec/lib/canvas/converter/classic_quiz/matching_spec.rb +38 -0
  89. data/spec/lib/canvas/converter/classic_quiz/multiple_answer_spec.rb +33 -0
  90. data/spec/lib/canvas/converter/classic_quiz/multiple_choice_spec.rb +31 -0
  91. data/spec/lib/canvas/converter/classic_quiz/multiple_dropdown_spec.rb +39 -0
  92. data/spec/lib/canvas/converter/classic_quiz/numerical_spec.rb +41 -0
  93. data/spec/lib/canvas/converter/classic_quiz/text_spec.rb +20 -0
  94. data/spec/lib/canvas/converter/classic_quiz/true_false_spec.rb +28 -0
  95. data/spec/lib/canvas/converter/classic_quiz/unknown_spec.rb +25 -0
  96. data/spec/lib/canvas/converter/common_error.rb +16 -0
  97. data/spec/lib/canvas/converter/new_quiz/categorization_spec.rb +55 -0
  98. data/spec/lib/canvas/converter/new_quiz/essay_spec.rb +26 -0
  99. data/spec/lib/canvas/converter/new_quiz/file_upload_spec.rb +24 -0
  100. data/spec/lib/canvas/converter/new_quiz/fill_in_blank_spec.rb +111 -0
  101. data/spec/lib/canvas/converter/new_quiz/formula_spec.rb +23 -0
  102. data/spec/lib/canvas/converter/new_quiz/hotspot_spec.rb +182 -0
  103. data/spec/lib/canvas/converter/new_quiz/matching_spec.rb +30 -0
  104. data/spec/lib/canvas/converter/new_quiz/multiple_answer_spec.rb +34 -0
  105. data/spec/lib/canvas/converter/new_quiz/multiple_choice_spec.rb +54 -0
  106. data/spec/lib/canvas/converter/new_quiz/numerical_spec.rb +48 -0
  107. data/spec/lib/canvas/converter/new_quiz/ordering_spec.rb +25 -0
  108. data/spec/lib/canvas/converter/new_quiz/stimulus_spec.rb +20 -0
  109. data/spec/lib/canvas/converter/new_quiz/true_false_spec.rb +24 -0
  110. data/spec/lib/canvas/converter/new_quiz/unknown_spec.rb +36 -0
  111. data/spec/lib/factories/classic_quiz_item_converter_factory_spec.rb +183 -0
  112. data/spec/lib/factories/new_quiz_item_converter_factory_spec.rb +71 -0
  113. data/spec/lib/services/learnosity_data_api_client_spec.rb +130 -0
  114. data/spec/lib/services/new_quiz_learnosity_transformer_spec.rb +196 -0
  115. data/spec/spec_helper.rb +20 -0
  116. metadata +229 -0
@@ -0,0 +1,115 @@
1
+ # Copyright (C) 2025 - present Instructure, Inc.
2
+ # This code is made publicly available for educational and reference purposes only.
3
+ # You may not copy, modify, redistribute, or use this code in any software or service without explicit permission.
4
+
5
+ module AmsMigration
6
+ module Services
7
+ class NewQuizLearnosityTransformer
8
+ attr_reader :root_account_uuid
9
+
10
+ def initialize(root_account_uuid:)
11
+ @root_account_uuid = root_account_uuid
12
+ end
13
+
14
+ def transform(quiz)
15
+ serialized = serialize_quiz_items(quiz[:quiz_items])
16
+
17
+ questions = convert_to_questions(quiz[:quiz_items], serialized)
18
+ features = {}
19
+ items = convert_to_items(quiz[:quiz_items], serialized)
20
+ activities = [convert_to_activity(quiz, serialized)]
21
+
22
+ {
23
+ activities:,
24
+ items:,
25
+ questions:,
26
+ features:
27
+ }
28
+ end
29
+
30
+ protected
31
+
32
+ def serialize_quiz_items(quiz_items)
33
+ quiz_items.to_h do |item|
34
+ converted = AmsMigration::CanvasQuizzes::NewQuizItemConverterFactory.create_converter(item).convert
35
+ [item[:id], converted]
36
+ end
37
+ end
38
+
39
+ def convert_to_questions(quiz_entries, serialized)
40
+ quiz_entries.filter_map do |quiz_entry|
41
+ converted = serialized[quiz_entry[:id]]
42
+ next unless supported?(converted)
43
+
44
+ # TODO: should we use quiz_entry.id or item.id? here.
45
+ # This really depends on how we want to share bank items because in learnosity sharing is done at the item level, not question level.
46
+ # It is unclear how this is going to work with AMS Item Service either.
47
+ # For now I am using quiz_entry.id
48
+ id = quiz_entry[:id]
49
+
50
+ {
51
+ "reference" => "q-#{nq_ls_id(id)}",
52
+ "type" => converted.dig(:question, :type),
53
+ "data" => converted[:question]
54
+ }
55
+ end
56
+ end
57
+
58
+ def convert_to_activity(wrapper, serialized_items)
59
+ quiz = wrapper[:quiz]
60
+ quiz_entries = wrapper[:quiz_items]
61
+ data = {
62
+ "items" => quiz_entries.select { |item| supported?(serialized_items[item[:id]]) }
63
+ .sort_by { |item| item[:position] }
64
+ .map { |item| "i-#{nq_ls_id(item[:id])}" }
65
+ }
66
+
67
+ {
68
+ "reference" => "a-#{nq_ls_id(quiz[:id])}",
69
+ "data" => data,
70
+ "title" => quiz[:title],
71
+ "tags" => item_tags(quiz[:id])
72
+ }
73
+ end
74
+
75
+ def convert_to_items(quiz_entries, serialized)
76
+ quiz_entries.filter_map do |quiz_entry|
77
+ converted = serialized[quiz_entry[:id]]
78
+ next unless supported?(converted)
79
+
80
+ title = converted[:title]
81
+ id = quiz_entry[:id]
82
+ {
83
+ "reference" => "i-#{nq_ls_id(id)}",
84
+ "title" => title,
85
+ "status" => "published",
86
+ "definition" => {
87
+ "widgets" => [
88
+ { "reference" => "q-#{nq_ls_id(id)}" }
89
+ ]
90
+ },
91
+ "tags" => item_tags(id)
92
+ }
93
+ end
94
+ end
95
+
96
+ def nq_ls_id(id)
97
+ "nq-#{root_account_uuid}-#{id}"
98
+ end
99
+
100
+ def supported?(converted)
101
+ question = converted[:question]
102
+
103
+ question.is_a?(Hash) && !question.empty? && question[:type] != "unsupported_canvas_question_type"
104
+ end
105
+
106
+ def item_tags(id)
107
+ [
108
+ { "type" => "import_original_id", "name" => id.to_s },
109
+ { "type" => "import_account_id", "name" => root_account_uuid.to_s },
110
+ { "type" => "import_system", "name" => "NQ" }
111
+ ]
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,3 @@
1
+ module AmsMigration
2
+ VERSION = "0.1.3".freeze
3
+ end
@@ -0,0 +1,45 @@
1
+ require_relative "ams_migration/version"
2
+
3
+ require "nokogiri"
4
+ require "json"
5
+ require "active_support/core_ext/hash"
6
+
7
+ # Require base classes first
8
+ require_relative "ams_migration/canvas/converter/classic_quiz/classic_question"
9
+ require_relative "ams_migration/canvas/converter/classic_quiz/multiple_choice"
10
+
11
+ require_relative "ams_migration/canvas/converter/new_quiz/new_question"
12
+ require_relative "ams_migration/canvas/converter/new_quiz/multiple_choice"
13
+
14
+ Dir[File.expand_path("ams_migration/canvas/converter/**/*.rb", __dir__)].each do |file|
15
+ next if file.end_with?("classic_question.rb", "new_question.rb", "multiple_choice.rb")
16
+
17
+ require_relative file
18
+ end
19
+
20
+ # Require factories
21
+ Dir[File.expand_path("factories/*.rb", __dir__)].each do |file|
22
+ require_relative file
23
+ end
24
+
25
+ # require service classes
26
+ Dir[File.expand_path("ams_migration/services/**/*.rb", __dir__)].each do |file|
27
+ require_relative file
28
+ end
29
+
30
+ module AmsMigration
31
+ class Error < StandardError; end
32
+
33
+ module Canvas
34
+ module Converter
35
+ module ClassicQuiz
36
+ end
37
+
38
+ module NewQuiz
39
+ end
40
+ end
41
+ end
42
+
43
+ module CanvasQuizzes
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ module AmsMigration
2
+ module CanvasQuizzes
3
+ # Factory that handles the Canvas Quiz to MC Question converter
4
+ # based on the Classic Quiz Item passed into the create_converter method.
5
+ class ClassicQuizItemConverterFactory
6
+ TYPE_FIELD = "question_type".freeze
7
+
8
+ def self.create_converter(item)
9
+ type = item[TYPE_FIELD]
10
+ question = item.to_json
11
+
12
+ case type
13
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::MULTI_CHOICE
14
+ AmsMigration::Canvas::Converter::ClassicQuiz::MultipleChoice.new(question)
15
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::MULTIPLE_ANSWERS
16
+ AmsMigration::Canvas::Converter::ClassicQuiz::MultipleAnswer.new(question)
17
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::MATCHING
18
+ AmsMigration::Canvas::Converter::ClassicQuiz::Matching.new(question)
19
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::FILL_IN_BLANK
20
+ AmsMigration::Canvas::Converter::ClassicQuiz::FillInBlank.new(question)
21
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::FILL_IN_MULTIPLE_BLANKS
22
+ AmsMigration::Canvas::Converter::ClassicQuiz::FillInMultipleBlanks.new(question)
23
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::MULTIPLE_DROPDOWNS
24
+ AmsMigration::Canvas::Converter::ClassicQuiz::MultipleDropdown.new(question)
25
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::TRUE_FALSE
26
+ AmsMigration::Canvas::Converter::ClassicQuiz::TrueFalse.new(question)
27
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::NUMERICAL
28
+ AmsMigration::Canvas::Converter::ClassicQuiz::Numerical.new(question)
29
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::TEXT_ONLY
30
+ AmsMigration::Canvas::Converter::ClassicQuiz::Text.new(question)
31
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::CALCULATED
32
+ AmsMigration::Canvas::Converter::ClassicQuiz::Calculated.new(question)
33
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::FILE_UPLOAD
34
+ AmsMigration::Canvas::Converter::ClassicQuiz::FileUpload.new(question)
35
+ when AmsMigration::Canvas::Converter::ClassicQuiz::ClassicQuestion::ESSAY
36
+ AmsMigration::Canvas::Converter::ClassicQuiz::Essay.new(question)
37
+ else
38
+ AmsMigration::Canvas::Converter::ClassicQuiz::Unknown.new(question)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,76 @@
1
+ module AmsMigration
2
+ module CanvasQuizzes
3
+ # Factory that handles the Canvas Quiz to MC Question converter
4
+ # based on the New Quiz Item passed into the create_converter method.
5
+ class NewQuizItemConverterFactory
6
+ QUESTION_TYPE_KEY = "interaction_type_slug".freeze
7
+ ENTRY_TYPE_ITEM = "Item".freeze
8
+ ENTRY_TYPE_STIMULUS = "Stimulus".freeze
9
+ ENTRY_TYPE_BANK_ENTRY = "BankEntry".freeze
10
+ ENTRY_TYPE_BANK = "Bank".freeze
11
+
12
+ def self.create_converter(item)
13
+ item = normalize(item.dup.with_indifferent_access)
14
+ type = type_of(item)
15
+ question = item.to_json
16
+
17
+ case type
18
+ when "choice"
19
+ AmsMigration::Canvas::Converter::NewQuiz::MultipleChoice.new(question)
20
+ when "multi-answer"
21
+ AmsMigration::Canvas::Converter::NewQuiz::MultipleAnswer.new(question)
22
+ when "matching"
23
+ AmsMigration::Canvas::Converter::NewQuiz::Matching.new(question)
24
+ when "categorization"
25
+ AmsMigration::Canvas::Converter::NewQuiz::Categorization.new(question)
26
+ when "essay"
27
+ AmsMigration::Canvas::Converter::NewQuiz::Essay.new(question)
28
+ when "file-upload"
29
+ AmsMigration::Canvas::Converter::NewQuiz::FileUpload.new(question)
30
+ when "formula"
31
+ AmsMigration::Canvas::Converter::NewQuiz::Formula.new(question)
32
+ when "ordering"
33
+ AmsMigration::Canvas::Converter::NewQuiz::Ordering.new(question)
34
+ when "true-false"
35
+ AmsMigration::Canvas::Converter::NewQuiz::TrueFalse.new(question)
36
+ when "hot-spot"
37
+ AmsMigration::Canvas::Converter::NewQuiz::Hotspot.new(question)
38
+ when "rich-fill-blank"
39
+ AmsMigration::Canvas::Converter::NewQuiz::FillInBlank.new(question)
40
+ when "stimulus"
41
+ AmsMigration::Canvas::Converter::NewQuiz::Stimulus.new(question)
42
+ when "numeric"
43
+ AmsMigration::Canvas::Converter::NewQuiz::Numerical.new(question)
44
+ else
45
+ AmsMigration::Canvas::Converter::NewQuiz::Unknown.new(question)
46
+ end
47
+ end
48
+
49
+ def self.entry_type(item)
50
+ item["entry_type"]
51
+ end
52
+
53
+ def self.type_of(item)
54
+ entry_type_map = {
55
+ ENTRY_TYPE_ITEM => item["entry"]&.[](QUESTION_TYPE_KEY) || item[QUESTION_TYPE_KEY],
56
+ ENTRY_TYPE_STIMULUS => "stimulus",
57
+ ENTRY_TYPE_BANK => "BankItem Type" # Currently Unsupported, See MCE-23091
58
+ }
59
+
60
+ entry_type_map[entry_type(item)]
61
+ end
62
+
63
+ # We hardcoded converters based on the 'Item' and 'Stimulus' entry types. When the input is 'BankEntry',
64
+ # we need to modify the input to have the expected shape so that it can be passed into our converters.
65
+ def self.normalize(item)
66
+ return item unless entry_type(item) == ENTRY_TYPE_BANK_ENTRY
67
+
68
+ item["entry_type"] = item["entry"]["entry_type"]
69
+ item["entry"] = item["entry"]["entry"]
70
+ item
71
+ end
72
+
73
+ private_class_method :entry_type, :type_of, :normalize
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": 603207,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251789,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "calculated_question",
9
+ "question_text": "<p></p>",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "<p>General comments</p>",
17
+ "answers": [],
18
+ "variables": null,
19
+ "formulas": null,
20
+ "answer_tolerance": null,
21
+ "formula_decimal_places": null,
22
+ "matches": null,
23
+ "matching_answer_incorrect_matches": null
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": 603207,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251789,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "essay_question",
9
+ "question_text": "<p>This is an essay</p> <img src=\"https://dummyfileurl.com/file.png\" alt=\"file.png\" data-api-endpoint=\"https://dummyfileurl.com\" data-api-returntype=\"File\" />",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "<p>General comments</p>",
17
+ "answers": [],
18
+ "variables": null,
19
+ "formulas": null,
20
+ "answer_tolerance": null,
21
+ "formula_decimal_places": null,
22
+ "matches": null,
23
+ "matching_answer_incorrect_matches": null
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": 603207,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251789,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "file_upload_question",
9
+ "question_text": "<p></p>",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "<p>General comments</p>",
17
+ "answers": [],
18
+ "variables": null,
19
+ "formulas": null,
20
+ "answer_tolerance": null,
21
+ "formula_decimal_places": null,
22
+ "matches": null,
23
+ "matching_answer_incorrect_matches": null
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": 603207,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251789,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "file_upload_question",
9
+ "question_text": "<p></p>",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "<p>General comments</p>",
17
+ "answers": [],
18
+ "variables": null,
19
+ "formulas": null,
20
+ "answer_tolerance": null,
21
+ "formula_decimal_places": null,
22
+ "matches": null,
23
+ "matching_answer_incorrect_matches": null
24
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "id": 603200,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251782,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "short_answer_question",
9
+ "question_text": "<p>This is the fill in the blank</p> <img src=\"https://dummyfileurl.com/file.png\" alt=\"file.png\" data-api-endpoint=\"https://dummyfileurl.com\" data-api-returntype=\"File\" />",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "",
17
+ "answers": [
18
+ {
19
+ "id": 8166,
20
+ "text": "answer 1",
21
+ "comments": "",
22
+ "comments_html": "<p>answer comment 1</p>",
23
+ "weight": 100
24
+ },
25
+ {
26
+ "id": 1101,
27
+ "text": "answer 2",
28
+ "comments": "",
29
+ "comments_html": "<p>answer comment 2</p>",
30
+ "weight": 100
31
+ },
32
+ {
33
+ "id": 4121,
34
+ "text": "answer 3",
35
+ "comments": "",
36
+ "comments_html": "<p>answer comment 3</p>",
37
+ "weight": 100
38
+ },
39
+ {
40
+ "id": 814,
41
+ "text": "answer 4",
42
+ "comments": "",
43
+ "comments_html": "<p>answer comment 4</p>",
44
+ "weight": 100
45
+ }
46
+ ],
47
+ "variables": null,
48
+ "formulas": null,
49
+ "answer_tolerance": null,
50
+ "formula_decimal_places": null,
51
+ "matches": null,
52
+ "matching_answer_incorrect_matches": null
53
+ }
@@ -0,0 +1,57 @@
1
+ {
2
+ "id": 603201,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251783,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "fill_in_multiple_blanks_question",
9
+ "question_text": "<p><span>Roses are [color1], violets are [color2]</span></p> <img src=\"https://dummyfileurl.com/file.png\" alt=\"file.png\" data-api-endpoint=\"https://dummyfileurl.com\" data-api-returntype=\"File\" />",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "",
17
+ "answers": [
18
+ {
19
+ "id": "6444",
20
+ "text": "red",
21
+ "comments": "",
22
+ "comments_html": "<p>red comments</p>",
23
+ "weight": 100,
24
+ "blank_id": "color1"
25
+ },
26
+ {
27
+ "id": "4936",
28
+ "text": "blue",
29
+ "comments": "",
30
+ "comments_html": "<p>blue comments</p>",
31
+ "weight": 100,
32
+ "blank_id": "color1"
33
+ },
34
+ {
35
+ "id": "9143",
36
+ "text": "green",
37
+ "comments": "",
38
+ "comments_html": "<p>green comments</p>",
39
+ "weight": 100,
40
+ "blank_id": "color2"
41
+ },
42
+ {
43
+ "id": "9387",
44
+ "text": "pink",
45
+ "comments": "",
46
+ "comments_html": "<p>pink comments</p>",
47
+ "weight": 100,
48
+ "blank_id": "color2"
49
+ }
50
+ ],
51
+ "variables": null,
52
+ "formulas": null,
53
+ "answer_tolerance": null,
54
+ "formula_decimal_places": null,
55
+ "matches": null,
56
+ "matching_answer_incorrect_matches": null
57
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "id": 603204,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251786,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "matching_question",
9
+ "question_text": "<p>Matching question</p> <img src=\"https://dummyfileurl.com/file.png\" alt=\"file.png\" data-api-endpoint=\"https://dummyfileurl.com\" data-api-returntype=\"File\" />",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "",
17
+ "answers": [
18
+ {
19
+ "id": 1803,
20
+ "text": "",
21
+ "left": "",
22
+ "right": "",
23
+ "comments": "",
24
+ "comments_html": "",
25
+ "match_id": 3540
26
+ },
27
+ {
28
+ "id": 5931,
29
+ "text": "",
30
+ "left": "",
31
+ "right": "",
32
+ "comments": "",
33
+ "comments_html": "",
34
+ "match_id": 3540
35
+ },
36
+ {
37
+ "id": 6193,
38
+ "text": "L1",
39
+ "left": "L1",
40
+ "right": "R1",
41
+ "comments": "",
42
+ "comments_html": "",
43
+ "match_id": 3284
44
+ },
45
+ {
46
+ "id": 4501,
47
+ "text": "L2",
48
+ "left": "L2",
49
+ "right": "R2",
50
+ "comments": "",
51
+ "comments_html": "",
52
+ "match_id": 9849
53
+ },
54
+ {
55
+ "id": 2844,
56
+ "text": "L3",
57
+ "left": "L3",
58
+ "right": "R3",
59
+ "comments": "",
60
+ "comments_html": "",
61
+ "match_id": 4557
62
+ }
63
+ ],
64
+ "variables": null,
65
+ "formulas": null,
66
+ "answer_tolerance": null,
67
+ "formula_decimal_places": null,
68
+ "matches": [
69
+ {
70
+ "text": "",
71
+ "match_id": 3540
72
+ },
73
+ {
74
+ "text": "R1",
75
+ "match_id": 3284
76
+ },
77
+ {
78
+ "text": "R2",
79
+ "match_id": 9849
80
+ },
81
+ {
82
+ "text": "R3",
83
+ "match_id": 4557
84
+ },
85
+ {
86
+ "text": "d1",
87
+ "match_id": 2385
88
+ },
89
+ {
90
+ "text": "d2",
91
+ "match_id": 8504
92
+ },
93
+ {
94
+ "text": "d3",
95
+ "match_id": 8560
96
+ },
97
+ {
98
+ "text": "d4",
99
+ "match_id": 6143
100
+ },
101
+ {
102
+ "text": "d5",
103
+ "match_id": 5727
104
+ }
105
+ ],
106
+ "matching_answer_incorrect_matches": "d1\nd2\nd3\nd4\nd5"
107
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "id": 603202,
3
+ "quiz_id": 70667,
4
+ "quiz_group_id": null,
5
+ "assessment_question_id": 1251784,
6
+ "position": null,
7
+ "question_name": "Question",
8
+ "question_type": "multiple_answers_question",
9
+ "question_text": "<p>Multiple answer text</p> <img src=\"https://dummyfileurl.com/file.png\" alt=\"file.png\" data-api-endpoint=\"https://dummyfileurl.com\" data-api-returntype=\"File\" />",
10
+ "points_possible": 1,
11
+ "correct_comments": "",
12
+ "incorrect_comments": "",
13
+ "neutral_comments": "",
14
+ "correct_comments_html": "",
15
+ "incorrect_comments_html": "",
16
+ "neutral_comments_html": "",
17
+ "answers": [
18
+ {
19
+ "id": "6739",
20
+ "text": "Answer 1",
21
+ "comments": "",
22
+ "comments_html": "<p>Answer 1 comments</p>",
23
+ "weight": 100,
24
+ "html": "<p>Answer 1</p>"
25
+ },
26
+ {
27
+ "id": "1316",
28
+ "text": "Answer 2",
29
+ "comments": "",
30
+ "comments_html": "<p>Answer 2 comments</p>",
31
+ "weight": 100,
32
+ "html": "<p>Answer 2</p>"
33
+ },
34
+ {
35
+ "id": "6779",
36
+ "text": "Answer 3",
37
+ "comments": "",
38
+ "comments_html": "<p>Answer 3 comments</p>",
39
+ "weight": 0
40
+ }
41
+ ],
42
+ "variables": null,
43
+ "formulas": null,
44
+ "answer_tolerance": null,
45
+ "formula_decimal_places": null,
46
+ "matches": null,
47
+ "matching_answer_incorrect_matches": null
48
+ }