From 0cb2c64de4283d1ae271b7161e392debb4b63613 Mon Sep 17 00:00:00 2001 From: MAEDA Go Date: Thu, 24 Sep 2026 18:23:06 +0900 Subject: [PATCH] Raise the maximum number of files that can be attached at once to 50 --- app/assets/javascripts/attachments.js | 4 ++-- app/views/attachments/_form.html.erb | 4 +++- config/configuration.yml.example | 8 ++++++++ lib/redmine/configuration.rb | 1 + test/system/issues_test.rb | 17 +++++++++++++++++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/attachments.js b/app/assets/javascripts/attachments.js index edaa6a615..ec499535f 100644 --- a/app/assets/javascripts/attachments.js +++ b/app/assets/javascripts/attachments.js @@ -9,7 +9,7 @@ function addFile(inputEl, file, eagerUpload) { var attachmentsFields = attachmentsForm.find('.attachments_fields'); var attachmentsIcons = attachmentsForm.find('.attachments_icons'); var addAttachment = attachmentsForm.find('.add_attachment'); - var maxFiles = ($(inputEl).attr('multiple') == 'multiple' ? 10 : 1); + var maxFiles = $(inputEl).data('max-number-of-files'); var delIcon = attachmentsIcons.find('svg.svg-del').clone(); var attachmentIcon = attachmentsIcons.find('svg.svg-attachment').clone(); @@ -185,7 +185,7 @@ function uploadAndAttachFiles(files, inputEl) { $.each(files, function() {addFile(inputEl, this, true);}); } - if (filesLength > ($(inputEl).attr('multiple') == 'multiple' ? 10 : 1)) { + if (filesLength > $(inputEl).data('max-number-of-files')) { window.alert($(inputEl).data('max-number-of-files-message')); } return sizeExceeded; diff --git a/app/views/attachments/_form.html.erb b/app/views/attachments/_form.html.erb index ae55d7576..90eca8285 100644 --- a/app/views/attachments/_form.html.erb +++ b/app/views/attachments/_form.html.erb @@ -3,6 +3,7 @@ <% saved_attachments ||= container.saved_attachments if defined?(container) && container %> <% multiple = true unless defined?(multiple) && multiple == false %> <% show_add = multiple || saved_attachments.blank? %> +<% max_number_of_files = multiple ? Redmine::Configuration['max_attachments_at_once'].to_i : 1 %> <% description = (defined?(description) && description == false ? false : true) %> <% css_class = (defined?(filedrop) && filedrop == false ? '' : (attachment_format_custom_field ? 'custom-field-filedrop' : 'filedrop')) %> @@ -38,7 +39,8 @@ :multiple => multiple, :onchange => 'addInputFiles(this);', :data => { - :max_number_of_files_message => l(:error_attachments_too_many, :max_number_of_files => (multiple ? 10 : 1)), + :max_number_of_files => max_number_of_files, + :max_number_of_files_message => l(:error_attachments_too_many, :max_number_of_files => max_number_of_files), :max_file_size => Setting.attachment_max_size.to_i.kilobytes, :max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)), :max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i, diff --git a/config/configuration.yml.example b/config/configuration.yml.example index 76b329371..9dec44bdd 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -208,6 +208,14 @@ default: # Maximum number of simultaneous AJAX uploads #max_concurrent_ajax_uploads: 2 + # Maximum number of files that can be attached at once with the + # attachment form + # + # This limit is only applied in the browser, to keep the form usable when + # many files are dropped by mistake. The number of attachments is not + # limited by the server nor by the REST API. + #max_attachments_at_once: 50 + # URL of the avatar server # # By default, Redmine uses Gravatar as the avatar server for displaying diff --git a/lib/redmine/configuration.rb b/lib/redmine/configuration.rb index f479494a5..2cd8594e4 100644 --- a/lib/redmine/configuration.rb +++ b/lib/redmine/configuration.rb @@ -26,6 +26,7 @@ module Redmine 'avatar_server_url' => 'https://www.gravatar.com', 'email_delivery' => nil, 'max_concurrent_ajax_uploads' => 2, + 'max_attachments_at_once' => 50, 'sudo_mode' => true, 'common_mark_enable_hardbreaks' => true, 'thumbnails_generation_timeout' => 10, diff --git a/test/system/issues_test.rb b/test/system/issues_test.rb index ee7e4def9..00ff20a06 100644 --- a/test/system/issues_test.rb +++ b/test/system/issues_test.rb @@ -174,6 +174,23 @@ class IssuesSystemTest < ApplicationSystemTestCase assert_equal 'Some description', issue.attachments.first.description end + def test_create_issue_should_not_attach_more_files_than_max_attachments_at_once + set_tmp_attachments_directory + log_user('jsmith', 'jsmith') + + Redmine::Configuration.with('max_attachments_at_once' => 3) do + visit '/projects/ecookbook/issues/new' + end + files = %w(testfile.txt hello.pdf japanese-utf-8.txt iso8859-1.txt).map do |name| + Rails.root.join('test/fixtures/files', name) + end + accept_alert(/maximum number of files that can be attached simultaneously \(3\)/) do + attach_file 'attachments[dummy][file]', files + end + assert_selector '.attachments_fields > span', :count => 3 + assert_no_selector '.add_attachment', :visible => true + end + def test_create_issue_with_new_target_version log_user('jsmith', 'jsmith') -- 2.55.0