Commit 77985826 authored by Alexandru Croitor's avatar Alexandru Croitor

Show header and footer system messages in email

* Add email_header_and_footer_enabled flag to appearances table
* Set email_header_and_footer_enabled default value to false
* Add checkbox to appearance to toggle show header and footer in emails
* Add email_header_and_footer_enabled to allowed params in controller
* Add header and footer messages to the html and text email layouts
* Remove the color styling for emails header and footer
* Add empty_mailer layout for emails without layout,
to have the header and footer applied
parent 177f9ca8
...@@ -78,6 +78,7 @@ class Admin::AppearancesController < Admin::ApplicationController ...@@ -78,6 +78,7 @@ class Admin::AppearancesController < Admin::ApplicationController
footer_message footer_message
message_background_color message_background_color
message_font_color message_font_color
email_header_and_footer_enabled
] ]
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
module AppearancesHelper module AppearancesHelper
include MarkupHelper
def brand_title def brand_title
current_appearance&.title.presence || default_brand_title current_appearance&.title.presence || default_brand_title
end end
...@@ -47,7 +49,7 @@ module AppearancesHelper ...@@ -47,7 +49,7 @@ module AppearancesHelper
class_names = [] class_names = []
class_names << 'with-performance-bar' if performance_bar_enabled? class_names << 'with-performance-bar' if performance_bar_enabled?
render_message(:header_message, class_names) render_message(:header_message, class_names: class_names)
end end
def footer_message def footer_message
...@@ -58,10 +60,10 @@ module AppearancesHelper ...@@ -58,10 +60,10 @@ module AppearancesHelper
private private
def render_message(field_sym, class_names = []) def render_message(field_sym, class_names: [], style: message_style)
class_names << field_sym.to_s.dasherize class_names << field_sym.to_s.dasherize
content_tag :div, class: class_names, style: message_style do content_tag :div, class: class_names, style: style do
markdown_field(current_appearance, field_sym) markdown_field(current_appearance, field_sym)
end end
end end
......
...@@ -131,4 +131,42 @@ module EmailsHelper ...@@ -131,4 +131,42 @@ module EmailsHelper
project.id.to_s + "." + project_path_as_domain + "." + Gitlab.config.gitlab.host project.id.to_s + "." + project_path_as_domain + "." + Gitlab.config.gitlab.host
end end
def html_header_message
return unless show_header?
render_message(:header_message, style: '')
end
def html_footer_message
return unless show_footer?
render_message(:footer_message, style: '')
end
def text_header_message
return unless show_header?
strip_tags(render_message(:header_message, style: ''))
end
def text_footer_message
return unless show_footer?
strip_tags(render_message(:footer_message, style: ''))
end
private
def show_footer?
email_header_and_footer_enabled? && current_appearance&.show_footer?
end
def show_header?
email_header_and_footer_enabled? && current_appearance&.show_header?
end
def email_header_and_footer_enabled?
current_appearance&.email_header_and_footer_enabled?
end
end end
# frozen_string_literal: true # frozen_string_literal: true
class AbuseReportMailer < BaseMailer class AbuseReportMailer < BaseMailer
layout 'empty_mailer'
helper EmailsHelper
def notify(abuse_report_id) def notify(abuse_report_id)
return unless deliverable? return unless deliverable?
......
# frozen_string_literal: true # frozen_string_literal: true
class EmailRejectionMailer < BaseMailer class EmailRejectionMailer < BaseMailer
layout 'empty_mailer'
helper EmailsHelper
def rejection(reason, original_raw, can_retry = false) def rejection(reason, original_raw, can_retry = false)
@reason = reason @reason = reason
@original_message = Mail::Message.new(original_raw) @original_message = Mail::Message.new(original_raw)
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
class RepositoryCheckMailer < BaseMailer class RepositoryCheckMailer < BaseMailer
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
layout 'empty_mailer'
helper EmailsHelper
def notify(failed_count) def notify(failed_count)
@message = @message =
if failed_count == 1 if failed_count == 1
......
...@@ -20,6 +20,7 @@ class Appearance < ActiveRecord::Base ...@@ -20,6 +20,7 @@ class Appearance < ActiveRecord::Base
default_value_for :message_background_color, '#E75E40' default_value_for :message_background_color, '#E75E40'
default_value_for :message_font_color, '#FFFFFF' default_value_for :message_font_color, '#FFFFFF'
default_value_for :email_header_and_footer_enabled, false
mount_uploader :logo, AttachmentUploader mount_uploader :logo, AttachmentUploader
mount_uploader :header_logo, AttachmentUploader mount_uploader :header_logo, AttachmentUploader
......
...@@ -13,6 +13,15 @@ ...@@ -13,6 +13,15 @@
.form-group .form-group
= form.label :footer_message, _('Footer message'), class: 'col-form-label label-bold' = form.label :footer_message, _('Footer message'), class: 'col-form-label label-bold'
= form.text_area :footer_message, placeholder: _('State your message to activate'), class: "form-control js-autosize" = form.text_area :footer_message, placeholder: _('State your message to activate'), class: "form-control js-autosize"
.form-group
.form-check
= form.check_box :email_header_and_footer_enabled, class: 'form-check-input'
= form.label :email_header_and_footer_enabled, class: 'label-bold' do
= _('Enable header and footer in emails')
.hint
= _('Add header and footer to emails. Please note that color settings will only be applied within the application interface')
.form-group.js-toggle-colors-container .form-group.js-toggle-colors-container
%button.btn.btn-link.js-toggle-colors-link{ type: 'button' } %button.btn.btn-link.js-toggle-colors-link{ type: 'button' }
= _('Customize colors') = _('Customize colors')
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" } %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" }
%tr.header %tr.header
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
= html_header_message
= header_logo = header_logo
%tr %tr
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" }
...@@ -72,3 +73,6 @@ ...@@ -72,3 +73,6 @@
= _("You're receiving this email because of your account on %{host}. %{manage_notifications_link} &middot; %{help_link}").html_safe % { host: Gitlab.config.gitlab.host, manage_notifications_link: manage_notifications_link, help_link: help_link } = _("You're receiving this email because of your account on %{host}. %{manage_notifications_link} &middot; %{help_link}").html_safe % { host: Gitlab.config.gitlab.host, manage_notifications_link: manage_notifications_link, help_link: help_link }
= yield :additional_footer = yield :additional_footer
%tr
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
= html_footer_message
= html_header_message
= yield
= html_footer_message
<%= text_header_message %>
<%= yield -%>
<%= text_footer_message %>
<%= text_header_message %>
<%= yield -%> <%= yield -%>
-- <%# signature marker %> -- <%# signature marker %>
<%= _("You're receiving this email because of your account on %{host}.") % { host: Gitlab.config.gitlab.host } %> <%= _("You're receiving this email because of your account on %{host}.") % { host: Gitlab.config.gitlab.host } %>
<%= text_footer_message %>
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
= yield :head = yield :head
%body %body
.content .content
= html_header_message
= yield = yield
.footer{ style: "margin-top: 10px;" } .footer{ style: "margin-top: 10px;" }
%p %p
...@@ -30,3 +31,4 @@ ...@@ -30,3 +31,4 @@
adjust your notification settings. adjust your notification settings.
= email_action @target_url = email_action @target_url
= html_footer_message
<%= text_header_message %>
<%= yield -%> <%= yield -%>
-- <%# signature marker %> -- <%# signature marker %>
...@@ -10,3 +12,5 @@ ...@@ -10,3 +12,5 @@
<% end -%> <% end -%>
<%= "You're receiving this email because #{notification_reason_text(@reason)}." %> <%= "You're receiving this email because #{notification_reason_text(@reason)}." %>
<%= text_footer_message -%>
---
title: Show header and footer system messages in email
merge_request: 25474
author:
type: added
# frozen_string_literal: true
class AddEmailHeaderAndFooterEnabledFlagToAppearancesTable < ActiveRecord::Migration[5.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
add_column_with_default(:appearances, :email_header_and_footer_enabled, :boolean, default: false)
end
def down
remove_column(:appearances, :email_header_and_footer_enabled)
end
end
...@@ -44,6 +44,7 @@ ActiveRecord::Schema.define(version: 20190220150130) do ...@@ -44,6 +44,7 @@ ActiveRecord::Schema.define(version: 20190220150130) do
t.text "message_background_color" t.text "message_background_color"
t.text "message_font_color" t.text "message_font_color"
t.string "favicon" t.string "favicon"
t.boolean "email_header_and_footer_enabled", default: false, null: false
end end
create_table "application_setting_terms", force: :cascade do |t| create_table "application_setting_terms", force: :cascade do |t|
......
...@@ -7,6 +7,10 @@ Navigate to the **Admin** area and go to the **Appearance** page. ...@@ -7,6 +7,10 @@ Navigate to the **Admin** area and go to the **Appearance** page.
Under **System header and footer** insert your header message and/or footer message. Under **System header and footer** insert your header message and/or footer message.
Both background and font color of the header and footer are customizable. Both background and font color of the header and footer are customizable.
You can also apply the header and footer messages to gitlab emails,
by checking the **Enable header and footer in emails** checkbox.
Note that color settings will only be applied within the app interface and not to emails
![appearance](system_header_and_footer_messages/appearance.png) ![appearance](system_header_and_footer_messages/appearance.png)
After saving, all GitLab pages will contain the custom system header and/or footer messages: After saving, all GitLab pages will contain the custom system header and/or footer messages:
......
...@@ -393,6 +393,9 @@ msgstr "" ...@@ -393,6 +393,9 @@ msgstr ""
msgid "Add a table" msgid "Add a table"
msgstr "" msgstr ""
msgid "Add header and footer to emails. Please note that color settings will only be applied within the application interface"
msgstr ""
msgid "Add image comment" msgid "Add image comment"
msgstr "" msgstr ""
...@@ -2959,6 +2962,9 @@ msgstr "" ...@@ -2959,6 +2962,9 @@ msgstr ""
msgid "Enable group Runners" msgid "Enable group Runners"
msgstr "" msgstr ""
msgid "Enable header and footer in emails"
msgstr ""
msgid "Enable or disable version check and usage ping." msgid "Enable or disable version check and usage ping."
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper' require 'spec_helper'
describe Admin::AppearancesController do describe Admin::AppearancesController do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:header_message) { "Header message" } let(:header_message) { 'Header message' }
let(:footer_message) { "Footer" } let(:footer_message) { 'Footer' }
describe 'POST #create' do describe 'POST #create' do
let(:create_params) do let(:create_params) do
{ {
title: "Foo", title: 'Foo',
description: "Bar", description: 'Bar',
header_message: header_message, header_message: header_message,
footer_message: footer_message footer_message: footer_message
} }
...@@ -24,10 +26,27 @@ describe Admin::AppearancesController do ...@@ -24,10 +26,27 @@ describe Admin::AppearancesController do
expect(Appearance.current).to have_attributes( expect(Appearance.current).to have_attributes(
header_message: header_message, header_message: header_message,
footer_message: footer_message footer_message: footer_message,
email_header_and_footer_enabled: false,
message_background_color: '#E75E40',
message_font_color: '#FFFFFF'
)
end
context 'when enabling header and footer in email' do
it 'creates appearance with enabled flag' do
create_params[:email_header_and_footer_enabled] = true
post :create, params: { appearance: create_params }
expect(Appearance.current).to have_attributes(
header_message: header_message,
footer_message: footer_message,
email_header_and_footer_enabled: true
) )
end end
end end
end
describe 'PUT #update' do describe 'PUT #update' do
let(:update_params) do let(:update_params) do
...@@ -48,8 +67,25 @@ describe Admin::AppearancesController do ...@@ -48,8 +67,25 @@ describe Admin::AppearancesController do
expect(Appearance.current).to have_attributes( expect(Appearance.current).to have_attributes(
header_message: header_message, header_message: header_message,
footer_message: footer_message footer_message: footer_message,
email_header_and_footer_enabled: false,
message_background_color: '#E75E40',
message_font_color: '#FFFFFF'
)
end
context 'when enabling header and footer in email' do
it 'updates appearance with enabled flag' do
update_params[:email_header_and_footer_enabled] = true
post :update, params: { appearance: update_params }
expect(Appearance.current).to have_attributes(
header_message: header_message,
footer_message: footer_message,
email_header_and_footer_enabled: true
) )
end end
end end
end
end end
...@@ -142,4 +142,58 @@ describe EmailsHelper do ...@@ -142,4 +142,58 @@ describe EmailsHelper do
end end
end end
end end
describe 'header and footer messages' do
context 'when email_header_and_footer_enabled is enabled' do
it 'returns header and footer messages' do
create :appearance, header_message: 'Foo', footer_message: 'Bar', email_header_and_footer_enabled: true
aggregate_failures do
expect(html_header_message).to eq(%{<div class="header-message" style=""><p>Foo</p></div>})
expect(html_footer_message).to eq(%{<div class="footer-message" style=""><p>Bar</p></div>})
expect(text_header_message).to eq('Foo')
expect(text_footer_message).to eq('Bar')
end
end
context 'when header and footer messages are empty' do
it 'returns nil' do
create :appearance, header_message: '', footer_message: '', email_header_and_footer_enabled: true
aggregate_failures do
expect(html_header_message).to eq(nil)
expect(html_footer_message).to eq(nil)
expect(text_header_message).to eq(nil)
expect(text_footer_message).to eq(nil)
end
end
end
context 'when header and footer messages are nil' do
it 'returns nil' do
create :appearance, header_message: nil, footer_message: nil, email_header_and_footer_enabled: true
aggregate_failures do
expect(html_header_message).to eq(nil)
expect(html_footer_message).to eq(nil)
expect(text_header_message).to eq(nil)
expect(text_footer_message).to eq(nil)
end
end
end
end
context 'when email_header_and_footer_enabled is disabled' do
it 'returns header and footer messages' do
create :appearance, header_message: 'Foo', footer_message: 'Bar', email_header_and_footer_enabled: false
aggregate_failures do
expect(html_header_message).to eq(nil)
expect(html_footer_message).to eq(nil)
expect(text_header_message).to eq(nil)
expect(text_footer_message).to eq(nil)
end
end
end
end
end end
...@@ -4,25 +4,24 @@ describe AbuseReportMailer do ...@@ -4,25 +4,24 @@ describe AbuseReportMailer do
include EmailSpec::Matchers include EmailSpec::Matchers
describe '.notify' do describe '.notify' do
context 'with admin_notification_email set' do
before do before do
stub_application_setting(admin_notification_email: 'admin@example.com') stub_application_setting(admin_notification_email: 'admin@example.com')
end end
it 'sends to the admin_notification_email' do let(:report) { create(:abuse_report) }
report = create(:abuse_report)
mail = described_class.notify(report.id) subject { described_class.notify(report.id) }
expect(mail).to deliver_to 'admin@example.com' it_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
context 'with admin_notification_email set' do
it 'sends to the admin_notification_email' do
is_expected.to deliver_to 'admin@example.com'
end end
it 'includes the user in the subject' do it 'includes the user in the subject' do
report = create(:abuse_report) is_expected.to have_subject "#{report.user.name} (#{report.user.username}) was reported for abuse"
mail = described_class.notify(report.id)
expect(mail).to have_subject "#{report.user.name} (#{report.user.username}) was reported for abuse"
end end
end end
......
# frozen_string_literal: true
require 'rails_helper'
describe EmailRejectionMailer do
include EmailSpec::Matchers
describe '#rejection' do
let(:raw_email) { 'From: someone@example.com\nraw email here' }
subject { described_class.rejection('some rejection reason', raw_email) }
it_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
end
end
...@@ -13,6 +13,9 @@ describe Emails::AutoDevops do ...@@ -13,6 +13,9 @@ describe Emails::AutoDevops do
subject { Notify.autodevops_disabled_email(pipeline, owner.email) } subject { Notify.autodevops_disabled_email(pipeline, owner.email) }
it_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
it 'sents email with correct subject' do it 'sents email with correct subject' do
is_expected.to have_subject("#{project.name} | Auto DevOps pipeline was disabled for #{project.name}") is_expected.to have_subject("#{project.name} | Auto DevOps pipeline was disabled for #{project.name}")
end end
......
...@@ -29,5 +29,14 @@ describe Emails::Issues do ...@@ -29,5 +29,14 @@ describe Emails::Issues do
expect(subject).to have_body_text "23, 34, 58" expect(subject).to have_body_text "23, 34, 58"
end end
context 'with header and footer' do
let(:results) { { success: 165, error_lines: [], parse_error: false } }
subject { Notify.import_issues_csv_email(user.id, project.id, results) }
it_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
end
end end
end end
This diff is collapsed.
...@@ -17,5 +17,12 @@ describe RepositoryCheckMailer do ...@@ -17,5 +17,12 @@ describe RepositoryCheckMailer do
expect(mail).to have_subject 'GitLab Admin | 3 projects failed their last repository check' expect(mail).to have_subject 'GitLab Admin | 3 projects failed their last repository check'
end end
context 'with footer and header' do
subject { described_class.notify(1) }
it_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
end
end end
end end
...@@ -78,4 +78,22 @@ describe Appearance do ...@@ -78,4 +78,22 @@ describe Appearance do
it { is_expected.to allow_value(hex).for(:message_font_color) } it { is_expected.to allow_value(hex).for(:message_font_color) }
it { is_expected.not_to allow_value('000').for(:message_font_color) } it { is_expected.not_to allow_value('000').for(:message_font_color) }
end end
describe 'email_header_and_footer_enabled' do
context 'default email_header_and_footer_enabled flag value' do
it 'returns email_header_and_footer_enabled as true' do
appearance = build(:appearance)
expect(appearance.email_header_and_footer_enabled?).to eq(false)
end
end
context 'when setting email_header_and_footer_enabled flag value' do
it 'returns email_header_and_footer_enabled as true' do
appearance = build(:appearance, email_header_and_footer_enabled: true)
expect(appearance.email_header_and_footer_enabled?).to eq(true)
end
end
end
end end
...@@ -252,3 +252,31 @@ shared_examples 'a note email' do ...@@ -252,3 +252,31 @@ shared_examples 'a note email' do
end end
end end
end end
shared_examples 'appearance header and footer enabled' do
it "contains header and footer" do
create :appearance, header_message: "Foo", footer_message: "Bar", email_header_and_footer_enabled: true
aggregate_failures do
expect(subject.html_part).to have_body_text("<div class=\"header-message\" style=\"\"><p>Foo</p></div>")
expect(subject.html_part).to have_body_text("<div class=\"footer-message\" style=\"\"><p>Bar</p></div>")
expect(subject.text_part).to have_body_text(/^Foo/)
expect(subject.text_part).to have_body_text(/Bar$/)
end
end
end
shared_examples 'appearance header and footer not enabled' do
it "does not contain header and footer" do
create :appearance, header_message: "Foo", footer_message: "Bar", email_header_and_footer_enabled: false
aggregate_failures do
expect(subject.html_part).not_to have_body_text("<div class=\"header-message\" style=\"\"><p>Foo</p></div>")
expect(subject.html_part).not_to have_body_text("<div class=\"footer-message\" style=\"\"><p>Bar</p></div>")
expect(subject.text_part).not_to have_body_text(/^Foo/)
expect(subject.text_part).not_to have_body_text(/Bar$/)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment