diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2020-10-15 12:24:38 +0300 |
---|---|---|
committer | Christoph Wurst <christoph@winzerhof-wurst.at> | 2020-10-30 19:16:24 +0300 |
commit | 15867528b25cad3e1262014d0fa4f967a73d64be (patch) | |
tree | 6dd7c46876325acf8aad147b9ef791a73376c102 /lib/Listener | |
parent | fe074001833362fa1eb4d18576131b0678907fb5 (diff) |
Store special mailboxes as preference of the account
… instead of using a fragile autodetection every time we need one of
those. We will still try to auto-detect the mailboxes but the users will
have to option to change the destinations.
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib/Listener')
-rw-r--r-- | lib/Listener/DeleteDraftListener.php | 51 | ||||
-rw-r--r-- | lib/Listener/DraftMailboxCreatorListener.php | 99 | ||||
-rw-r--r-- | lib/Listener/MailboxesSynchronizedSpecialMailboxesUpdater.php | 122 | ||||
-rw-r--r-- | lib/Listener/SaveSentMessageListener.php | 56 | ||||
-rw-r--r-- | lib/Listener/TrashMailboxCreatorListener.php | 102 |
5 files changed, 148 insertions, 282 deletions
diff --git a/lib/Listener/DeleteDraftListener.php b/lib/Listener/DeleteDraftListener.php index 3f701aa8f..87f46b47a 100644 --- a/lib/Listener/DeleteDraftListener.php +++ b/lib/Listener/DeleteDraftListener.php @@ -34,7 +34,6 @@ use OCA\Mail\Db\Message; use OCA\Mail\Events\DraftSavedEvent; use OCA\Mail\Events\MessageSentEvent; use OCA\Mail\IMAP\IMAPClientFactory; -use OCA\Mail\IMAP\MailboxSync; use OCA\Mail\IMAP\MessageMapper; use OCP\AppFramework\Db\DoesNotExistException; use OCP\EventDispatcher\Event; @@ -52,21 +51,16 @@ class DeleteDraftListener implements IEventListener { /** @var MessageMapper */ private $messageMapper; - /** @var MailboxSync */ - private $mailboxSync; - /** @var LoggerInterface */ private $logger; public function __construct(IMAPClientFactory $imapClientFactory, MailboxMapper $mailboxMapper, MessageMapper $messageMapper, - MailboxSync $mailboxSync, LoggerInterface $logger) { $this->imapClientFactory = $imapClientFactory; $this->mailboxMapper = $mailboxMapper; $this->messageMapper = $messageMapper; - $this->mailboxSync = $mailboxSync; $this->logger = $logger; } @@ -84,7 +78,12 @@ class DeleteDraftListener implements IEventListener { */ private function deleteDraft(Account $account, Message $draft): void { $client = $this->imapClientFactory->getClient($account); - $draftsMailbox = $this->getDraftsMailbox($account); + try { + $draftsMailbox = $this->getDraftsMailbox($account); + } catch (DoesNotExistException $e) { + $this->logger->warning("Account has no draft mailbox set, can't delete the draft"); + return; + } try { $this->messageMapper->addFlag( @@ -108,38 +107,14 @@ class DeleteDraftListener implements IEventListener { } } + /** + * @throws DoesNotExistException + */ private function getDraftsMailbox(Account $account): Mailbox { - try { - return $this->mailboxMapper->findSpecial($account, 'drafts'); - } catch (DoesNotExistException $e) { - $this->logger->debug('Creating drafts mailbox'); - $this->createDraftsMailbox($account); - $this->logger->debug('Drafts mailbox created'); - } - - return $this->mailboxMapper->findSpecial($account, 'drafts'); - } - - private function createDraftsMailbox(Account $account): void { - $client = $this->imapClientFactory->getClient($account); - - try { - // TODO: localize mailbox name - $client->createMailbox( - 'Drafts', - [ - 'special_use' => [ - \Horde_Imap_Client::SPECIALUSE_DRAFTS, - ], - ] - ); - } catch (Horde_Imap_Client_Exception $e) { - $this->logger->error('Could not create drafts mailbox', [ - 'exception' => $e, - ]); + $draftsMailboxId = $account->getMailAccount()->getDraftsMailboxId(); + if ($draftsMailboxId === null) { + throw new DoesNotExistException("No drafts mailbox ID set"); } - - // TODO: find a more elegant solution for updating the mailbox cache - $this->mailboxSync->sync($account, $this->logger,true); + return $this->mailboxMapper->findById($draftsMailboxId); } } diff --git a/lib/Listener/DraftMailboxCreatorListener.php b/lib/Listener/DraftMailboxCreatorListener.php deleted file mode 100644 index f4d915e81..000000000 --- a/lib/Listener/DraftMailboxCreatorListener.php +++ /dev/null @@ -1,99 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace OCA\Mail\Listener; - -use Horde_Imap_Client_Exception; -use OCA\Mail\Account; -use OCA\Mail\Db\MailboxMapper; -use OCA\Mail\Events\SaveDraftEvent; -use OCA\Mail\IMAP\IMAPClientFactory; -use OCA\Mail\IMAP\MailboxSync; -use OCP\AppFramework\Db\DoesNotExistException; -use OCP\EventDispatcher\Event; -use OCP\EventDispatcher\IEventListener; -use Psr\Log\LoggerInterface; - -class DraftMailboxCreatorListener implements IEventListener { - - /** @var MailboxMapper */ - private $mailboxMapper; - - /** @var IMAPClientFactory */ - private $imapClientFactory; - - /** @var MailboxSync */ - private $mailboxSync; - - /** @var LoggerInterface */ - private $logger; - - public function __construct(MailboxMapper $mailboxMapper, - IMAPClientFactory $imapClientFactory, - MailboxSync $mailboxSync, - LoggerInterface $logger) { - $this->mailboxMapper = $mailboxMapper; - $this->imapClientFactory = $imapClientFactory; - $this->mailboxSync = $mailboxSync; - $this->logger = $logger; - } - - public function handle(Event $event): void { - if (!($event instanceof SaveDraftEvent)) { - return; - } - - try { - $this->mailboxMapper->findSpecial($event->getAccount(), 'drafts'); - } catch (DoesNotExistException $e) { - $this->logger->debug('Creating drafts mailbox'); - $this->createDraftsMailbox($event->getAccount()); - $this->logger->debug('Drafts mailbox created'); - } - } - - private function createDraftsMailbox(Account $account): void { - $client = $this->imapClientFactory->getClient($account); - - try { - // TODO: localize mailbox name - $client->createMailbox( - 'Drafts', - [ - 'special_use' => [ - \Horde_Imap_Client::SPECIALUSE_DRAFTS, - ], - ] - ); - } catch (Horde_Imap_Client_Exception $e) { - $this->logger->error('Could not create drafts mailbox', [ - 'exception' => $e, - ]); - } - - // TODO: find a more elegant solution for updating the mailbox cache - $this->mailboxSync->sync($account, $this->logger,true); - } -} diff --git a/lib/Listener/MailboxesSynchronizedSpecialMailboxesUpdater.php b/lib/Listener/MailboxesSynchronizedSpecialMailboxesUpdater.php new file mode 100644 index 000000000..32c009061 --- /dev/null +++ b/lib/Listener/MailboxesSynchronizedSpecialMailboxesUpdater.php @@ -0,0 +1,122 @@ +<?php + +declare(strict_types=1); + +/* + * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace OCA\Mail\Listener; + +use OCA\Mail\Db\MailAccountMapper; +use OCA\Mail\Db\Mailbox; +use OCA\Mail\Db\MailboxMapper; +use OCA\Mail\Events\MailboxesSynchronizedEvent; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use Psr\Log\LoggerInterface; +use function array_combine; +use function array_key_exists; +use function array_map; +use function in_array; +use function json_decode; +use function strtolower; + +class MailboxesSynchronizedSpecialMailboxesUpdater implements IEventListener { + + /** @var MailAccountMapper */ + private $mailAccountMapper; + + /** @var MailboxMapper */ + private $mailboxMapper; + + /** @var LoggerInterface */ + private $logger; + + public function __construct(MailAccountMapper $mailAccountMapper, + MailboxMapper $mailboxMapper, + LoggerInterface $logger) { + $this->mailAccountMapper = $mailAccountMapper; + $this->mailboxMapper = $mailboxMapper; + $this->logger = $logger; + } + + /** + * @param Event $event + */ + public function handle(Event $event): void { + /** @var MailboxesSynchronizedEvent $event */ + $account = $event->getAccount(); + $mailAccount = $account->getMailAccount(); + $mailboxes = $this->indexMailboxes( + $this->mailboxMapper->findAll($account) + ); + + if ($mailAccount->getDraftsMailboxId() === null || !array_key_exists($mailAccount->getDraftsMailboxId(), $mailboxes)) { + $draftsMailbox = $this->findSpecial($mailboxes, 'drafts'); + $mailAccount->setDraftsMailboxId($draftsMailbox->getId()); + } + if ($mailAccount->getSentMailboxId() === null || !array_key_exists($mailAccount->getSentMailboxId(), $mailboxes)) { + $sentMailbox = $this->findSpecial($mailboxes, 'sent'); + $mailAccount->setSentMailboxId($sentMailbox->getId()); + } + if ($mailAccount->getTrashMailboxId() === null || !array_key_exists($mailAccount->getTrashMailboxId(), $mailboxes)) { + $trashMailbox = $this->findSpecial($mailboxes, 'trash'); + $mailAccount->setTrashMailboxId($trashMailbox->getId()); + } + + $this->mailAccountMapper->update($mailAccount); + } + + private function indexMailboxes(array $mailboxes): array { + return array_combine( + array_map(function (Mailbox $mb): int { + return $mb->getId(); + }, $mailboxes), + $mailboxes + ); + } + + /** + * @param Mailbox[] $mailboxes + * @throws DoesNotExistException + */ + private function findSpecial(array $mailboxes, string $specialUse): Mailbox { + // First, let's try to detect by special use attribute + foreach ($mailboxes as $mailbox) { + $specialUses = json_decode($mailbox->getSpecialUse(), true) ?? []; + if (in_array($specialUse, $specialUses, true)) { + return $mailbox; + } + } + + // No luck so far, let's do another round and just guess + foreach ($mailboxes as $mailbox) { + // TODO: also check localized name + if (strtolower($mailbox->getName()) === strtolower($specialUse)) { + return $mailbox; + } + } + + // Give up + throw new DoesNotExistException("Special mailbox $specialUse does not exist"); + } +} diff --git a/lib/Listener/SaveSentMessageListener.php b/lib/Listener/SaveSentMessageListener.php index aa43eb6fc..37eedd93c 100644 --- a/lib/Listener/SaveSentMessageListener.php +++ b/lib/Listener/SaveSentMessageListener.php @@ -26,13 +26,10 @@ declare(strict_types=1); namespace OCA\Mail\Listener; use Horde_Imap_Client_Exception; -use OCA\Mail\Account; -use OCA\Mail\Db\Mailbox; use OCA\Mail\Db\MailboxMapper; use OCA\Mail\Events\MessageSentEvent; use OCA\Mail\Exception\ServiceException; use OCA\Mail\IMAP\IMAPClientFactory; -use OCA\Mail\IMAP\MailboxSync; use OCA\Mail\IMAP\MessageMapper; use OCP\AppFramework\Db\DoesNotExistException; use OCP\EventDispatcher\Event; @@ -50,21 +47,16 @@ class SaveSentMessageListener implements IEventListener { /** @var MessageMapper */ private $messageMapper; - /** @var MailboxSync */ - private $mailboxSync; - /** @var LoggerInterface */ private $logger; public function __construct(MailboxMapper $mailboxMapper, IMAPClientFactory $imapClientFactory, MessageMapper $messageMapper, - MailboxSync $mailboxSync, LoggerInterface $logger) { $this->mailboxMapper = $mailboxMapper; $this->imapClientFactory = $imapClientFactory; $this->messageMapper = $messageMapper; - $this->mailboxSync = $mailboxSync; $this->logger = $logger; } @@ -73,13 +65,22 @@ class SaveSentMessageListener implements IEventListener { return; } + $sentMailboxId = $event->getAccount()->getMailAccount()->getSentMailboxId(); + if ($sentMailboxId === null) { + $this->logger->warning("No sent mailbox exists, can't save sent message"); + return; + } + // Save the message in the sent mailbox try { - $sentMailbox = $this->mailboxMapper->findSpecial($event->getAccount(), 'sent'); + $sentMailbox = $this->mailboxMapper->findById( + $sentMailboxId + ); } catch (DoesNotExistException $e) { - $this->logger->debug('creating sent mailbox'); - $sentMailbox = $this->createSentMailbox($event->getAccount()); - $this->logger->debug('sent mailbox created'); + $this->logger->error("Sent mailbox could not be found", [ + 'exception' => $e, + ]); + return; } try { @@ -92,35 +93,4 @@ class SaveSentMessageListener implements IEventListener { throw new ServiceException('Could not save sent message on IMAP', 0, $e); } } - - /** - * @throws DoesNotExistException - * @throws ServiceException - */ - private function createSentMailbox(Account $account): Mailbox { - $client = $this->imapClientFactory->getClient($account); - - try { - // TODO: localize mailbox name - $client->createMailbox( - 'Sent', - [ - 'special_use' => [ - \Horde_Imap_Client::SPECIALUSE_SENT, - ], - ] - ); - } catch (Horde_Imap_Client_Exception $e) { - // Let's assume this error is caused because the mailbox already exists, - // caused by concurrent requests or out-of-sync mailbox cache - $this->logger->warning('Could not create sent mailbox: ' . $e->getMessage(), [ - 'exception' => $e, - ]); - } - - // TODO: find a more elegant solution for updating the mailbox cache - $this->mailboxSync->sync($account, $this->logger,true); - - return $this->mailboxMapper->findSpecial($account, 'sent'); - } } diff --git a/lib/Listener/TrashMailboxCreatorListener.php b/lib/Listener/TrashMailboxCreatorListener.php deleted file mode 100644 index 3a57e2b4d..000000000 --- a/lib/Listener/TrashMailboxCreatorListener.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace OCA\Mail\Listener; - -use Horde_Imap_Client_Exception; -use OCA\Mail\Account; -use OCA\Mail\Db\MailboxMapper; -use OCA\Mail\Events\BeforeMessageDeletedEvent; -use OCA\Mail\IMAP\IMAPClientFactory; -use OCA\Mail\IMAP\MailboxSync; -use OCP\AppFramework\Db\DoesNotExistException; -use OCP\EventDispatcher\Event; -use OCP\EventDispatcher\IEventListener; -use Psr\Log\LoggerInterface; - -class TrashMailboxCreatorListener implements IEventListener { - - /** @var MailboxMapper */ - private $mailboxMapper; - - /** @var IMAPClientFactory */ - private $imapClientFactory; - - /** @var MailboxSync */ - private $mailboxSync; - - /** @var LoggerInterface */ - private $logger; - - public function __construct(MailboxMapper $mailboxMapper, - IMAPClientFactory $imapClientFactory, - MailboxSync $mailboxSync, - LoggerInterface $logger) { - $this->mailboxMapper = $mailboxMapper; - $this->imapClientFactory = $imapClientFactory; - $this->mailboxSync = $mailboxSync; - $this->logger = $logger; - } - - public function handle(Event $event): void { - if (!($event instanceof BeforeMessageDeletedEvent)) { - return; - } - - try { - $this->mailboxMapper->findSpecial( - $event->getAccount(), - 'trash' - ); - } catch (DoesNotExistException $e) { - $this->logger->debug("Creating trash mailbox"); - $this->createTrash($event->getAccount()); - $this->logger->debug("Trash mailbox created"); - } - } - - private function createTrash(Account $account): void { - $client = $this->imapClientFactory->getClient($account); - - try { - // TODO: localize mailbox name - $client->createMailbox( - 'Trash', - [ - 'special_use' => [ - \Horde_Imap_Client::SPECIALUSE_TRASH, - ], - ] - ); - - // TODO: find a more elegant solution for updating the mailbox cache - $this->mailboxSync->sync($account, $this->logger,true); - } catch (Horde_Imap_Client_Exception $e) { - $this->logger->error('Could not creat trash mailbox', [ - 'exception' => $e, - ]); - } - } -} |