forked from instructure/canvas-lms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcc_exporter.rb
More file actions
216 lines (185 loc) · 7.26 KB
/
Copy pathcc_exporter.rb
File metadata and controls
216 lines (185 loc) · 7.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#
# Copyright (C) 2011 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require 'action_controller_test_process'
module CC
class CCExporter
include TextHelper
ZIP_DIR = 'zip_dir'
attr_accessor :course, :user, :export_dir, :manifest, :zip_file, :for_course_copy, :for_master_migration
delegate :add_error, :add_item_to_export, :to => :@content_export, :allow_nil => true
def initialize(content_export, opts={})
@content_export = content_export
@course = opts[:course] || @content_export.context
raise "CCExporter supports only Courses" unless @course.is_a?(Course) # a Course is a Course, of course, of course
@user = opts[:user] || @content_export.user
@export_dir = nil
@manifest = nil
@zip_file = nil
@zip_name = nil
@logger = Rails.logger
@migration_config = ConfigFile.load('external_migration')
@migration_config ||= {:keep_after_complete => false}
@for_course_copy = opts[:for_course_copy]
@qti_only_export = @content_export && @content_export.qti_export?
@manifest_opts = opts.slice(:version)
@deletions = opts[:deletions]
@for_master_migration = true if @content_export && @content_export.for_master_migration?
end
def self.export(content_export, opts={})
exporter = CCExporter.new(content_export, opts)
exporter.export
end
def export
begin
if for_external_migration? && !@content_export.selective_export?
# we already know we're exporting all the data so we can begin the external exports now
@pending_exports = Canvas::Migration::ExternalContent::Migrator.begin_exports(@course)
end
create_export_dir
create_zip_file
if @qti_only_export
@manifest = CC::QTI::QTIManifest.new(self)
else
@manifest = Manifest.new(self, @manifest_opts)
end
@manifest.create_document
@manifest.close
if for_external_migration?
if @content_export.selective_export?
# if it's selective, we have to wait until we've completed the rest of the export
# before we really know what we exported. because magic
@pending_exports = Canvas::Migration::ExternalContent::Migrator.begin_exports(@course,
:selective => true, :exported_assets => @content_export.exported_assets.to_a)
end
external_content = Canvas::Migration::ExternalContent::Migrator.retrieve_exported_content(@content_export, @pending_exports)
write_external_content(external_content)
end
@export_dirs = [@export_dir]
if @for_master_migration
# for efficiency to the max, short-circuit the usual course copy process (i.e. zip up, save, and then unzip again)
# and instead go straight to the intermediate json
converter = CC::Importer::Canvas::Converter.new(:unzipped_file_path => @export_dir, :deletions => @deletions)
@export_dirs << converter.base_export_dir # make sure we clean this up too afterwards
converter.export
@export_path = converter.course["full_export_file_path"] # this is the course_export.json
@export_type = 'application/json'
else
copy_all_to_zip
@zip_file.close
@export_path = @zip_path
end
if @content_export && File.exist?(@export_path)
att = Attachment.new
att.context = @content_export
att.user = @content_export.user
att.uploaded_data = Rack::Test::UploadedFile.new(@export_path, @export_type || Attachment.mimetype(@export_path))
if att.save
@content_export.attachment = att
@content_export.save
end
end
rescue
add_error(I18n.t('course_exports.errors.course_export', "Error running course export."), $!)
@logger.error $!
return false
ensure
@zip_file.close if @zip_file
if !@migration_config[:keep_after_complete]
@export_dirs.each do |export_dir|
FileUtils::rm_rf(export_dir) if File.directory?(export_dir)
end
end
end
true
end
def write_external_content(external_content)
return unless external_content.present?
folder = File.join(@export_dir, CCHelper::EXTERNAL_CONTENT_FOLDER)
FileUtils::mkdir_p(folder)
external_content.each do |service_key, data|
path = File.join(folder, "#{service_key}.json")
File.write(path, data.to_json)
end
end
def referenced_files
@manifest ? @manifest.referenced_files : {}
end
def set_progress(progress)
@content_export.fast_update_progress(progress) if @content_export
end
def errors
@content_export ? @content_export.error_messages : []
end
def export_id
@content_export ? @content_export.id : nil
end
def create_key(*args)
@content_export ? @content_export.create_key(*args) : CCHelper.create_key(*args)
end
def export_object?(obj, asset_type=nil)
@content_export ? @content_export.export_object?(obj, asset_type) : true
end
def add_exported_asset(obj)
@content_export && @content_export.add_exported_asset(obj)
end
def export_symbol?(obj)
@content_export ? @content_export.export_symbol?(obj) : true
end
def epub_export?
@content_export ? @content_export.epub_export.present? : nil
end
def for_external_migration?
@content_export && !(@qti_only_export || epub_export?)
end
private
def copy_all_to_zip
Dir["#{@export_dir}/**/**"].each do |file|
file_path = file.sub(@export_dir+'/', '')
next if file_path.starts_with? ZIP_DIR
@zip_file.add(file_path, file)
end
end
def create_export_dir
slug = "common_cartridge_#{@course.id}_user_#{@user.id}"
if @migration_config[:data_folder]
folder = @migration_config[:data_folder]
else
folder = Dir.tmpdir
end
@export_dir = File.join(folder, slug)
i = 1
while File.exist?(@export_dir) && File.directory?(@export_dir)
i += 1
@export_dir = File.join(folder, "#{slug}_attempt_#{i}")
end
FileUtils::mkdir_p @export_dir
@export_dir
end
def create_zip_file
name = CanvasTextHelper.truncate_text(@course.name.to_url, {:max_length => 200, :ellipsis => ''})
if @qti_only_export
@zip_name = "#{name}-quiz-export.zip"
else
@zip_name = "#{name}-export.#{CCHelper::CC_EXTENSION}"
end
FileUtils::mkdir_p File.join(@export_dir, ZIP_DIR)
@zip_path = File.join(@export_dir, ZIP_DIR, @zip_name)
@zip_file = Zip::File.new(@zip_path, Zip::File::CREATE)
end
end
end