Files
Vishnu NarayananandGitHub ee6382109a feat: prevent deleted email conversations from syncing again (#14612)
# Pull Request Template

## Description

Prevent deleted email conversations from being synced into Chatwoot
again while they are still within the IMAP sync window.

When an admin explicitly deletes an email conversation, the incoming
email message IDs are stored temporarily in Redis. IMAP sync checks
these recently deleted message IDs in addition to existing message
records. Each Redis key expires automatically after two days.

This applies only to explicit conversation deletion. Individual message
deletion, inbox deletion, and account deletion keep their existing
behavior.

Fixes
[CW-7214](https://linear.app/chatwoot/issue/CW-7214/deleted-mails-in-gmail-inbox-gets-synced-again)
2026-06-15 17:06:40 +05:30

36 lines
1.5 KiB
Ruby

require 'rails_helper'
RSpec.describe Conversations::DeleteService do
let(:account) { create(:account) }
let(:user) { create(:user, account: account) }
let(:ip) { '127.0.0.1' }
let(:service) { described_class.new(conversation: conversation, user: user, ip: ip) }
context 'when deleting an email conversation' do
let(:inbox) { create(:channel_email, :imap_email, account: account).inbox }
let(:conversation) { create(:conversation, account: account, inbox: inbox) }
let!(:incoming_message) { create(:message, account: account, inbox: inbox, conversation: conversation, source_id: 'incoming@example.com') }
let(:deleted_message_tracker) { instance_double(Imap::DeletedMessageTracker, record: true) }
before do
allow(Imap::DeletedMessageTracker).to receive(:new).with(inbox: inbox).and_return(deleted_message_tracker)
end
it 'records incoming message source ids and enqueues the deletion job' do
expect { service.perform }.to have_enqueued_job(DeleteObjectJob).with(conversation, user, ip)
expect(deleted_message_tracker).to have_received(:record).with([incoming_message.source_id])
end
end
context 'when deleting a non-email conversation' do
let(:conversation) { create(:conversation, account: account) }
it 'enqueues the deletion job without recording message source ids' do
expect(Imap::DeletedMessageTracker).not_to receive(:new)
expect { service.perform }.to have_enqueued_job(DeleteObjectJob).with(conversation, user, ip)
end
end
end