Project

General

Profile

Actions

Feature #7056

closed

Download all attachments at once

Added by Chris Haverman almost 14 years ago. Updated over 1 year ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Attachments
Target version:
Start date:
2010-12-06
Due date:
% Done:

0%

Estimated time:
Resolution:
Fixed

Description

Did a quick search to see if this had been reported; didn't see anything.

Basically I'd like there to be a way to download all attachments to an issue in a single click rather than each one separately.


Files

compress_the_all_attachments_in_issue.patch (8.93 KB) compress_the_all_attachments_in_issue.patch Mizuki ISHIKAWA, 2018-10-11 07:26
compress_the_all_attachments_in_issue_v2.patch (12.9 KB) compress_the_all_attachments_in_issue_v2.patch Mizuki ISHIKAWA, 2018-12-25 03:31
error_message.png (287 KB) error_message.png Mizuki ISHIKAWA, 2018-12-25 03:45
compress_the_all_attachments_in_issue_v3.patch (12.9 KB) compress_the_all_attachments_in_issue_v3.patch Mizuki ISHIKAWA, 2019-12-20 01:57
screenshot-v4.png (104 KB) screenshot-v4.png Go MAEDA, 2020-02-18 08:42
compress_the_all_attachments_in_issue_v4.patch (13.5 KB) compress_the_all_attachments_in_issue_v4.patch Go MAEDA, 2020-02-18 08:42
compress_the_all_attachments_in_issue_v5.patch (13.2 KB) compress_the_all_attachments_in_issue_v5.patch Go MAEDA, 2020-03-07 16:10
compress_the_all_attachments_in_issue_v6.patch (13.2 KB) compress_the_all_attachments_in_issue_v6.patch Go MAEDA, 2020-03-14 05:27
attachments-that-causes-EntryExistsError@2x.png (50.7 KB) attachments-that-causes-EntryExistsError@2x.png Go MAEDA, 2020-03-15 03:16
compress_the_all_attachments_in_issue_v7.patch (13.2 KB) compress_the_all_attachments_in_issue_v7.patch Go MAEDA, 2020-03-15 03:25
download.png (152 KB) download.png Marius BĂLTEANU, 2020-03-15 14:12
diff_v7_and_v8.patch (2.32 KB) diff_v7_and_v8.patch Mizuki ISHIKAWA, 2020-03-17 02:50
compress_the_all_attachments_in_issue_v8.patch (13.4 KB) compress_the_all_attachments_in_issue_v8.patch Mizuki ISHIKAWA, 2020-03-17 02:50
human-readable-file-size.patch (1.85 KB) human-readable-file-size.patch Go MAEDA, 2020-03-22 04:52
file-size-before@2x.png (68 KB) file-size-before@2x.png Go MAEDA, 2020-03-22 04:52
file-size-after@2x.png (67.1 KB) file-size-after@2x.png Go MAEDA, 2020-03-22 04:52
download_all_fix.patch (3.81 KB) download_all_fix.patch fix Errno::EACCES Pavel Rosický, 2020-03-24 21:50
zip-create-via-stream.patch (4.61 KB) zip-create-via-stream.patch Yuichi HARADA, 2020-04-08 04:10
zip-create-via-stream2.patch (5.06 KB) zip-create-via-stream2.patch Pavel Rosický, 2020-04-08 12:11
zip-create-via-stream-v3.patch (4.65 KB) zip-create-via-stream-v3.patch Yuichi HARADA, 2020-04-09 09:09
flashes.gif (476 KB) flashes.gif Mizuki ISHIKAWA, 2023-08-09 09:43
clipboard-202308092348-zmjsq.png (42.8 KB) clipboard-202308092348-zmjsq.png Grubs _, 2023-08-09 15:48

Related issues

Related to Redmine - Feature #8708: Provide a "download multiple files at once" featureReopened2011-06-29

Actions
Related to Redmine - Feature #35462: Download all attachments in a journalClosedGo MAEDA

Actions
Has duplicate Redmine - Feature #2662: Download a documentClosed2009-02-04

Actions
Actions #1

Updated by zac folk almost 14 years ago

I agree, this would be really useful.

Actions #2

Updated by Motaz Abuthiab almost 12 years ago

+1

Actions #3

Updated by Nicolas QUETGLAS about 11 years ago

+1

Actions #4

Updated by Go MAEDA over 9 years ago

  • Related to Feature #8708: Provide a "download multiple files at once" feature added
Actions #5

Updated by Nikolay Yurchenko over 7 years ago

+1

Actions #6

Updated by Klément Grisel over 6 years ago

+1

Actions #7

Updated by Mizuki ISHIKAWA about 6 years ago

In order to realize this feature, I thought of compressing and downloading Issue's attachment.
By applying this patch, you can download all of the attached files as a zip file. (using gem rubyzip)

Non-ascii file names are garbled in older versions (Windows 7, Windows Vista, Windows XP).
Windows 7 is scheduled to end support in 2020.
https://github.com/rubyzip/rubyzip/wiki/Files-with-non-ascii-filenames

Any feedback on this patch is welcome.

Actions #8

Updated by Go MAEDA about 6 years ago

Thank you for posting the patch. Could you explain why attachments_to_zip method creates temporary files in Attachment.storage_path instead of tmp directory?

Actions #9

Updated by Go MAEDA about 6 years ago

I think the patch should consider the free space of the disk. Suppose that the total size of attachments of the issue is 1GB. If the free space of the disk is less than 1GB, the creation of a zip archive will fail and the server may stop working due to disk full.

Here are some ideas to avoid the problem.

  • Show an error message indicates no sufficient disk space if the total size of attachments exceeds the free disk space
  • Create and send a zip archive without creating a temporary file
Actions #10

Updated by Mizuki ISHIKAWA almost 6 years ago

Go MAEDA wrote:

Thank you for posting the patch. Could you explain why attachments_to_zip method creates temporary files in Attachment.storage_path instead of tmp directory?

There was no particular reason. I changed the temporary file storage location to the tmp directory.

Go MAEDA wrote:

I think the patch should consider the free space of the disk. Suppose that the total size of attachments of the issue is 1GB. If the free space of the disk is less than 1GB, the creation of a zip archive will fail and the server may stop working due to disk full.

Here are some ideas to avoid the problem.

  • Show an error message indicates no sufficient disk space if the total size of attachments exceeds the free disk space
  • Create and send a zip archive without creating a temporary file

Thank you for your feedback.

Because I could not think of a good way to check disk space, I thought about limiting the maximum capacity of temporary files.

The maximum capacity of temporary file can be set in configration.yml.
By doing this setting, it is impossible to create a temporary file larger than the assumption of the server administrator.

Actions #11

Updated by Go MAEDA over 5 years ago

  • Target version set to Candidate for next major release
Actions #12

Updated by Go MAEDA almost 5 years ago

Mizuki ISHIKAWA wrote:

Non-ascii file names are garbled in older versions (Windows 7, Windows Vista, Windows XP).

I don't think this is a problem because Windows 7 is going to reach EOL next month (2020-01-14).
https://www.microsoft.com/en-us/microsoft-365/windows/end-of-windows-7-support

Actions #13

Updated by Mizuki ISHIKAWA almost 5 years ago

I modified the patch to apply to the latest trunk.

Actions #14

Updated by Go MAEDA almost 5 years ago

I have changed the patch:

  • Add a label to the bulk download button
  • Move the button to below the attachments list (like usability plugin)
  • Updated messages
  • Raised the default value for bulk_download_max_size to 512MB

Actions #15

Updated by Go MAEDA over 4 years ago

Actions #16

Updated by Go MAEDA over 4 years ago

I have updated the patch. Moved bulk_download_max_size setting from configuration.yml to /settings GUI for consistency.

Actions #17

Updated by Go MAEDA over 4 years ago

  • Target version changed from Candidate for next major release to 4.2.0

Setting the target version to 4.2.0.

Actions #18

Updated by Go MAEDA over 4 years ago

Slightly updated the patch:

  • Changed the method name Attachment.attachments_to_zip to Attachment.archive_attachments because attachments_to_zip is too specific. No one knows if the feature uses ZIP format forever, so I think the method name should not depend on a specific archive format
  • Changed the text for label_download_all_attachments from "Download all attached files" to simpler "Download all files"
Actions #19

Updated by Go MAEDA over 4 years ago

The patch may raise Zip::EntryExistsError when you try to download a ZIP file if a file that has "(2)" suffix in its basename is attached.

Started GET "/attachments/issues/32/download" for 127.0.0.1 at 2020-03-15 10:59:03 +0900
Processing by AttachmentsController#download_all as HTML
.
.
.
Completed 500 Internal Server Error in 28ms (ActiveRecord: 4.9ms)

Zip::EntryExistsError (add failed. Entry testfile(2).txt already exists):

app/models/attachment.rb:362:in `block (2 levels) in archive_attachments'
app/models/attachment.rb:355:in `each'
app/models/attachment.rb:355:in `block in archive_attachments'
app/models/attachment.rb:354:in `archive_attachments'
app/controllers/attachments_controller.rb:139:in `block in download_all'
app/controllers/attachments_controller.rb:138:in `download_all'
lib/redmine/sudo_mode.rb:64:in `sudo_mode'

I have fixed the above issue. Also, I have changed the "(n)" suffix for duplicate filenames to start from 1 instead of 2. It is the same behavior as Chrome and Firefox do when downloading files with the same name.

Actions #20

Updated by Marius BĂLTEANU over 4 years ago

I like this feature.

What do you think if we show the link next to edit attached files icon (as Mizuki proposed first time) in order to keep the links grouped?

I don't find very UX friendly to have the Edit button to the right and the "Download all" button under attachments and thumbnails.

Actions #21

Updated by Marius BĂLTEANU over 4 years ago

  • Related to deleted (Feature #8708: Provide a "download multiple files at once" feature)
Actions #22

Updated by Marius BĂLTEANU over 4 years ago

  • Has duplicate Feature #8708: Provide a "download multiple files at once" feature added
Actions #23

Updated by Marius BĂLTEANU over 4 years ago

Also, we should add a test for the new route added by this patch.

Actions #24

Updated by Marius BĂLTEANU over 4 years ago

  • Has duplicate deleted (Feature #8708: Provide a "download multiple files at once" feature)
Actions #25

Updated by Marius BĂLTEANU over 4 years ago

  • Related to Feature #8708: Provide a "download multiple files at once" feature added
Actions #26

Updated by Go MAEDA over 4 years ago

Marius BALTEANU wrote:

What do you think if we show the link next to edit attached files icon (as Mizuki proposed first time) in order to keep the links grouped?

I prefer the current position becuase the position you suggest is very far from the list of files and many people may not notice this useful feature. But it is OK to move the button to the right if we can move this patch forward by doing that.

Actions #27

Updated by Marius BĂLTEANU over 4 years ago

Go MAEDA wrote:

Marius BALTEANU wrote:

What do you think if we show the link next to edit attached files icon (as Mizuki proposed first time) in order to keep the links grouped?

I prefer the current position becuase the position you suggest is very far from the list of files and many people may not notice this useful feature. But it is OK to move the button to the right if we can move this patch forward by doing that.

I agree with you that having all the action icons in the right corner is maybe not the best option, but this is in the current UI and we cannot just drop some action icons in other places. We should keep the consistency and if we do a change to resolve the distance, we should do it for all the icons because there is no difference between the Edit icon and Delete icon. In all other screens we have the icons one after each other. From my point of view, we can commit this if we move the icon and add the missing test.

Actions #28

Updated by Mizuki ISHIKAWA over 4 years ago

Thanks for contributions for releasing this feature.

I updated the patch.
  • Add tests to test/integration/routing/attachments_test.rb
  • Move icon position to original position
Actions #29

Updated by Go MAEDA over 4 years ago

  • Subject changed from Download All Attachments in Issue to Download all attachments at once
  • Status changed from New to Closed
  • Assignee set to Go MAEDA
  • Resolution set to Fixed

Committed the patch. Thank you for improving Redmine.

Actions #30

Updated by Go MAEDA over 4 years ago

The attached patch human-readable-file-size.patch fixes the format of file size in the message error_bulk_download_size_too_big to human-readable.

Before:

After:

Actions #31

Updated by Go MAEDA over 4 years ago

  • Status changed from Reopened to Closed

Go MAEDA wrote:

The attached patch human-readable-file-size.patch fixes the format of file size in the message error_bulk_download_size_too_big to human-readable.

Committed the patch in r19609.

Actions #32

Updated by Pavel Rosický over 4 years ago

unfortunately, this feature doesn't work on Windows.

Error:
AttachmentTest#test_archive_attachments:
Errno::EACCES: Permission denied @ rb_file_s_rename - (c:/redmine/tmp/attachments_zip20200324-12432-yknlax20200324-12432-1qjlddf, c:/redmine/tmp/attachments_zip20200324-12432-yknlax)
    app/models/attachment.rb:355:in `archive_attachments'
    test/unit/attachment_test.rb:284:in `block in test_archive_attachments'
    test/unit/attachment_test.rb:283:in `test_archive_attachments'

I've attached a quick fix.

Actions #33

Updated by Go MAEDA over 4 years ago

  • Status changed from Closed to Reopened
Actions #34

Updated by Yuichi HARADA over 4 years ago

Pavel Rosický wrote:

unfortunately, this feature doesn't work on Windows.

[...]

Thanks for reporting this problem.
I fixed it to create a zip file via stream. No temporary file is needed.

diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb
index b69dcf983..0c76490b2 100644
--- a/app/controllers/attachments_controller.rb
+++ b/app/controllers/attachments_controller.rb
@@ -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

diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index b5a3332ac..734b8f7fa 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -346,28 +346,28 @@ 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|
+    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
+    end.string
   end

   # Moves an existing attachment to its target directory
Actions #35

Updated by Pavel Rosický over 4 years ago

Yuichi HARADA thanks, it looks good!

but I'm getting a warning

zlib(finalizer): the stream was freed prematurely.

the output StreamIO should be closed

Actions #37

Updated by Yuichi HARADA over 4 years ago

Pavel Rosický wrote:

Yuichi HARADA thanks, it looks good!

but I'm getting a warning
[...]

the output StreamIO should be closed

Thanks for pointing it out.
I had forgotten to perform StringIO#close . Fixed a patch.

Actions #38

Updated by Go MAEDA over 4 years ago

  • Status changed from Reopened to Closed

Pavel Rosický wrote:

unfortunately, this feature doesn't work on Windows.

[...]

I've attached a quick fix.

Committed a fix for the issue in r19688. Thank you.

Actions #39

Updated by Go MAEDA over 3 years ago

  • Related to Feature #35462: Download all attachments in a journal added
Actions #40

Updated by Grubs _ over 1 year ago

v5.0.5.stable and the download all files icon has some issues where the mouse hover over "flashes" and the shadow box with the text "Download all files" does not always display. If the mouse cursor is hovered over the download icon the cursor alternates between an arrow and hand at a cycle of about 1 per second.

This issue is showing in "Documents", when there is more than one file attached to the document.

If the user clicks on the download all button it does work most times, but there is often no feedback to the user to indicate that their click on the download arrow has registered. (particularly if there is a large number of files attached to the one Document)

This may be a jquerey issue with the css that is attempting to display the shadow box rather than a redmine issue. I don't know.

The function of the "download all" does work - but the user feedback seems off and users are spamming the download all button because they don't know their click has registered.

Tested with Firefox 116.02 and Edge 115.0.1901.188 (on Windows 10 22H2)

P.S great job on this BTW. brilliant. Apologies for re-opening.

Actions #41

Updated by Mizuki ISHIKAWA over 1 year ago

Grubs _ wrote in #note-40:

v5.0.5.stable and the download all files icon has some issues where the mouse hover over "flashes" and the shadow box with the text "Download all files" does not always display. If the mouse cursor is hovered over the download icon the cursor alternates between an arrow and hand at a cycle of about 1 per second.

This issue is showing in "Documents", when there is more than one file attached to the document.

If the user clicks on the download all button it does work most times, but there is often no feedback to the user to indicate that their click on the download arrow has registered. (particularly if there is a large number of files attached to the one Document)

This may be a jquerey issue with the css that is attempting to display the shadow box rather than a redmine issue. I don't know.

The function of the "download all" does work - but the user feedback seems off and users are spamming the download all button because they don't know their click has registered.

Tested with Firefox 116.02 and Edge 115.0.1901.188 (on Windows 10 22H2)

P.S great job on this BTW. brilliant. Apologies for re-opening.

I was able to reproduce this problem.
When the cursor is focused on an icon that exists on the right-hand side and tries to display a tooltip, the tooltip content breaks lines because it is at the edge of the screen.
This causes the cursor to focus on the tooltip element that overlaps the icon and the tooltip, which is only visible when hovering over the icon, disappears. After the tooltip disappears, the tooltip appears again because of the focus on the icon, disappears, and so on.
This is the likely cause of the blinking.

This problem is not limited to download links, but can occur with any icon that exists at the edge of the screen.

Actions #42

Updated by Grubs _ over 1 year ago

Many thanks for the insight.

I fixed this by changing the CSS of my theme application.css to display the previously hidden link text "Download all files" which pushes the download icon away from the left edge of the screen and fixes the flashing.

The Download All Icon now takes up more width and the popup is now redundant but users can find it much easier. The small icon was not obvious on the right edge of the screen. I also changed the icon div container CSS so the file list begins below the download all link allowing the file names and descriptions to use the full width of the screen.


/* puts the edit and Download all icon on its own line */
div.attachments .contextual {
  float: unset;
  text-align: right;
}

/* this displays the "Download all files" link text */
div.contextual .icon-download {
  width: unset;
  font-size: 13px;
  }

Actions

Also available in: Atom PDF