mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 21:04:33 +08:00
FIX: IMAP sync email update uniqueness across groups and minor improvements (#10332)
Adds a imap_group_id column to IncomingEmail to deal with an issue where we were trying to update emails in the mailbox, calling IncomingEmail.where(imap_sync: true). However UID and UIDVALIDITY could be the same across accounts. So if group A used IMAP details for Gmail account A, and group B used IMAP details for Gmail account B, and both tried to sync changes to an email with UID of 3 (e.g. changing Labels), one account could affect the other. This even applied to Archiving! Also in this PR: * Fix error occurring if we do a uid_fetch and no emails are returned * Allow for creating labels within the target mailbox (previously we would not do this, only use existing labels) * Improve consistency for log messages * Add specs for generic IMAP provider (Gmail specs still to come) * Add custom archiving support for Gmail * Only use Message-ID for uniqueness of IncomingEmail if it was generated by us * Various refactors and improvements
This commit is contained in:
@ -84,6 +84,7 @@ describe Imap::Sync do
|
||||
expect(incoming_email.imap_uid_validity).to eq(1)
|
||||
expect(incoming_email.imap_uid).to eq(100)
|
||||
expect(incoming_email.imap_sync).to eq(false)
|
||||
expect(incoming_email.imap_group_id).to eq(group.id)
|
||||
end
|
||||
|
||||
it 'does not duplicate topics' do
|
||||
@ -98,19 +99,39 @@ describe Imap::Sync do
|
||||
.and change { IncomingEmail.count }.by(0)
|
||||
end
|
||||
|
||||
it 'does not duplicate incoming emails' do
|
||||
it 'creates a new incoming email if the message ID does not match the receiver post id regex' do
|
||||
incoming_email = Fabricate(:incoming_email, message_id: message_id)
|
||||
|
||||
expect { sync_handler.process }
|
||||
.to change { Topic.count }.by(0)
|
||||
.and change { Post.where(post_type: Post.types[:regular]).count }.by(0)
|
||||
.and change { IncomingEmail.count }.by(0)
|
||||
.to change { Topic.count }.by(1)
|
||||
.and change { Post.where(post_type: Post.types[:regular]).count }.by(1)
|
||||
.and change { IncomingEmail.count }.by(1)
|
||||
|
||||
incoming_email.reload
|
||||
expect(incoming_email.message_id).to eq(message_id)
|
||||
expect(incoming_email.imap_uid_validity).to eq(1)
|
||||
expect(incoming_email.imap_uid).to eq(100)
|
||||
expect(incoming_email.imap_sync).to eq(false)
|
||||
last_incoming = IncomingEmail.where(message_id: message_id).last
|
||||
expect(last_incoming.message_id).to eq(message_id)
|
||||
expect(last_incoming.imap_uid_validity).to eq(1)
|
||||
expect(last_incoming.imap_uid).to eq(100)
|
||||
expect(last_incoming.imap_sync).to eq(false)
|
||||
expect(last_incoming.imap_group_id).to eq(group.id)
|
||||
end
|
||||
|
||||
context "when the message id matches the receiver post id regex" do
|
||||
let(:message_id) { "topic/999/324@test.localhost" }
|
||||
it 'does not duplicate incoming email' do
|
||||
incoming_email = Fabricate(:incoming_email, message_id: message_id)
|
||||
|
||||
expect { sync_handler.process }
|
||||
.to change { Topic.count }.by(0)
|
||||
.and change { Post.where(post_type: Post.types[:regular]).count }.by(0)
|
||||
.and change { IncomingEmail.count }.by(0)
|
||||
|
||||
incoming_email.reload
|
||||
expect(incoming_email.message_id).to eq(message_id)
|
||||
expect(incoming_email.imap_uid_validity).to eq(1)
|
||||
expect(incoming_email.imap_uid).to eq(100)
|
||||
expect(incoming_email.imap_sync).to eq(false)
|
||||
expect(incoming_email.imap_group_id).to eq(group.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -165,7 +186,7 @@ describe Imap::Sync do
|
||||
|
||||
provider.stubs(:uids).with(to: 100).returns([100])
|
||||
provider.stubs(:uids).with(from: 101).returns([200])
|
||||
provider.stubs(:emails).with([100], ['UID', 'FLAGS', 'LABELS'], anything).returns(
|
||||
provider.stubs(:emails).with([100], ['UID', 'FLAGS', 'LABELS', 'ENVELOPE'], anything).returns(
|
||||
[
|
||||
{
|
||||
'UID' => 100,
|
||||
@ -205,7 +226,7 @@ describe Imap::Sync do
|
||||
|
||||
provider.stubs(:uids).with(to: 200).returns([100, 200])
|
||||
provider.stubs(:uids).with(from: 201).returns([])
|
||||
provider.stubs(:emails).with([100, 200], ['UID', 'FLAGS', 'LABELS'], anything).returns(
|
||||
provider.stubs(:emails).with([100, 200], ['UID', 'FLAGS', 'LABELS', 'ENVELOPE'], anything).returns(
|
||||
[
|
||||
{
|
||||
'UID' => 100,
|
||||
@ -244,7 +265,9 @@ describe Imap::Sync do
|
||||
let(:second_message_id) { SecureRandom.hex }
|
||||
let(:second_body) { '<p>This is an <b>answer</b> to this message.</p>' }
|
||||
|
||||
it 'is updated' do
|
||||
# TODO: Improve the invalidating flow for mailbox change. This is a destructive
|
||||
# action so it should not be done often.
|
||||
xit 'is updated' do
|
||||
provider = MockedImapProvider.any_instance
|
||||
|
||||
provider.stubs(:open_mailbox).returns(uid_validity: 1)
|
||||
@ -285,8 +308,8 @@ describe Imap::Sync do
|
||||
.and change { Post.where(post_type: Post.types[:regular]).count }.by(2)
|
||||
.and change { IncomingEmail.count }.by(2)
|
||||
|
||||
imap_data = Topic.last.incoming_email.pluck(:imap_uid_validity, :imap_uid)
|
||||
expect(imap_data).to contain_exactly([1, 100], [1, 200])
|
||||
imap_data = Topic.last.incoming_email.pluck(:imap_uid_validity, :imap_uid, :imap_group_id)
|
||||
expect(imap_data).to contain_exactly([1, 100, group.id], [1, 200, group.id])
|
||||
|
||||
provider.stubs(:open_mailbox).returns(uid_validity: 2)
|
||||
provider.stubs(:uids).with.returns([111, 222])
|
||||
@ -326,8 +349,8 @@ describe Imap::Sync do
|
||||
.and change { Post.where(post_type: Post.types[:regular]).count }.by(0)
|
||||
.and change { IncomingEmail.count }.by(0)
|
||||
|
||||
imap_data = Topic.last.incoming_email.pluck(:imap_uid_validity, :imap_uid)
|
||||
expect(imap_data).to contain_exactly([2, 111], [2, 222])
|
||||
imap_data = Topic.last.incoming_email.pluck(:imap_uid_validity, :imap_uid, :imap_group_id)
|
||||
expect(imap_data).to contain_exactly([2, 111, group.id], [2, 222, group.id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user