Feature #7056 » zip-create-via-stream2.patch
| trunk/app/controllers/attachments_controller.rb (revision 19686) → trunk/app/controllers/attachments_controller.rb (working copy) | ||
|---|---|---|
| 137 | 137 |
end |
| 138 | 138 | |
| 139 | 139 |
def download_all |
| 140 |
Tempfile.create('attachments_zip-', Rails.root.join('tmp')) do |tempfile|
|
|
| 141 |
zip_file = Attachment.archive_attachments(tempfile, @attachments)
|
|
| 142 |
if zip_file
|
|
| 143 |
send_data(
|
|
| 144 |
File.read(zip_file.path),
|
|
| 145 |
:type => 'application/zip',
|
|
| 146 |
:filename => "#{@container.class.to_s.downcase}-#{@container.id}-attachments.zip")
|
|
| 147 |
else
|
|
| 148 |
render_404
|
|
| 149 |
end
|
|
| 140 |
zip_data = Attachment.archive_attachments(@attachments)
|
|
| 141 |
if zip_data
|
|
| 142 |
file_name = "#{@container.class.to_s.downcase}-#{@container.id}-attachments.zip"
|
|
| 143 |
send_data( |
|
| 144 |
zip_data,
|
|
| 145 |
:type => Redmine::MimeType.of(file_name),
|
|
| 146 |
:filename => file_name
|
|
| 147 |
)
|
|
| 148 |
else
|
|
| 149 |
render_404
|
|
| 150 | 150 |
end |
| 151 | 151 |
end |
| 152 | 152 | |
| trunk/app/models/attachment.rb (revision 19686) → trunk/app/models/attachment.rb (working copy) | ||
|---|---|---|
| 346 | 346 |
Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all
|
| 347 | 347 |
end |
| 348 | 348 | |
| 349 |
def self.archive_attachments(out_file, attachments)
|
|
| 350 |
attachments = attachments.select(&:readable?)
|
|
| 351 |
return nil if attachments.blank?
|
|
| 349 |
def self.archive_attachments(attachments) |
|
| 350 |
attachments = attachments.select{|attachment| File.readable?(attachment.diskfile) }
|
|
| 351 |
return if attachments.blank? |
|
| 352 | 352 | |
| 353 | 353 |
Zip.unicode_names = true |
| 354 | 354 |
archived_file_names = [] |
| 355 |
Zip::File.open(out_file.path, Zip::File::CREATE) do |zip|
|
|
| 355 |
buffer = Zip::OutputStream.write_buffer do |zos|
|
|
| 356 | 356 |
attachments.each do |attachment| |
| 357 | 357 |
filename = attachment.filename |
| 358 | 358 |
# rename the file if a file with the same name already exists |
| 359 | 359 |
dup_count = 0 |
| 360 | 360 |
while archived_file_names.include?(filename) |
| 361 | 361 |
dup_count += 1 |
| 362 |
basename = File.basename(attachment.filename, '.*') |
|
| 363 | 362 |
extname = File.extname(attachment.filename) |
| 363 |
basename = File.basename(attachment.filename, extname) |
|
| 364 | 364 |
filename = "#{basename}(#{dup_count})#{extname}"
|
| 365 | 365 |
end |
| 366 |
zip.add(filename, attachment.diskfile) |
|
| 366 |
zos.put_next_entry(filename) |
|
| 367 |
zos << IO.binread(attachment.diskfile) |
|
| 367 | 368 |
archived_file_names << filename |
| 368 | 369 |
end |
| 369 | 370 |
end |
| 370 |
out_file |
|
| 371 |
buffer.string |
|
| 372 |
ensure |
|
| 373 |
buffer&.close |
|
| 371 | 374 |
end |
| 372 | 375 | |
| 373 | 376 |
# Moves an existing attachment to its target directory |
| trunk/test/unit/attachment_test.rb (revision 19686) → trunk/test/unit/attachment_test.rb (working copy) | ||
|---|---|---|
| 280 | 280 | |
| 281 | 281 |
def test_archive_attachments |
| 282 | 282 |
attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
|
| 283 |
Tempfile.create('attachments_zip', Rails.root.join('tmp')) do |tempfile|
|
|
| 284 |
zip_file = Attachment.archive_attachments(tempfile, [attachment]) |
|
| 285 |
assert_instance_of File, zip_file |
|
| 283 |
zip_data = Attachment.archive_attachments([attachment]) |
|
| 284 |
file_names = [] |
|
| 285 |
Zip::InputStream.open(StringIO.new(zip_data)) do |io| |
|
| 286 |
while (entry = io.get_next_entry) |
|
| 287 |
file_names << entry.name |
|
| 288 |
end |
|
| 286 | 289 |
end |
| 290 |
assert_equal ['testfile.txt'], file_names |
|
| 287 | 291 |
end |
| 288 | 292 | |
| 289 | 293 |
def test_archive_attachments_without_attachments |
| 290 |
Tempfile.create('attachments_zip', Rails.root.join('tmp')) do |tempfile|
|
|
| 291 |
zip_file = Attachment.archive_attachments(tempfile, []) |
|
| 292 |
assert_nil zip_file |
|
| 293 |
end |
|
| 294 |
zip_data = Attachment.archive_attachments([]) |
|
| 295 |
assert_nil zip_data |
|
| 294 | 296 |
end |
| 295 | 297 | |
| 296 | 298 |
def test_archive_attachments_should_rename_duplicate_file_names |
| 297 | 299 |
attachment1 = Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
|
| 298 | 300 |
attachment2 = Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
|
| 299 |
Tempfile.create('attachments_zip', Rails.root.join('tmp')) do |tempfile|
|
|
| 300 |
zip_file = Attachment.archive_attachments(tempfile, [attachment1, attachment2]) |
|
| 301 |
Zip::File.open(zip_file.path) do |z| |
|
| 302 |
assert_equal ['testfile.txt', 'testfile(1).txt'], z.map(&:name) |
|
| 301 |
zip_data = Attachment.archive_attachments([attachment1, attachment2]) |
|
| 302 |
file_names = [] |
|
| 303 |
Zip::InputStream.open(StringIO.new(zip_data)) do |io| |
|
| 304 |
while (entry = io.get_next_entry) |
|
| 305 |
file_names << entry.name |
|
| 303 | 306 |
end |
| 304 | 307 |
end |
| 308 |
assert_equal ['testfile.txt', 'testfile(1).txt'], file_names |
|
| 305 | 309 |
end |
| 306 | 310 | |
| 307 | 311 |
def test_move_from_root_to_target_directory_should_move_root_files |