diff --git a/app/controllers/public/api/v1/portals/articles_controller.rb b/app/controllers/public/api/v1/portals/articles_controller.rb index b4739e0d1..1f8be3ad7 100644 --- a/app/controllers/public/api/v1/portals/articles_controller.rb +++ b/app/controllers/public/api/v1/portals/articles_controller.rb @@ -43,8 +43,6 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::B end def render_article_content(content) - # rubocop:disable Rails/OutputSafety - CommonMarker.render_html(content).html_safe - # rubocop:enable Rails/OutputSafety + ChatwootMarkdownRenderer.new(content).render_article end end diff --git a/app/helpers/message_format_helper.rb b/app/helpers/message_format_helper.rb index 1e89c56c1..2c50fd609 100644 --- a/app/helpers/message_format_helper.rb +++ b/app/helpers/message_format_helper.rb @@ -7,8 +7,6 @@ module MessageFormatHelper end def render_message_content(message_content) - # rubocop:disable Rails/OutputSafety - CommonMarker.render_html(message_content).html_safe - # rubocop:enable Rails/OutputSafety + ChatwootMarkdownRenderer.new(message_content).render_message end end diff --git a/app/views/mailers/conversation_reply_mailer/conversation_transcript.html.erb b/app/views/mailers/conversation_reply_mailer/conversation_transcript.html.erb index a372a1c43..9bcd231f9 100644 --- a/app/views/mailers/conversation_reply_mailer/conversation_transcript.html.erb +++ b/app/views/mailers/conversation_reply_mailer/conversation_transcript.html.erb @@ -7,7 +7,7 @@
Click here to rate the conversation.
<% elsif message.content.present? %> - <%= CommonMarker.render_html(message.content).html_safe %> + <%= ChatwootMarkdownRenderer.new(message.content).render_message %> <% end %> <% if message.attachments.count.positive? %>diff --git a/app/views/mailers/conversation_reply_mailer/reply_without_summary.html.erb b/app/views/mailers/conversation_reply_mailer/reply_without_summary.html.erb index 42c7ed6ab..3c9b8034a 100644 --- a/app/views/mailers/conversation_reply_mailer/reply_without_summary.html.erb +++ b/app/views/mailers/conversation_reply_mailer/reply_without_summary.html.erb @@ -1,7 +1,7 @@ <% @messages.each do |message| %>
<% if message.content %>
- <%= CommonMarker.render_html(message.content).html_safe %>
+ <%= ChatwootMarkdownRenderer.new(message.content).render_message %>
<% end %>
<% if message.attachments %>
<% message.attachments.each do |attachment| %>
diff --git a/lib/chatwoot_markdown_renderer.rb b/lib/chatwoot_markdown_renderer.rb
new file mode 100644
index 000000000..5fa8998b3
--- /dev/null
+++ b/lib/chatwoot_markdown_renderer.rb
@@ -0,0 +1,26 @@
+class ChatwootMarkdownRenderer
+ def initialize(content)
+ @content = content
+ end
+
+ def render_message
+ html = CommonMarker.render_html(@content)
+ render_as_html_safe(html)
+ end
+
+ def render_article
+ superscript_renderer = SuperscriptRenderer.new
+ doc = CommonMarker.render_doc(@content, :DEFAULT)
+ html = superscript_renderer.render(doc)
+
+ render_as_html_safe(html)
+ end
+
+ private
+
+ def render_as_html_safe(html)
+ # rubocop:disable Rails/OutputSafety
+ html.html_safe
+ # rubocop:enable Rails/OutputSafety
+ end
+end
diff --git a/lib/superscript_renderer.rb b/lib/superscript_renderer.rb
new file mode 100644
index 000000000..485ffd1f0
--- /dev/null
+++ b/lib/superscript_renderer.rb
@@ -0,0 +1,28 @@
+class SuperscriptRenderer < CommonMarker::HtmlRenderer
+ def text(node)
+ content = node.string_content
+
+ # Check for presence of '^' in the content
+ if content.include?('^')
+ # Split the text and insert tags where necessary
+ split_content = parse_sup(content)
+ # Output the transformed content
+ out(split_content.join)
+ else
+ # Output the original content
+ out(escape_html(content))
+ end
+ end
+
+ private
+
+ def parse_sup(content)
+ content.split(/(\^[^\^]+\^)/).map do |segment|
+ if segment.start_with?('^') && segment.end_with?('^')
+ "#{escape_html(segment[1..-2])}"
+ else
+ escape_html(segment)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/public/api/v1/portals/articles_controller_spec.rb b/spec/controllers/public/api/v1/portals/articles_controller_spec.rb
index 079a85bc1..86651fee1 100644
--- a/spec/controllers/public/api/v1/portals/articles_controller_spec.rb
+++ b/spec/controllers/public/api/v1/portals/articles_controller_spec.rb
@@ -6,7 +6,10 @@ RSpec.describe 'Public Articles API', type: :request do
let!(:portal) { create(:portal, slug: 'test-portal', config: { allowed_locales: %w[en es] }, custom_domain: 'www.example.com') }
let!(:category) { create(:category, name: 'category', portal: portal, account_id: account.id, locale: 'en', slug: 'category_slug') }
let!(:category_2) { create(:category, name: 'category', portal: portal, account_id: account.id, locale: 'es', slug: 'category_slug') }
- let!(:article) { create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id) }
+ let!(:article) do
+ create(:article, category: category, portal: portal, account_id: account.id, author_id: agent.id,
+ content: 'This is a *test* content with ^markdown^')
+ end
before do
ENV['HELPCENTER_URL'] = ENV.fetch('FRONTEND_URL', nil)
@@ -43,6 +46,7 @@ RSpec.describe 'Public Articles API', type: :request do
it 'Fetch article with the id' do
get "/hc/#{portal.slug}/articles/#{article.slug}"
expect(response).to have_http_status(:success)
+ expect(response.body).to include(ChatwootMarkdownRenderer.new(article.content).render_article)
expect(article.reload.views).to eq 1
end
diff --git a/spec/lib/chatwoot_markdown_renderer_spec.rb b/spec/lib/chatwoot_markdown_renderer_spec.rb
new file mode 100644
index 000000000..74e6777c2
--- /dev/null
+++ b/spec/lib/chatwoot_markdown_renderer_spec.rb
@@ -0,0 +1,44 @@
+require 'rails_helper'
+
+RSpec.describe ChatwootMarkdownRenderer do
+ let(:markdown_content) { 'This is a *test* content with ^markdown^' }
+ let(:doc) { instance_double(CommonMarker::Node) }
+ let(:renderer) { described_class.new(markdown_content) }
+ let(:superscript_renderer) { instance_double(SuperscriptRenderer) }
+ let(:html_content) { ' This is a test content with markdown This is a test content with ^markdown^ This is an example with ^broken superscript. This is an example with broken^ superscript. This is an example with broken superscript^.