diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index d00ba1c3d7d..4bafe972516 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -3644,6 +3644,16 @@ en:
title: "Override your site's robots.txt file:"
warning: "This will permanently override any related site settings."
overridden: Your site's default robots.txt file is overridden.
+ email_style:
+ title: "Email Style"
+ heading: "Customize Email Style"
+ html: "HTML Template"
+ css: "CSS"
+ reset: "Reset to default"
+ reset_confirm: "Are you sure you want to reset to the default %{fieldName} and lose all your changes?"
+ save_error_with_reason: "Your changes were not saved. %{error}"
+ instructions: "Customize the template in which all html emails are rendered, and style using CSS."
+
email:
title: "Emails"
settings: "Settings"
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 6dc6bd93c9c..6290dcaf63e 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -1854,6 +1854,7 @@ en:
suppress_digest_email_after_days: "Suppress summary emails for users not seen on the site for more than (n) days."
digest_suppress_categories: "Suppress these categories from summary emails."
disable_digest_emails: "Disable summary emails for all users."
+ apply_custom_styles_to_digest: "Custom email template and css are applied to summary emails."
email_accent_bg_color: "The accent color to be used as the background of some elements in HTML emails. Enter a color name ('red') or hex value ('#FF0000')."
email_accent_fg_color: "The color of text rendered on the email bg color in HTML emails. Enter a color name ('white') or hex value ('#FFFFFF')."
email_link_color: "The color of links in HTML emails. Enter a color name ('blue') or hex value ('#0000FF')."
@@ -4554,3 +4555,6 @@ en:
title: "Delete User"
confirm: "Are you sure you want to delete that user? This will remove all of their posts and block their email and IP address."
reason: "Deleted via review queue"
+
+ email_style:
+ html_missing_placeholder: "The html template must include %{placeholder}"
diff --git a/config/routes.rb b/config/routes.rb
index d1e4bf0bb2a..68b1b00fe93 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -244,6 +244,9 @@ Discourse::Application.routes.draw do
get 'robots' => 'robots_txt#show'
put 'robots.json' => 'robots_txt#update'
delete 'robots.json' => 'robots_txt#reset'
+
+ resource :email_style, only: [:show, :update]
+ get 'email_style/:field' => 'email_styles#show', constraints: { field: /html|css/ }
end
resources :embeddable_hosts, constraints: AdminConstraint.new
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 5535315930d..29dc73a1dd5 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -911,6 +911,7 @@ email:
disable_digest_emails:
default: false
client: true
+ apply_custom_styles_to_digest: true
email_accent_bg_color: "#2F70AC"
email_accent_fg_color: "#FFFFFF"
email_link_color: "#006699"
@@ -1024,6 +1025,12 @@ email:
enable_forwarded_emails: false
always_show_trimmed_content: false
private_email: false
+ email_custom_template:
+ default: ""
+ hidden: true
+ email_custom_css:
+ default: ""
+ hidden: true
email_total_attachment_size_limit_kb:
default: 0
max: 51200
diff --git a/lib/email/message_builder.rb b/lib/email/message_builder.rb
index 92f4a2bab89..88669eb729d 100644
--- a/lib/email/message_builder.rb
+++ b/lib/email/message_builder.rb
@@ -107,16 +107,17 @@ module Email
html_override.gsub!("%{respond_instructions}", "")
end
- styled = Email::Styles.new(html_override, @opts)
- styled.format_basic
-
- if style = @opts[:style]
- styled.public_send("format_#{style}")
- end
+ html = UserNotificationRenderer.with_view_paths(
+ Rails.configuration.paths["app/views"]
+ ).render(
+ template: 'layouts/email_template',
+ format: :html,
+ locals: { html_body: html_override.html_safe }
+ )
Mail::Part.new do
content_type 'text/html; charset=UTF-8'
- body styled.to_html
+ body html
end
end
diff --git a/lib/email/renderer.rb b/lib/email/renderer.rb
index f8d0328dc40..0c616be0436 100644
--- a/lib/email/renderer.rb
+++ b/lib/email/renderer.rb
@@ -17,15 +17,21 @@ module Email
end
def html
- if @message.html_part
- style = Email::Styles.new(@message.html_part.body.to_s, @opts)
- style.format_basic
- style.format_html
+ style = if @message.html_part
+ Email::Styles.new(@message.html_part.body.to_s, @opts)
else
- style = Email::Styles.new(PrettyText.cook(text), @opts)
- style.format_basic
+ unstyled = UserNotificationRenderer.with_view_paths(
+ Rails.configuration.paths["app/views"]
+ ).render(
+ template: 'layouts/email_template',
+ format: :html,
+ locals: { html_body: PrettyText.cook(text).html_safe }
+ )
+ Email::Styles.new(unstyled, @opts)
end
+ style.format_basic
+ style.format_html
style.to_html
end
diff --git a/lib/email/styles.rb b/lib/email/styles.rb
index 7dc7f14b3ae..1b6373878d0 100644
--- a/lib/email/styles.rb
+++ b/lib/email/styles.rb
@@ -16,6 +16,7 @@ module Email
@html = html
@opts = opts || {}
@fragment = Nokogiri::HTML.fragment(@html)
+ @custom_styles = nil
end
def self.register_plugin_style(&block)
@@ -32,6 +33,26 @@ module Email
end
end
+ def custom_styles
+ return @custom_styles unless @custom_styles.nil?
+
+ css = EmailStyle.new.css
+ @custom_styles = {}
+
+ if !css.blank?
+ require 'css_parser' unless defined?(CssParser)
+
+ parser = CssParser::Parser.new(import: false)
+ parser.load_string!(css)
+ parser.each_selector do |selector, value|
+ @custom_styles[selector] ||= +''
+ @custom_styles[selector] << value
+ end
+ end
+
+ @custom_styles
+ end
+
def format_basic
uri = URI(Discourse.base_url)
@@ -83,29 +104,6 @@ module Email
end
end
- def format_notification
- style('.previous-discussion', 'font-size: 17px; color: #444; margin-bottom:10px;')
- style('.notification-date', "text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px")
- style('.username', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#{SiteSetting.email_link_color};text-decoration:none;font-weight:bold")
- style('.user-title', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;margin-left:7px;color: #999;")
- style('.user-name', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;margin-left:7px;color: #{SiteSetting.email_link_color};font-weight:normal;")
- style('.post-wrapper', "margin-bottom:25px;")
- style('.user-avatar', 'vertical-align:top;width:55px;')
- style('.user-avatar img', nil, width: '45', height: '45')
- style('hr', 'background-color: #ddd; height: 1px; border: 1px;')
- style('.rtl', 'direction: rtl;')
- style('div.body', 'padding-top:5px;')
- style('.whisper div.body', 'font-style: italic; color: #9c9c9c;')
- style('.lightbox-wrapper .meta', 'display: none')
- correct_first_body_margin
- correct_footer_style
- style('div.undecorated-link-footer a', "font-weight: normal;")
- correct_footer_style_hilight_first
- reset_tables
- onebox_styles
- plugin_styles
- end
-
def onebox_styles
# Links to other topics
style('aside.quote', 'padding: 12px 25px 2px 12px; margin-bottom: 10px;')
@@ -164,6 +162,16 @@ module Email
end
def format_html
+ html_lang = SiteSetting.default_locale.sub("_", "-")
+ style('html', nil, lang: html_lang, 'xml:lang' => html_lang)
+ style('body', "text-align:#{ Rtl.new(nil).enabled? ? 'right' : 'left' };")
+ style('body', nil, dir: Rtl.new(nil).enabled? ? 'rtl' : 'ltr')
+
+ style('.with-dir',
+ "text-align:#{ Rtl.new(nil).enabled? ? 'right' : 'left' };",
+ dir: Rtl.new(nil).enabled? ? 'rtl' : 'ltr'
+ )
+
style('.with-accent-colors', "background-color: #{SiteSetting.email_accent_bg_color}; color: #{SiteSetting.email_accent_fg_color};")
style('h4', 'color: #222;')
style('h3', 'margin: 15px 0 20px 0;')
@@ -177,11 +185,39 @@ module Email
style('code', 'background-color: #f1f1ff; padding: 2px 5px;')
style('pre code', 'display: block; background-color: #f1f1ff; padding: 5px;')
style('.featured-topic a', "text-decoration: none; font-weight: bold; color: #{SiteSetting.email_link_color}; line-height:1.5em;")
+ style('.summary-email', "-moz-box-sizing:border-box;-ms-text-size-adjust:100%;-webkit-box-sizing:border-box;-webkit-text-size-adjust:100%;box-sizing:border-box;color:#0a0a0a;font-family:Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.3;margin:0;min-width:100%;padding:0;width:100%")
+
+ style('.previous-discussion', 'font-size: 17px; color: #444; margin-bottom:10px;')
+ style('.notification-date', "text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px")
+ style('.username', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#{SiteSetting.email_link_color};text-decoration:none;font-weight:bold")
+ style('.user-title', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;margin-left:7px;color: #999;")
+ style('.user-name', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;margin-left:7px;color: #{SiteSetting.email_link_color};font-weight:normal;")
+ style('.post-wrapper', "margin-bottom:25px;")
+ style('.user-avatar', 'vertical-align:top;width:55px;')
+ style('.user-avatar img', nil, width: '45', height: '45')
+ style('hr', 'background-color: #ddd; height: 1px; border: 1px;')
+ style('.rtl', 'direction: rtl;')
+ style('div.body', 'padding-top:5px;')
+ style('.whisper div.body', 'font-style: italic; color: #9c9c9c;')
+ style('.lightbox-wrapper .meta', 'display: none')
+ correct_first_body_margin
+ correct_footer_style
+ style('div.undecorated-link-footer a', "font-weight: normal;")
+ correct_footer_style_hilight_first
+ reset_tables
onebox_styles
plugin_styles
style('.post-excerpt img', "max-width: 50%; max-height: 400px;")
+
+ format_custom
+ end
+
+ def format_custom
+ custom_styles.each do |selector, value|
+ style(selector, value)
+ end
end
# this method is reserved for styles specific to plugin
@@ -240,7 +276,7 @@ module Email
end
def correct_first_body_margin
- @fragment.css('.body p').each do |element|
+ @fragment.css('div.body p').each do |element|
element['style'] = "margin-top:0; border: 0;"
end
end
diff --git a/spec/integration/email_style_spec.rb b/spec/integration/email_style_spec.rb
new file mode 100644
index 00000000000..e035aec1028
--- /dev/null
+++ b/spec/integration/email_style_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require "rails_helper"
+
+describe EmailStyle do
+ before do
+ SiteSetting.email_custom_template = "
FOR YOU
%{email_content}
"
+ SiteSetting.email_custom_css = 'h1 { color: red; } div.body { color: #FAB; }'
+ end
+
+ after do
+ SiteSetting.remove_override!(:email_custom_template)
+ SiteSetting.remove_override!(:email_custom_css)
+ end
+
+ context 'invite' do
+ fab!(:invite) { Fabricate(:invite) }
+ let(:invite_mail) { InviteMailer.send_invite(invite) }
+
+ subject(:mail_html) { Email::Renderer.new(invite_mail).html }
+
+ it 'applies customizations' do
+ expect(mail_html.scan('
FOR YOU
').count).to eq(1)
+ expect(mail_html).to match("#{Discourse.base_url}/invites/#{invite.invite_key}")
+ end
+
+ it 'can apply RTL attrs' do
+ SiteSetting.default_locale = 'he'
+ body_attrs = mail_html.match(/])+/)
+ expect(body_attrs[0]&.downcase).to match(/text-align:\s*right/)
+ expect(body_attrs[0]&.downcase).to include('dir="rtl"')
+ end
+ end
+
+ context 'user_replied' do
+ let(:response_by_user) { Fabricate(:user, name: "John Doe") }
+ let(:category) { Fabricate(:category, name: 'India') }
+ let(:topic) { Fabricate(:topic, category: category, title: "Super cool topic") }
+ let(:post) { Fabricate(:post, topic: topic, raw: 'This is My super duper cool topic') }
+ let(:response) { Fabricate(:basic_reply, topic: post.topic, user: response_by_user) }
+ let(:user) { Fabricate(:user) }
+ let(:notification) { Fabricate(:replied_notification, user: user, post: response) }
+
+ let(:mail) do
+ UserNotifications.user_replied(
+ user,
+ post: response,
+ notification_type: notification.notification_type,
+ notification_data_hash: notification.data_hash
+ )
+ end
+
+ subject(:mail_html) { Email::Renderer.new(mail).html }
+
+ it "customizations are applied to html part of emails" do
+ expect(mail_html.scan('
FOR YOU
').count).to eq(1)
+ matches = mail_html.match(/
#{post.raw}/)
+ expect(matches[1]).to include('color: #FAB;') # custom
+ expect(matches[1]).to include('padding-top:5px;') # div.body
+ end
+
+ # TODO: translation override
+ end
+
+ context 'signup' do
+ let(:signup_mail) { UserNotifications.signup(Fabricate(:user)) }
+ subject(:mail_html) { Email::Renderer.new(signup_mail).html }
+
+ it "customizations are applied to html part of emails" do
+ expect(mail_html.scan('
FOR YOU
').count).to eq(1)
+ expect(mail_html).to include('activate-account')
+ end
+
+ context 'translation override' do
+ before do
+ TranslationOverride.upsert!(
+ 'en',
+ 'user_notifications.signup.text_body_template',
+ "CLICK THAT LINK: %{base_url}/u/activate-account/%{email_token}"
+ )
+ end
+
+ after do
+ TranslationOverride.revert!('en', ['user_notifications.signup.text_body_template'])
+ end
+
+ it "applies customizations when translation override exists" do
+ expect(mail_html.scan('
FOR YOU
').count).to eq(1)
+ expect(mail_html.scan('CLICK THAT LINK').count).to eq(1)
+ end
+ end
+
+ context 'with some bad css' do
+ before do
+ SiteSetting.email_custom_css = '@import "nope.css"; h1 {{{ size: really big; '
+ end
+
+ it "can render the html" do
+ expect(mail_html.scan(/
FOR YOU<\/h1>/).count).to eq(1)
+ expect(mail_html).to include('activate-account')
+ end
+ end
+ end
+
+ context 'digest' do
+ fab!(:popular_topic) { Fabricate(:topic, user: Fabricate(:coding_horror), created_at: 1.hour.ago) }
+ let(:summary_email) { UserNotifications.digest(Fabricate(:user)) }
+ subject(:mail_html) { Email::Renderer.new(summary_email).html }
+
+ it "customizations are applied to html part of emails" do
+ expect(mail_html.scan('
FOR YOU
').count).to eq(1)
+ expect(mail_html).to include(popular_topic.title)
+ end
+
+ it "doesn't apply customizations if apply_custom_styles_to_digest is disabled" do
+ SiteSetting.apply_custom_styles_to_digest = false
+ expect(mail_html).to_not include('
FOR YOU
')
+ expect(mail_html).to_not include('FOR YOU')
+ expect(mail_html).to include(popular_topic.title)
+ end
+ end
+end
diff --git a/spec/mailers/user_notifications_spec.rb b/spec/mailers/user_notifications_spec.rb
index 7106d4641f2..f86892b3281 100644
--- a/spec/mailers/user_notifications_spec.rb
+++ b/spec/mailers/user_notifications_spec.rb
@@ -260,7 +260,7 @@ describe UserNotifications do
expect(mail.subject).to match(/Taggo/)
expect(mail.subject).to match(/Taggie/)
- mail_html = mail.html_part.to_s
+ mail_html = mail.html_part.body.to_s
expect(mail_html.scan(/My super duper cool topic/).count).to eq(1)
expect(mail_html.scan(/In Reply To/).count).to eq(1)
@@ -287,7 +287,7 @@ describe UserNotifications do
notification_data_hash: notification.data_hash
)
- expect(mail.html_part.to_s.scan(/In Reply To/).count).to eq(0)
+ expect(mail.html_part.body.to_s.scan(/In Reply To/).count).to eq(0)
SiteSetting.enable_names = true
SiteSetting.display_name_on_posts = true
@@ -304,7 +304,7 @@ describe UserNotifications do
notification_data_hash: notification.data_hash
)
- mail_html = mail.html_part.to_s
+ mail_html = mail.html_part.body.to_s
expect(mail_html.scan(/>Bob Marley/).count).to eq(1)
expect(mail_html.scan(/>bobmarley/).count).to eq(0)
@@ -317,7 +317,7 @@ describe UserNotifications do
notification_data_hash: notification.data_hash
)
- mail_html = mail.html_part.to_s
+ mail_html = mail.html_part.body.to_s
expect(mail_html.scan(/>Bob Marley/).count).to eq(0)
expect(mail_html.scan(/>bobmarley/).count).to eq(1)
end
@@ -331,8 +331,8 @@ describe UserNotifications do
notification_data_hash: notification.data_hash
)
- expect(mail.html_part.to_s).to_not include(response.raw)
- expect(mail.html_part.to_s).to_not include(topic.url)
+ expect(mail.html_part.body.to_s).to_not include(response.raw)
+ expect(mail.html_part.body.to_s).to_not include(topic.url)
expect(mail.text_part.to_s).to_not include(response.raw)
expect(mail.text_part.to_s).to_not include(topic.url)
end
@@ -365,10 +365,10 @@ describe UserNotifications do
expect(mail.subject).not_to match(/Uncategorized/)
# 1 respond to links as no context by default
- expect(mail.html_part.to_s.scan(/to respond/).count).to eq(1)
+ expect(mail.html_part.body.to_s.scan(/to respond/).count).to eq(1)
# 1 unsubscribe link
- expect(mail.html_part.to_s.scan(/To unsubscribe/).count).to eq(1)
+ expect(mail.html_part.body.to_s.scan(/To unsubscribe/).count).to eq(1)
# side effect, topic user is updated with post number
tu = TopicUser.get(post.topic_id, user)
@@ -384,7 +384,7 @@ describe UserNotifications do
notification_data_hash: notification.data_hash
)
- expect(mail.html_part.to_s).to_not include(response.raw)
+ expect(mail.html_part.body.to_s).to_not include(response.raw)
expect(mail.text_part.to_s).to_not include(response.raw)
end
@@ -451,13 +451,13 @@ describe UserNotifications do
expect(mail.subject).to include("[PM] ")
# 1 "visit message" link
- expect(mail.html_part.to_s.scan(/Visit Message/).count).to eq(1)
+ expect(mail.html_part.body.to_s.scan(/Visit Message/).count).to eq(1)
# 1 respond to link
- expect(mail.html_part.to_s.scan(/to respond/).count).to eq(1)
+ expect(mail.html_part.body.to_s.scan(/to respond/).count).to eq(1)
# 1 unsubscribe link
- expect(mail.html_part.to_s.scan(/To unsubscribe/).count).to eq(1)
+ expect(mail.html_part.body.to_s.scan(/To unsubscribe/).count).to eq(1)
# side effect, topic user is updated with post number
tu = TopicUser.get(topic.id, user)
@@ -473,8 +473,8 @@ describe UserNotifications do
notification_data_hash: notification.data_hash
)
- expect(mail.html_part.to_s).to_not include(response.raw)
- expect(mail.html_part.to_s).to_not include(topic.url)
+ expect(mail.html_part.body.to_s).to_not include(response.raw)
+ expect(mail.html_part.body.to_s).to_not include(topic.url)
expect(mail.text_part.to_s).to_not include(response.raw)
expect(mail.text_part.to_s).to_not include(topic.url)
end
@@ -635,7 +635,7 @@ describe UserNotifications do
# WARNING: you reached the limit of 100 email notifications per day. Further emails will be suppressed.
# Consider watching less topics or disabling mailing list mode.
- expect(mail.html_part.to_s).to match(I18n.t("user_notifications.reached_limit", count: 2))
+ expect(mail.html_part.body.to_s).to match(I18n.t("user_notifications.reached_limit", count: 2))
expect(mail.body.to_s).to match(I18n.t("user_notifications.reached_limit", count: 2))
end
diff --git a/spec/requests/admin/email_styles_controller_spec.rb b/spec/requests/admin/email_styles_controller_spec.rb
new file mode 100644
index 00000000000..9d1f297e7eb
--- /dev/null
+++ b/spec/requests/admin/email_styles_controller_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::EmailStylesController do
+ fab!(:admin) { Fabricate(:admin) }
+ let(:default_html) { File.read("#{Rails.root}/app/views/email/default_template.html") }
+ let(:default_css) { "" }
+
+ before do
+ sign_in(admin)
+ end
+
+ after do
+ SiteSetting.remove_override!(:email_custom_template)
+ SiteSetting.remove_override!(:email_custom_css)
+ end
+
+ describe 'show' do
+ it 'returns default values' do
+ get '/admin/customize/email_style.json'
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)['email_style']
+ expect(json['html']).to eq(default_html)
+ expect(json['css']).to eq(default_css)
+ end
+
+ it 'returns customized values' do
+ SiteSetting.email_custom_template = "For you: %{email_content}"
+ SiteSetting.email_custom_css = ".user-name { font-size: 24px; }"
+ get '/admin/customize/email_style.json'
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)['email_style']
+ expect(json['html']).to eq("For you: %{email_content}")
+ expect(json['css']).to eq(".user-name { font-size: 24px; }")
+ end
+ end
+
+ describe 'update' do
+ let(:valid_params) do
+ {
+ html: 'For you: %{email_content}',
+ css: '.user-name { color: purple; }'
+ }
+ end
+
+ it 'changes the settings' do
+ SiteSetting.email_custom_css = ".user-name { font-size: 24px; }"
+ put '/admin/customize/email_style.json', params: { email_style: valid_params }
+ expect(response.status).to eq(200)
+ expect(SiteSetting.email_custom_template).to eq(valid_params[:html])
+ expect(SiteSetting.email_custom_css).to eq(valid_params[:css])
+ end
+
+ it 'reports errors' do
+ put '/admin/customize/email_style.json', params: {
+ email_style: valid_params.merge(html: 'No email content')
+ }
+ expect(response.status).to eq(422)
+ json = JSON.parse(response.body)
+ expect(json['errors']).to include(
+ I18n.t(
+ 'email_style.html_missing_placeholder',
+ placeholder: '%{email_content}'
+ )
+ )
+ end
+ end
+end
diff --git a/spec/services/email_style_updater_spec.rb b/spec/services/email_style_updater_spec.rb
new file mode 100644
index 00000000000..3ef6f1c7ea9
--- /dev/null
+++ b/spec/services/email_style_updater_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe EmailStyleUpdater do
+ fab!(:admin) { Fabricate(:admin) }
+ let(:default_html) { File.read("#{Rails.root}/app/views/email/default_template.html") }
+ let(:updater) { EmailStyleUpdater.new(admin) }
+
+ describe 'update' do
+ it 'can change the settings' do
+ expect(
+ updater.update(
+ html: 'For you: %{email_content}',
+ css: 'h1 { color: blue; }'
+ )
+ ).to eq(true)
+ expect(SiteSetting.email_custom_template).to eq('For you: %{email_content}')
+ expect(SiteSetting.email_custom_css).to eq('h1 { color: blue; }')
+ end
+
+ it 'will not store defaults' do
+ updater.update(html: default_html, css: '')
+ expect(SiteSetting.email_custom_template).to_not be_present
+ expect(SiteSetting.email_custom_css).to_not be_present
+ end
+
+ it 'can clear settings if defaults given' do
+ SiteSetting.email_custom_template = 'For you: %{email_content}'
+ SiteSetting.email_custom_css = 'h1 { color: blue; }'
+ updater.update(html: default_html, css: '')
+ expect(SiteSetting.email_custom_template).to_not be_present
+ expect(SiteSetting.email_custom_css).to_not be_present
+ end
+
+ it 'fails if html is missing email_content' do
+ expect(updater.update(html: 'No email content', css: '')).to eq(false)
+ expect(updater.errors).to include(
+ I18n.t(
+ 'email_style.html_missing_placeholder',
+ placeholder: '%{email_content}'
+ )
+ )
+ end
+ end
+end