diff --git a/app/helpers/mailer_helper.rb b/app/helpers/mailer_helper.rb new file mode 100644 index 000000000..e50e74f44 --- /dev/null +++ b/app/helpers/mailer_helper.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2022 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module MailerHelper + def show_recipients(recipients) + recipients.take(Setting.show_recipients_limit.to_i).map(&:name).join(', ') + (recipients.size > Setting.show_recipients_limit.to_i ? '...' : '') + end +end diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 558c280ec..12b06b6d6 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -24,6 +24,7 @@ class Mailer < ActionMailer::Base helper :application helper :issues helper :custom_fields + helper :mailer include Redmine::I18n include Roadie::Rails::Automatic @@ -70,7 +71,7 @@ def self.default_url_options end # Builds a mail for notifying user about a new issue - def issue_add(user, issue) + def issue_add(user, issue, recipients=nil) redmine_headers 'Project' => issue.project.identifier, 'Issue-Tracker' => issue.tracker.name, 'Issue-Id' => issue.id, @@ -82,6 +83,7 @@ def issue_add(user, issue) @author = issue.author @issue = issue @user = user + @recipients = recipients @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue) subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]" subject += " (#{issue.status.name})" if Setting.show_status_changes_in_mail_subject? @@ -97,12 +99,12 @@ def issue_add(user, issue) def self.deliver_issue_add(issue) users = issue.notified_users | issue.notified_watchers | issue.notified_mentions users.each do |user| - issue_add(user, issue).deliver_later + issue_add(user, issue, users).deliver_later end end # Builds a mail for notifying user about an issue update - def issue_edit(user, journal) + def issue_edit(user, journal, recipients=nil) issue = journal.journalized redmine_headers 'Project' => issue.project.identifier, 'Issue-Tracker' => issue.tracker.name, @@ -118,6 +120,7 @@ def issue_edit(user, journal) s += issue.subject @issue = issue @user = user + @recipients = recipients @journal = journal @journal_details = journal.visible_details @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}") @@ -136,16 +139,17 @@ def self.deliver_issue_edit(journal) journal.notes? || journal.visible_details(user).any? end users.each do |user| - issue_edit(user, journal).deliver_later + issue_edit(user, journal, users).deliver_later end end # Builds a mail to user about a new document. - def document_added(user, document, author) + def document_added(user, document, author, recipients=nil) redmine_headers 'Project' => document.project.identifier @author = author @document = document @user = user + @recipients = recipients @document_url = url_for(:controller => 'documents', :action => 'show', :id => document) mail :to => user, :subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}" @@ -158,12 +162,12 @@ def document_added(user, document, author) def self.deliver_document_added(document, author) users = document.notified_users users.each do |user| - document_added(user, document, author).deliver_later + document_added(user, document, author, users).deliver_later end end # Builds a mail to user about new attachements. - def attachments_added(user, attachments) + def attachments_added(user, attachments, recipients=nil) container = attachments.first.container added_to = '' added_to_url = '' @@ -182,6 +186,7 @@ def attachments_added(user, attachments) redmine_headers 'Project' => container.project.identifier @attachments = attachments @user = user + @recipients = recipients @added_to = added_to @added_to_url = added_to_url mail :to => user, @@ -202,18 +207,19 @@ def self.deliver_attachments_added(attachments) end users.each do |user| - attachments_added(user, attachments).deliver_later + attachments_added(user, attachments, users).deliver_later end end # Builds a mail to user about a new news. - def news_added(user, news) + def news_added(user, news, recipients=nil) redmine_headers 'Project' => news.project.identifier @author = news.author message_id news references news @news = news @user = user + @recipients = recipients @news_url = url_for(:controller => 'news', :action => 'show', :id => news) mail :to => user, :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}" @@ -226,12 +232,12 @@ def news_added(user, news) def self.deliver_news_added(news) users = news.notified_users | news.notified_watchers_for_added_news users.each do |user| - news_added(user, news).deliver_later + news_added(user, news, users).deliver_later end end # Builds a mail to user about a new news comment. - def news_comment_added(user, comment) + def news_comment_added(user, comment, recipients=nil) news = comment.commented redmine_headers 'Project' => news.project.identifier @author = comment.author @@ -240,6 +246,7 @@ def news_comment_added(user, comment) @news = news @comment = comment @user = user + @recipients = recipients @news_url = url_for(:controller => 'news', :action => 'show', :id => news) mail :to => user, :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}" @@ -253,12 +260,12 @@ def self.deliver_news_comment_added(comment) news = comment.commented users = news.notified_users | news.notified_watchers users.each do |user| - news_comment_added(user, comment).deliver_later + news_comment_added(user, comment, users).deliver_later end end # Builds a mail to user about a new message. - def message_posted(user, message) + def message_posted(user, message, recipients=nil) redmine_headers 'Project' => message.project.identifier, 'Topic-Id' => (message.parent_id || message.id) @author = message.author @@ -266,6 +273,7 @@ def message_posted(user, message) references message.root @message = message @user = user + @recipients = recipients @message_url = url_for(message.event_url) mail :to => user, :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}" @@ -281,18 +289,19 @@ def self.deliver_message_posted(message) users |= message.board.notified_watchers users.each do |user| - message_posted(user, message).deliver_later + message_posted(user, message, users).deliver_later end end # Builds a mail to user about a new wiki content. - def wiki_content_added(user, wiki_content) + def wiki_content_added(user, wiki_content, recipients=nil) redmine_headers 'Project' => wiki_content.project.identifier, 'Wiki-Page-Id' => wiki_content.page.id @author = wiki_content.author message_id wiki_content @wiki_content = wiki_content @user = user + @recipients = recipients @wiki_content_url = url_for(:controller => 'wiki', :action => 'show', :project_id => wiki_content.project, :id => wiki_content.page.title) @@ -310,18 +319,19 @@ def wiki_content_added(user, wiki_content) def self.deliver_wiki_content_added(wiki_content) users = wiki_content.notified_users | wiki_content.page.wiki.notified_watchers | wiki_content.notified_mentions users.each do |user| - wiki_content_added(user, wiki_content).deliver_later + wiki_content_added(user, wiki_content, users).deliver_later end end # Builds a mail to user about an update of the specified wiki content. - def wiki_content_updated(user, wiki_content) + def wiki_content_updated(user, wiki_content, recipients=nil) redmine_headers 'Project' => wiki_content.project.identifier, 'Wiki-Page-Id' => wiki_content.page.id @author = wiki_content.author message_id wiki_content @wiki_content = wiki_content @user = user + @recipients = recipients @wiki_content_url = url_for(:controller => 'wiki', :action => 'show', :project_id => wiki_content.project, @@ -348,7 +358,7 @@ def self.deliver_wiki_content_updated(wiki_content) users |= wiki_content.notified_mentions users.each do |user| - wiki_content_updated(user, wiki_content).deliver_later + wiki_content_updated(user, wiki_content, users).deliver_later end end @@ -367,8 +377,9 @@ def self.deliver_account_information(user, password) end # Builds a mail to user about an account activation request. - def account_activation_request(user, new_user) + def account_activation_request(user, new_user, recipients=nil) @new_user = new_user + @recipients = recipients @url = url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc') @@ -385,7 +396,7 @@ def self.deliver_account_activation_request(new_user) # Send the email to all active administrators users = User.active.where(:admin => true) users.each do |user| - account_activation_request(user, new_user).deliver_later + account_activation_request(user, new_user, users.to_a).deliver_later end end @@ -469,7 +480,8 @@ def self.deliver_register(user, token) # field: :field_mail, # value: address # ) => Mail::Message object - def security_notification(user, sender, options={}) + def security_notification(user, sender, options={}, recipients=nil) + @recipients = recipients @sender = sender redmine_headers 'Sender' => sender.login @message = @@ -506,12 +518,13 @@ def self.deliver_security_notification(users, sender, options={}) options[:remote_ip] ||= sender.remote_ip Array.wrap(users).each do |user| - security_notification(user, sender, options).deliver_later + security_notification(user, sender, options, users).deliver_later end end # Build a mail to user about application settings changes made by sender. - def settings_updated(user, sender, changes, options={}) + def settings_updated(user, sender, changes, options={}, recipients=nil) + @recipients = recipients @sender = sender redmine_headers 'Sender' => sender.login @changes = changes @@ -538,7 +551,7 @@ def self.deliver_settings_updated(sender, changes, options={}) users = User.active.where(admin: true).to_a users.each do |user| - settings_updated(user, sender, changes, options).deliver_later + settings_updated(user, sender, changes, options, users).deliver_later end end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb index fff36c0cb..a9fde2f0d 100644 --- a/app/views/layouts/mailer.html.erb +++ b/app/views/layouts/mailer.html.erb @@ -25,6 +25,11 @@ span.footer { font-size: 0.8em; font-style: italic; } +span.recipients { + font-size: 0.8em; + font-style: italic; + color: #959595; +} blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 0;} blockquote blockquote { margin-left: 0;} pre, code {font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace;} @@ -78,5 +83,11 @@ table, td, th { <% if Setting.emails_footer.present? -%> <%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer).html_safe %> <% end -%> +<% if Setting.show_recipients_in_mail_footer? && @recipients.present? %> + + <%= l(:text_sent_email_to_recipients) %>
+ <%= show_recipients @recipients %> +
+<% end %> diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb index a4c69862b..11b1393ba 100644 --- a/app/views/layouts/mailer.text.erb +++ b/app/views/layouts/mailer.text.erb @@ -6,3 +6,8 @@ -- <%= Setting.emails_footer %> <% end -%> +<% if Setting.show_recipients_in_mail_footer? && @recipients.present? %> + +<%= l(:text_sent_email_to_recipients) %> +<%= show_recipients @recipients %> +<% end -%> \ No newline at end of file diff --git a/app/views/settings/_notifications.html.erb b/app/views/settings/_notifications.html.erb index aafbe4340..15812d91a 100644 --- a/app/views/settings/_notifications.html.erb +++ b/app/views/settings/_notifications.html.erb @@ -7,6 +7,10 @@

<%= setting_check_box :plain_text_mail %>

<%= setting_check_box :show_status_changes_in_mail_subject %>

+ +

<%= setting_check_box :show_recipients_in_mail_footer, :data => {:enables => '#settings_show_recipients_limit'} %>

+ +

<%= setting_text_field :show_recipients_limit, :size => 6%>

<%=l(:text_select_mail_notifications)%> diff --git a/config/locales/en.yml b/config/locales/en.yml index f9064c866..86a8efa6f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -514,6 +514,8 @@ en: setting_timelog_max_hours_per_day: Maximum hours that can be logged per day and user setting_timelog_accept_future_dates: Accept time logs on future dates setting_show_status_changes_in_mail_subject: Show status changes in issue mail notifications subject + setting_show_recipients_in_mail_footer: Show recipients in mail notifications footer + setting_show_recipients_limit: Maximum number of recipients in mail notifications footer setting_project_list_defaults: Projects list defaults setting_twofa: Two-factor authentication @@ -1259,6 +1261,7 @@ en: text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages text_issue_added: "Issue %{id} has been reported by %{author}." text_issue_updated: "Issue %{id} has been updated by %{author}." + text_sent_email_to_recipients: The following recipients have also received this email. text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content? text_issue_category_destroy_question: "Some issues (%{count}) are assigned to this category. What do you want to do?" text_issue_category_destroy_assignments: Remove category assignments diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 0215e7555..6cca121f2 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -898,6 +898,7 @@ ja: text_issues_ref_in_commit_messages: コミットメッセージ内でチケットの参照/修正 text_issue_added: "チケット %{id} を %{author} さんが作成しました。" text_issue_updated: "チケット %{id} を %{author} さんが更新しました。" + text_sent_email_to_recipients: 次のユーザーにもこのメールを送信しました。 text_wiki_destroy_confirmation: 本当にこのwikiとその内容のすべてを削除しますか? text_issue_category_destroy_question: "%{count}件のチケットがこのカテゴリに割り当てられています。" text_issue_category_destroy_assignments: カテゴリの割り当てを削除する @@ -1260,6 +1261,8 @@ ja: text_status_no_workflow: このステータスはどのトラッカーのワークフローでも使われていません setting_mail_handler_preferred_body_part: マルチパート (HTML) メールの優先パート setting_show_status_changes_in_mail_subject: 通知メールの題名にステータス変更の情報を挿入 + setting_show_recipients_in_mail_footer: 通知メールのフッタに受信者の情報を挿入 + setting_show_recipients_limit: 通知メールのフッタに挿入される受信者数の上限 label_inherited_from_parent_project: 親プロジェクトから継承 label_inherited_from_group: グループ %{name} から継承 label_trackers_description: トラッカーの説明 diff --git a/config/settings.yml b/config/settings.yml index 6db94a50f..2b1297cd1 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -341,3 +341,8 @@ timelog_accept_future_dates: default: 1 show_status_changes_in_mail_subject: default: 1 +show_recipients_in_mail_footer: + default: 0 +show_recipients_limit: + format: int + default: 15 \ No newline at end of file diff --git a/test/helpers/mailer_helper_test.rb b/test/helpers/mailer_helper_test.rb new file mode 100644 index 000000000..5abfd8f85 --- /dev/null +++ b/test/helpers/mailer_helper_test.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006-2022 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../test_helper', __FILE__) + +class MailerHelperTest < Redmine::HelperTest + include MailerHelper + + fixtures :users + + # TODO: fix method name + def test_1 + recipients = [User.find(2), User.find(3)] + ret = show_recipients recipients + assert_equal 'John Smith, Dave Lopper', ret + end + + def test_2 + with_settings :show_recipients_limit => 3 do + recipients = User.all.to_a + ret = show_recipients recipients + assert_equal 'Redmine Admin, John Smith, Dave Lopper...', ret + end + end + +end \ No newline at end of file diff --git a/test/unit/mailer_test.rb b/test/unit/mailer_test.rb index ee029d3e6..b8d332c4a 100644 --- a/test/unit/mailer_test.rb +++ b/test/unit/mailer_test.rb @@ -383,6 +383,10 @@ def test_message_posted_message_id end end + def test_message_posted_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + def test_reply_posted_message_id set_tmp_attachments_directory message = Message.find(3) @@ -531,6 +535,21 @@ def test_issue_add_should_include_issue_status_type_badge end end + def test_issue_add_should_include_recipients_on_mail_footer + with_settings :show_recipients_in_mail_footer => '1' do + issue = Issue.find(1) + Mailer.deliver_issue_add(issue) + mail = last_email + assert_select_email do + assert_select 'span.recipients' do |span| + assert_include 'The following recipients have also received this email.', span.text + assert_include 'John Smith', span.text + assert_include 'Dave Lopper', span.text + end + end + end + end + def test_issue_edit_subject_should_include_status_changes_if_setting_is_enabled with_settings :show_status_changes_in_mail_subject => 1 do issue = Issue.find(2) @@ -655,6 +674,46 @@ def test_issue_edit_should_notify_mentioned_users_in_notes assert_include User.find(1).mail, recipients end + def test_issue_edit_should_include_recipients_on_mail_footer + with_settings :show_recipients_in_mail_footer => '1' do + issue = Issue.find(1) + issue.init_journal(User.current) + issue.update(:status_id => 4) + journal = issue.journals.last + Mailer.deliver_issue_edit(journal) + mail = last_email + assert_select_email do + assert_select 'span.recipients' do |span| + assert_include 'The following recipients have also received this email.', span.text + assert_include 'John Smith', span.text + assert_include 'Dave Lopper', span.text + end + end + end + end + + def test_document_added_should_include_recipients_on_mail_footer + with_settings :show_recipients_in_mail_footer => '1' do + document = Document.find(1) + author = User.find(2) + Mailer.deliver_document_added(document, author) + mail = last_email + assert_select_email do + assert_select 'span.recipients' do |span| + assert_include 'The following recipients have also received this email.', span.text + assert_include 'John Smith', span.text + assert_include 'Dave Lopper', span.text + end + end + end + end + + def test_documents_file_added_should_include_recipients_on_mail_footer + # def test_attachments_added_should_include_recipients_on_mail_footer + # Mailer.deliver_attachments_added(document, author) + flunk 'Not Implemented' + end + def test_issue_should_send_email_notification_with_suppress_empty_fields ActionMailer::Base.deliveries.clear with_settings :notified_events => %w(issue_added) do @@ -705,6 +764,11 @@ def test_version_file_added end end + def test_version_file_added_should_include_recipients_on_mail_footer + # def test_attachments_added_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + def test_project_file_added attachements = [Attachment.find_by_container_type('Project')] assert Mailer.deliver_attachments_added(attachements) @@ -715,6 +779,11 @@ def test_project_file_added end end + def test_project_file_added_should_include_recipients_on_mail_footer + # def test_attachments_added_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + def test_news_added_should_notify_project_news_watchers set_tmp_attachments_directory user1 = User.generate! @@ -739,6 +808,14 @@ def test_news_added_should_notify_project_news_watchers end end + def test_news_added_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + + def test_news_comments_added_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + def test_wiki_content_added content = WikiContent.find(1) assert_difference 'ActionMailer::Base.deliveries.size', 2 do @@ -765,6 +842,10 @@ def test_wiki_content_added_should_notify_mentioned_users_in_content assert_include User.find(1).mail, recipients end + def test_wiki_content_added_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + def test_wiki_content_updated content = WikiContent.find(1) assert Mailer.deliver_wiki_content_updated(content) @@ -790,6 +871,10 @@ def test_wiki_content_updated_should_notify_mentioned_users_in_updated_content assert_include User.find(1).mail, recipients end + def test_wiki_content_updated_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + def test_register token = Token.find(1) assert Mailer.deliver_register(token.user, token) @@ -800,6 +885,10 @@ def test_register end end + def test_account_activation_request_should_include_recipients_on_mail_footer + flunk 'Not Implemented' + end + def test_test_email_later user = User.find(1) assert Mailer.test_email(user).deliver_later @@ -1043,6 +1132,16 @@ def test_security_notification_should_include_link end end + def test_security_notification_should_include_recipients_on_mail_footer + # 管理者を追加削除すると送信される + flunk 'Not Implemented' + end + + def test_settings_updated_should_include_recipients_on_mail_footer + # リポジトリを変えると送信される + flunk 'Not Implemented' + end + def test_mailer_should_not_change_locale # Set current language to italian set_language_if_valid 'it'