summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorGo MAEDA <maeda@farend.jp>2020-03-21 05:59:31 +0000
committerGo MAEDA <maeda@farend.jp>2020-03-21 05:59:31 +0000
commitab47fb8ae0e6685900e3a22de3b9ce265a5b05fa (patch)
tree22a50ddb755864b883f02833b03db48feb072691 /app
parent6abf527aa0e3271ebd38c1ac50a4691dab611b2e (diff)
downloadredmine-ab47fb8ae0e6685900e3a22de3b9ce265a5b05fa.tar.gz
redmine-ab47fb8ae0e6685900e3a22de3b9ce265a5b05fa.zip
Download all attachments at once (#7056).
Patch by Mizuki ISHIKAWA. git-svn-id: http://svn.redmine.org/redmine/trunk@19601 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r--app/controllers/attachments_controller.rb34
-rw-r--r--app/helpers/attachments_helper.rb4
-rw-r--r--app/models/attachment.rb25
-rw-r--r--app/views/attachments/_links.html.erb5
-rw-r--r--app/views/settings/_attachments.html.erb2
5 files changed, 68 insertions, 2 deletions
diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb
index db90b55da..7e198d0bb 100644
--- a/app/controllers/attachments_controller.rb
+++ b/app/controllers/attachments_controller.rb
@@ -19,6 +19,8 @@
class AttachmentsController < ApplicationController
before_action :find_attachment, :only => [:show, :download, :thumbnail, :update, :destroy]
+ before_action :find_container, :only => [:edit_all, :update_all, :download_all]
+ before_action :find_downloadable_attachments, :only => :download_all
before_action :find_editable_attachments, :only => [:edit_all, :update_all]
before_action :file_readable, :read_authorize, :only => [:show, :download, :thumbnail]
before_action :update_authorize, :only => :update
@@ -132,6 +134,20 @@ class AttachmentsController < ApplicationController
render :action => 'edit_all'
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
+ end
+ end
+
def update
@attachment.safe_attributes = params[:attachment]
saved = @attachment.save
@@ -195,6 +211,11 @@ class AttachmentsController < ApplicationController
end
def find_editable_attachments
+ @attachments = @container.attachments.select(&:editable?)
+ render_404 if @attachments.empty?
+ end
+
+ def find_container
klass = params[:object_type].to_s.singularize.classify.constantize rescue nil
unless klass && klass.reflect_on_association(:attachments)
render_404
@@ -206,15 +227,24 @@ class AttachmentsController < ApplicationController
render_403
return
end
- @attachments = @container.attachments.select(&:editable?)
if @container.respond_to?(:project)
@project = @container.project
end
- render_404 if @attachments.empty?
rescue ActiveRecord::RecordNotFound
render_404
end
+ def find_downloadable_attachments
+ @attachments = @container.attachments.select{|a| File.readable?(a.diskfile) }
+ bulk_download_max_size = Setting.bulk_download_max_size.to_i.kilobytes
+ if @attachments.sum(&:filesize) > bulk_download_max_size
+ flash[:error] = l(:error_bulk_download_size_too_big,
+ :max_size => bulk_download_max_size.to_i.kilobytes)
+ redirect_to back_url
+ return
+ end
+ end
+
# Checks that the file exists and is readable
def file_readable
if @attachment.readable?
diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb
index 47e5ea78a..e496958bf 100644
--- a/app/helpers/attachments_helper.rb
+++ b/app/helpers/attachments_helper.rb
@@ -27,6 +27,10 @@ module AttachmentsHelper
object_attachments_path container.class.name.underscore.pluralize, container.id
end
+ def container_attachments_download_path(container)
+ object_attachments_download_path container.class.name.underscore.pluralize, container.id
+ end
+
# Displays view/delete links to the attachments of the given object
# Options:
# :author -- author names are not displayed if set to false
diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index 6b8c75cc4..a89a0c37e 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -19,6 +19,7 @@
require "digest"
require "fileutils"
+require "zip"
class Attachment < ActiveRecord::Base
include Redmine::SafeAttributes
@@ -345,6 +346,30 @@ 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)
+ attachments = attachments.select{|attachment| File.readable?(attachment.diskfile) }
+ return nil if attachments.blank?
+
+ Zip.unicode_names = true
+ archived_file_names = []
+ Zip::File.open(out_file.path, Zip::File::CREATE) do |zip|
+ 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)
+ filename = "#{basename}(#{dup_count})#{extname}"
+ end
+ zip.add(filename, attachment.diskfile)
+ archived_file_names << filename
+ end
+ end
+ out_file
+ end
+
# Moves an existing attachment to its target directory
def move_to_target_directory!
return unless !new_record? & readable?
diff --git a/app/views/attachments/_links.html.erb b/app/views/attachments/_links.html.erb
index 0a9f5e3eb..25d022029 100644
--- a/app/views/attachments/_links.html.erb
+++ b/app/views/attachments/_links.html.erb
@@ -5,6 +5,11 @@
:title => l(:label_edit_attachments),
:class => 'icon-only icon-edit'
) if options[:editable] %>
+ <%= link_to(l(:label_download_all_attachments),
+ container_attachments_download_path(container),
+ :title => l(:label_download_all_attachments),
+ :class => 'icon-only icon-download'
+ ) if attachments.size > 1 %>
</div>
<table>
<% for attachment in attachments %>
diff --git a/app/views/settings/_attachments.html.erb b/app/views/settings/_attachments.html.erb
index 818845e55..f0430e4a9 100644
--- a/app/views/settings/_attachments.html.erb
+++ b/app/views/settings/_attachments.html.erb
@@ -3,6 +3,8 @@
<div class="box tabular settings">
<p><%= setting_text_field :attachment_max_size, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %></p>
+<p><%= setting_text_field :bulk_download_max_size, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %></p>
+
<p><%= setting_text_area :attachment_extensions_allowed %>
<em class="info"><%= l(:text_comma_separated) %> <%= l(:label_example) %>: txt, png</em></p>