moodle2cc 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog +7 -0
  3. data/lib/moodle2cc.rb +3 -0
  4. data/lib/moodle2cc/canvas_cc/calculated_question_writer.rb +11 -0
  5. data/lib/moodle2cc/canvas_cc/matching_question_writer.rb +6 -4
  6. data/lib/moodle2cc/canvas_cc/models/assessment.rb +1 -1
  7. data/lib/moodle2cc/canvas_cc/models/calculated_question.rb +13 -1
  8. data/lib/moodle2cc/canvas_cc/models/course.rb +2 -2
  9. data/lib/moodle2cc/canvas_cc/models/multiple_dropdowns_question.rb +7 -0
  10. data/lib/moodle2cc/canvas_cc/models/page.rb +7 -1
  11. data/lib/moodle2cc/canvas_cc/models/question.rb +1 -0
  12. data/lib/moodle2cc/canvas_cc/multiple_answers_question_writer.rb +7 -6
  13. data/lib/moodle2cc/canvas_cc/multiple_dropdowns_question_writer.rb +30 -0
  14. data/lib/moodle2cc/canvas_cc/question_writer.rb +2 -1
  15. data/lib/moodle2cc/moodle2/extractor.rb +7 -0
  16. data/lib/moodle2cc/moodle2/models.rb +1 -1
  17. data/lib/moodle2cc/moodle2/models/course.rb +3 -2
  18. data/lib/moodle2cc/moodle2/models/label.rb +5 -5
  19. data/lib/moodle2cc/moodle2/models/questionnaire.rb +1 -1
  20. data/lib/moodle2cc/moodle2/models/quizzes.rb +1 -0
  21. data/lib/moodle2cc/moodle2/models/quizzes/calculated_question.rb +2 -1
  22. data/lib/moodle2cc/moodle2/models/quizzes/multichoice_question.rb +6 -0
  23. data/lib/moodle2cc/moodle2/models/quizzes/question.rb +1 -1
  24. data/lib/moodle2cc/moodle2/models/wiki.rb +10 -0
  25. data/lib/moodle2cc/moodle2/parsers.rb +1 -0
  26. data/lib/moodle2cc/moodle2/parsers/course_parser.rb +5 -5
  27. data/lib/moodle2cc/moodle2/parsers/parser_helper.rb +7 -2
  28. data/lib/moodle2cc/moodle2/parsers/question_parsers/calculated_parser.rb +11 -1
  29. data/lib/moodle2cc/moodle2/parsers/question_parsers/match_parser.rb +2 -1
  30. data/lib/moodle2cc/moodle2/parsers/question_parsers/multichoice_parser.rb +2 -0
  31. data/lib/moodle2cc/moodle2/parsers/questionnaire_parser.rb +5 -0
  32. data/lib/moodle2cc/moodle2/parsers/quiz_parser.rb +5 -0
  33. data/lib/moodle2cc/moodle2/parsers/section_parser.rb +5 -1
  34. data/lib/moodle2cc/moodle2/parsers/wiki_parser.rb +47 -0
  35. data/lib/moodle2cc/moodle2converter/assessment_converter.rb +6 -4
  36. data/lib/moodle2cc/moodle2converter/assignment_converter.rb +1 -1
  37. data/lib/moodle2cc/moodle2converter/book_converter.rb +4 -4
  38. data/lib/moodle2cc/moodle2converter/converter_helper.rb +14 -0
  39. data/lib/moodle2cc/moodle2converter/discussion_converter.rb +1 -1
  40. data/lib/moodle2cc/moodle2converter/feedback_converter.rb +3 -3
  41. data/lib/moodle2cc/moodle2converter/html_converter.rb +16 -1
  42. data/lib/moodle2cc/moodle2converter/label_converter.rb +2 -2
  43. data/lib/moodle2cc/moodle2converter/migrator.rb +70 -2
  44. data/lib/moodle2cc/moodle2converter/question_bank_converter.rb +1 -1
  45. data/lib/moodle2cc/moodle2converter/question_converters.rb +1 -0
  46. data/lib/moodle2cc/moodle2converter/question_converters/calculated_converter.rb +1 -0
  47. data/lib/moodle2cc/moodle2converter/question_converters/matching_converter.rb +3 -0
  48. data/lib/moodle2cc/moodle2converter/question_converters/multichoice_converter.rb +15 -0
  49. data/lib/moodle2cc/moodle2converter/question_converters/multiple_blanks_converter.rb +1 -1
  50. data/lib/moodle2cc/moodle2converter/question_converters/question_converter.rb +3 -5
  51. data/lib/moodle2cc/moodle2converter/questionnaire_converter.rb +44 -8
  52. data/lib/moodle2cc/moodle2converter/section_converter.rb +3 -3
  53. data/lib/moodle2cc/moodle2converter/wiki_converter.rb +37 -0
  54. data/lib/moodle2cc/version.rb +1 -1
  55. data/spec/moodle2cc/canvas_cc/calculated_question_writer_spec.rb +7 -0
  56. data/spec/moodle2cc/canvas_cc/matching_question_writer_spec.rb +2 -2
  57. data/spec/moodle2cc/canvas_cc/models/assessment_spec.rb +1 -1
  58. data/spec/moodle2cc/canvas_cc/models/calculated_question_spec.rb +25 -0
  59. data/spec/moodle2cc/canvas_cc/models/page_spec.rb +6 -0
  60. data/spec/moodle2cc/canvas_cc/multiple_answers_question_writer_spec.rb +4 -1
  61. data/spec/moodle2cc/canvas_cc/multiple_blanks_question_writer_spec.rb +1 -1
  62. data/spec/moodle2cc/canvas_cc/multiple_dropdowns_question_writer_spec.rb +46 -0
  63. data/spec/moodle2cc/moodle2/extractor_spec.rb +8 -0
  64. data/spec/moodle2cc/moodle2/models/label_spec.rb +4 -4
  65. data/spec/moodle2cc/moodle2/parsers/parser_helper_spec.rb +10 -0
  66. data/spec/moodle2cc/moodle2/parsers/question_parsers/calculated_parser_spec.rb +17 -0
  67. data/spec/moodle2cc/moodle2/parsers/questionnaire_parser_spec.rb +4 -0
  68. data/spec/moodle2cc/moodle2/parsers/quiz_parser_spec.rb +1 -1
  69. data/spec/moodle2cc/moodle2/parsers/wiki_parser_spec.rb +23 -0
  70. data/spec/moodle2cc/moodle2converter/assessment_converter_spec.rb +12 -7
  71. data/spec/moodle2cc/moodle2converter/converter_helper_spec.rb +5 -0
  72. data/spec/moodle2cc/moodle2converter/html_converter_spec.rb +7 -2
  73. data/spec/moodle2cc/moodle2converter/label_converter_spec.rb +17 -0
  74. data/spec/moodle2cc/moodle2converter/migrator_spec.rb +83 -2
  75. data/spec/moodle2cc/moodle2converter/question_converters/calculated_converter_spec.rb +2 -0
  76. data/spec/moodle2cc/moodle2converter/question_converters/matching_converter_spec.rb +2 -3
  77. data/spec/moodle2cc/moodle2converter/question_converters/multichoice_converter_spec.rb +26 -0
  78. data/spec/moodle2cc/moodle2converter/question_converters/question_converter_spec.rb +0 -3
  79. data/spec/moodle2cc/moodle2converter/wiki_converter_spec.rb +36 -0
  80. data/test/fixtures/moodle2/backup/activities/quiz_5/quiz.xml +1 -1
  81. data/test/fixtures/moodle2/backup/activities/wiki_58541/calendar.xml +3 -0
  82. data/test/fixtures/moodle2/backup/activities/wiki_58541/completion.xml +3 -0
  83. data/test/fixtures/moodle2/backup/activities/wiki_58541/grades.xml +7 -0
  84. data/test/fixtures/moodle2/backup/activities/wiki_58541/inforef.xml +47 -0
  85. data/test/fixtures/moodle2/backup/activities/wiki_58541/module.xml +28 -0
  86. data/test/fixtures/moodle2/backup/activities/wiki_58541/roles.xml +7 -0
  87. data/test/fixtures/moodle2/backup/activities/wiki_58541/wiki.xml +70 -0
  88. data/test/fixtures/moodle2/backup/moodle_backup.xml +7 -0
  89. metadata +33 -2
@@ -22,10 +22,20 @@ module Moodle2CC::Moodle2
22
22
  end
23
23
 
24
24
  q_node.search('dataset_definitions/dataset_definition').each do |ds_node|
25
+ var_name = parse_text(ds_node, 'name')
25
26
  question.dataset_definitions << {
26
- :name => parse_text(ds_node, 'name'),
27
+ :name => var_name,
27
28
  :options => parse_text(ds_node, 'options')
28
29
  }
30
+ ds_node.search('dataset_items/dataset_item').each do |ds_item_node|
31
+ ident = parse_text(ds_item_node, 'number')
32
+ var_set = question.var_sets.detect{|vs| vs[:ident] == ident}
33
+ unless var_set
34
+ var_set = {:ident => ident, :vars => {}}
35
+ question.var_sets << var_set
36
+ end
37
+ var_set[:vars][var_name] = parse_text(ds_item_node, 'value')
38
+ end
29
39
  end
30
40
 
31
41
  q_node.search('calculated_records/calculated_record').each do |cr_node|
@@ -2,9 +2,10 @@ module Moodle2CC::Moodle2
2
2
  class Parsers::QuestionParsers::MatchParser < Parsers::QuestionParsers::QuestionParser
3
3
  include Parsers::ParserHelper
4
4
  register_parser_type('match')
5
+ register_parser_type('ddmatch')
5
6
 
6
7
  def parse_question(node)
7
- question = super
8
+ question = super(node, 'match')
8
9
 
9
10
  q_node = node.at_xpath("plugin_qtype_#{question.qtype}_question")
10
11
 
@@ -9,6 +9,8 @@ module Moodle2CC::Moodle2
9
9
  answer_parser = Parsers::AnswerParser.new
10
10
  question.answers += node.search('answers/answer').map { |n| answer_parser.parse(n) }
11
11
 
12
+ question.single = parse_boolean(node, 'plugin_qtype_multichoice_question/multichoice/single')
13
+
12
14
  question
13
15
  end
14
16
 
@@ -39,6 +39,11 @@ module Moodle2CC::Moodle2::Parsers
39
39
  question.type_id = parse_text(node, 'type_id')
40
40
  question.position = parse_text(node, 'position')
41
41
  question.content = parse_text(node, 'content')
42
+
43
+ question.length = parse_text(node, 'length') # used for rating scale
44
+ question.precise = parse_text(node, 'precise') # used for rating scale type
45
+
46
+ question.deleted = parse_boolean(node, 'deleted')
42
47
  node.search('quest_choices/quest_choice').each do |choice_node|
43
48
  question.choices << {
44
49
  :id => choice_node.attributes['id'].value,
@@ -69,6 +69,11 @@ module Moodle2CC::Moodle2::Parsers
69
69
  }
70
70
  end
71
71
 
72
+ question_order = parse_text(xml, '/activity/quiz/questions').to_s.split(',')
73
+ unless question_order.empty?
74
+ quiz.question_instances.sort_by!{|qi| question_order.index(qi[:question])}
75
+ end
76
+
72
77
  xml.search('/activity/quiz/feedbacks/feedback').each do |node|
73
78
  quiz.feedbacks << {
74
79
  :text => parse_text(node, 'feedbacktext'),
@@ -25,7 +25,11 @@ module Moodle2CC::Moodle2::Parsers
25
25
  section.summary = parse_text(section_xml, '/section/summary')
26
26
  section.summary_format = parse_text(section_xml, 'section/summaryformat')
27
27
  section.sequence = parse_text(section_xml, 'section/sequence')
28
- section.sequence = section.sequence.split(',') if section.sequence
28
+ if section.sequence
29
+ section.sequence = section.sequence.split(',')
30
+ else
31
+ section.sequence = []
32
+ end
29
33
  section.visible = parse_text(section_xml, 'section/visible') == '1' ? true : false
30
34
  section.available_from = parse_text(section_xml, 'section/availablefrom')
31
35
  section.available_until = parse_text(section_xml, 'section/availableuntil')
@@ -0,0 +1,47 @@
1
+ module Moodle2CC::Moodle2::Parsers
2
+ class WikiParser
3
+ include ParserHelper
4
+
5
+ WIKI_XML = 'wiki.xml'
6
+ WIKI_MODULE_NAME = 'wiki'
7
+
8
+ def initialize(backup_dir)
9
+ @backup_dir = backup_dir
10
+ end
11
+
12
+ def parse
13
+ activity_dirs = activity_directories(@backup_dir, WIKI_MODULE_NAME)
14
+ activity_dirs.map { |dir| parse_wiki(dir) }
15
+ end
16
+
17
+ private
18
+
19
+ def parse_wiki(dir)
20
+ wiki = Moodle2CC::Moodle2::Models::Wiki.new
21
+ activity_dir = File.join(@backup_dir, dir)
22
+ File.open(File.join(activity_dir, WIKI_XML)) do |f|
23
+ wiki_xml = Nokogiri::XML(f)
24
+ wiki.id = wiki_xml.at_xpath('/activity/wiki/@id').value
25
+ wiki.module_id = wiki_xml.at_xpath('/activity/@moduleid').value
26
+ wiki.name = parse_text(wiki_xml, '/activity/wiki/name')
27
+ wiki.intro = parse_text(wiki_xml, '/activity/wiki/intro')
28
+ wiki.intro_format = parse_text(wiki_xml, '/activity/wiki/introformat')
29
+
30
+ wiki.first_page_title = parse_text(wiki_xml, '/activity/wiki/firstpagetitle')
31
+
32
+ wiki_xml.search('/activity/wiki/subwikis/subwiki/pages/page').each do |node|
33
+ wiki.pages << {
34
+ :id => node.attributes['id'].value,
35
+ :title => parse_text(node, 'title'),
36
+ :content => parse_text(node, 'cachedcontent')
37
+ }
38
+ end
39
+ end
40
+ parse_module(activity_dir, wiki)
41
+
42
+ wiki
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -11,7 +11,7 @@ module Moodle2CC::Moodle2Converter
11
11
  def convert_quiz(moodle_quiz)
12
12
  canvas_assessment = Moodle2CC::CanvasCC::Models::Assessment.new
13
13
  canvas_assessment.identifier = generate_unique_identifier_for(moodle_quiz.id, ASSESSMENT_SUFFIX)
14
- canvas_assessment.title = moodle_quiz.name
14
+ canvas_assessment.title = truncate_text(moodle_quiz.name)
15
15
  canvas_assessment.description = moodle_quiz.intro
16
16
  canvas_assessment.workflow_state = workflow_state(moodle_quiz.visible)
17
17
 
@@ -25,7 +25,9 @@ module Moodle2CC::Moodle2Converter
25
25
  canvas_assessment.access_code = moodle_quiz.password
26
26
  canvas_assessment.ip_filter = moodle_quiz.subnet
27
27
  canvas_assessment.shuffle_answers = moodle_quiz.shuffle_answers
28
- canvas_assessment.time_limit = Integer(moodle_quiz.time_limit) if moodle_quiz.time_limit
28
+ if moodle_quiz.time_limit && moodle_quiz.time_limit.to_i > 0
29
+ canvas_assessment.time_limit = (moodle_quiz.time_limit.to_f / 60).ceil
30
+ end
29
31
  canvas_assessment.quiz_type = 'practice_quiz'
30
32
 
31
33
  canvas_assessment.question_references = moodle_quiz.question_instances
@@ -36,7 +38,7 @@ module Moodle2CC::Moodle2Converter
36
38
  def convert_choice(moodle_choice)
37
39
  canvas_assessment = Moodle2CC::CanvasCC::Models::Assessment.new
38
40
  canvas_assessment.identifier = generate_unique_identifier_for(moodle_choice.id, CHOICE_ASSESSMENT_SUFFIX)
39
- canvas_assessment.title = moodle_choice.name
41
+ canvas_assessment.title = truncate_text(moodle_choice.name)
40
42
  canvas_assessment.description = ''
41
43
  canvas_assessment.workflow_state = workflow_state(moodle_choice.visible)
42
44
 
@@ -49,7 +51,7 @@ module Moodle2CC::Moodle2Converter
49
51
 
50
52
  question = Moodle2CC::CanvasCC::Models::Question.create('multiple_choice_question')
51
53
  question.identifier = generate_unique_identifier_for(moodle_choice.id, '_choice_question')
52
- question.title = moodle_choice.name
54
+ question.title = truncate_text(moodle_choice.name)
53
55
  question.material = moodle_choice.intro
54
56
  question.answers = []
55
57
  moodle_choice.options.each_with_index do |option, num|
@@ -5,7 +5,7 @@ module Moodle2CC::Moodle2Converter
5
5
  def convert(moodle_assignment)
6
6
  canvas_assignment = Moodle2CC::CanvasCC::Models::Assignment.new
7
7
  canvas_assignment.identifier = generate_unique_identifier_for(moodle_assignment.id, ASSIGNMENT_SUFFIX)
8
- canvas_assignment.title = moodle_assignment.name
8
+ canvas_assignment.title = truncate_text(moodle_assignment.name)
9
9
  canvas_assignment.body = moodle_assignment.intro
10
10
  canvas_assignment.due_at = Time.at(Integer(moodle_assignment.due_date)) if moodle_assignment.due_date
11
11
  canvas_assignment.lock_at = Time.at(Integer(moodle_assignment.cut_off_date)) if moodle_assignment.cut_off_date
@@ -24,7 +24,7 @@ module Moodle2CC
24
24
  page.identifier = generate_unique_identifier_for_book_intro(moodle_book)
25
25
  page.body = moodle_book.intro
26
26
  if pages.any?{|p| page.title == p.title}
27
- page.title = "#{page.title} (Introduction)"
27
+ page.title = "#{truncate_text(page.title, MAX_TITLE_LENGTH - 20)} (Introduction)"
28
28
  end
29
29
  page.workflow_state = workflow_state(moodle_book.visible)
30
30
  pages.unshift(page)
@@ -46,7 +46,7 @@ module Moodle2CC
46
46
  def create_title(moodle_book)
47
47
  module_item = create_module_item_with_defaults()
48
48
  module_item.content_type = Moodle2CC::CanvasCC::Models::ModuleItem::CONTENT_TYPE_CONTEXT_MODULE_SUB_HEADER
49
- module_item.title = moodle_book.name
49
+ module_item.title = truncate_text(moodle_book.name)
50
50
  module_item.indent = "0"
51
51
  module_item.identifier = generate_unique_identifier()
52
52
  module_item.workflow_state = workflow_state(moodle_book.visible)
@@ -67,7 +67,7 @@ module Moodle2CC
67
67
 
68
68
  def create_chapter(moodle_chapter)
69
69
  module_item = create_module_item_with_defaults()
70
- module_item.title = moodle_chapter.title
70
+ module_item.title = truncate_text(moodle_chapter.title)
71
71
  module_item.indent = moodle_chapter.subchapter ? "2" : "1"
72
72
  module_item.identifier = generate_unique_identifier()
73
73
  module_item.identifierref = generate_unique_identifier_for_activity(moodle_chapter)
@@ -88,7 +88,7 @@ module Moodle2CC
88
88
  page = CanvasCC::Models::Page.new
89
89
  page.type = CanvasCC::Models::Resource::WEB_CONTENT_TYPE
90
90
  page.href = generate_unique_resource_path(CanvasCC::Models::Page::BOOK_PATH, title)
91
- page.title = title
91
+ page.title = truncate_text(title)
92
92
  page.workflow_state = CanvasCC::Models::WorkflowState::ACTIVE
93
93
  page.editing_roles = CanvasCC::Models::Page::EDITING_ROLE_TEACHER
94
94
  page
@@ -20,6 +20,7 @@ module Moodle2CC
20
20
 
21
21
  ACTIVITY_LOOKUP = {
22
22
  Moodle2::Models::Page => {suffix: PAGE_SUFFIX, content_type: CanvasCC::Models::ModuleItem::CONTENT_TYPE_WIKI_PAGE},
23
+ Moodle2::Models::Wiki => {suffix: PAGE_SUFFIX, content_type: CanvasCC::Models::ModuleItem::CONTENT_TYPE_WIKI_PAGE},
23
24
  Moodle2::Models::Assignment => {suffix: ASSIGNMENT_SUFFIX, content_type: CanvasCC::Models::ModuleItem::CONTENT_TYPE_ASSIGNMENT},
24
25
  Moodle2::Models::Folder => {suffix: FOLDER_SUFFIX, content_type: CanvasCC::Models::ModuleItem::CONTENT_TYPE_WIKI_PAGE},
25
26
  Moodle2::Models::Forum => {suffix: DISCUSSION_SUFFIX, content_type: CanvasCC::Models::ModuleItem::CONTENT_TYPE_DISCUSSION_TOPIC},
@@ -35,6 +36,8 @@ module Moodle2CC
35
36
  Moodle2::Models::Resource => {suffix: nil, content_type: CanvasCC::Models::ModuleItem::CONTENT_TYPE_ATTACHMENT}
36
37
  }
37
38
 
39
+ MAX_TITLE_LENGTH = 250
40
+
38
41
  def generate_unique_resource_path(base_path, readable_name, file_extension = 'html')
39
42
  file_name_suffix = readable_name ? Moodle2CC::CanvasCC::Models::Page.convert_name_to_url(readable_name) : ''
40
43
  ext = file_extension ? ".#{file_extension}" : ''
@@ -69,6 +72,17 @@ module Moodle2CC
69
72
  moodle_visibility ? CanvasCC::Models::WorkflowState::ACTIVE : CanvasCC::Models::WorkflowState::UNPUBLISHED
70
73
  end
71
74
 
75
+ def truncate_text(text, max_length = nil, ellipsis = '...')
76
+ max_length ||= MAX_TITLE_LENGTH
77
+ return text if !text || text.length <= max_length
78
+
79
+ actual_length = max_length - ellipsis.length
80
+
81
+ # First truncate the text down to the bytes max, then lop off any invalid
82
+ # unicode characters at the end.
83
+ truncated = text[0,actual_length][/.{0,#{actual_length}}/mu]
84
+ truncated + ellipsis
85
+ end
72
86
 
73
87
  end
74
88
  end
@@ -6,7 +6,7 @@ module Moodle2CC::Moodle2Converter
6
6
  def convert(forum)
7
7
  discussion = Moodle2CC::CanvasCC::Models::Discussion.new
8
8
  discussion.identifier = generate_unique_identifier_for(forum.id, DISCUSSION_SUFFIX)
9
- discussion.title = forum.name
9
+ discussion.title = truncate_text(forum.name)
10
10
  discussion.text = forum.intro
11
11
  discussion.discussion_type = 'threaded'
12
12
  discussion.workflow_state = workflow_state(forum.visible)
@@ -5,7 +5,7 @@ module Moodle2CC::Moodle2Converter
5
5
  def convert_feedback(moodle_feedback)
6
6
  canvas_assessment = Moodle2CC::CanvasCC::Models::Assessment.new
7
7
  canvas_assessment.identifier = generate_unique_identifier_for(moodle_feedback.id, FEEDBACK_ASSESSMENT_SUFFIX)
8
- canvas_assessment.title = moodle_feedback.name
8
+ canvas_assessment.title = truncate_text(moodle_feedback.name)
9
9
  canvas_assessment.description = moodle_feedback.intro
10
10
  canvas_assessment.workflow_state = workflow_state(moodle_feedback.visible)
11
11
 
@@ -40,10 +40,10 @@ module Moodle2CC::Moodle2Converter
40
40
  canvas_question = Moodle2CC::CanvasCC::Models::Question.create(canvas_type)
41
41
  canvas_question.identifier = generate_unique_identifier_for(moodle_question.id, "_feedback_question")
42
42
  if moodle_question.type == 'label'
43
- canvas_question.title = moodle_question.name
43
+ canvas_question.title = truncate_text(moodle_question.name)
44
44
  canvas_question.material = moodle_question.presentation
45
45
  else
46
- canvas_question.title = moodle_question.label
46
+ canvas_question.title = truncate_text(moodle_question.label)
47
47
  canvas_question.material = moodle_question.name
48
48
  end
49
49
 
@@ -17,7 +17,9 @@ module Moodle2CC::Moodle2Converter
17
17
  end
18
18
 
19
19
  def convert(content)
20
- update_links(content.gsub('id="main"', ''))
20
+ content = update_links(content.gsub('id="main"', ''))
21
+ content = convert_equations(content)
22
+ content
21
23
  end
22
24
 
23
25
  private
@@ -92,5 +94,18 @@ module Moodle2CC::Moodle2Converter
92
94
  end
93
95
  end
94
96
 
97
+ def convert_equations(content)
98
+ # turn moodle equations ( e.g. $$3 * x$$ ) into canvas equations
99
+ content.gsub(/\$\$([^\$]*)\$\$/) do |match|
100
+ latex = $1.to_s.gsub("\"", "\\\"")
101
+ if latex.length > 0
102
+ url = "/equation_images/#{CGI.escape(CGI.escape(latex).gsub("+", "%20"))}"
103
+
104
+ "<img class=\"equation_image\" title=\"#{latex}\" alt=\"#{latex}\" src=\"#{url}\">"
105
+ else
106
+ ""
107
+ end
108
+ end
109
+ end
95
110
  end
96
111
  end
@@ -7,7 +7,7 @@ module Moodle2CC
7
7
  module_item = CanvasCC::Models::ModuleItem.new
8
8
  module_item.identifier = generate_unique_identifier
9
9
  module_item.workflow_state = workflow_state(moodle_label.visible)
10
- module_item.title = moodle_label.converted_title
10
+ module_item.title = truncate_text(moodle_label.converted_title)
11
11
  module_item.indent = '0'
12
12
 
13
13
  if moodle_label.convert_to_page?
@@ -25,7 +25,7 @@ module Moodle2CC
25
25
  if moodle_label.convert_to_page?
26
26
  canvas_page = CanvasCC::Models::Page.new
27
27
  canvas_page.identifier = generate_unique_identifier_for_activity(moodle_label)
28
- canvas_page.title = moodle_label.converted_title
28
+ canvas_page.title = truncate_text(moodle_label.converted_title)
29
29
  canvas_page.workflow_state = workflow_state(moodle_label.visible)
30
30
  canvas_page.editing_roles = CanvasCC::Models::Page::EDITING_ROLE_TEACHER
31
31
  canvas_page.body = moodle_label.intro
@@ -1,6 +1,8 @@
1
1
  module Moodle2CC::Moodle2Converter
2
2
  class Migrator
3
3
 
4
+ include ConverterHelper
5
+
4
6
  def initialize(source_file, output_dir)
5
7
  @extractor = Moodle2CC::Moodle2::Extractor.new(source_file)
6
8
  @output_dir = output_dir
@@ -11,6 +13,7 @@ module Moodle2CC::Moodle2Converter
11
13
  cc_course = convert_course(moodle_course)
12
14
  cc_course.files += convert_files(moodle_course.files)
13
15
  cc_course.pages += convert_pages(moodle_course.pages)
16
+ cc_course.pages += convert_wikis(moodle_course.wikis)
14
17
  cc_course.discussions += convert_discussions(moodle_course.forums)
15
18
  cc_course.assignments += convert_assignments(moodle_course.assignments)
16
19
 
@@ -19,7 +22,6 @@ module Moodle2CC::Moodle2Converter
19
22
  cc_course.assessments += convert_assessments(moodle_course.quizzes, moodle_course.choices,
20
23
  moodle_course.feedbacks, moodle_course.questionnaires)
21
24
  cc_course.question_banks += convert_question_banks(moodle_course.question_categories)
22
- cc_course.resolve_question_references
23
25
 
24
26
  cc_course.pages += convert_sections_to_pages(moodle_course.sections)
25
27
  cc_course.pages += convert_folders(moodle_course)
@@ -29,8 +31,10 @@ module Moodle2CC::Moodle2Converter
29
31
 
30
32
  cc_course.canvas_modules += convert_sections(moodle_course.sections)
31
33
 
34
+ resolve_duplicate_page_titles!(cc_course)
32
35
  convert_html!(cc_course, moodle_course)
33
36
 
37
+ cc_course.resolve_question_references!
34
38
  @path = Moodle2CC::CanvasCC::CartridgeCreator.new(cc_course).create(@output_dir)
35
39
  end
36
40
  @path
@@ -61,6 +65,11 @@ module Moodle2CC::Moodle2Converter
61
65
  pages.map { |page| page_converter.convert(page) }
62
66
  end
63
67
 
68
+ def convert_wikis(wikis)
69
+ wiki_converter = Moodle2CC::Moodle2Converter::WikiConverter.new
70
+ wikis.map { |wiki| wiki_converter.convert(wiki) }.flatten
71
+ end
72
+
64
73
  def convert_discussions(discussions)
65
74
  discussion_converter = Moodle2CC::Moodle2Converter::DiscussionConverter.new
66
75
  discussions.map { |discussion| discussion_converter.convert(discussion) }
@@ -118,8 +127,67 @@ module Moodle2CC::Moodle2Converter
118
127
  cc_course.pages.each {|page| page.body = html_converter.convert(page.body)}
119
128
  cc_course.discussions.each {|discussion| discussion.text = html_converter.convert(discussion.text)}
120
129
  cc_course.assignments.each {|assignment| assignment.body = html_converter.convert(assignment.body)}
121
- cc_course.assessments.each {|assessment| assessment.description = html_converter.convert(assessment.description)}
130
+
131
+ cc_course.assessments.each do |assessment|
132
+ assessment.description = html_converter.convert(assessment.description)
133
+
134
+ next unless assessment.items
135
+ assessment.items.each do |item|
136
+ if item.is_a?(Moodle2CC::CanvasCC::Models::QuestionGroup)
137
+ item.questions.each do |question|
138
+ convert_question_html!(question, html_converter)
139
+ end
140
+ elsif item.is_a?(Moodle2CC::CanvasCC::Models::Question)
141
+ convert_question_html!(item, html_converter)
142
+ end
143
+ end
144
+ end
145
+
146
+ cc_course.question_banks.each do |question_bank|
147
+ question_bank.questions.each do |question|
148
+ convert_question_html!(question, html_converter)
149
+ end
150
+ end
151
+ end
152
+
153
+ def convert_question_html!(question, html_converter)
154
+ question.material = html_converter.convert(question.material)
155
+ question.general_feedback = html_converter.convert(question.general_feedback) if question.general_feedback
156
+
157
+ question.answers.each do |answer|
158
+ answer.answer_text = html_converter.convert(answer.answer_text)
159
+ answer.feedback = html_converter.convert(answer.feedback) if answer.feedback
160
+ end
161
+
162
+ question.post_process! if question.is_a?(Moodle2CC::CanvasCC::Models::CalculatedQuestion)
122
163
  end
123
164
 
165
+ def resolve_duplicate_page_titles!(cc_course)
166
+ page_titles = cc_course.pages.map(&:title)
167
+ duplicate_page_map = cc_course.pages.group_by(&:title).select{|k, v| v.count > 1}
168
+ duplicate_page_map.each do |title, dup_pages|
169
+ dup_pages.sort_by!{|page| find_module_index_for_page(cc_course, page)}
170
+
171
+ dup_pages.each_with_index do |page, index|
172
+ next if index == 0
173
+ num = index + 1
174
+ while (title = "#{page.title}-#{num}") && page_titles.include?(title)
175
+ num += 1
176
+ end
177
+ page.title = title
178
+ end
179
+ end
180
+ end
181
+
182
+ def find_module_index_for_page(cc_course, canvas_page)
183
+ cc_course.canvas_modules.each_with_index do |canvas_module, module_index|
184
+ canvas_module.module_items.each_with_index do |module_item, item_index|
185
+ if module_item.identifierref.to_s == canvas_page.identifier.to_s
186
+ return [module_index, item_index]
187
+ end
188
+ end
189
+ end
190
+ [Float::INFINITY]
191
+ end
124
192
  end
125
193
  end