mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 04:48:33 +08:00
## Summary Correctly emit `URL` properties in ICS export without RFC 5545 TEXT escaping by introducing `IcalEncoder.encode_uri`, which decodes HTML entities, strips CR/LF characters, and leaves valid URI delimiters such as commas and semicolons intact. This change is applied to both the Discourse Events calendar feed and the user bookmarks ICS feed; all textual properties (`SUMMARY`, `LOCATION`, `DESCRIPTION`) continue to use the existing TEXT encoder. ## Source - Patch Triage: https://patch.discourse.org/patch-triage/1547 Co-authored-by: discourse-patch-triage <272280883+discourse-patch-triage[bot]@users.noreply.github.com>
78 lines
2.6 KiB
Ruby
Vendored
78 lines
2.6 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe IcalEncoder do
|
|
describe ".encode" do
|
|
it "returns empty string for nil" do
|
|
expect(described_class.encode(nil)).to eq("")
|
|
end
|
|
|
|
it "returns empty string for blank string" do
|
|
expect(described_class.encode("")).to eq("")
|
|
end
|
|
|
|
it "passes through plain text" do
|
|
expect(described_class.encode("Hello World")).to eq("Hello World")
|
|
end
|
|
|
|
it "strips HTML tags" do
|
|
expect(described_class.encode("<b>Bold</b> and <i>italic</i>")).to eq("Bold and italic")
|
|
end
|
|
|
|
it "decodes HTML entities" do
|
|
expect(described_class.encode("Tom & Jerry")).to eq("Tom & Jerry")
|
|
expect(described_class.encode("1 < 2 > 0")).to eq("1 < 2 > 0")
|
|
expect(described_class.encode(""quoted"")).to eq('"quoted"')
|
|
end
|
|
|
|
it "strips HTML tags then decodes entities" do
|
|
expect(
|
|
described_class.encode("<a href="https://example.com">link</a>"),
|
|
).to eq('<a href="https://example.com">link</a>')
|
|
end
|
|
|
|
it "escapes commas" do
|
|
expect(described_class.encode("New York, NY")).to eq("New York\\, NY")
|
|
end
|
|
|
|
it "escapes semicolons" do
|
|
expect(described_class.encode("one; two")).to eq("one\\; two")
|
|
end
|
|
|
|
it "escapes backslashes" do
|
|
expect(described_class.encode("path\\to\\file")).to eq("path\\\\to\\\\file")
|
|
end
|
|
|
|
it "escapes newlines" do
|
|
expect(described_class.encode("line one\nline two")).to eq("line one\\nline two")
|
|
expect(described_class.encode("line one\r\nline two")).to eq("line one\\nline two")
|
|
end
|
|
|
|
it "returns html_safe strings to prevent double-escaping in ERB templates" do
|
|
expect(described_class.encode("Tom & Jerry")).to be_html_safe
|
|
end
|
|
|
|
it "handles complex HTML content from Discourse posts" do
|
|
html =
|
|
'<a class="lightbox" href="https://example.com/image.jpg">[Image]</a> \nSome text with & special chars'
|
|
result = described_class.encode(html)
|
|
expect(result).not_to include("<")
|
|
expect(result).not_to include("&")
|
|
expect(result).not_to include(""")
|
|
expect(result).to include("& special chars")
|
|
end
|
|
end
|
|
|
|
describe ".encode_uri" do
|
|
it "preserves URI delimiters and removes newlines" do
|
|
result =
|
|
described_class.encode_uri(
|
|
"https://example.com/events?tags=one,two;sort=asc&name=Tom\r\nATTACH:https://bad.example",
|
|
)
|
|
|
|
expect(result).to eq(
|
|
"https://example.com/events?tags=one,two;sort=asc&name=TomATTACH:https://bad.example",
|
|
)
|
|
expect(result).to be_html_safe
|
|
end
|
|
end
|
|
end
|