canvas_cc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/canvas_cc.gemspec +37 -0
  8. data/lib/canvas_cc/canvas/assessment.rb +124 -0
  9. data/lib/canvas_cc/canvas/assignment.rb +98 -0
  10. data/lib/canvas_cc/canvas/converter.rb +30 -0
  11. data/lib/canvas_cc/canvas/course.rb +143 -0
  12. data/lib/canvas_cc/canvas/discussion_topic.rb +64 -0
  13. data/lib/canvas_cc/canvas/label.rb +8 -0
  14. data/lib/canvas_cc/canvas/question.rb +492 -0
  15. data/lib/canvas_cc/canvas/question_bank.rb +57 -0
  16. data/lib/canvas_cc/canvas/question_group.rb +35 -0
  17. data/lib/canvas_cc/canvas/resource.rb +16 -0
  18. data/lib/canvas_cc/canvas/templates/assignment.html.erb +9 -0
  19. data/lib/canvas_cc/canvas/templates/syllabus.html.erb +9 -0
  20. data/lib/canvas_cc/canvas/templates/wiki_content.html.erb +10 -0
  21. data/lib/canvas_cc/canvas/web_content.rb +15 -0
  22. data/lib/canvas_cc/canvas/web_link.rb +16 -0
  23. data/lib/canvas_cc/canvas/wiki.rb +26 -0
  24. data/lib/canvas_cc/canvas_cc/assessment_writer.rb +82 -0
  25. data/lib/canvas_cc/canvas_cc/assignment_group_writer.rb +48 -0
  26. data/lib/canvas_cc/canvas_cc/assignment_writer.rb +68 -0
  27. data/lib/canvas_cc/canvas_cc/calculated_question_writer.rb +72 -0
  28. data/lib/canvas_cc/canvas_cc/canvas_export_writer.rb +18 -0
  29. data/lib/canvas_cc/canvas_cc/cartridge_creator.rb +60 -0
  30. data/lib/canvas_cc/canvas_cc/course_setting_writer.rb +35 -0
  31. data/lib/canvas_cc/canvas_cc/discussion_writer.rb +52 -0
  32. data/lib/canvas_cc/canvas_cc/essay_question_writer.rb +19 -0
  33. data/lib/canvas_cc/canvas_cc/file_meta_writer.rb +38 -0
  34. data/lib/canvas_cc/canvas_cc/ims_manifest_generator.rb +123 -0
  35. data/lib/canvas_cc/canvas_cc/matching_question_writer.rb +43 -0
  36. data/lib/canvas_cc/canvas_cc/models/answer.rb +12 -0
  37. data/lib/canvas_cc/canvas_cc/models/assessment.rb +102 -0
  38. data/lib/canvas_cc/canvas_cc/models/assignment.rb +30 -0
  39. data/lib/canvas_cc/canvas_cc/models/assignment_group.rb +9 -0
  40. data/lib/canvas_cc/canvas_cc/models/calculated_question.rb +19 -0
  41. data/lib/canvas_cc/canvas_cc/models/canvas_file.rb +22 -0
  42. data/lib/canvas_cc/canvas_cc/models/canvas_module.rb +10 -0
  43. data/lib/canvas_cc/canvas_cc/models/course.rb +53 -0
  44. data/lib/canvas_cc/canvas_cc/models/discussion.rb +36 -0
  45. data/lib/canvas_cc/canvas_cc/models/discussion_topic.rb +5 -0
  46. data/lib/canvas_cc/canvas_cc/models/matching_question.rb +7 -0
  47. data/lib/canvas_cc/canvas_cc/models/module_item.rb +16 -0
  48. data/lib/canvas_cc/canvas_cc/models/multiple_dropdowns_question.rb +7 -0
  49. data/lib/canvas_cc/canvas_cc/models/numerical_question.rb +7 -0
  50. data/lib/canvas_cc/canvas_cc/models/page.rb +41 -0
  51. data/lib/canvas_cc/canvas_cc/models/question.rb +37 -0
  52. data/lib/canvas_cc/canvas_cc/models/question_bank.rb +42 -0
  53. data/lib/canvas_cc/canvas_cc/models/question_group.rb +10 -0
  54. data/lib/canvas_cc/canvas_cc/models/resource.rb +23 -0
  55. data/lib/canvas_cc/canvas_cc/models/web_content.rb +7 -0
  56. data/lib/canvas_cc/canvas_cc/models/web_link.rb +7 -0
  57. data/lib/canvas_cc/canvas_cc/models/workflow_state.rb +6 -0
  58. data/lib/canvas_cc/canvas_cc/module_meta_writer.rb +52 -0
  59. data/lib/canvas_cc/canvas_cc/multiple_answers_question_writer.rb +41 -0
  60. data/lib/canvas_cc/canvas_cc/multiple_blanks_question_writer.rb +51 -0
  61. data/lib/canvas_cc/canvas_cc/multiple_choice_question_writer.rb +48 -0
  62. data/lib/canvas_cc/canvas_cc/multiple_dropdowns_question_writer.rb +30 -0
  63. data/lib/canvas_cc/canvas_cc/numerical_question_writer.rb +40 -0
  64. data/lib/canvas_cc/canvas_cc/page_writer.rb +38 -0
  65. data/lib/canvas_cc/canvas_cc/question_bank_writer.rb +44 -0
  66. data/lib/canvas_cc/canvas_cc/question_group_writer.rb +23 -0
  67. data/lib/canvas_cc/canvas_cc/question_writer.rb +129 -0
  68. data/lib/canvas_cc/canvas_cc/short_answer_question_writer.rb +42 -0
  69. data/lib/canvas_cc/canvas_cc/text_only_question_writer.rb +19 -0
  70. data/lib/canvas_cc/canvas_cc/true_false_question_writer.rb +38 -0
  71. data/lib/canvas_cc/cc/assessment.rb +25 -0
  72. data/lib/canvas_cc/cc/assignment.rb +61 -0
  73. data/lib/canvas_cc/cc/cc_helper.rb +285 -0
  74. data/lib/canvas_cc/cc/converter.rb +137 -0
  75. data/lib/canvas_cc/cc/course.rb +16 -0
  76. data/lib/canvas_cc/cc/discussion_topic.rb +53 -0
  77. data/lib/canvas_cc/cc/label.rb +6 -0
  78. data/lib/canvas_cc/cc/question.rb +23 -0
  79. data/lib/canvas_cc/cc/resource.rb +30 -0
  80. data/lib/canvas_cc/cc/templates/assignment.html.erb +13 -0
  81. data/lib/canvas_cc/cc/templates/syllabus.html.erb +9 -0
  82. data/lib/canvas_cc/cc/templates/wiki_content.html.erb +10 -0
  83. data/lib/canvas_cc/cc/web_content.rb +48 -0
  84. data/lib/canvas_cc/cc/web_link.rb +75 -0
  85. data/lib/canvas_cc/cc/wiki.rb +73 -0
  86. data/lib/canvas_cc/version.rb +3 -0
  87. data/lib/canvas_cc.rb +94 -0
  88. data/spec/moodle2cc/canvas_cc/assessment_writer_spec.rb +95 -0
  89. data/spec/moodle2cc/canvas_cc/assignment_group_writer_spec.rb +51 -0
  90. data/spec/moodle2cc/canvas_cc/assignment_writer_spec.rb +74 -0
  91. data/spec/moodle2cc/canvas_cc/calculated_question_writer_spec.rb +88 -0
  92. data/spec/moodle2cc/canvas_cc/canvas_export_writer_spec.rb +26 -0
  93. data/spec/moodle2cc/canvas_cc/cartridge_creator_spec.rb +50 -0
  94. data/spec/moodle2cc/canvas_cc/course_setting_writer_spec.rb +47 -0
  95. data/spec/moodle2cc/canvas_cc/discussion_writer_spec.rb +38 -0
  96. data/spec/moodle2cc/canvas_cc/essay_question_writer_spec.rb +31 -0
  97. data/spec/moodle2cc/canvas_cc/file_meta_writer_spec.rb +57 -0
  98. data/spec/moodle2cc/canvas_cc/ims_manifest_generator_spec.rb +141 -0
  99. data/spec/moodle2cc/canvas_cc/matching_question_writer_spec.rb +51 -0
  100. data/spec/moodle2cc/canvas_cc/models/assessment_spec.rb +131 -0
  101. data/spec/moodle2cc/canvas_cc/models/assignment_group_spec.rb +9 -0
  102. data/spec/moodle2cc/canvas_cc/models/assignment_spec.rb +45 -0
  103. data/spec/moodle2cc/canvas_cc/models/calculated_question_spec.rb +25 -0
  104. data/spec/moodle2cc/canvas_cc/models/canvas_file_spec.rb +23 -0
  105. data/spec/moodle2cc/canvas_cc/models/canvas_module_spec.rb +16 -0
  106. data/spec/moodle2cc/canvas_cc/models/course_spec.rb +43 -0
  107. data/spec/moodle2cc/canvas_cc/models/discussion_spec.rb +47 -0
  108. data/spec/moodle2cc/canvas_cc/models/discussion_topic_spec.rb +7 -0
  109. data/spec/moodle2cc/canvas_cc/models/module_item_spec.rb +15 -0
  110. data/spec/moodle2cc/canvas_cc/models/page_spec.rb +34 -0
  111. data/spec/moodle2cc/canvas_cc/models/question_spec.rb +8 -0
  112. data/spec/moodle2cc/canvas_cc/models/resource_spec.rb +17 -0
  113. data/spec/moodle2cc/canvas_cc/models/web_content_spec.rb +7 -0
  114. data/spec/moodle2cc/canvas_cc/models/web_link_spec.rb +9 -0
  115. data/spec/moodle2cc/canvas_cc/module_meta_writer_spec.rb +118 -0
  116. data/spec/moodle2cc/canvas_cc/multiple_answers_question_writer_spec.rb +50 -0
  117. data/spec/moodle2cc/canvas_cc/multiple_blanks_question_writer_spec.rb +77 -0
  118. data/spec/moodle2cc/canvas_cc/multiple_choice_question_writer_spec.rb +69 -0
  119. data/spec/moodle2cc/canvas_cc/multiple_dropdowns_question_writer_spec.rb +46 -0
  120. data/spec/moodle2cc/canvas_cc/numerical_question_writer_spec.rb +69 -0
  121. data/spec/moodle2cc/canvas_cc/page_writer_spec.rb +29 -0
  122. data/spec/moodle2cc/canvas_cc/question_bank_writer_spec.rb +43 -0
  123. data/spec/moodle2cc/canvas_cc/question_writer_spec.rb +129 -0
  124. data/spec/moodle2cc/canvas_cc/short_answer_question_writer_spec.rb +50 -0
  125. data/spec/moodle2cc/canvas_cc/text_only_question_writer_spec.rb +23 -0
  126. data/spec/moodle2cc/canvas_cc/true_false_question_writer_spec.rb +62 -0
  127. data/spec/spec_helper.rb +12 -0
  128. data/spec/support/shared_examples_for_models.rb +26 -0
  129. data/test/acceptance/migrator_test.rb +24 -0
  130. data/test/fixtures/cc.imscc +0 -0
  131. data/test/fixtures/common_cartridge/ims_manifest_simple.xml +45 -0
  132. data/test/fixtures/common_cartridge/schema/cccv1p0.xsd +563 -0
  133. data/test/fixtures/common_cartridge/schema/ccv1p1_imsccauth_v1p1.xsd +203 -0
  134. data/test/fixtures/common_cartridge/schema/ccv1p1_imscp_v1p2_v1p0.xsd +827 -0
  135. data/test/fixtures/common_cartridge/schema/ccv1p1_lommanifest_v1p0.xsd +822 -0
  136. data/test/fixtures/common_cartridge/schema/ccv1p1_lomresource_v1p0.xsd +273 -0
  137. data/test/fixtures/common_cartridge/schema/xml.xsd +286 -0
  138. data/test/test_helper.rb +71 -0
  139. data/test/test_question_helper.rb +122 -0
  140. data/test/test_wiki_helper.rb +21 -0
  141. data/test/unit/canvas/assessment_test.rb +261 -0
  142. data/test/unit/canvas/assignment_test.rb +220 -0
  143. data/test/unit/canvas/converter_test.rb +171 -0
  144. data/test/unit/canvas/course_test.rb +176 -0
  145. data/test/unit/canvas/discussion_topic_test.rb +129 -0
  146. data/test/unit/canvas/label_test.rb +32 -0
  147. data/test/unit/canvas/question_bank_test.rb +92 -0
  148. data/test/unit/canvas/question_group_test.rb +90 -0
  149. data/test/unit/canvas/question_test.rb +876 -0
  150. data/test/unit/canvas/web_content_test.rb +46 -0
  151. data/test/unit/canvas/web_link_test.rb +48 -0
  152. data/test/unit/canvas/wiki_test.rb +74 -0
  153. data/test/unit/cc/assessment_test.rb +48 -0
  154. data/test/unit/cc/assignment_test.rb +72 -0
  155. data/test/unit/cc/cc_helper_test.rb +19 -0
  156. data/test/unit/cc/converter_test.rb +173 -0
  157. data/test/unit/cc/course_test.rb +36 -0
  158. data/test/unit/cc/discussion_topic_test.rb +83 -0
  159. data/test/unit/cc/label_test.rb +29 -0
  160. data/test/unit/cc/question_test.rb +54 -0
  161. data/test/unit/cc/web_content_test.rb +76 -0
  162. data/test/unit/cc/web_link_test.rb +159 -0
  163. data/test/unit/cc/wiki_test.rb +139 -0
  164. data/test/unit/logger_test.rb +33 -0
  165. data/test/unit/migrator_test.rb +67 -0
  166. data/test/unit/resource_factory_test.rb +216 -0
  167. metadata +499 -0
@@ -0,0 +1,51 @@
1
+ module CanvasCc::CanvasCC
2
+ class MultipleBlanksQuestionWriter < QuestionWriter
3
+ register_writer_type 'fill_in_multiple_blanks_question'
4
+
5
+ private
6
+
7
+ def self.write_responses(presentation_node, question)
8
+ resp_idents = question.answers.map{|a| a.resp_ident}.uniq
9
+ resp_idents.each do |resp_ident|
10
+ presentation_node.response_lid(:ident => resp_ident, :rcardinality => 'Single') do |response_node|
11
+ response_node.render_choice do |choice_node|
12
+ question.answers.select{|a| a.resp_ident == resp_ident}.each do |answer|
13
+ choice_node.response_label(:ident => answer.id) do |label_node|
14
+ label_node.material do |material_node|
15
+ material_node.mattext answer.answer_text, :texttype => 'text/html'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.write_response_conditions(processing_node, question)
25
+ # Feedback
26
+ question.answers.each do |answer|
27
+ next unless answer.feedback && answer.feedback.strip.length > 0
28
+ processing_node.respcondition(:continue => 'Yes') do |condition_node|
29
+ condition_node.conditionvar do |var_node|
30
+ var_node.varequal answer.id, :respident => answer.resp_ident
31
+ end
32
+ condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb")
33
+ end
34
+ end
35
+
36
+ # Scores
37
+ question.answers.each do |answer|
38
+ processing_node.respcondition(:continue => 'No') do |condition_node|
39
+ condition_node.conditionvar do |var_node|
40
+ var_node.varequal answer.id, :respident => answer.resp_ident
41
+ end
42
+ condition_node.setvar(convert_fraction_to_score(answer.fraction), :varname => 'SCORE', :action => 'Set')
43
+ end
44
+ end
45
+ end
46
+
47
+ def self.write_additional_nodes(item_node, question)
48
+ write_standard_answer_feedbacks(item_node, question)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,48 @@
1
+ module CanvasCc::CanvasCC
2
+ class MultipleChoiceQuestionWriter < QuestionWriter
3
+ register_writer_type 'multiple_choice_question'
4
+
5
+ private
6
+
7
+ def self.write_responses(presentation_node, question)
8
+ presentation_node.response_lid(:ident => 'response1', :rcardinality => 'Single') do |response_node|
9
+ response_node.render_choice do |choice_node|
10
+ question.answers.each do |answer|
11
+ choice_node.response_label(:ident => answer.id) do |label_node|
12
+ label_node.material do |material_node|
13
+ material_node.mattext answer.answer_text, :texttype => 'text/html'
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ def self.write_response_conditions(processing_node, question)
22
+ # Feedback
23
+ question.answers.each do |answer|
24
+ next unless answer.feedback && answer.feedback.strip.length > 0
25
+ processing_node.respcondition(:continue => 'Yes') do |condition_node|
26
+ condition_node.conditionvar do |var_node|
27
+ var_node.varequal answer.id, :respident => 'response1'
28
+ end
29
+ condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb")
30
+ end
31
+ end
32
+
33
+ # Scores
34
+ question.answers.each do |answer|
35
+ processing_node.respcondition(:continue => 'No') do |condition_node|
36
+ condition_node.conditionvar do |var_node|
37
+ var_node.varequal answer.id, :respident => 'response1'
38
+ end
39
+ condition_node.setvar(convert_fraction_to_score(answer.fraction), :varname => 'SCORE', :action => 'Set')
40
+ end
41
+ end
42
+ end
43
+
44
+ def self.write_additional_nodes(item_node, question)
45
+ write_standard_answer_feedbacks(item_node, question)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,30 @@
1
+ module CanvasCc::CanvasCC
2
+ class MultipleDropdownsQuestionWriter < QuestionWriter
3
+ register_writer_type 'multiple_dropdowns_question'
4
+
5
+ private
6
+
7
+ def self.write_responses(presentation_node, question)
8
+ question.responses.each do |response|
9
+ presentation_node.response_lid(:ident => "response_#{response[:id]}") do |response_node|
10
+ response_node.material do |material_node|
11
+ material_node.mattext(response[:id], :texttype => 'text/plain')
12
+ end
13
+ response_node.render_choice do |choice_node|
14
+ response[:choices].each do |choice|
15
+ choice_node.response_label(:ident => choice[:id]) do |label_node|
16
+ label_node.material do |material_node|
17
+ material_node.mattext(choice[:text], :texttype => 'text/plain')
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.write_response_conditions(processing_node, question)
27
+ # this is always an answerless questionnaire question (for now), so no response conditions are necessary
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ module CanvasCc::CanvasCC
2
+ class NumericalQuestionWriter < QuestionWriter
3
+ register_writer_type 'numerical_question'
4
+
5
+ private
6
+
7
+ def self.write_responses(presentation_node, question)
8
+ presentation_node.response_str(:rcardinality => 'Single', :ident => 'response1') do |response_node|
9
+ response_node.render_fib(:fibtype => 'Decimal') do |render_fib_node|
10
+ render_fib_node.response_label(:ident => 'answer1')
11
+ end
12
+ end
13
+ end
14
+
15
+ def self.write_response_conditions(processing_node, question)
16
+ question.answers.each do |answer|
17
+ tolerance = question.tolerances[answer.id]
18
+ processing_node.respcondition(:continue => 'No') do |condition_node|
19
+ condition_node.conditionvar do |var_node|
20
+ var_node.or do |or_node|
21
+ or_node.varequal answer.answer_text, :respident => 'response1'
22
+ or_node.and do |and_node|
23
+ and_node.vargte answer.answer_text.to_f - tolerance.to_f, :respident => 'response1'
24
+ and_node.varlte answer.answer_text.to_f + tolerance.to_f, :respident => 'response1'
25
+ end
26
+ end
27
+ end
28
+ condition_node.setvar(convert_fraction_to_score(answer.fraction), :varname => "SCORE", :action => 'Set')
29
+ if answer.feedback && answer.feedback.strip.length > 0
30
+ condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb")
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.write_additional_nodes(item_node, question)
37
+ write_standard_answer_feedbacks(item_node, question)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ module CanvasCc::CanvasCC
2
+ class PageWriter
3
+
4
+ def initialize(work_dir, *pages)
5
+ @work_dir = work_dir
6
+ @pages = pages
7
+ end
8
+
9
+ def write
10
+ Dir.mkdir(File.join(@work_dir, CanvasCc::CanvasCC::Models::Page::WIKI_CONTENT))
11
+ @pages.each { |page| write_html(page) }
12
+ end
13
+
14
+
15
+ private
16
+
17
+ def write_html(page)
18
+ builder = Nokogiri::HTML::Builder.new(:encoding => 'UTF-8') do |doc|
19
+ doc.html { |html|
20
+ html.head { |head|
21
+ head.meta('http-equiv' => 'Content-Type', content: 'text/html; charset=utf-8')
22
+ head.meta(name: 'identifier', content: page.identifier)
23
+ head.meta(name: 'editing_roles', content: page.editing_roles)
24
+ head.meta(name: 'workflow_state', content: page.workflow_state)
25
+ head.title page.title
26
+ }
27
+ html.body { |body|
28
+ body << Nokogiri::HTML::fragment(page.body)
29
+ }
30
+ }
31
+ end
32
+ file = File.join(@work_dir, page.href)
33
+ FileUtils.mkdir_p(File.dirname(file))
34
+ File.open(file, 'w') { |f| f.write(builder.to_html) }
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,44 @@
1
+ module CanvasCc::CanvasCC
2
+ class QuestionBankWriter
3
+
4
+ def initialize(work_dir, *question_banks)
5
+ @work_dir = work_dir
6
+ @question_banks = question_banks
7
+ end
8
+
9
+ def write
10
+ @question_banks.each do |bank|
11
+ write_bank(bank)
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def write_bank(bank)
18
+ bank_resource = bank.question_bank_resource
19
+
20
+ xml = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
21
+ xml.questestinterop("xmlns" => "http://www.imsglobal.org/xsd/ims_qtiasiv1p2",
22
+ "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
23
+ "xsi:schemaLocation"=> "http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd"
24
+ ) { |xml|
25
+ xml.objectbank(:ident => bank_resource.identifier) { |xml|
26
+ xml.qtimetadata { |xml|
27
+ xml.qtimetadatafield { |xml|
28
+ xml.fieldlabel 'bank_title'
29
+ xml.fieldentry bank.title
30
+ }
31
+ }
32
+ bank.questions.each do |question|
33
+ CanvasCc::CanvasCC::QuestionWriter.write_question(xml, question)
34
+ end
35
+ }
36
+ }
37
+ end.to_xml
38
+
39
+ file_path = File.join(@work_dir, bank_resource.href)
40
+ FileUtils.mkdir_p(File.dirname(file_path)) unless File.exists?(File.dirname(file_path))
41
+ File.open(file_path, 'w') { |f| f.write(xml) }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ module CanvasCc::CanvasCC
2
+ class QuestionGroupWriter
3
+
4
+ def self.write_question_group(node, question_group)
5
+ node.section(:title => question_group.title, :ident => question_group.identifier) do |section_node|
6
+ section_node.selection_ordering do |so_node|
7
+ so_node.selection do |s_node|
8
+ s_node.selection_number question_group.selection_number
9
+ if question_group.points_per_item
10
+ s_node.selection_extension do |se_node|
11
+ se_node.points_per_item question_group.points_per_item
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ question_group.questions.each do |question|
18
+ CanvasCc::CanvasCC::QuestionWriter.write_question(section_node, question)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,129 @@
1
+ module CanvasCc::CanvasCC
2
+ class QuestionWriter
3
+
4
+ @@subclasses = {}
5
+
6
+ def self.write_question(node, question)
7
+ if c = @@subclasses[question.question_type]
8
+ c.write_question_item_xml(node, question)
9
+ else
10
+ raise "Unknown question writer type: #{question.question_type}"
11
+ end
12
+ end
13
+
14
+ def self.register_writer_type(name)
15
+ @@subclasses[name] = self
16
+ end
17
+
18
+ def self.write_question_item_xml(node, question)
19
+ node.item(:title => question.title, :ident => question.identifier) do |item_node|
20
+ write_qti_metadata(item_node, question)
21
+ write_presentation(item_node, question)
22
+ write_resprocessing(item_node, question)
23
+ write_general_feedback(item_node, question)
24
+ write_additional_nodes(item_node, question)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def self.write_qti_metadata(item_node, question)
31
+ item_node.itemmetadata do |meta_node|
32
+ meta_node.qtimetadata do |qtime_node|
33
+ CanvasCc::CanvasCC::Models::Question::QTI_META_ATTRIBUTES.each do |attr|
34
+ value = question.send(attr).to_s
35
+ if value && value.length > 0
36
+ qtime_node.qtimetadatafield do |field_node|
37
+ field_node.fieldlabel attr.to_s
38
+ field_node.fieldentry value
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def self.write_presentation(item_node, question)
47
+ item_node.presentation do |presentation_node|
48
+ presentation_node.material do |material_node|
49
+ material_node.mattext(question.material, :texttype => 'text/html')
50
+ end
51
+
52
+ write_responses(presentation_node, question)
53
+ end
54
+ end
55
+
56
+ def self.write_responses(presentation_node, question)
57
+ raise "needs to be implemented in question writer subclass"
58
+ end
59
+
60
+ def self.write_resprocessing(item_node, question)
61
+ item_node.resprocessing do |processing_node|
62
+ processing_node.outcomes do |outcomes_node|
63
+ outcomes_node.decvar(:maxvalue => '100', :minvalue => '0', :varname => 'SCORE', :vartype => 'Decimal')
64
+ end
65
+ if question.general_feedback
66
+ processing_node.respcondition(:continue => 'Yes') do |condition_node|
67
+ condition_node.conditionvar do |var_node|
68
+ var_node.other
69
+ end
70
+ condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => 'general_fb')
71
+ end
72
+ end
73
+ write_response_conditions(processing_node, question)
74
+ end
75
+ end
76
+
77
+ def self.write_response_conditions(processing_node, question)
78
+ raise "needs to be implemented in question writer subclass"
79
+ end
80
+
81
+ def self.write_general_feedback(item_node, question)
82
+ if question.general_feedback && question.general_feedback.length > 0
83
+ item_node.itemfeedback(:ident => 'general_fb') do |fb_node|
84
+ fb_node.flow_mat do |flow_node|
85
+ flow_node.material do |material_node|
86
+ material_node.mattext(question.general_feedback, :texttype => 'text/html')
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def self.write_additional_nodes(item_node, question)
94
+ # implement in sub-classes if needed
95
+ end
96
+
97
+ # used for 'multiple_choice_question', 'numerical_question', 'short_answer_question', 'true_false_question'
98
+ def self.write_standard_answer_feedbacks(item_node, question)
99
+ question.answers.each do |answer|
100
+ next unless answer.feedback && answer.feedback.strip.length > 0
101
+ item_node.itemfeedback(:ident => "#{answer.id}_fb") do |feedback_node|
102
+ feedback_node.flow_mat do |flow_node|
103
+ flow_node.material do |material_node|
104
+ material_node.mattext answer.feedback, :texttype => 'text/html'
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # helper
112
+ def self.convert_fraction_to_score(fraction)
113
+ return 100 if fraction.nil?
114
+ (100 * fraction).to_i
115
+ end
116
+ end
117
+ end
118
+
119
+ require_relative 'calculated_question_writer'
120
+ require_relative 'essay_question_writer'
121
+ require_relative 'matching_question_writer'
122
+ require_relative 'multiple_answers_question_writer'
123
+ require_relative 'multiple_blanks_question_writer'
124
+ require_relative 'multiple_choice_question_writer'
125
+ require_relative 'multiple_dropdowns_question_writer'
126
+ require_relative 'numerical_question_writer'
127
+ require_relative 'short_answer_question_writer'
128
+ require_relative 'text_only_question_writer'
129
+ require_relative 'true_false_question_writer'
@@ -0,0 +1,42 @@
1
+ module CanvasCc::CanvasCC
2
+ class ShortAnswerQuestionWriter < QuestionWriter
3
+ register_writer_type 'short_answer_question'
4
+
5
+ private
6
+
7
+ def self.write_responses(presentation_node, question)
8
+ presentation_node.response_str(:rcardinality => 'Single', :ident => 'response1') do |response_node|
9
+ response_node.render_fib do |render_node|
10
+ render_node.response_label(:ident => 'answer1', :rshuffle => 'No')
11
+ end
12
+ end
13
+ end
14
+
15
+ def self.write_response_conditions(processing_node, question)
16
+ # Feedback
17
+ question.answers.each do |answer|
18
+ next unless answer.feedback && answer.feedback.strip.length > 0
19
+ processing_node.respcondition(:continue => 'Yes') do |condition_node|
20
+ condition_node.conditionvar do |var_node|
21
+ var_node.varequal answer.answer_text, :respident => 'response1'
22
+ end
23
+ condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb")
24
+ end
25
+ end
26
+
27
+ # Conditions
28
+ question.answers.each do |answer|
29
+ processing_node.respcondition(:continue => 'No') do |condition_node|
30
+ condition_node.conditionvar do |var_node|
31
+ var_node.varequal answer.answer_text, :respident => 'response1'
32
+ end
33
+ condition_node.setvar(convert_fraction_to_score(answer.fraction), :varname => 'SCORE', :action => "Set")
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.write_additional_nodes(item_node, question)
39
+ write_standard_answer_feedbacks(item_node, question)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,19 @@
1
+ module CanvasCc::CanvasCC
2
+ class TextOnlyQuestionWriter < QuestionWriter
3
+
4
+ register_writer_type 'text_only_question'
5
+
6
+ private
7
+
8
+ def self.write_question_item_xml(node, question)
9
+ node.item(:title => question.title, :ident => question.identifier) do |item_node|
10
+ write_qti_metadata(item_node, question)
11
+ item_node.presentation do |presentation_node|
12
+ presentation_node.material do |material_node|
13
+ material_node.mattext(question.material, :texttype => 'text/html')
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ module CanvasCc::CanvasCC
2
+ class TrueFalseQuestionWriter < QuestionWriter
3
+
4
+ register_writer_type 'true_false_question'
5
+
6
+ private
7
+
8
+ def self.write_responses(presentation_node, question)
9
+ presentation_node.response_lid(:rcardinality => 'Single', :ident => 'response1') do |response_node|
10
+ response_node.render_choice do |render_choice_node|
11
+ question.answers.each do |answer|
12
+ render_choice_node.response_label(:ident => answer.id) do |response_label_node|
13
+ response_label_node.material do |material_node|
14
+ material_node.mattext(answer.answer_text, :texttype => 'text/html')
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.write_response_conditions(processing_node, question)
23
+ question.answers.each do |answer|
24
+ processing_node.respcondition(:continue => 'No') do |condition_node|
25
+ condition_node.conditionvar do |var_node|
26
+ var_node.varequal answer.id, :respident => 'response1'
27
+ end
28
+ condition_node.displayfeedback(:feedbacktype => 'Response', :linkrefid => "#{answer.id}_fb") if answer.feedback && answer.feedback.strip.length > 0
29
+ condition_node.setvar(convert_fraction_to_score(answer.fraction), :varname => 'SCORE', :action => "Set")
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.write_additional_nodes(item_node, question)
35
+ write_standard_answer_feedbacks(item_node, question)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ module CanvasCc::CC
2
+ class Assessment
3
+ include CCHelper
4
+ include Resource
5
+
6
+ def initialize(mod, position=0)
7
+ super
8
+ end
9
+
10
+ def create_resource_node(resources_node)
11
+ resources_node.resource(
12
+ :identifier => identifier,
13
+ :type => ASSESSMENT_TYPE
14
+ ) do |resource_node|
15
+ create_resource_sub_nodes(resource_node)
16
+ end
17
+ end
18
+
19
+ def create_resource_sub_nodes(resource_node)
20
+ end
21
+
22
+ def create_files(export_dir)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,61 @@
1
+ module CanvasCc::CC
2
+ class Assignment
3
+ include CCHelper
4
+ include Resource
5
+
6
+ attr_accessor :body, :meta_fields
7
+
8
+ def initialize(mod, position=0)
9
+ super
10
+ @body = convert_file_path_tokens(mod.description)
11
+ @meta_fields = build_meta_fields(mod)
12
+ @rel_path = File.join(CC_ASSIGNMENT_FOLDER, "#{file_slug(@title)}.html")
13
+ @resource_type = nil
14
+ end
15
+
16
+ # Common Cartridge doesn't have anywhere to put assignment meta data like this
17
+ # So add them as HTML meta fields in the HTML file
18
+ def build_meta_fields(mod)
19
+ fields = {}
20
+ %w{mod_type assignment_type}.each do |key|
21
+ fields[key] = mod.send(key) if mod.respond_to?(key)
22
+ end
23
+ if mod.grade_item
24
+ CanvasCc::Moodle::GradeItem::PROPERTIES.each do |key|
25
+ fields[key] = mod.grade_item.send(key) if mod.grade_item.respond_to?(key)
26
+ end
27
+ end
28
+
29
+ fields
30
+ end
31
+
32
+ def create_resource_node(resources_node)
33
+ resources_node.resource(
34
+ :href => @rel_path,
35
+ :type => @resource_type || WEBCONTENT,
36
+ :identifier => identifier
37
+ ) do |resource_node|
38
+ resource_node.file(:href => @rel_path)
39
+ create_resource_sub_nodes(resource_node)
40
+ # todo if CC 1.2 add assignment meta tag
41
+ end
42
+ end
43
+
44
+ def create_resource_sub_nodes(resource_node)
45
+ end
46
+
47
+ def create_files(export_dir)
48
+ create_html(export_dir)
49
+ end
50
+
51
+ def create_html(export_dir)
52
+ template = File.expand_path('../templates/assignment.html.erb', __FILE__)
53
+ path = File.join(export_dir, @rel_path)
54
+ FileUtils.mkdir_p(File.dirname(path))
55
+ File.open(path, 'w') do |file|
56
+ erb = ERB.new(File.read(template))
57
+ file.write(erb.result(binding))
58
+ end
59
+ end
60
+ end
61
+ end