feat: update message status and last seen timestamps (#52)

* feat: update message status and last seen timestamps

* test: enhance message status and content update handling in Baileys service tests

* feat: update last seen timestamps in conversation on message update

* chore: simplify status update condition for incoming messages

* feat: optimize last seen timestamp updates in conversation

* chore: improve last seen spec

* feat: update message content handling in content update scenario
This commit is contained in:
Cayo P. R. Oliveira 2025-05-29 09:55:39 -03:00 committed by GitHub
parent 59675caf68
commit c3e0e70490
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 38 additions and 15 deletions

View File

@ -285,6 +285,7 @@ class Whatsapp::IncomingMessageBaileysService < Whatsapp::IncomingMessageBaseSer
def update_status def update_status
status = status_mapper status = status_mapper
update_last_seen_at if incoming? && status == 'read'
@message.update!(status: status) if status.present? && status_transition_allowed?(status) @message.update!(status: status) if status.present? && status_transition_allowed?(status)
end end
@ -314,6 +315,14 @@ class Whatsapp::IncomingMessageBaileysService < Whatsapp::IncomingMessageBaseSer
end end
end end
def update_last_seen_at
conversation = @message.conversation
to_update = { agent_last_seen_at: Time.current }
to_update[:assignee_last_seen_at] = Time.current if conversation.assignee_id.present?
conversation.update_columns(to_update) # rubocop:disable Rails/SkipsModelValidations
end
def status_transition_allowed?(new_status) def status_transition_allowed?(new_status)
return false if @message.status == 'read' return false if @message.status == 'read'
return false if @message.status == 'delivered' && new_status == 'sent' return false if @message.status == 'delivered' && new_status == 'sent'

View File

@ -567,10 +567,13 @@ describe Whatsapp::IncomingMessageBaileysService do
end end
context 'when processing messages.update event' do context 'when processing messages.update event' do
let!(:message) { create(:message, source_id: 'msg_123', status: 'sent') } let(:conversation) do
let(:update_payload) do contact = create(:contact, account: inbox.account)
{ key: { id: 'msg_123' }, update: { status: 3 } } contact_inbox = create(:contact_inbox, inbox: inbox, contact: contact)
create(:conversation, inbox: inbox, contact_inbox: contact_inbox, assignee_id: contact.id)
end end
let!(:message) { create(:message, inbox: inbox, conversation: conversation, source_id: 'msg_123', status: 'sent') }
let(:update_payload) { { key: { id: 'msg_123' }, update: { status: 3 } } }
let(:params) do let(:params) do
{ {
webhookVerifyToken: webhook_verify_token, webhookVerifyToken: webhook_verify_token,
@ -589,36 +592,34 @@ describe Whatsapp::IncomingMessageBaileysService do
end end
end end
context 'when message is found' do context 'when is a status update' do
it 'updates the message status' do it 'updates the message status' do
described_class.new(inbox: inbox, params: params).perform described_class.new(inbox: inbox, params: params).perform
expect(message.reload.status).to eq('delivered') expect(message.reload.status).to eq('delivered')
end end
it 'updates the message content' do it 'updates conversation agent_last_seen_at and assignee_last_seen_at' do
update_payload[:update] = { message: { editedMessage: { message: { conversation: 'New message content' } } } } freeze_time
update_payload[:key][:fromMe] = false
update_payload[:update][:status] = 4
conversation.update!(agent_last_seen_at: 1.day.ago, assignee_last_seen_at: 1.day.ago)
described_class.new(inbox: inbox, params: params).perform described_class.new(inbox: inbox, params: params).perform
original_content = message.content expect(conversation.reload.agent_last_seen_at).to eq(Time.current)
expect(message.reload.content).to eq('New message content') expect(conversation.assignee_last_seen_at).to eq(Time.current)
expect(message.is_edited).to be(true)
expect(message.previous_content).to eq(original_content)
end end
end
context 'when the status transition is not allowed (message already read)' do it "does not downgrade a 'read' message to delivered" do
it 'does not update the status' do
message.update!(status: 'read') message.update!(status: 'read')
described_class.new(inbox: inbox, params: params).perform described_class.new(inbox: inbox, params: params).perform
expect(message.reload.status).to eq('read') expect(message.reload.status).to eq('read')
end end
end
context 'when update unsupported status' do
it 'logs warning for unsupported played status' do it 'logs warning for unsupported played status' do
update_payload[:update][:status] = 5 update_payload[:update][:status] = 5
@ -639,6 +640,19 @@ describe Whatsapp::IncomingMessageBaileysService do
expect(Rails.logger).to have_received(:warn) expect(Rails.logger).to have_received(:warn)
end end
end end
context 'when is a content update' do
it 'updates the message content' do
original_content = message.content
update_payload[:update] = { message: { editedMessage: { message: { conversation: 'New message content' } } } }
described_class.new(inbox: inbox, params: params).perform
expect(message.reload.content).to eq('New message content')
expect(message.is_edited).to be(true)
expect(message.previous_content).to eq(original_content)
end
end
end end
end end