Skip to content

Commit

Permalink
Merge pull request opf#14016 from opf/impl/meeting-email-notifications
Browse files Browse the repository at this point in the history
add email notifications for meetings
  • Loading branch information
dombesz authored Nov 6, 2023
2 parents d326b48 + 1bf135e commit cc7fea1
Show file tree
Hide file tree
Showing 37 changed files with 738 additions and 377 deletions.
80 changes: 80 additions & 0 deletions app/helpers/mail_layout_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 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 docs/COPYRIGHT.rdoc for more details.
#++

module MailLayoutHelper
def placeholder_table_styles(options = {})
default_options = {
style: 'table-layout:fixed;border-collapse:separate;border-spacing:0;font-family:Helvetica;' <<
(options[:style].present? ? options.delete(:style) : ''),
cellspacing: "0",
cellpadding: "0"
}

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 action_button(&block)
render(
partial: 'mailer/mailer_button',
locals: { block: }
)
end

def placeholder_cell(number, vertical:)
style = if vertical
"max-width:#{number}; min-width:#{number}; width:#{number}"
else
"line-height:#{number}; max-width:0; min-width:0; height:#{number}; width:0; font-size:#{number}"
end

content_tag('td', '&nbsp;'.html_safe, style:)
end

def user_salutation(user)
case Setting.emails_salutation
when :name
I18n.t(:'mail.salutation', user: user.name)
else
I18n.t(:'mail.salutation', user: user.firstname)
end
end
end
35 changes: 0 additions & 35 deletions app/helpers/mail_notification_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,39 +57,4 @@ def status_colors(status)
color_id = selected_color(status)
Color.find(color_id).color_styles.map { |k, v| "#{k}:#{v};" }.join(' ') if color_id
end

def placeholder_table_styles(options = {})
default_options = {
style: 'table-layout:fixed;border-collapse:separate;border-spacing:0;font-family:Helvetica;' <<
(options[:style].present? ? options.delete(:style) : ''),
cellspacing: "0",
cellpadding: "0"
}

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}"
else
"line-height:#{number}; max-width:0; min-width:0; height:#{number}; width:0; font-size:#{number}"
end

content_tag('td', '&nbsp;'.html_safe, style:)
end
end
15 changes: 3 additions & 12 deletions app/mailers/announcement_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@
class AnnouncementMailer < ApplicationMailer
include OpenProject::StaticRouting::UrlHelpers
include OpenProject::TextFormatting
helper :mail_notification
helper :mail_notification,
:mail_layout

def announce(user, subject:, body:, salutation: :firstname, body_header: nil, body_subheader: nil)
def announce(user, subject:, body:, body_header: nil, body_subheader: nil)
with_locale_for(user) do
localized_subject = localized(subject)

Expand All @@ -44,7 +45,6 @@ def announce(user, subject:, body:, salutation: :firstname, body_header: nil, bo
locals = {
body: localized(body),
user:,
salutation: user_salutation(user, salutation),
header_summary: localized_subject,
body_header: localized(body_header),
body_subheader: localized(body_subheader)
Expand All @@ -65,13 +65,4 @@ def localized(input)
input
end
end

def user_salutation(user, salutation)
case salutation
when :firstname
I18n.t(:'mail.salutation', user: user.firstname)
else
salutation % { firstname: user.firstname, lastname: user.lastname, name: user.name }
end
end
end
3 changes: 2 additions & 1 deletion app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class ApplicationMailer < ActionMailer::Base

helper :application, # for format_text
:work_packages, # for css classes
:custom_fields # for show_value
:custom_fields, # for show_value
:mail_layout # for layouting

include OpenProject::LocaleHelper

Expand Down
17 changes: 14 additions & 3 deletions app/views/admin/settings/mail_notifications_settings/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,19 @@ See COPYRIGHT and LICENSE files for more details.
<div class="form--field"><%= setting_text_field :mail_from, size: 60, container_class: '-middle' %></div>
<div class="form--field"><%= setting_check_box :bcc_recipients %></div>
<div class="form--field"><%= setting_check_box :plain_text_mail %></div>
<div class="form--field">
<%= setting_select :emails_salutation,
[
[User.human_attribute_name(:firstname), :firstname],
[t('mail.salutation_full_name'), :name],
],
container_class: '-middle' %>
</div>
</section>

<fieldset id="emails_decorators" class="form--fieldset"><legend class="form--fieldset-legend"><%= t(:setting_emails_header) %> & <%= t(:setting_emails_footer) %></legend>
<fieldset id="emails_decorators" class="form--fieldset">
<legend class="form--fieldset-legend"><%= t(:setting_emails_header) %>
& <%= I18n.t(:setting_emails_footer) %></legend>
<%= render Settings::TextSettingComponent.new(I18n.locale, name: "emails_header") %>
<%= render Settings::TextSettingComponent.new(I18n.locale, name: "emails_footer") %>
</fieldset>
Expand All @@ -54,7 +64,7 @@ See COPYRIGHT and LICENSE files for more details.
email_methods << :letter_opener if Rails.env.development?
%>
<%= content_tag :fieldset, id: "mail_configuration", class: "form--fieldset" do %>
<legend class="form--fieldset-legend"><%=t(:text_setup_mail_configuration)%></legend>
<legend class="form--fieldset-legend"><%= t(:text_setup_mail_configuration) %></legend>
<div class="form--field"><%= setting_select(:email_delivery_method, email_methods, id: "email_delivery_method_switch", container_class: '-slim') %></div>
<div id="email_delivery_method_smtp" class="email_delivery_method_settings">
<div class="form--field"><%= setting_text_field :smtp_address, container_class: '-middle' %></div>
Expand All @@ -70,7 +80,8 @@ See COPYRIGHT and LICENSE files for more details.
<div class="form--field"><%= setting_text_field :sendmail_location %></div>
</div>
<div id="email_delivery_method_letter_opener" class="email_delivery_method_settings">
<p>Letter opener is used to render emails as a file in your Rails tmp folder. Mails will automatically open in your browser if supported.</p>
<p>Letter opener is used to render emails as a file in your Rails tmp folder. Mails will automatically open in
your browser if supported.</p>
</div>
<% end unless OpenProject::Configuration['email_delivery_configuration'] == 'legacy' %>
Expand Down
3 changes: 1 addition & 2 deletions app/views/announcement_mailer/announce.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<%= render layout: 'mailer/spacer_table' do %>
<%= render partial: 'mailer/notification_mailer_header',
<%= render partial: 'mailer/mailer_header',
locals: {
summary: header_summary,
salutation: salutation,
user: user
} %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/announcement_mailer/announce.text.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= salutation %>
<%= user_salutation(user) %>
<%= header_summary %>
<%= "-" * 100 %>
Expand Down
3 changes: 1 addition & 2 deletions app/views/digest_mailer/work_packages.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
<tr>
<%= placeholder_cell('12px', vertical: true) %>
<td>
<%= render partial: 'mailer/notification_mailer_header',
<%= render partial: 'mailer/mailer_header',
locals: {
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,
salutation: I18n.t(:'mail.salutation', user: @user.firstname)
} %>
<% @aggregated_notifications.first(DigestMailer::MAX_SHOWN_WORK_PACKAGES).each do |work_package, notifications_by_work_package| %>
Expand Down
22 changes: 22 additions & 0 deletions app/views/mailer/_mailer_button.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<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>
<table <%= placeholder_table_styles %>>
<tr>
<td style="padding: 8px 12px; border: 1px solid #878787; border-radius: 16px; overflow: hidden; text-overflow: ellipsis;white-space: nowrap;">
<%= capture(&block) %>
</td>
</tr>
</table>
</td>
</tr>
</table>
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,22 @@
<tr>
<td>
<span style="font-size: 24px; color: #333333;">
<%= salutation %>
<%= user_salutation(user) %>
</span>
</td>
</tr>
<tr>
<%= placeholder_cell('8px', vertical: false) %>
</tr>
<% if local_assigns[:summary] %>
<tr>
<td>
<span style="font-size:16px; color: #1A67A3; font-weight: 600;">
<%= summary %>
</span>
</td>
</tr>
<% end %>
<tr>
<%= placeholder_cell('24px', vertical: false) %>
</tr>
Expand All @@ -42,9 +44,11 @@
</td>
</tr>
<% end %>
<% if local_assigns[:bottom_spacing] != false %>
<tr>
<%= placeholder_cell('40px', vertical: false) %>
</tr>
<% end %>
</table>
</td>
<%= placeholder_cell('16px', vertical: true) %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/sharing_mailer/shared_work_package.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
end
%>
<%= render partial: 'mailer/notification_mailer_header',
<%= render partial: 'mailer/mailer_header',
locals: {
user: @shared_with_user,
summary:,
button_href: shared_work_package_path(@work_package.id),
button_text: I18n.t(:'mail.sharing.work_packages.open_work_package'),
salutation: I18n.t(:'mail.salutation', user: @shared_with_user.firstname)
} %>
<%= render layout: 'mailer/notification_row',
Expand Down
3 changes: 1 addition & 2 deletions app/views/work_package_mailer/mentioned.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
<tr>
<%= placeholder_cell('12px', vertical: true) %>
<td>
<%= render partial: 'mailer/notification_mailer_header',
<%= render partial: 'mailer/mailer_header',
locals: {
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,
salutation: I18n.t(:'mail.salutation', user: @user.firstname)
} %>
<%= render layout: 'mailer/notification_row',
Expand Down
4 changes: 4 additions & 0 deletions config/constants/settings/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ class Definition
default: nil,
env_alias: 'EMAIL_DELIVERY_METHOD'
},
emails_salutation: {
allowed: %w[firstname name],
default: :firstname
},
emails_footer: {
default: {
'en' => ''
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2266,6 +2266,7 @@ en:
see_in_center: 'See comment in notification center'
settings: 'Change email settings'
salutation: 'Hello %{user}'
salutation_full_name: 'Full name'
work_packages:
created_at: 'Created at %{timestamp} by %{user} '
login_to_see_all: 'Log in to see all notifications.'
Expand Down Expand Up @@ -2749,6 +2750,7 @@ en:
<a href="%{link}" target="_blank">%{link}</a>.
setting_attachment_whitelist: "Attachment upload whitelist"
setting_email_delivery_method: "Email delivery method"
setting_emails_salutation: "Address user in emails with"
setting_sendmail_location: "Location of the sendmail executable"
setting_smtp_enable_starttls_auto: "Automatically use STARTTLS if available"
setting_smtp_ssl: "Use SSL connection"
Expand Down
46 changes: 46 additions & 0 deletions lib/open_project/patches/mailer_controller_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 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.
#++
#

module OpenProject::Patches::MailerControllerCsp
extend ActiveSupport::Concern

included do
prepend_before_action :extend_content_security_policy

def extend_content_security_policy
append_content_security_policy_directives(
script_src: %w('unsafe-inline'),
)
end
end
end

OpenProject::Patches.patch_gem_version 'rails', '7.0.8' do
Rails::MailersController.include OpenProject::Patches::MailerControllerCsp
end
Loading

0 comments on commit cc7fea1

Please sign in to comment.