canvas_cc 0.0.1

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