moodle2cc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE +661 -0
- data/README.md +38 -0
- data/Rakefile +12 -0
- data/bin/moodle2cc +6 -0
- data/lib/moodle2cc.rb +60 -0
- data/lib/moodle2cc/canvas/.converter.rb.swo +0 -0
- data/lib/moodle2cc/canvas/.wiki.rb.swo +0 -0
- data/lib/moodle2cc/canvas/assessment.rb +109 -0
- data/lib/moodle2cc/canvas/assignment.rb +108 -0
- data/lib/moodle2cc/canvas/converter.rb +28 -0
- data/lib/moodle2cc/canvas/course.rb +145 -0
- data/lib/moodle2cc/canvas/discussion_topic.rb +64 -0
- data/lib/moodle2cc/canvas/label.rb +8 -0
- data/lib/moodle2cc/canvas/question.rb +468 -0
- data/lib/moodle2cc/canvas/question_bank.rb +54 -0
- data/lib/moodle2cc/canvas/resource.rb +16 -0
- data/lib/moodle2cc/canvas/templates/assignment.html.erb +9 -0
- data/lib/moodle2cc/canvas/templates/syllabus.html.erb +9 -0
- data/lib/moodle2cc/canvas/templates/wiki_content.html.erb +10 -0
- data/lib/moodle2cc/canvas/web_content.rb +10 -0
- data/lib/moodle2cc/canvas/web_link.rb +17 -0
- data/lib/moodle2cc/canvas/wiki.rb +25 -0
- data/lib/moodle2cc/cc/assessment.rb +25 -0
- data/lib/moodle2cc/cc/assignment.rb +66 -0
- data/lib/moodle2cc/cc/cc_helper.rb +282 -0
- data/lib/moodle2cc/cc/converter.rb +136 -0
- data/lib/moodle2cc/cc/course.rb +16 -0
- data/lib/moodle2cc/cc/discussion_topic.rb +53 -0
- data/lib/moodle2cc/cc/label.rb +6 -0
- data/lib/moodle2cc/cc/question.rb +23 -0
- data/lib/moodle2cc/cc/resource.rb +30 -0
- data/lib/moodle2cc/cc/templates/assignment.html.erb +9 -0
- data/lib/moodle2cc/cc/templates/syllabus.html.erb +9 -0
- data/lib/moodle2cc/cc/templates/wiki_content.html.erb +10 -0
- data/lib/moodle2cc/cc/web_content.rb +40 -0
- data/lib/moodle2cc/cc/web_link.rb +53 -0
- data/lib/moodle2cc/cc/wiki.rb +72 -0
- data/lib/moodle2cc/cli.rb +14 -0
- data/lib/moodle2cc/error.rb +3 -0
- data/lib/moodle2cc/migrator.rb +23 -0
- data/lib/moodle2cc/moodle/backup.rb +38 -0
- data/lib/moodle2cc/moodle/course.rb +24 -0
- data/lib/moodle2cc/moodle/grade_item.rb +24 -0
- data/lib/moodle2cc/moodle/info.rb +8 -0
- data/lib/moodle2cc/moodle/mod.rb +127 -0
- data/lib/moodle2cc/moodle/question.rb +98 -0
- data/lib/moodle2cc/moodle/question_category.rb +17 -0
- data/lib/moodle2cc/moodle/section.rb +37 -0
- data/lib/moodle2cc/resource_factory.rb +32 -0
- data/lib/moodle2cc/version.rb +3 -0
- data/moodle2cc.gemspec +29 -0
- data/test/acceptance/migrator_test.rb +23 -0
- data/test/fixtures/cc.imscc +0 -0
- data/test/fixtures/moodle_backup/course_files/folder/test.txt +1 -0
- data/test/fixtures/moodle_backup/course_files/test.txt +1 -0
- data/test/fixtures/moodle_backup/moodle.xml +916 -0
- data/test/test_helper.rb +43 -0
- data/test/test_question_helper.rb +107 -0
- data/test/test_wiki_helper.rb +21 -0
- data/test/unit/canvas/assessment_test.rb +218 -0
- data/test/unit/canvas/assignment_test.rb +220 -0
- data/test/unit/canvas/converter_test.rb +159 -0
- data/test/unit/canvas/course_test.rb +176 -0
- data/test/unit/canvas/discussion_topic_test.rb +129 -0
- data/test/unit/canvas/label_test.rb +32 -0
- data/test/unit/canvas/question_bank_test.rb +73 -0
- data/test/unit/canvas/question_test.rb +824 -0
- data/test/unit/canvas/web_content_test.rb +37 -0
- data/test/unit/canvas/web_link_test.rb +48 -0
- data/test/unit/canvas/wiki_test.rb +74 -0
- data/test/unit/cc/assessment_test.rb +48 -0
- data/test/unit/cc/assignment_test.rb +67 -0
- data/test/unit/cc/cc_helper_test.rb +19 -0
- data/test/unit/cc/converter_test.rb +159 -0
- data/test/unit/cc/course_test.rb +36 -0
- data/test/unit/cc/discussion_topic_test.rb +83 -0
- data/test/unit/cc/label_test.rb +29 -0
- data/test/unit/cc/question_test.rb +49 -0
- data/test/unit/cc/web_content_test.rb +76 -0
- data/test/unit/cc/web_link_test.rb +79 -0
- data/test/unit/cc/wiki_test.rb +139 -0
- data/test/unit/migrator_test.rb +56 -0
- data/test/unit/moodle/backup_test.rb +30 -0
- data/test/unit/moodle/course_test.rb +57 -0
- data/test/unit/moodle/grade_item_test.rb +72 -0
- data/test/unit/moodle/info_test.rb +21 -0
- data/test/unit/moodle/mod_test.rb +301 -0
- data/test/unit/moodle/question_category_test.rb +34 -0
- data/test/unit/moodle/question_test.rb +185 -0
- data/test/unit/moodle/section_test.rb +75 -0
- data/test/unit/resource_factory_test.rb +119 -0
- metadata +342 -0
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Moodle2CC
|
2
|
+
|
3
|
+
moodle2cc will convert Moodle 1.9 backup files into IMS Common Cartridge
|
4
|
+
formatted files.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'moodle2cc'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install moodle2cc
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
For Common Cartridge format
|
23
|
+
$ moodle2cc migrate <path-to-moodle-backup> <path-to-cc-export-directory>
|
24
|
+
|
25
|
+
For Canvas Common Cartridge format
|
26
|
+
$ moodle2cc migrate --format=canvas <path-to-moodle-backup> <path-to-cc-export-directory>
|
27
|
+
|
28
|
+
## Contributing
|
29
|
+
|
30
|
+
Run the tests:
|
31
|
+
|
32
|
+
$ bundle exec rake
|
33
|
+
|
34
|
+
1. Fork it
|
35
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
36
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
37
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
38
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/moodle2cc
ADDED
data/lib/moodle2cc.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'cgi'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'erb'
|
6
|
+
require 'happymapper'
|
7
|
+
require 'builder'
|
8
|
+
require 'nokogiri'
|
9
|
+
|
10
|
+
require 'moodle2cc/error'
|
11
|
+
require 'moodle2cc/migrator'
|
12
|
+
|
13
|
+
module Moodle2CC
|
14
|
+
class OpenStruct < ::OpenStruct
|
15
|
+
if defined? id
|
16
|
+
undef id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
autoload :ResourceFactory, 'moodle2cc/resource_factory'
|
21
|
+
|
22
|
+
module CC
|
23
|
+
autoload :Assessment, 'moodle2cc/cc/assessment'
|
24
|
+
autoload :Assignment, 'moodle2cc/cc/assignment'
|
25
|
+
autoload :CCHelper, 'moodle2cc/cc/cc_helper'
|
26
|
+
autoload :Converter, 'moodle2cc/cc/converter'
|
27
|
+
autoload :Course, 'moodle2cc/cc/course'
|
28
|
+
autoload :DiscussionTopic, 'moodle2cc/cc/discussion_topic'
|
29
|
+
autoload :Label, 'moodle2cc/cc/label'
|
30
|
+
autoload :Question, 'moodle2cc/cc/question'
|
31
|
+
autoload :Resource, 'moodle2cc/cc/resource'
|
32
|
+
autoload :WebContent, 'moodle2cc/cc/web_content'
|
33
|
+
autoload :WebLink, 'moodle2cc/cc/web_link'
|
34
|
+
autoload :Wiki, 'moodle2cc/cc/wiki'
|
35
|
+
end
|
36
|
+
module Canvas
|
37
|
+
autoload :Assessment, 'moodle2cc/canvas/assessment'
|
38
|
+
autoload :Assignment, 'moodle2cc/canvas/assignment'
|
39
|
+
autoload :Converter, 'moodle2cc/canvas/converter'
|
40
|
+
autoload :Course, 'moodle2cc/canvas/course'
|
41
|
+
autoload :DiscussionTopic, 'moodle2cc/canvas/discussion_topic'
|
42
|
+
autoload :Label, 'moodle2cc/canvas/label'
|
43
|
+
autoload :Question, 'moodle2cc/canvas/question'
|
44
|
+
autoload :QuestionBank, 'moodle2cc/canvas/question_bank'
|
45
|
+
autoload :Resource, 'moodle2cc/canvas/resource'
|
46
|
+
autoload :WebContent, 'moodle2cc/canvas/web_content'
|
47
|
+
autoload :WebLink, 'moodle2cc/canvas/web_link'
|
48
|
+
autoload :Wiki, 'moodle2cc/canvas/wiki'
|
49
|
+
end
|
50
|
+
module Moodle
|
51
|
+
autoload :Backup, 'moodle2cc/moodle/backup'
|
52
|
+
autoload :Course, 'moodle2cc/moodle/course'
|
53
|
+
autoload :GradeItem, 'moodle2cc/moodle/grade_item'
|
54
|
+
autoload :Info, 'moodle2cc/moodle/info'
|
55
|
+
autoload :Mod, 'moodle2cc/moodle/mod'
|
56
|
+
autoload :Question, 'moodle2cc/moodle/question'
|
57
|
+
autoload :QuestionCategory, 'moodle2cc/moodle/question_category'
|
58
|
+
autoload :Section, 'moodle2cc/moodle/section'
|
59
|
+
end
|
60
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Moodle2CC::Canvas
|
2
|
+
class Assessment < Moodle2CC::CC::Assessment
|
3
|
+
include Resource
|
4
|
+
META_ATTRIBUTES = [:title, :description, :lock_at, :unlock_at, :allowed_attempts,
|
5
|
+
:scoring_policy, :access_code, :ip_filter, :shuffle_answers, :time_limit, :quiz_type]
|
6
|
+
|
7
|
+
attr_accessor :non_cc_assessments_identifier, *META_ATTRIBUTES
|
8
|
+
|
9
|
+
def initialize(mod, position=0)
|
10
|
+
super
|
11
|
+
description = [mod.intro, mod.content, mod.text, mod.summary].compact.reject { |d| d.length == 0 }.first || ''
|
12
|
+
@description = convert_file_path_tokens(description)
|
13
|
+
if mod.time_close.to_i > 0
|
14
|
+
@lock_at = ims_datetime(Time.at(mod.time_close))
|
15
|
+
end
|
16
|
+
if mod.time_open.to_i > 0
|
17
|
+
@unlock_at = ims_datetime(Time.at(mod.time_open))
|
18
|
+
end
|
19
|
+
@time_limit = mod.time_limit
|
20
|
+
@allowed_attempts = mod.attempts_number
|
21
|
+
@scoring_policy = mod.grade_method == 4 ? 'keep_latest' : 'keep_highest'
|
22
|
+
@access_code = mod.password
|
23
|
+
@ip_filter = mod.subnet
|
24
|
+
@shuffle_answers = mod.shuffle_answers
|
25
|
+
@quiz_type = mod.mod_type == 'quiz' ? 'practice_quiz' : 'survey'
|
26
|
+
@non_cc_assessments_identifier = create_key(@id, 'non_cc_assessments_')
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_resource_node(resources_node)
|
30
|
+
super
|
31
|
+
|
32
|
+
href = File.join(identifier, ASSESSMENT_META)
|
33
|
+
resources_node.resource(
|
34
|
+
:href => href,
|
35
|
+
:type => LOR,
|
36
|
+
:identifier => non_cc_assessments_identifier
|
37
|
+
) do |resource_node|
|
38
|
+
resource_node.file(:href => href)
|
39
|
+
resource_node.file(:href => File.join(ASSESSMENT_NON_CC_FOLDER, "#{identifier}.xml.qti"))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_resource_sub_nodes(resource_node)
|
44
|
+
resource_node.dependency :identifierref => non_cc_assessments_identifier
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_files(export_dir)
|
48
|
+
create_assessment_meta_xml(export_dir)
|
49
|
+
create_non_cc_qti_xml(export_dir)
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_assessment_meta_xml(export_dir)
|
53
|
+
path = File.join(export_dir, identifier, ASSESSMENT_META)
|
54
|
+
FileUtils.mkdir_p(File.dirname(path))
|
55
|
+
File.open(path, 'w') do |file|
|
56
|
+
node = Builder::XmlMarkup.new(:target => file, :indent => 2)
|
57
|
+
node.instruct!
|
58
|
+
node.quiz(
|
59
|
+
:identifier => identifier,
|
60
|
+
'xsi:schemaLocation' => "http://canvas.instructure.com/xsd/cccv1p0 http://canvas.instructure.com/xsd/cccv1p0.xsd",
|
61
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
62
|
+
'xmlns' => "http://canvas.instructure.com/xsd/cccv1p0"
|
63
|
+
) do |quiz_node|
|
64
|
+
META_ATTRIBUTES.each do |attr|
|
65
|
+
quiz_node.tag!(attr, send(attr)) unless send(attr).nil?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_non_cc_qti_xml(export_dir)
|
72
|
+
path = File.join(export_dir, ASSESSMENT_NON_CC_FOLDER, "#{identifier}.xml.qti")
|
73
|
+
FileUtils.mkdir_p(File.dirname(path))
|
74
|
+
File.open(path, 'w') do |file|
|
75
|
+
node = Builder::XmlMarkup.new(:target => file, :indent => 2)
|
76
|
+
node.instruct!
|
77
|
+
node.questestinterop(
|
78
|
+
'xsi:schemaLocation' => "http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd",
|
79
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
80
|
+
'xmlns' => "http://www.imsglobal.org/xsd/ims_qtiasiv1p2"
|
81
|
+
) do |root_node|
|
82
|
+
root_node.assessment(:title => title, :ident => identifier) do |assessment_node|
|
83
|
+
assessment_node.qtimetadata do |qtimetadata_node|
|
84
|
+
qtimetadata_node.qtimetadatafield do |qtimetadatafield_node|
|
85
|
+
qtimetadatafield_node.fieldlabel "qmd_timelimit"
|
86
|
+
qtimetadatafield_node.fieldentry time_limit
|
87
|
+
end
|
88
|
+
qtimetadata_node.qtimetadatafield do |qtimetadatafield_node|
|
89
|
+
qtimetadatafield_node.fieldlabel "cc_maxattempts"
|
90
|
+
qtimetadatafield_node.fieldentry allowed_attempts
|
91
|
+
end
|
92
|
+
end
|
93
|
+
assessment_node.section(:ident => 'root_section') do |section_node|
|
94
|
+
@mod.questions.each do |question|
|
95
|
+
question = Question.new question, self
|
96
|
+
question.create_item_xml(section_node)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def create_module_meta_item_elements(item_node)
|
105
|
+
item_node.content_type 'Quiz'
|
106
|
+
item_node.identifierref @identifier
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Moodle2CC::Canvas
|
2
|
+
class Assignment < Moodle2CC::CC::Assignment
|
3
|
+
include Resource
|
4
|
+
SETTINGS_ATTRIBUTES = [:title, :points_possible, :grading_type, :due_at,
|
5
|
+
:lock_at, :unlock_at, :all_day, :all_day_date, :submission_types,
|
6
|
+
:position, :peer_reviews, :automatic_peer_reviews, :peer_review_count,
|
7
|
+
:anonymous_peer_reviews, :assignment_group_identifierref]
|
8
|
+
|
9
|
+
attr_accessor *SETTINGS_ATTRIBUTES
|
10
|
+
|
11
|
+
def initialize(mod, position=0)
|
12
|
+
super
|
13
|
+
@body = convert_file_path_tokens(mod.description)
|
14
|
+
@points_possible = mod.grade_item ? mod.grade_item.grade_max : mod.grade
|
15
|
+
@grading_type = 'points'
|
16
|
+
if mod.time_due.to_i > 0
|
17
|
+
@due_at = ims_datetime(Time.at(mod.time_due))
|
18
|
+
@all_day = Time.at(mod.time_due).utc.strftime('%H:%M') == '23:59' ? true : false
|
19
|
+
if @all_day
|
20
|
+
@all_day_date = ims_date(Time.at(mod.time_due))
|
21
|
+
end
|
22
|
+
if mod.prevent_late
|
23
|
+
@lock_at = @due_at
|
24
|
+
end
|
25
|
+
end
|
26
|
+
if mod.time_available.to_i > 0
|
27
|
+
@unlock_at = ims_datetime(Time.at(mod.time_available))
|
28
|
+
end
|
29
|
+
if mod.submission_end.to_i > 0
|
30
|
+
@due_at = ims_datetime(Time.at(mod.submission_end))
|
31
|
+
end
|
32
|
+
@submission_types = get_submission_types(mod)
|
33
|
+
@position = position
|
34
|
+
@peer_reviews = @automatic_peer_reviews = mod.mod_type == 'workshop'
|
35
|
+
@peer_review_count = mod.number_of_student_assessments
|
36
|
+
@anonymous_peer_reviews = mod.anonymous
|
37
|
+
@assignment_group_identifierref = create_key(mod.section_mod.section.id, 'assignment_group_')
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_submission_types(mod)
|
41
|
+
if mod.mod_type == 'assignment'
|
42
|
+
case mod.assignment_type
|
43
|
+
when 'online'
|
44
|
+
'online_text_entry'
|
45
|
+
when 'upload'
|
46
|
+
if mod.var2 == 1
|
47
|
+
'online_upload,online_text_entry'
|
48
|
+
else
|
49
|
+
'online_upload'
|
50
|
+
end
|
51
|
+
when 'uploadsingle'
|
52
|
+
'online_upload'
|
53
|
+
else
|
54
|
+
'none'
|
55
|
+
end
|
56
|
+
elsif mod.mod_type == 'workshop'
|
57
|
+
submission_types = ['online_text_entry']
|
58
|
+
submission_types.unshift('online_upload') if mod.number_of_attachments > 0
|
59
|
+
submission_types.join(',')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_resource_node(resources_node)
|
64
|
+
href = "#{identifier}/#{file_slug(@title)}.html"
|
65
|
+
resources_node.resource(
|
66
|
+
:href => href,
|
67
|
+
:type => LOR,
|
68
|
+
:identifier => identifier
|
69
|
+
) do |resource_node|
|
70
|
+
resource_node.file(:href => href)
|
71
|
+
resource_node.file(:href => File.join(identifier, ASSIGNMENT_SETTINGS))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_resource_sub_nodes(resource_node)
|
76
|
+
resource_node.file(:href => File.join(identifier, ASSIGNMENT_SETTINGS))
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_files(export_dir)
|
80
|
+
super
|
81
|
+
create_settings_xml(export_dir)
|
82
|
+
end
|
83
|
+
|
84
|
+
def create_settings_xml(export_dir)
|
85
|
+
path = File.join(export_dir, identifier, ASSIGNMENT_SETTINGS)
|
86
|
+
FileUtils.mkdir_p(File.dirname(path))
|
87
|
+
File.open(path, 'w') do |file|
|
88
|
+
settings_node = Builder::XmlMarkup.new(:target => file, :indent => 2)
|
89
|
+
settings_node.instruct!
|
90
|
+
settings_node.assignment(
|
91
|
+
:identifier => identifier,
|
92
|
+
'xsi:schemaLocation' => "http://canvas.instructure.com/xsd/cccv1p0 http://canvas.instructure.com/xsd/cccv1p0.xsd",
|
93
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
94
|
+
'xmlns' => "http://canvas.instructure.com/xsd/cccv1p0"
|
95
|
+
) do |assignment_node|
|
96
|
+
SETTINGS_ATTRIBUTES.each do |attr|
|
97
|
+
assignment_node.tag!(attr, send(attr)) unless send(attr).nil?
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_module_meta_item_elements(item_node)
|
104
|
+
item_node.content_type 'Assignment'
|
105
|
+
item_node.identifierref @identifier
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Moodle2CC::Canvas
|
2
|
+
class Converter < Moodle2CC::CC::Converter
|
3
|
+
def initialize(moodle_backup, destination_dir)
|
4
|
+
super
|
5
|
+
@resource_factory = Moodle2CC::ResourceFactory.new Moodle2CC::Canvas
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_resources(resources_node)
|
9
|
+
create_course_content(resources_node)
|
10
|
+
@moodle_backup.course.question_categories.each do |question_category|
|
11
|
+
create_question_bank_resource(resources_node, question_category)
|
12
|
+
end
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_question_bank_resource(resources_node, question_category)
|
17
|
+
question_bank = QuestionBank.new(question_category)
|
18
|
+
question_bank.create_resource_node(resources_node)
|
19
|
+
question_bank.create_files(@export_dir)
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_course_content(resources_node)
|
23
|
+
course = Course.new(@moodle_backup.course)
|
24
|
+
course.create_resource_node(resources_node)
|
25
|
+
course.create_files(@export_dir)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module Moodle2CC::Canvas
|
2
|
+
class Course < Moodle2CC::CC::Course
|
3
|
+
|
4
|
+
attr_accessor :id, :title, :course_code, :start_at, :format, :is_public, :syllabus_body
|
5
|
+
|
6
|
+
def initialize(course)
|
7
|
+
super
|
8
|
+
|
9
|
+
@course = course
|
10
|
+
|
11
|
+
@id = course.id
|
12
|
+
@title = course.fullname
|
13
|
+
@course_code = course.shortname
|
14
|
+
@start_at = ims_datetime(Time.at(course.startdate))
|
15
|
+
@is_public = course.visible
|
16
|
+
@syllabus_body = convert_file_path_tokens(course.sections.first.summary)
|
17
|
+
@resource_factory = Moodle2CC::ResourceFactory.new Moodle2CC::Canvas
|
18
|
+
end
|
19
|
+
|
20
|
+
def identifier
|
21
|
+
create_key(id, 'course_')
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_resource_node(resources_node)
|
25
|
+
syllabus_href = File.join(COURSE_SETTINGS_DIR, SYLLABUS)
|
26
|
+
resources_node.resource(
|
27
|
+
:intendeduse => 'syllabus',
|
28
|
+
:href => syllabus_href,
|
29
|
+
:type => LOR,
|
30
|
+
:identifier => create_key(syllabus_href, 'resource_')
|
31
|
+
) do |resource_node|
|
32
|
+
resource_node.file(:href => File.join(COURSE_SETTINGS_DIR, SYLLABUS))
|
33
|
+
resource_node.file(:href => File.join(COURSE_SETTINGS_DIR, COURSE_SETTINGS))
|
34
|
+
resource_node.file(:href => File.join(COURSE_SETTINGS_DIR, FILES_META))
|
35
|
+
resource_node.file(:href => File.join(COURSE_SETTINGS_DIR, MODULE_META))
|
36
|
+
resource_node.file(:href => File.join(COURSE_SETTINGS_DIR, ASSIGNMENT_GROUPS))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_files(export_dir)
|
41
|
+
create_syllabus_file(export_dir)
|
42
|
+
create_course_settings_xml(export_dir)
|
43
|
+
create_files_meta_xml(export_dir)
|
44
|
+
create_assignment_groups_xml(export_dir)
|
45
|
+
create_module_meta_xml(export_dir)
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_syllabus_file(export_dir)
|
49
|
+
template = File.expand_path('../templates/syllabus.html.erb', __FILE__)
|
50
|
+
path = File.join(export_dir, COURSE_SETTINGS_DIR, SYLLABUS)
|
51
|
+
FileUtils.mkdir_p(File.dirname(path))
|
52
|
+
File.open(path, 'w') do |file|
|
53
|
+
erb = ERB.new(File.read(template))
|
54
|
+
file.write(erb.result(binding))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_course_settings_xml(export_dir)
|
59
|
+
path = File.join(export_dir, COURSE_SETTINGS_DIR, COURSE_SETTINGS)
|
60
|
+
FileUtils.mkdir_p(File.dirname(path))
|
61
|
+
File.open(path, 'w') do |file|
|
62
|
+
document = Builder::XmlMarkup.new(:target => file, :indent => 2)
|
63
|
+
document.instruct!
|
64
|
+
document.course(
|
65
|
+
:identifier => identifier,
|
66
|
+
'xsi:schemaLocation' => "http://canvas.instructure.com/xsd/cccv1p0 http://canvas.instructure.com/xsd/cccv1p0.xsd",
|
67
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
68
|
+
'xmlns' => "http://canvas.instructure.com/xsd/cccv1p0"
|
69
|
+
) do |course_node|
|
70
|
+
course_node.title @title
|
71
|
+
course_node.course_code @course_code
|
72
|
+
course_node.start_at @start_at
|
73
|
+
course_node.is_public @is_public
|
74
|
+
course_node.license 'private'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_module_meta_xml(export_dir)
|
80
|
+
path = File.join(export_dir, COURSE_SETTINGS_DIR, MODULE_META)
|
81
|
+
FileUtils.mkdir_p(File.dirname(path))
|
82
|
+
File.open(path, 'w') do |file|
|
83
|
+
document = Builder::XmlMarkup.new(:target => file, :indent => 2)
|
84
|
+
document.instruct!
|
85
|
+
document.modules(
|
86
|
+
'xsi:schemaLocation' => "http://canvas.instructure.com/xsd/cccv1p0 http://canvas.instructure.com/xsd/cccv1p0.xsd",
|
87
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
88
|
+
'xmlns' => "http://canvas.instructure.com/xsd/cccv1p0"
|
89
|
+
) do |modules_node|
|
90
|
+
@course.sections.each do |section|
|
91
|
+
next unless section.visible
|
92
|
+
modules_node.module(:identifier => create_key(section.id, 'section_')) do |module_node|
|
93
|
+
module_node.title "#{@format} #{section.number}"
|
94
|
+
module_node.position section.number
|
95
|
+
module_node.require_sequential_progress false
|
96
|
+
module_node.items do |items_node|
|
97
|
+
section.mods.each_with_index do |mod, index|
|
98
|
+
next unless mod.visible
|
99
|
+
resource = @resource_factory.get_resource_from_mod(mod.instance)
|
100
|
+
resource.create_module_meta_item_node(items_node, index) if resource
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_assignment_groups_xml(export_dir)
|
110
|
+
path = File.join(export_dir, COURSE_SETTINGS_DIR, ASSIGNMENT_GROUPS)
|
111
|
+
FileUtils.mkdir_p(File.dirname(path))
|
112
|
+
File.open(path, 'w') do |file|
|
113
|
+
document = Builder::XmlMarkup.new(:target => file, :indent => 2)
|
114
|
+
document.instruct!
|
115
|
+
document.assignmentGroups(
|
116
|
+
'xsi:schemaLocation' => "http://canvas.instructure.com/xsd/cccv1p0 http://canvas.instructure.com/xsd/cccv1p0.xsd",
|
117
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
118
|
+
'xmlns' => "http://canvas.instructure.com/xsd/cccv1p0"
|
119
|
+
) do |assignment_groups_node|
|
120
|
+
@course.sections.each do |section|
|
121
|
+
next unless section.visible
|
122
|
+
next unless section.mods.select { |mod| mod.visible && mod.instance.mod_type == "assignment" }.length > 0
|
123
|
+
assignment_groups_node.assignmentGroup(:identifier => create_key(section.id, "assignment_group_")) do |assignment_group_node|
|
124
|
+
assignment_group_node.title "Week #{section.number}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def create_files_meta_xml(export_dir)
|
132
|
+
path = File.join(export_dir, COURSE_SETTINGS_DIR, FILES_META)
|
133
|
+
FileUtils.mkdir_p(File.dirname(path))
|
134
|
+
File.open(path, 'w') do |file|
|
135
|
+
document = Builder::XmlMarkup.new(:target => file, :indent => 2)
|
136
|
+
document.instruct!
|
137
|
+
document.filesMeta(
|
138
|
+
'xsi:schemaLocation' => "http://canvas.instructure.com/xsd/cccv1p0 http://canvas.instructure.com/xsd/cccv1p0.xsd",
|
139
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
140
|
+
'xmlns' => "http://canvas.instructure.com/xsd/cccv1p0")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|