diff --git a/app/models/message.rb b/app/models/message.rb index 5f98493d0..2964d9286 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -153,15 +153,6 @@ class Message < ApplicationRecord merge_sender_attributes(data) end - def search_data - data = attributes.symbolize_keys - data[:conversation] = conversation.present? ? conversation_push_event_data : nil - data[:attachments] = attachments.map(&:push_event_data) if attachments.present? - data[:sender] = sender.push_event_data if sender - data[:inbox] = inbox - data - end - def conversation_push_event_data { assignee_id: conversation.assignee_id, @@ -259,6 +250,10 @@ class Message < ApplicationRecord true end + def search_data + Messages::SearchDataPresenter.new(self).search_data + end + private def prevent_message_flooding diff --git a/app/presenters/messages/search_data_presenter.rb b/app/presenters/messages/search_data_presenter.rb new file mode 100644 index 000000000..dba0b9499 --- /dev/null +++ b/app/presenters/messages/search_data_presenter.rb @@ -0,0 +1,58 @@ +class Messages::SearchDataPresenter < SimpleDelegator + def search_data + { + **searchable_content, + **message_attributes, + **search_additional_data, + conversation: conversation_data + } + end + + private + + def searchable_content + { + content: content, + attachments: attachment_data, + content_attributes: content_attributes_data + } + end + + def message_attributes + { + account_id: account_id, + inbox_id: inbox_id, + conversation_id: conversation_id, + message_type: message_type, + private: private, + created_at: created_at, + source_id: source_id, + sender_id: sender_id, + sender_type: sender_type + } + end + + def attachment_data + attachments.filter_map do |a| + { transcribed_text: a.meta&.dig('transcribed_text') } + end.presence + end + + def content_attributes_data + email_subject = content_attributes.dig(:email, :subject) + return {} if email_subject.blank? + + { email: { subject: email_subject } } + end + + def conversation_data + { id: conversation.display_id } + end + + def search_additional_data + { + campaign_id: additional_attributes&.dig('campaign_id'), + automation_rule_id: content_attributes&.dig('automation_rule_id') + } + end +end diff --git a/spec/presenters/messages/search_data_presenter_spec.rb b/spec/presenters/messages/search_data_presenter_spec.rb new file mode 100644 index 000000000..a5062086a --- /dev/null +++ b/spec/presenters/messages/search_data_presenter_spec.rb @@ -0,0 +1,78 @@ +require 'rails_helper' + +RSpec.describe Messages::SearchDataPresenter do + let(:presenter) { described_class.new(message) } + let(:account) { create(:account) } + let(:inbox) { create(:inbox, account: account) } + let(:contact) { create(:contact, account: account) } + let(:conversation) { create(:conversation, account: account, inbox: inbox, contact: contact) } + let(:message) { create(:message, account: account, inbox: inbox, conversation: conversation, sender: contact) } + + describe '#search_data' do + let(:expected_data) do + { + content: message.content, + account_id: message.account_id, + inbox_id: message.inbox_id, + conversation_id: message.conversation_id, + message_type: message.message_type, + private: message.private, + created_at: message.created_at, + source_id: message.source_id, + sender_id: message.sender_id, + sender_type: message.sender_type, + conversation: { + id: conversation.display_id + } + } + end + + it 'returns search index payload with core fields' do + expect(presenter.search_data).to include(expected_data) + end + + context 'with attachments' do + before do + attachment = message.attachments.new(account_id: message.account_id, file_type: :image) + attachment.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png') + attachment.meta = { 'transcribed_text' => 'Hello world' } + end + + it 'includes attachment transcriptions' do + attachments_data = presenter.search_data[:attachments] + expect(attachments_data).to be_an(Array) + expect(attachments_data.first).to include(transcribed_text: 'Hello world') + end + end + + context 'with email content attributes' do + before do + message.update( + content_attributes: { email: { subject: 'Test Subject' } } + ) + end + + it 'includes email subject' do + content_attrs = presenter.search_data[:content_attributes] + expect(content_attrs[:email][:subject]).to eq('Test Subject') + end + end + + context 'with campaign and automation data' do + before do + message.update( + additional_attributes: { 'campaign_id' => '123' }, + content_attributes: { 'automation_rule_id' => '456' } + ) + end + + it 'includes campaign_id' do + expect(presenter.search_data[:campaign_id]).to eq('123') + end + + it 'includes automation_rule_id' do + expect(presenter.search_data[:automation_rule_id]).to eq('456') + end + end + end +end