1
0
mirror of https://github.com/meineerde/redmine.git synced 2026-02-03 23:53:23 +00:00

Fix that bulk download raises Errno::EACCES on Windows (#7056).

Patch by Yuichi HARADA.


git-svn-id: http://svn.redmine.org/redmine/trunk@19688 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Go MAEDA 2020-04-11 07:58:01 +00:00
parent 62c7da1b3f
commit ea54e1acdb
3 changed files with 33 additions and 26 deletions

View File

@ -137,16 +137,16 @@ class AttachmentsController < ApplicationController
end
def download_all
Tempfile.create('attachments_zip-', Rails.root.join('tmp')) do |tempfile|
zip_file = Attachment.archive_attachments(tempfile, @attachments)
if zip_file
send_data(
File.read(zip_file.path),
:type => 'application/zip',
:filename => "#{@container.class.to_s.downcase}-#{@container.id}-attachments.zip")
else
render_404
end
zip_data = Attachment.archive_attachments(@attachments)
if zip_data
file_name = "#{@container.class.to_s.downcase}-#{@container.id}-attachments.zip"
send_data(
zip_data,
:type => Redmine::MimeType.of(file_name),
:filename => file_name
)
else
render_404
end
end

View File

@ -346,28 +346,31 @@ class Attachment < ActiveRecord::Base
Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all
end
def self.archive_attachments(out_file, attachments)
def self.archive_attachments(attachments)
attachments = attachments.select(&:readable?)
return nil if attachments.blank?
Zip.unicode_names = true
archived_file_names = []
Zip::File.open(out_file.path, Zip::File::CREATE) do |zip|
buffer = Zip::OutputStream.write_buffer do |zos|
attachments.each do |attachment|
filename = attachment.filename
# rename the file if a file with the same name already exists
dup_count = 0
while archived_file_names.include?(filename)
dup_count += 1
basename = File.basename(attachment.filename, '.*')
extname = File.extname(attachment.filename)
basename = File.basename(attachment.filename, extname)
filename = "#{basename}(#{dup_count})#{extname}"
end
zip.add(filename, attachment.diskfile)
zos.put_next_entry(filename)
zos << IO.binread(attachment.diskfile)
archived_file_names << filename
end
end
out_file
buffer.string
ensure
buffer&.close
end
# Moves an existing attachment to its target directory

View File

@ -280,28 +280,32 @@ class AttachmentTest < ActiveSupport::TestCase
def test_archive_attachments
attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
Tempfile.create('attachments_zip', Rails.root.join('tmp')) do |tempfile|
zip_file = Attachment.archive_attachments(tempfile, [attachment])
assert_instance_of File, zip_file
zip_data = Attachment.archive_attachments([attachment])
file_names = []
Zip::InputStream.open(StringIO.new(zip_data)) do |io|
while (entry = io.get_next_entry)
file_names << entry.name
end
end
assert_equal ['testfile.txt'], file_names
end
def test_archive_attachments_without_attachments
Tempfile.create('attachments_zip', Rails.root.join('tmp')) do |tempfile|
zip_file = Attachment.archive_attachments(tempfile, [])
assert_nil zip_file
end
zip_data = Attachment.archive_attachments([])
assert_nil zip_data
end
def test_archive_attachments_should_rename_duplicate_file_names
attachment1 = Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
attachment2 = Attachment.create!(:file => uploaded_test_file("testfile.txt", ""), :author_id => 1)
Tempfile.create('attachments_zip', Rails.root.join('tmp')) do |tempfile|
zip_file = Attachment.archive_attachments(tempfile, [attachment1, attachment2])
Zip::File.open(zip_file.path) do |z|
assert_equal ['testfile.txt', 'testfile(1).txt'], z.map(&:name)
zip_data = Attachment.archive_attachments([attachment1, attachment2])
file_names = []
Zip::InputStream.open(StringIO.new(zip_data)) do |io|
while (entry = io.get_next_entry)
file_names << entry.name
end
end
assert_equal ['testfile.txt', 'testfile(1).txt'], file_names
end
def test_move_from_root_to_target_directory_should_move_root_files