From 36b6c0cb9caad8240e6190c6bc3c8ba59296bdb5 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 3 Nov 2023 02:21:54 +0530 Subject: [PATCH] feat: support image height in markdown rendering of messages (#8177) - This PR adds BaseMarkdownRenderer, it takes all the required attributes from the image node, parses the cw_image_height query and renders it. --- lib/base_markdown_renderer.rb | 39 +++++++++++++++++++++ lib/chatwoot_markdown_renderer.rb | 4 ++- spec/lib/base_markdown_renderer_spec.rb | 33 +++++++++++++++++ spec/lib/chatwoot_markdown_renderer_spec.rb | 3 ++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 lib/base_markdown_renderer.rb create mode 100644 spec/lib/base_markdown_renderer_spec.rb diff --git a/lib/base_markdown_renderer.rb b/lib/base_markdown_renderer.rb new file mode 100644 index 000000000..df49918b3 --- /dev/null +++ b/lib/base_markdown_renderer.rb @@ -0,0 +1,39 @@ +class BaseMarkdownRenderer < CommonMarker::HtmlRenderer + def image(node) + src, title = extract_img_attributes(node) + height = extract_image_height(src) + + render_img_tag(src, title, height) + end + + private + + def extract_img_attributes(node) + [ + escape_href(node.url), + escape_html(node.title) + ] + end + + def extract_image_height(src) + query_params = parse_query_params(src) + query_params['cw_image_height']&.first + end + + def parse_query_params(url) + parsed_url = URI.parse(url) + CGI.parse(parsed_url.query || '') + rescue URI::InvalidURIError + {} + end + + def render_img_tag(src, title, height = nil) + title_attribute = title.present? ? " title=\"#{title}\"" : '' + height_attribute = height ? " height=\"#{height}\" width=\"auto\"" : '' + + plain do + # plain ensures that the content is not wrapped in a paragraph tag + out("") + end + end +end diff --git a/lib/chatwoot_markdown_renderer.rb b/lib/chatwoot_markdown_renderer.rb index 2d837f8b7..73b52e1d6 100644 --- a/lib/chatwoot_markdown_renderer.rb +++ b/lib/chatwoot_markdown_renderer.rb @@ -4,7 +4,9 @@ class ChatwootMarkdownRenderer end def render_message - html = CommonMarker.render_html(@content) + markdown_renderer = BaseMarkdownRenderer.new + doc = CommonMarker.render_doc(@content, :DEFAULT) + html = markdown_renderer.render(doc) render_as_html_safe(html) end diff --git a/spec/lib/base_markdown_renderer_spec.rb b/spec/lib/base_markdown_renderer_spec.rb new file mode 100644 index 000000000..262e78daf --- /dev/null +++ b/spec/lib/base_markdown_renderer_spec.rb @@ -0,0 +1,33 @@ +require 'rails_helper' + +describe BaseMarkdownRenderer do + let(:renderer) { described_class.new } + + def render_markdown(markdown) + doc = CommonMarker.render_doc(markdown, :DEFAULT) + renderer.render(doc) + end + + describe '#image' do + context 'when image has a height' do + it 'renders the img tag with the correct attributes' do + markdown = '![Sample Title](https://example.com/image.jpg?cw_image_height=100)' + expect(render_markdown(markdown)).to include('') + end + end + + context 'when image does not have a height' do + it 'renders the img tag without the height attribute' do + markdown = '![Sample Title](https://example.com/image.jpg)' + expect(render_markdown(markdown)).to include('') + end + end + + context 'when image has an invalid URL' do + it 'renders the img tag without crashing' do + markdown = '![Sample Title](invalid_url)' + expect { render_markdown(markdown) }.not_to raise_error + end + end + end +end diff --git a/spec/lib/chatwoot_markdown_renderer_spec.rb b/spec/lib/chatwoot_markdown_renderer_spec.rb index dbe9b8245..a3109a7f2 100644 --- a/spec/lib/chatwoot_markdown_renderer_spec.rb +++ b/spec/lib/chatwoot_markdown_renderer_spec.rb @@ -5,6 +5,7 @@ RSpec.describe ChatwootMarkdownRenderer do let(:doc) { instance_double(CommonMarker::Node) } let(:renderer) { described_class.new(markdown_content) } let(:markdown_renderer) { instance_double(CustomMarkdownRenderer) } + let(:base_markdown_renderer) { instance_double(BaseMarkdownRenderer) } let(:html_content) { '

This is a test content with markdown

' } before do @@ -31,6 +32,8 @@ RSpec.describe ChatwootMarkdownRenderer do before do allow(CommonMarker).to receive(:render_html).with(markdown_content).and_return(message_html_content) + allow(BaseMarkdownRenderer).to receive(:new).and_return(base_markdown_renderer) + allow(base_markdown_renderer).to receive(:render).with(doc).and_return(message_html_content) end it 'renders the markdown message to html' do