mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-30 18:47:51 +00:00 
			
		
		
		
	Merge branch 'develop' into fix/extend-phone-normalization-to-twilio-whatsapp
This commit is contained in:
		| @@ -178,7 +178,13 @@ class Messages::MessageBuilder | |||||||
|     email_attributes = ensure_indifferent_access(@message.content_attributes[:email] || {}) |     email_attributes = ensure_indifferent_access(@message.content_attributes[:email] || {}) | ||||||
|     normalized_content = normalize_email_body(@message.content) |     normalized_content = normalize_email_body(@message.content) | ||||||
|  |  | ||||||
|     email_attributes[:html_content] = build_html_content(normalized_content) |     # Use custom HTML content if provided, otherwise generate from message content | ||||||
|  |     email_attributes[:html_content] = if custom_email_content_provided? | ||||||
|  |                                         build_custom_html_content | ||||||
|  |                                       else | ||||||
|  |                                         build_html_content(normalized_content) | ||||||
|  |                                       end | ||||||
|  |  | ||||||
|     email_attributes[:text_content] = build_text_content(normalized_content) |     email_attributes[:text_content] = build_text_content(normalized_content) | ||||||
|     email_attributes |     email_attributes | ||||||
|   end |   end | ||||||
| @@ -213,4 +219,17 @@ class Messages::MessageBuilder | |||||||
|  |  | ||||||
|     ChatwootMarkdownRenderer.new(content).render_message.to_s |     ChatwootMarkdownRenderer.new(content).render_message.to_s | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   def custom_email_content_provided? | ||||||
|  |     @params[:email_html_content].present? | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   def build_custom_html_content | ||||||
|  |     html_content = ensure_indifferent_access(@message.content_attributes.dig(:email, :html_content) || {}) | ||||||
|  |  | ||||||
|  |     html_content[:full] = @params[:email_html_content] | ||||||
|  |     html_content[:reply] = @params[:email_html_content] | ||||||
|  |  | ||||||
|  |     html_content | ||||||
|  |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -1,9 +1,11 @@ | |||||||
| <% if @message.content %> | <% if @message.content_attributes.dig('email', 'html_content', 'reply').present? %> | ||||||
|   <%= ChatwootMarkdownRenderer.new(@message.outgoing_content).render_message %> | <%= @message.content_attributes.dig('email', 'html_content', 'reply').html_safe %> | ||||||
|  | <% elsif @message.content %> | ||||||
|  | <%= ChatwootMarkdownRenderer.new(@message.outgoing_content).render_message %> | ||||||
| <% end %> | <% end %> | ||||||
| <% if @large_attachments.present? %> | <% if @large_attachments.present? %> | ||||||
|   <p>Attachments:</p> | <p>Attachments:</p> | ||||||
|   <% @large_attachments.each do |attachment| %> | <% @large_attachments.each do |attachment| %> | ||||||
|     <p><a href="<%= attachment.file_url %>" target="_blank"><%= attachment.file.filename.to_s %></a></p> | <p><a href="<%= attachment.file_url %>" target="_blank"><%= attachment.file.filename.to_s %></a></p> | ||||||
|   <% end %> | <% end %> | ||||||
| <% end %> | <% end %> | ||||||
|   | |||||||
| @@ -179,6 +179,63 @@ describe Messages::MessageBuilder do | |||||||
|         expect(message.content_attributes[:cc_emails]).to eq ['test1@test.com', 'test2@test.com', 'test3@test.com'] |         expect(message.content_attributes[:cc_emails]).to eq ['test1@test.com', 'test2@test.com', 'test3@test.com'] | ||||||
|         expect(message.content_attributes[:bcc_emails]).to eq ['test1@test.com', 'test2@test.com', 'test3@test.com'] |         expect(message.content_attributes[:bcc_emails]).to eq ['test1@test.com', 'test2@test.com', 'test3@test.com'] | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  |       context 'when custom email content is provided' do | ||||||
|  |         before do | ||||||
|  |           account.enable_features('quoted_email_reply') | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'creates message with custom HTML email content' do | ||||||
|  |           params = ActionController::Parameters.new({ | ||||||
|  |                                                       content: 'Regular message content', | ||||||
|  |                                                       email_html_content: '<p>Custom <strong>HTML</strong> content</p>' | ||||||
|  |                                                     }) | ||||||
|  |  | ||||||
|  |           message = described_class.new(user, conversation, params).perform | ||||||
|  |  | ||||||
|  |           expect(message.content_attributes.dig('email', 'html_content', 'full')).to eq '<p>Custom <strong>HTML</strong> content</p>' | ||||||
|  |           expect(message.content_attributes.dig('email', 'html_content', 'reply')).to eq '<p>Custom <strong>HTML</strong> content</p>' | ||||||
|  |           expect(message.content_attributes.dig('email', 'text_content', 'full')).to eq 'Regular message content' | ||||||
|  |           expect(message.content_attributes.dig('email', 'text_content', 'reply')).to eq 'Regular message content' | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'does not process custom email content when quoted_email_reply feature is disabled' do | ||||||
|  |           account.disable_features('quoted_email_reply') | ||||||
|  |           params = ActionController::Parameters.new({ | ||||||
|  |                                                       content: 'Regular message content', | ||||||
|  |                                                       email_html_content: '<p>Custom HTML content</p>' | ||||||
|  |                                                     }) | ||||||
|  |  | ||||||
|  |           message = described_class.new(user, conversation, params).perform | ||||||
|  |  | ||||||
|  |           expect(message.content_attributes.dig('email', 'html_content')).to be_nil | ||||||
|  |           expect(message.content_attributes.dig('email', 'text_content')).to be_nil | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'does not process custom email content for private messages' do | ||||||
|  |           params = ActionController::Parameters.new({ | ||||||
|  |                                                       content: 'Regular message content', | ||||||
|  |                                                       email_html_content: '<p>Custom HTML content</p>', | ||||||
|  |                                                       private: true | ||||||
|  |                                                     }) | ||||||
|  |  | ||||||
|  |           message = described_class.new(user, conversation, params).perform | ||||||
|  |  | ||||||
|  |           expect(message.content_attributes.dig('email', 'html_content')).to be_nil | ||||||
|  |           expect(message.content_attributes.dig('email', 'text_content')).to be_nil | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'falls back to default behavior when no custom email content is provided' do | ||||||
|  |           params = ActionController::Parameters.new({ | ||||||
|  |                                                       content: 'Regular **markdown** content' | ||||||
|  |                                                     }) | ||||||
|  |  | ||||||
|  |           message = described_class.new(user, conversation, params).perform | ||||||
|  |  | ||||||
|  |           expect(message.content_attributes.dig('email', 'html_content', 'full')).to include('<strong>markdown</strong>') | ||||||
|  |           expect(message.content_attributes.dig('email', 'text_content', 'full')).to eq 'Regular **markdown** content' | ||||||
|  |         end | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -335,6 +335,118 @@ RSpec.describe ConversationReplyMailer do | |||||||
|           expect(mail.body.encoded).not_to match(%r{<a [^>]*>avatar\.png</a>}) |           expect(mail.body.encoded).not_to match(%r{<a [^>]*>avatar\.png</a>}) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  |       context 'with custom email content' do | ||||||
|  |         it 'uses custom HTML content when available and creates multipart email' do | ||||||
|  |           message_with_custom_content = create(:message, | ||||||
|  |                                                conversation: conversation, | ||||||
|  |                                                account: account, | ||||||
|  |                                                message_type: 'outgoing', | ||||||
|  |                                                content: 'Regular message content', | ||||||
|  |                                                content_attributes: { | ||||||
|  |                                                  email: { | ||||||
|  |                                                    html_content: { | ||||||
|  |                                                      reply: '<p>Custom <strong>HTML</strong> content for email</p>' | ||||||
|  |                                                    }, | ||||||
|  |                                                    text_content: { | ||||||
|  |                                                      reply: 'Custom text content for email' | ||||||
|  |                                                    } | ||||||
|  |                                                  } | ||||||
|  |                                                }) | ||||||
|  |  | ||||||
|  |           mail = described_class.email_reply(message_with_custom_content).deliver_now | ||||||
|  |  | ||||||
|  |           # Check HTML part contains custom HTML content | ||||||
|  |           html_part = mail.html_part || mail | ||||||
|  |           expect(html_part.body.encoded).to include('<p>Custom <strong>HTML</strong> content for email</p>') | ||||||
|  |           expect(html_part.body.encoded).not_to include('Regular message content') | ||||||
|  |  | ||||||
|  |           # Check text part contains custom text content | ||||||
|  |           text_part = mail.text_part | ||||||
|  |           if text_part | ||||||
|  |             expect(text_part.body.encoded).to include('Custom text content for email') | ||||||
|  |             expect(text_part.body.encoded).not_to include('Regular message content') | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'falls back to markdown rendering when custom HTML content is not available' do | ||||||
|  |           message_without_custom_content = create(:message, | ||||||
|  |                                                   conversation: conversation, | ||||||
|  |                                                   account: account, | ||||||
|  |                                                   message_type: 'outgoing', | ||||||
|  |                                                   content: 'Regular **markdown** content') | ||||||
|  |  | ||||||
|  |           mail = described_class.email_reply(message_without_custom_content).deliver_now | ||||||
|  |  | ||||||
|  |           html_part = mail.html_part || mail | ||||||
|  |           expect(html_part.body.encoded).to include('<strong>markdown</strong>') | ||||||
|  |           expect(html_part.body.encoded).to include('Regular') | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'handles empty custom HTML content gracefully' do | ||||||
|  |           message_with_empty_content = create(:message, | ||||||
|  |                                               conversation: conversation, | ||||||
|  |                                               account: account, | ||||||
|  |                                               message_type: 'outgoing', | ||||||
|  |                                               content: 'Regular **markdown** content', | ||||||
|  |                                               content_attributes: { | ||||||
|  |                                                 email: { | ||||||
|  |                                                   html_content: { | ||||||
|  |                                                     reply: '' | ||||||
|  |                                                   } | ||||||
|  |                                                 } | ||||||
|  |                                               }) | ||||||
|  |  | ||||||
|  |           mail = described_class.email_reply(message_with_empty_content).deliver_now | ||||||
|  |  | ||||||
|  |           html_part = mail.html_part || mail | ||||||
|  |           expect(html_part.body.encoded).to include('<strong>markdown</strong>') | ||||||
|  |           expect(html_part.body.encoded).to include('Regular') | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'handles nil custom HTML content gracefully' do | ||||||
|  |           message_with_nil_content = create(:message, | ||||||
|  |                                             conversation: conversation, | ||||||
|  |                                             account: account, | ||||||
|  |                                             message_type: 'outgoing', | ||||||
|  |                                             content: 'Regular **markdown** content', | ||||||
|  |                                             content_attributes: { | ||||||
|  |                                               email: { | ||||||
|  |                                                 html_content: { | ||||||
|  |                                                   reply: nil | ||||||
|  |                                                 } | ||||||
|  |                                               } | ||||||
|  |                                             }) | ||||||
|  |  | ||||||
|  |           mail = described_class.email_reply(message_with_nil_content).deliver_now | ||||||
|  |  | ||||||
|  |           expect(mail.body.encoded).to include('<strong>markdown</strong>') | ||||||
|  |           expect(mail.body.encoded).to include('Regular') | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         it 'uses custom text content in text part when only text is provided' do | ||||||
|  |           message_with_text_only = create(:message, | ||||||
|  |                                           conversation: conversation, | ||||||
|  |                                           account: account, | ||||||
|  |                                           message_type: 'outgoing', | ||||||
|  |                                           content: 'Regular message content', | ||||||
|  |                                           content_attributes: { | ||||||
|  |                                             email: { | ||||||
|  |                                               text_content: { | ||||||
|  |                                                 reply: 'Custom text content only' | ||||||
|  |                                               } | ||||||
|  |                                             } | ||||||
|  |                                           }) | ||||||
|  |  | ||||||
|  |           mail = described_class.email_reply(message_with_text_only).deliver_now | ||||||
|  |  | ||||||
|  |           text_part = mail.text_part | ||||||
|  |           if text_part | ||||||
|  |             expect(text_part.body.encoded).to include('Custom text content only') | ||||||
|  |             expect(text_part.body.encoded).not_to include('Regular message content') | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     context 'when smtp enabled for email channel' do |     context 'when smtp enabled for email channel' do | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Muhsin Keloth
					Muhsin Keloth