send 12.0 update mail

pull/9805/head
ulferts 3 years ago
parent 44cdc13307
commit aace67b63e
No known key found for this signature in database
GPG Key ID: A205708DE1284017
  1. 16
      app/helpers/mail_notification_helper.rb
  2. 55
      app/mailers/announcement_mailer.rb
  3. 42
      app/views/announcement_mailer/announce.html.erb
  4. 13
      app/views/announcement_mailer/announce.text.erb
  5. 92
      app/views/digest_mailer/work_packages.html.erb
  6. 21
      app/views/mailer/_border_table.html.erb
  7. 20
      app/views/mailer/_notification_mailer_header.html.erb
  8. 13
      app/views/mailer/_notification_row.html.erb
  9. 17
      app/views/mailer/_notification_settings_table.html.erb
  10. 21
      app/views/mailer/_spacer_table.html.erb
  11. 37
      app/views/work_package_mailer/mentioned.html.erb
  12. 23
      config/locales/en.yml
  13. 13
      db/migrate/20211105142202_queue_notification_update_mail.rb
  14. 63
      spec/mailers/announcement_mailer_spec.rb

@ -43,7 +43,7 @@ module MailNotificationHelper
suffix = "svg+xml"
end
email_image_tag(logo, suffix, options)
email_image_tag(logo, suffix, **options)
end
def email_image_tag(image, suffix, **options)
@ -84,6 +84,20 @@ module MailNotificationHelper
default_options.merge(options).map { |k, v| "#{k}=#{v}" }.join(' ')
end
def placeholder_text_styles(**overwrites)
{
color: '#878787',
'line-height': '24px',
'font-size': '14px',
'white-space': 'normal',
overflow: 'hidden',
'max-width': '100%',
width: '100%'
}.merge(overwrites)
.map { |k, v| "#{k}: #{v}" }
.join('; ')
end
def placeholder_cell(number, vertical:)
style = if vertical
"max-width:#{number}; min-width:#{number}; width:#{number}"

@ -0,0 +1,55 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2021 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# 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.
#
# See COPYRIGHT and LICENSE files for more details.
#++
# Sends mails for announcements.
# For now, it cannot handle sending events on any Announcement model but is rather focused
# on handing very simple mails where only the recipient, subject and body is provided.
class AnnouncementMailer < ApplicationMailer
include OpenProject::StaticRouting::UrlHelpers
include OpenProject::TextFormatting
helper :mail_notification
def announce(user, subject:, body:, body_header: nil, body_subheader: nil)
with_locale_for(user) do
mail to: user.mail,
subject: subject do |format|
locals = {
body: body,
user: user,
header_summary: subject,
body_header: body_header,
body_subheader: body_subheader
}
format.html { render locals: locals }
format.text { render locals: locals }
end
end
end
end

@ -0,0 +1,42 @@
<%= render layout: 'mailer/spacer_table' do %>
<%= render partial: 'mailer/notification_mailer_header',
locals: {
summary: header_summary,
user: user
} %>
<%= render layout: 'mailer/border_table' do %>
<tr>
<%= placeholder_cell('24px', vertical: true) %>
<td>
<table>
<% if body_subheader %>
<tr>
<td style="<%= placeholder_text_styles('font-weight': 'bold') %>">
<%= format_text body_subheader %>
</td>
</tr>
<% end %>
<% if body_header %>
<tr>
<td style="<%= placeholder_text_styles(color: '#333333', 'line-height': '36px', 'font-size': '18px', 'font-weight': 'bold') %>">
<%= format_text body_header %>
</td>
</tr>
<% end %>
<tr>
<td style="<%= placeholder_text_styles %>">
<%= format_text body %>
</td>
</tr>
</table>
</td>
<%= placeholder_cell('24px', vertical: true) %>
</tr>
<tr>
<%= placeholder_cell('24px', vertical: false) %>
</tr>
<% end %>
<%= render partial: 'mailer/notification_settings_table' %>
<% end %>

@ -0,0 +1,13 @@
<%= I18n.t(:'mail.salutation', user: user.firstname) %>
<%= header_summary %>
<%= "-" * 100 %>
<%= "+" * 50 %>
<%= strip_tags body_subheader %>
<%= strip_tags body_header %>
<%= "+" * 50 %>
<%= strip_tags body %>
<%= "-" * 100 %>

@ -8,16 +8,13 @@
<tr>
<%= placeholder_cell('12px', vertical: true) %>
<td>
<%= render layout: 'mailer/notification_mailer_header',
<%= render partial: 'mailer/notification_mailer_header',
locals: {
summary: "#{I18n.t(:'mail.digests.you_have')} #{digest_summary_text(@notification_ids.length, @mentioned_count)}"
} do %>
<a href="<%= notifications_center_url %>"
target="_blank"
style="background: #D1E5F5; padding: 8px 12px; color: #1A67A3; border: 1px solid #1A67A3; border-radius: 16px; text-decoration: none;font-size: 14px;">
<%= I18n.t(:'mail.notification.center') %>
</a>
<% end %>
summary: "#{I18n.t(:'mail.digests.you_have')} #{digest_summary_text(@notification_ids.length, @mentioned_count)}",
button_href: notifications_center_url,
button_text: I18n.t(:'mail.notification.center'),
user: @user
} %>
<% @aggregated_notifications.first(DigestMailer::MAX_SHOWN_WORK_PACKAGES).each do | work_package, notifications_by_work_package| %>
<%= render layout: 'mailer/notification_row',
@ -25,7 +22,8 @@
work_package: work_package,
unique_reasons: unique_reasons_of_notifications(notifications_by_work_package),
show_count: true,
count: notifications_by_work_package.length
count: notifications_by_work_package.length,
user: @user
} do %>
<table <%= placeholder_table_styles %>>
<tr>
@ -38,50 +36,36 @@
<% end %>
<% end %>
<table <%= placeholder_table_styles(style: 'font-size:14px;') %>>
<tr>
<td>
<table <%= placeholder_table_styles(width:'100%',style: 'width:100%;') %>>
<tr>
<td>
<% if @aggregated_notifications.length > DigestMailer::MAX_SHOWN_WORK_PACKAGES %>
<table>
<tr>
<td>
<span style="font-size:14px;">
<% number_of_overflowing_work_packages = @aggregated_notifications.length - DigestMailer::MAX_SHOWN_WORK_PACKAGES %>
<% count = number_of_overflowing_work_packages === 1 ? 'one' : 'other' %>
<%= I18n.t(:"mail.work_packages.more_to_see.#{count}", count: number_of_overflowing_work_packages) %>
</span>
</td>
<%= placeholder_cell('10px', vertical: true) %>
<td>
<a href="<%= notifications_center_url %>"
target="_blank"
style="background-color: #D1E5F5;
padding: 8px 12px;
color: #1A67A3;
border: 1px solid #1A67A3;
border-radius: 16px;
text-decoration: none;
font-size:14px;
white-space: nowrap;">
<%= I18n.t(:'mail.work_packages.see_all') %>
</a>
</td>
</tr>
</table>
<% end %>
</td>
</tr>
</table>
</td>
<%= placeholder_cell('10px', vertical: true) %>
<td>
<%= render partial: 'mailer/notification_settings_button' %>
</td>
</tr>
</table>
<%= render layout: 'mailer/notification_settings_table' do %>
<% if @aggregated_notifications.length > DigestMailer::MAX_SHOWN_WORK_PACKAGES %>
<table>
<tr>
<td>
<span style="font-size:14px;">
<% number_of_overflowing_work_packages = @aggregated_notifications.length - DigestMailer::MAX_SHOWN_WORK_PACKAGES %>
<% count = number_of_overflowing_work_packages === 1 ? 'one' : 'other' %>
<%= I18n.t(:"mail.work_packages.more_to_see.#{count}", count: number_of_overflowing_work_packages) %>
</span>
</td>
<%= placeholder_cell('10px', vertical: true) %>
<td>
<a href="<%= notifications_center_url %>"
target="_blank"
style="background-color: #D1E5F5;
padding: 8px 12px;
color: #1A67A3;
border: 1px solid #1A67A3;
border-radius: 16px;
text-decoration: none;
font-size:14px;
white-space: nowrap;">
<%= I18n.t(:'mail.work_packages.see_all') %>
</a>
</td>
</tr>
</table>
<% end %>
<% end %>
<table>
<tr>

@ -0,0 +1,21 @@
<table <%= placeholder_table_styles(width:'100%',style: "width:100%;border-width:1px;border-color:#E0E0E0;border-style:solid;border-radius:10px") %>>
<tr>
<%= placeholder_cell('12px', vertical: false) %>
</tr>
<tr>
<td>
<table <%= placeholder_table_styles(width:'100%',style: 'width:100%;font-size:14px;') %>>
<%= yield %>
</table>
</td>
</tr>
<tr>
<%= placeholder_cell('12px', vertical: false) %>
</tr>
</table>
<table>
<tr>
<%= placeholder_cell('20px', vertical: false) %>
</tr>
</table>

@ -8,7 +8,7 @@
<tr>
<td>
<span style="font-size: 24px; color: #333333;">
<%= I18n.t(:'mail.salutation', user: @user.firstname) %>
<%= I18n.t(:'mail.salutation', user: user.firstname) %>
</span>
</td>
</tr>
@ -25,11 +25,17 @@
<tr>
<%= placeholder_cell('24px', vertical: false) %>
</tr>
<tr>
<td>
<%= yield %>
</td>
</tr>
<% if defined?(button_href) && defined?(button_text) %>
<tr>
<td>
<a href="<%= button_href %>"
target="_blank"
style="background: #D1E5F5; padding: 8px 12px; color: #1A67A3; border: 1px solid #1A67A3; border-radius: 16px; text-decoration: none; font-size: 14px;">
<%= button_text %>
</a>
</td>
</tr>
<% end %>
<tr>
<%= placeholder_cell('40px', vertical: false) %>
</tr>
@ -40,7 +46,7 @@
<table <%= placeholder_table_styles %>>
<tr>
<td style="width: 96px; height: 96px;">
<%= logo_tag({ alt: "#{Setting.app_title} #{I18n.t(:'mail.logo_alt_text')}", style: "height: 96px;max-width: 240px;"}) %>
<%= logo_tag(alt: "#{Setting.app_title} #{I18n.t(:'mail.logo_alt_text')}", style: "height: 96px;max-width: 240px;") %>
</td>
</tr>
</table>

@ -1,10 +1,7 @@
<a style="text-decoration: none;display: block;"
href="<%= notifications_path(work_package.id) %>"
target="_blank">
<table <%= placeholder_table_styles(width:'100%',style: "width:100%;border-width:1px;border-color:#E0E0E0;border-style:solid;border-radius:10px") %>>
<tr>
<%= placeholder_cell('12px', vertical: false) %>
</tr>
<%= render layout: 'mailer/border_table' do %>
<tr>
<td>
<table <%= placeholder_table_styles(width:'100%',style: 'width:100%;font-size:14px;') %>>
@ -97,11 +94,5 @@
<tr>
<%= placeholder_cell('12px', vertical: false) %>
</tr>
</table>
<table>
<tr>
<%= placeholder_cell('20px', vertical: false) %>
</tr>
</table>
<% end %>
</a>

@ -0,0 +1,17 @@
<table <%= placeholder_table_styles(style: 'font-size:14px;') %>>
<tr>
<td>
<table <%= placeholder_table_styles(width:'100%',style: 'width:100%;') %>>
<tr>
<td>
<%= yield %>
</td>
</tr>
</table>
</td>
<%= placeholder_cell('10px', vertical: true) %>
<td>
<%= render partial: 'mailer/notification_settings_button' %>
</td>
</tr>
</table>

@ -0,0 +1,21 @@
<table <%= placeholder_table_styles %>>
<tr>
<%= placeholder_cell('20px', vertical: false) %>
</tr>
</table>
<table <%= placeholder_table_styles(width:'100%',style: 'width:100%;max-width:700px;') %>>
<tr>
<%= placeholder_cell('12px', vertical: true) %>
<td>
<%= yield %>
<table>
<tr>
<%= placeholder_cell('40px', vertical: false) %>
</tr>
</table>
</td>
<%= placeholder_cell('12px', vertical: true) %>
</tr>
</table>

@ -8,48 +8,31 @@
<tr>
<%= placeholder_cell('12px', vertical: true) %>
<td>
<%= render layout: 'mailer/notification_mailer_header',
<%= render partial: 'mailer/notification_mailer_header',
locals: {
summary: "#{I18n.t(:'mail.work_packages.mentioned_by', user: @journal.user)}"
} do %>
<a href="<%= notifications_path(@work_package.id) %>"
target="_blank"
style="background: #D1E5F5; padding: 8px 12px; color: #1A67A3; border: 1px solid #1A67A3; border-radius: 16px; text-decoration: none;font-size: 14px;">
<%= I18n.t(:'mail.notification.see_in_center') %>
</a>
<% end %>
summary: I18n.t(:'mail.work_packages.mentioned_by', user: @journal.user),
button_href: notifications_path(@work_package.id),
button_text: I18n.t(:'mail.notification.see_in_center'),
user: @user
} %>
<%= render layout: 'mailer/notification_row',
locals: {
work_package: @work_package,
unique_reasons: [:mentioned],
show_count: false
show_count: false,
user: @user
} do %>
<table <%= placeholder_table_styles(width:'100%',style: 'width:100%;') %>>
<tr>
<td style="color: #878787; line-height: 24px; font-size: 14px; white-space: normal; overflow: hidden; max-width: 100%; width: 100%;">
<td style="<%= placeholder_text_styles %>">
<%= format_text @journal.notes, only_path: false %>
</td>
</tr>
</table>
<% end %>
<table <%= placeholder_table_styles(style: 'font-size:14px;') %>>
<tr>
<td>
<table <%= placeholder_table_styles(width:'100%',style: 'width:100%;') %>>
<tr>
<td>
</td>
</tr>
</table>
</td>
<%= placeholder_cell('10px', vertical: true) %>
<td>
<%= render partial: 'mailer/notification_settings_button' %>
</td>
</tr>
</table>
<%= render partial: 'mailer/notification_settings_table' %>
<table>
<tr>

@ -1404,6 +1404,29 @@ en:
mentioned: "You have been mentioned in %{work_package}"
responsible: "You have become accountable for %{work_package}"
watched: "You are watching %{work_package}"
update_info_mail:
body: >
We are excited to announce the release of OpenProject 12.0. It's a major release that will hopefully significantly improve the way you use OpenProject.
Starting with this release, we are introducing Notification Center. From now on, you will receive notifications for updates to work packages directly in OpenProject. You can mark these notifications as read, reply to a comment or even directly modify work package attributes without leaving Notification Center.
This also means that we will no longer be using emails for notifications. We think Notification Center is a better place to view and act upon these updates. Nevertheless, if you would like continue receiving updates via email, you can choose to receive daily email reminders at particular times of your choosing.
You can set your preferences for notifications and email reminders via your account settings, or leave them unchanged to keep the default ones. You can do this through the “Change email settings” button bellow.
We hope you find Notification Center useful and that it makes you even more productive.
Sincerely,
The OpenProject team
body_header: 'Version 12.0 with Notification Center'
body_subheader: 'News'
subject: 'Important changes to notifications with the release of 12.0'
label_accessibility: "Accessibility"
label_account: "Account"

@ -0,0 +1,13 @@
class QueueNotificationUpdateMail < ActiveRecord::Migration[6.1]
def up
User.active.find_each do |user|
AnnouncementMailer
.announce(user,
subject: I18n.t(:'notifications.update_info_mail.subject'),
body: I18n.t(:'notifications.update_info_mail.body'),
body_header: I18n.t(:'notifications.update_info_mail.body_header'),
body_subheader: I18n.t(:'notifications.update_info_mail.body_subheader'))
.deliver_later
end
end
end

@ -0,0 +1,63 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2021 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# 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.
#
# See COPYRIGHT and LICENSE files for more details.
#++
require 'spec_helper'
describe AnnouncementMailer, type: :mailer do
let(:announcement_subject) { 'Some subject' }
let(:recipient) { FactoryBot.build_stubbed(:user) }
let(:announcement_body) { 'Some body text' }
describe '#announce' do
subject(:mail) do
described_class.announce(recipient,
subject: announcement_subject,
body: announcement_body)
end
it "has a subject" do
expect(mail.subject)
.to eq announcement_subject
end
it 'includes the body' do
expect(mail.body.encoded)
.to include(announcement_body)
end
it "includes the subject in the body as well" do
expect(mail.body.encoded)
.to include announcement_subject
end
it 'sends to the recipient' do
expect(mail.to)
.to match_array [recipient.mail]
end
end
end
Loading…
Cancel
Save