diff --git a/app/helpers/message_format_helper.rb b/app/helpers/message_format_helper.rb index 2c50fd609..8b271e3a3 100644 --- a/app/helpers/message_format_helper.rb +++ b/app/helpers/message_format_helper.rb @@ -1,9 +1,13 @@ module MessageFormatHelper - include RegexHelper - def transform_user_mention_content(message_content) # attachment message without content, message_content is nil - message_content.presence ? message_content.gsub(MENTION_REGEX, '\1') : '' + return '' unless message_content.presence + + # Use CommonMarker to convert markdown to plain text for notifications + # This handles all markdown formatting (links, bold, italic, etc.) not just mentions + # Converts: [@👍 customer support](mention://team/1/%F0%9F%91%8D%20customer%20support) + # To: @👍 customer support + CommonMarker.render_doc(message_content).to_plaintext.strip end def render_message_content(message_content) diff --git a/lib/regex_helper.rb b/lib/regex_helper.rb index 31916da7d..5e4c2abf0 100644 --- a/lib/regex_helper.rb +++ b/lib/regex_helper.rb @@ -5,7 +5,13 @@ module RegexHelper # valid unicode letter, unicode number, underscore, hyphen # shouldn't start with a underscore or hyphen UNICODE_CHARACTER_NUMBER_HYPHEN_UNDERSCORE = Regexp.new('\A[\p{L}\p{N}]+[\p{L}\p{N}_-]+\Z') - MENTION_REGEX = Regexp.new('\[(@[\w_. ]+)\]\(mention://(?:user|team)/\d+/(.*?)+\)') + # Regex to match mention markdown links and extract display names + # Matches: [@display name](mention://user|team/id/url_encoded_name) + # Captures: 1) @display name (including emojis), 2) url_encoded_name + # Uses [^]]+ to match any characters except ] in display name to support emojis + # NOTE: Still used by Slack integration (lib/integrations/slack/send_on_slack_service.rb) + # while notifications use CommonMarker for better markdown processing + MENTION_REGEX = Regexp.new('\[(@[^]]+)\]\(mention://(?:user|team)/\d+/([^)]+)\)') TWILIO_CHANNEL_SMS_REGEX = Regexp.new('^\+\d{1,15}\z') TWILIO_CHANNEL_WHATSAPP_REGEX = Regexp.new('^whatsapp:\+\d{1,15}\z') diff --git a/spec/helpers/message_format_helper_spec.rb b/spec/helpers/message_format_helper_spec.rb index c5bafe67d..fe1335b8f 100644 --- a/spec/helpers/message_format_helper_spec.rb +++ b/spec/helpers/message_format_helper_spec.rb @@ -3,9 +3,37 @@ require 'rails_helper' describe MessageFormatHelper do describe '#transform_user_mention_content' do context 'when transform_user_mention_content called' do - it 'return transormed text correctly' do + it 'return transformed text correctly' do expect(helper.transform_user_mention_content('[@john](mention://user/1/John%20K), check this ticket')).to eq '@john, check this ticket' end + + it 'handles emoji in display names correctly' do + content = '[@👍 customer support](mention://team/1/%F0%9F%91%8D%20customer%20support), please help' + expected = '@👍 customer support, please help' + expect(helper.transform_user_mention_content(content)).to eq expected + end + + it 'handles multiple mentions with emojis and spaces' do + content = 'Hey [@John Doe](mention://user/1/John%20Doe) and [@🚀 Dev Team](mention://team/2/%F0%9F%9A%80%20Dev%20Team)' + expected = 'Hey @John Doe and @🚀 Dev Team' + expect(helper.transform_user_mention_content(content)).to eq expected + end + + it 'handles emoji-only team names' do + expect(helper.transform_user_mention_content('[@🔥](mention://team/3/%F0%9F%94%A5) urgent')).to eq '@🔥 urgent' + end + + it 'handles special characters in names' do + expect(helper.transform_user_mention_content('[@user@domain.com](mention://user/4/user%40domain.com) check')).to eq '@user@domain.com check' + end + + it 'returns empty string for nil content' do + expect(helper.transform_user_mention_content(nil)).to eq '' + end + + it 'returns empty string for empty content' do + expect(helper.transform_user_mention_content('')).to eq '' + end end end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 07e7e3fe2..172389fe4 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -128,6 +128,39 @@ has been assigned to you" expect(notification.push_message_body).to eq "#{message.sender.name}: Hey @John Peter please check this?" end + it 'returns appropriate body suited for the notification type conversation_mention if username contains emoji' do + conversation = create(:conversation) + content = 'Hey [@👍 customer support](mention://team/1/%F0%9F%91%8D%20customer%20support) please check this?' + message = create(:message, sender: create(:user), content: content, conversation: conversation) + notification = create(:notification, notification_type: 'conversation_mention', primary_actor: conversation, secondary_actor: message) + expect(notification.push_message_body).to eq "#{message.sender.name}: Hey @👍 customer support please check this?" + end + + it 'returns appropriate body suited for the notification type conversation_mention if team name contains emoji and spaces' do + conversation = create(:conversation) + content = 'Please check [@🚀 Development Team](mention://team/2/%F0%9F%9A%80%20Development%20Team)' + message = create(:message, sender: create(:user), content: content, conversation: conversation) + notification = create(:notification, notification_type: 'conversation_mention', primary_actor: conversation, secondary_actor: message) + expect(notification.push_message_body).to eq "#{message.sender.name}: Please check @🚀 Development Team" + end + + it 'returns appropriate body suited for the notification type conversation_mention with mixed emoji and regular mentions' do + conversation = create(:conversation) + content = 'Hey [@John Doe](mention://user/1/John%20Doe) and ' \ + '[@👍 customer support](mention://team/1/%F0%9F%91%8D%20customer%20support) please review' + message = create(:message, sender: create(:user), content: content, conversation: conversation) + notification = create(:notification, notification_type: 'conversation_mention', primary_actor: conversation, secondary_actor: message) + expect(notification.push_message_body).to eq "#{message.sender.name}: Hey @John Doe and @👍 customer support please review" + end + + it 'returns appropriate body suited for the notification type conversation_mention with special characters in names' do + conversation = create(:conversation) + content = 'Please review [@user@domain.com](mention://user/4/user%40domain.com)' + message = create(:message, sender: create(:user), content: content, conversation: conversation) + notification = create(:notification, notification_type: 'conversation_mention', primary_actor: conversation, secondary_actor: message) + expect(notification.push_message_body).to eq "#{message.sender.name}: Please review @user@domain.com" + end + it 'calls remove duplicate notification job' do allow(Notification::RemoveDuplicateNotificationJob).to receive(:perform_later) notification = create(:notification, notification_type: 'conversation_mention')