From 6e726d436f51924083829bfe14ffa0a8f7f44985 Mon Sep 17 00:00:00 2001 From: Thomas Kalka Date: Sat, 30 Nov 2024 14:51:02 +0100 Subject: [PATCH] FIX: deduplicate css in mails (#30003) Feature: Resolve final styles in email notifications Context - https://meta.discourse.org/t/resolve-final-styles-in-email-notifications/310219 --- lib/email/styles.rb | 19 +++++++++++++++++++ spec/lib/email/styles_spec.rb | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/lib/email/styles.rb b/lib/email/styles.rb index 48b051cd88a..c378d0d7a05 100644 --- a/lib/email/styles.rb +++ b/lib/email/styles.rb @@ -374,12 +374,31 @@ module Email end end + def deduplicate_style(style) + styles = {} + + style + .split(";") + .select(&:present?) + .map { _1.split(":", 2).map(&:strip) } + .each { |k, v| styles[k] = v if k.present? && v.present? } + + styles.map { |k, v| "#{k}:#{v}" }.join(";") + end + + def deduplicate_styles + @fragment + .css("[style]") + .each { |element| element["style"] = deduplicate_style element["style"] } + end + def to_html # needs to be before class + id strip because we need to style redacted # media and also not double-redact already redacted from lower levels replace_secure_uploads_urls if SiteSetting.secure_uploads? strip_classes_and_ids replace_relative_urls + deduplicate_styles @fragment.to_html end diff --git a/spec/lib/email/styles_spec.rb b/spec/lib/email/styles_spec.rb index e7822da2cf9..4135fdb9a37 100644 --- a/spec/lib/email/styles_spec.rb +++ b/spec/lib/email/styles_spec.rb @@ -168,6 +168,24 @@ RSpec.describe Email::Styles do end end + describe "deduplicate styles" do + it "removes double definitions" do + frag = "hello" + styler = Email::Styles.new(frag) + styled = styler.to_html + styled = Nokogiri::HTML5.fragment(styled) + expect(styled.at("test")["style"]).to eq("color:red") + end + it "handles whitespace correctly" do + frag = + "hello" + styler = Email::Styles.new(frag) + styled = styler.to_html + styled = Nokogiri::HTML5.fragment(styled) + expect(styled.at("test")["style"]).to eq("color:red;background:yellow") + end + end + describe "dark mode emails" do it "adds dark_mode_styles when site setting active" do frag = html_fragment('
test
')