FEATURE: IMAP delete email sync for group inboxes (#10392)

Adds functionality to reflect topic delete in Discourse to IMAP inbox (Gmail only for now) and reflecting Gmail deletes in Discourse.

Adding lots of tests, various refactors and code improvements.

When Discourse topic is destroyed in PostDestroyer mark the topic incoming email as imap_sync: true, and do the opposite when post is recovered.
This commit is contained in:
Martin Brennan
2020-08-12 10:16:26 +10:00
committed by GitHub
parent 6391db5921
commit 95b71b35d6
11 changed files with 508 additions and 20 deletions

View File

@ -16,6 +16,13 @@ RSpec.describe Imap::Providers::Generic do
}
)
end
let(:dummy_mailboxes) do
[
Net::IMAP::MailboxList.new([], "/", "All Mail"),
Net::IMAP::MailboxList.new([:Noselect], "/", "Other"),
Net::IMAP::MailboxList.new([:Trash], "/", "Bin")
]
end
let(:imap_stub) { stub }
before do
@ -29,6 +36,101 @@ RSpec.describe Imap::Providers::Generic do
end
end
describe "#list_mailboxes" do
before do
imap_stub.expects(:list).with('', '*').returns(dummy_mailboxes)
end
it "does not return any mailboxes with the Noselect attribute" do
expect(provider.list_mailboxes).not_to include("Other")
end
it "filters by the provided attribute" do
expect(provider.list_mailboxes(:Trash)).to eq(["Bin"])
end
it "lists all mailboxes names" do
expect(provider.list_mailboxes).to eq(["All Mail", "Bin"])
end
end
describe "#trash_mailbox" do
before do
imap_stub.expects(:list).with('', '*').returns(dummy_mailboxes)
Discourse.cache.delete("imap_trash_mailbox_#{provider.account_digest}")
end
it "returns the mailbox with the special-use attribute \Trash" do
expect(provider.trash_mailbox).to eq("Bin")
end
it "caches the result based on the account username and server for 30 mins" do
provider.trash_mailbox
provider.expects(:list_mailboxes).never
provider.trash_mailbox
end
end
describe "#find_trashed_by_message_ids" do
before do
provider.stubs(:trash_mailbox).returns("Bin")
imap_stub.stubs(:examine).with("Inbox").twice
imap_stub.stubs(:responses).returns({ 'UIDVALIDITY' => [1] })
imap_stub.stubs(:examine).with("Bin")
imap_stub.stubs(:responses).returns({ 'UIDVALIDITY' => [9] })
provider.expects(:emails).with([4, 6], ['UID', 'ENVELOPE']).returns(
[
{
'ENVELOPE' => stub(message_id: "<h4786x34@test.com>"),
'UID' => 4
},
{
'ENVELOPE' => stub(message_id: "<f349xj84@test.com>"),
'UID' => 6
}
]
)
end
let(:message_ids) do
[
"h4786x34@test.com",
"dvsfuf39@test.com",
"f349xj84@test.com"
]
end
it "sends the message-id search in the correct format and returns the trashed emails and UIDVALIDITY" do
provider.open_mailbox("Inbox")
imap_stub.expects(:uid_search).with(
"OR OR HEADER Message-ID '<h4786x34@test.com>' HEADER Message-ID '<dvsfuf39@test.com>' HEADER Message-ID '<f349xj84@test.com>'"
).returns([4, 6])
resp = provider.find_trashed_by_message_ids(message_ids)
expect(resp.trashed_emails.map(&:message_id)).to match_array(['h4786x34@test.com', 'f349xj84@test.com'])
expect(resp.trash_uid_validity).to eq(9)
end
end
describe "#trash" do
it "stores the \Deleted flag on the UID and expunges" do
provider.stubs(:can?).with('MOVE').returns(false)
provider.expects(:store).with(78, 'FLAGS', [], ['\Deleted'])
imap_stub.expects(:expunge)
provider.trash(78)
end
context "if the server supports MOVE" do
it "calls trash_move which is implemented by the provider" do
provider.stubs(:can?).with('MOVE').returns(true)
provider.expects(:trash_move).with(78)
provider.trash(78)
end
end
end
describe "#uids" do
it "can search with from and to" do
imap_stub.expects(:uid_search).once.with("UID 5:9")