Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/mail.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnna Larch <anna@nextcloud.com>2021-05-06 23:36:20 +0300
committerAnna Larch <anna@nextcloud.com>2021-05-26 16:38:18 +0300
commit540ca4b1ef164f1a05e8c4f457ed8aca7ccebabd (patch)
tree20a536d98ca52f81010478c620208a2cbe5e6b90
parent4f5692a41c64d7878c9e6a167c72665cf70b8a33 (diff)
Add bg job for label sync
Signed-off-by: Anna Larch <anna@nextcloud.com>
-rw-r--r--lib/BackgroundJob/MigrateImportantJob.php111
-rw-r--r--lib/Db/MailboxMapper.php38
-rw-r--r--lib/IMAP/MessageMapper.php26
-rw-r--r--lib/Listener/DeleteDraftListener.php2
-rw-r--r--lib/Listener/FlagRepliedMessageListener.php2
-rw-r--r--lib/Migration/MigrateImportantFromImapAndDb.php98
-rw-r--r--lib/Migration/Version1100Date20210512142306.php38
-rw-r--r--lib/Service/MailManager.php8
-rw-r--r--lib/Service/Sync/SyncService.php6
-rw-r--r--tests/Integration/Framework/ImapTest.php2
-rw-r--r--tests/Integration/IMAP/MessageMapperTest.php203
-rw-r--r--tests/Integration/Migration/MigrateImportantFromImapAndDbTest.php239
-rw-r--r--tests/Unit/IMAP/MessageMapperTest.php65
-rw-r--r--tests/Unit/Job/TestMigrateImportantJob.php322
-rw-r--r--tests/Unit/Listener/DeleteDraftListenerTest.php2
-rw-r--r--tests/Unit/Listener/FlagRepliedMessageListenerTest.php2
-rw-r--r--tests/Unit/Migration/MigrateImportantFromImapAndDbTest.php239
-rw-r--r--tests/Unit/Service/MailManagerTest.php6
18 files changed, 1391 insertions, 18 deletions
diff --git a/lib/BackgroundJob/MigrateImportantJob.php b/lib/BackgroundJob/MigrateImportantJob.php
new file mode 100644
index 000000000..f04127435
--- /dev/null
+++ b/lib/BackgroundJob/MigrateImportantJob.php
@@ -0,0 +1,111 @@
+<?php
+/**
+ * @copyright 2021 Anna Larch <anna.larch@nextcloud.com>
+ *
+ * @author Anna Larch <anna.larch@nextcloud.com>
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @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\BackgroundJob;
+
+use OCA\Mail\Account;
+use OCA\Mail\Db\MailAccountMapper;
+use OCA\Mail\Db\Mailbox;
+use OCA\Mail\Db\MailboxMapper;
+
+use OCA\Mail\Exception\ServiceException;
+use OCA\Mail\Migration\MigrateImportantFromImapAndDb;
+use OCA\Mail\Service\MailManager;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\QueuedJob;
+use Psr\Log\LoggerInterface;
+
+class MigrateImportantJob extends QueuedJob {
+
+ /** @var MailboxMapper */
+ private $mailboxMapper;
+
+ /** @var MailAccountMapper */
+ private $mailAccountMapper;
+
+ /** @var MailManager */
+ private $mailManager;
+
+ /** @var MigrateImportantFromImapAndDb */
+ private $migration;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ public function __construct(MailboxMapper $mailboxMapper,
+ MailAccountMapper $mailAccountMapper,
+ MailManager $mailManager,
+ MigrateImportantFromImapAndDb $migration,
+ LoggerInterface $logger,
+ ITimeFactory $timeFactory
+ ) {
+ parent::__construct($timeFactory);
+ $this->mailboxMapper = $mailboxMapper;
+ $this->mailAccountMapper = $mailAccountMapper;
+ $this->mailManager = $mailManager;
+ $this->migration = $migration;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @param array $argument
+ */
+ public function run($argument) {
+ $mailboxId = (int)$argument['mailboxId'];
+ try {
+ /** @var Mailbox $mailbox*/
+ $mailbox = $this->mailboxMapper->findById($mailboxId);
+ } catch (DoesNotExistException $e) {
+ $this->logger->debug('Could not find mailbox <' . $mailboxId . '>');
+ return;
+ }
+
+ $accountId = $mailbox->getAccountId();
+ try {
+ $mailAccount = $this->mailAccountMapper->findById($accountId);
+ } catch (DoesNotExistException $e) {
+ $this->logger->debug('Could not find account <' . $accountId . '>');
+ return;
+ }
+
+ $account = new Account($mailAccount);
+ if ($this->mailManager->isPermflagsEnabled($account, $mailbox->getName()) === false) {
+ $this->logger->debug('Permflags not enabled for <' . $accountId . '>');
+ return;
+ }
+
+ try {
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ } catch (ServiceException $e) {
+ $this->logger->debug('Could not flag messages on IMAP for mailbox <' . $mailboxId . '>.');
+ }
+
+ try {
+ $this->migration->migrateImportantFromDb($account, $mailbox);
+ } catch (ServiceException $e) {
+ $this->logger->debug('Could not flag messages from DB on IMAP for mailbox <' . $mailboxId . '>.');
+ }
+ }
+}
diff --git a/lib/Db/MailboxMapper.php b/lib/Db/MailboxMapper.php
index 801fd64ca..5e3e74c4e 100644
--- a/lib/Db/MailboxMapper.php
+++ b/lib/Db/MailboxMapper.php
@@ -66,6 +66,21 @@ class MailboxMapper extends QBMapper {
}
/**
+ * @return \Generator<int>
+ */
+ public function findAllIds(): \Generator {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('id')
+ ->from($this->getTableName());
+
+ $cursor = $qb->execute();
+ while ($row = $cursor->fetch()) {
+ yield (int)$row['id'];
+ }
+ $cursor->closeCursor();
+ }
+
+ /**
* @throws DoesNotExistException
* @throws ServiceException
*/
@@ -246,4 +261,27 @@ class MailboxMapper extends QBMapper {
->where($qb2->expr()->in('id', $qb2->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY), IQueryBuilder::PARAM_INT_ARRAY));
$query->execute();
}
+
+ /**
+ * Get all UIDS for mail_messages.flag_important = true
+ *
+ * @return int[]
+ */
+ public function findFlaggedImportantUids(int $mailboxId) : array {
+ $qb = $this->db->getQueryBuilder();
+ $query = $qb->select('uid')
+ ->from('mail_messages')
+ ->where(
+ $qb->expr()->eq('mailbox_id', $qb->createNamedParameter($mailboxId)),
+ $qb->expr()->eq('flag_important', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
+ );
+
+ $cursor = $query->execute();
+ $uids = array_map(function (array $row) {
+ return (int)$row['uid'];
+ }, $cursor->fetchAll());
+ $cursor->closeCursor();
+
+ return $uids;
+ }
}
diff --git a/lib/IMAP/MessageMapper.php b/lib/IMAP/MessageMapper.php
index 95161fd8a..112d93c6c 100644
--- a/lib/IMAP/MessageMapper.php
+++ b/lib/IMAP/MessageMapper.php
@@ -28,6 +28,7 @@ use Horde_Imap_Client_Base;
use Horde_Imap_Client_Data_Fetch;
use Horde_Imap_Client_Exception;
use Horde_Imap_Client_Fetch_Query;
+use Horde_Imap_Client_Search_Query;
use Horde_Imap_Client_Ids;
use Horde_Imap_Client_Socket;
use Horde_Mime_Mail;
@@ -327,12 +328,12 @@ class MessageMapper {
*/
public function addFlag(Horde_Imap_Client_Socket $client,
Mailbox $mailbox,
- int $uid,
+ array $uids,
string $flag): void {
$client->store(
$mailbox->getName(),
[
- 'ids' => new Horde_Imap_Client_Ids($uid),
+ 'ids' => new Horde_Imap_Client_Ids($uids),
'add' => [$flag],
]
);
@@ -343,12 +344,12 @@ class MessageMapper {
*/
public function removeFlag(Horde_Imap_Client_Socket $client,
Mailbox $mailbox,
- int $uid,
+ array $uids,
string $flag): void {
$client->store(
$mailbox->getName(),
[
- 'ids' => new Horde_Imap_Client_Ids($uid),
+ 'ids' => new Horde_Imap_Client_Ids($uids),
'remove' => [$flag],
]
);
@@ -356,6 +357,23 @@ class MessageMapper {
/**
* @param Horde_Imap_Client_Socket $client
+ * @param Mailbox $mailbox
+ * @param string $flag
+ * @return int[]
+ *
+ * @throws Horde_Imap_Client_Exception
+ */
+ public function getFlagged(Horde_Imap_Client_Socket $client,
+ Mailbox $mailbox,
+ string $flag): array {
+ $query = new Horde_Imap_Client_Search_Query();
+ $query->flag($flag, true);
+ $messages = $client->search($mailbox->getName(), $query);
+ return $messages['match']->ids ?? [];
+ }
+
+ /**
+ * @param Horde_Imap_Client_Socket $client
* @param string $mailbox
* @param int $uid
*
diff --git a/lib/Listener/DeleteDraftListener.php b/lib/Listener/DeleteDraftListener.php
index 469ef070b..8d89d229b 100644
--- a/lib/Listener/DeleteDraftListener.php
+++ b/lib/Listener/DeleteDraftListener.php
@@ -96,7 +96,7 @@ class DeleteDraftListener implements IEventListener {
$this->messageMapper->addFlag(
$client,
$draftsMailbox,
- $draft->getUid(), // TODO: the UID could be from another mailbox
+ [$draft->getUid()], // TODO: the UID could be from another mailbox
Horde_Imap_Client::FLAG_DELETED
);
} catch (Horde_Imap_Client_Exception $e) {
diff --git a/lib/Listener/FlagRepliedMessageListener.php b/lib/Listener/FlagRepliedMessageListener.php
index 823732a02..977b95faf 100644
--- a/lib/Listener/FlagRepliedMessageListener.php
+++ b/lib/Listener/FlagRepliedMessageListener.php
@@ -83,7 +83,7 @@ class FlagRepliedMessageListener implements IEventListener {
$this->messageMapper->addFlag(
$client,
$mailbox,
- $event->getRepliedMessageData()->getMessage()->getUid(),
+ [$event->getRepliedMessageData()->getMessage()->getUid()],
Horde_Imap_Client::FLAG_ANSWERED
);
} catch (Horde_Imap_Client_Exception $e) {
diff --git a/lib/Migration/MigrateImportantFromImapAndDb.php b/lib/Migration/MigrateImportantFromImapAndDb.php
new file mode 100644
index 000000000..17f13e912
--- /dev/null
+++ b/lib/Migration/MigrateImportantFromImapAndDb.php
@@ -0,0 +1,98 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2021 Anna Larch <anna@nextcloud.com>
+ *
+ * @author 2021 Anna Larch <anna@nextcloud.com>
+ *
+ * @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/>.
+ *
+ * @link https://github.com/nextcloud/mail/issues/25
+ * @link https://github.com/nextcloud/mail/issues/4780
+ */
+
+namespace OCA\Mail\Migration;
+
+use Horde_Imap_Client_Exception;
+use OCA\Mail\Account;
+use OCA\Mail\Db\Mailbox;
+use OCA\Mail\Db\MailboxMapper;
+use OCA\Mail\Db\Tag;
+use OCA\Mail\Exception\ServiceException;
+use OCA\Mail\IMAP\IMAPClientFactory;
+use OCA\Mail\IMAP\MessageMapper;
+use Psr\Log\LoggerInterface;
+
+class MigrateImportantFromImapAndDb {
+
+ /** @var IMAPClientFactory */
+ private $clientFactory;
+
+ /** @var MessageMapper */
+ private $messageMapper;
+
+ /** @var MailboxMapper */
+ private $mailboxMapper;
+
+ /** @var LoggerInterface */
+ private $logger;
+
+ public function __construct(IMAPClientFactory $clientFactory,
+ MessageMapper $messageMapper,
+ MailboxMapper $mailboxMapper,
+ LoggerInterface $logger
+ ) {
+ $this->clientFactory = $clientFactory;
+ $this->messageMapper = $messageMapper;
+ $this->mailboxMapper = $mailboxMapper;
+ $this->logger = $logger;
+ }
+
+ public function migrateImportantOnImap(Account $account, Mailbox $mailbox): void {
+ $client = $this->clientFactory->getClient($account);
+ //get all messages that have an $important label from IMAP
+ try {
+ $uids = $this->messageMapper->getFlagged($client, $mailbox, '$important');
+ } catch (Horde_Imap_Client_Exception $e) {
+ throw new ServiceException("Could not fetch UIDs of important messages: " . $e->getMessage(), 0, $e);
+ }
+ // add $label1 for all that are tagged on IMAP
+ if (!empty($uids)) {
+ try {
+ $this->messageMapper->addFlag($client, $mailbox, $uids, Tag::LABEL_IMPORTANT);
+ } catch (Horde_Imap_Client_Exception $e) {
+ $this->logger->debug('Could not flag messages in mailbox <' . $mailbox->getId() . '>');
+ throw new ServiceException($e->getMessage(), 0, $e);
+ }
+ }
+ }
+
+ public function migrateImportantFromDb(Account $account, Mailbox $mailbox): void {
+ $client = $this->clientFactory->getClient($account);
+ $uids = $this->mailboxMapper->findFlaggedImportantUids($mailbox->getId());
+ // store our data on imap
+ if (!empty($uids)) {
+ try {
+ $this->messageMapper->addFlag($client, $mailbox, $uids, Tag::LABEL_IMPORTANT);
+ } catch (Horde_Imap_Client_Exception $e) {
+ $this->logger->debug('Could not flag messages in mailbox <' . $mailbox->getId() . '>');
+ throw new ServiceException($e->getMessage(), 0, $e);
+ }
+ }
+ }
+}
diff --git a/lib/Migration/Version1100Date20210512142306.php b/lib/Migration/Version1100Date20210512142306.php
new file mode 100644
index 000000000..38d0de51c
--- /dev/null
+++ b/lib/Migration/Version1100Date20210512142306.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OCA\Mail\Migration;
+
+use Closure;
+use OCA\Mail\BackgroundJob\MigrateImportantJob;
+use OCA\Mail\Db\MailboxMapper;
+use OCP\BackgroundJob\IJobList;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+class Version1100Date20210512142306 extends SimpleMigrationStep {
+
+ /** @var MailboxMapper */
+ private $mailboxMapper;
+
+ /** @var IJobList */
+ private $jobList;
+
+ public function __construct(MailboxMapper $mailboxMapper, IJobList $jobList) {
+ $this->mailboxMapper = $mailboxMapper;
+ $this->jobList = $jobList;
+ }
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
+ foreach ($this->mailboxMapper->findAllIds() as $mailboxId) {
+ $this->jobList->add(MigrateImportantJob::class, ['mailboxId' => $mailboxId]);
+ }
+ }
+}
diff --git a/lib/Service/MailManager.php b/lib/Service/MailManager.php
index bd87e3b13..29030a000 100644
--- a/lib/Service/MailManager.php
+++ b/lib/Service/MailManager.php
@@ -388,9 +388,9 @@ class MailManager implements IMailManager {
continue;
}
if ($value) {
- $this->imapMessageMapper->addFlag($client, $mb, $uid, $imapFlag);
+ $this->imapMessageMapper->addFlag($client, $mb, [$uid], $imapFlag);
} else {
- $this->imapMessageMapper->removeFlag($client, $mb, $uid, $imapFlag);
+ $this->imapMessageMapper->removeFlag($client, $mb, [$uid], $imapFlag);
}
}
} catch (Horde_Imap_Client_Exception $e) {
@@ -438,9 +438,9 @@ class MailManager implements IMailManager {
try {
if ($value) {
// imap keywords and flags work the same way
- $this->imapMessageMapper->addFlag($client, $mb, $message->getUid(), $tag->getImapLabel());
+ $this->imapMessageMapper->addFlag($client, $mb, [$message->getUid()], $tag->getImapLabel());
} else {
- $this->imapMessageMapper->removeFlag($client, $mb, $message->getUid(), $tag->getImapLabel());
+ $this->imapMessageMapper->removeFlag($client, $mb, [$message->getUid()], $tag->getImapLabel());
}
} catch (Horde_Imap_Client_Exception $e) {
throw new ServiceException(
diff --git a/lib/Service/Sync/SyncService.php b/lib/Service/Sync/SyncService.php
index f5ea294c5..9f56e383a 100644
--- a/lib/Service/Sync/SyncService.php
+++ b/lib/Service/Sync/SyncService.php
@@ -111,7 +111,7 @@ class SyncService {
public function syncMailbox(Account $account,
Mailbox $mailbox,
int $criteria,
- array $knownIds,
+ array $knownIds = null,
bool $partialOnly,
string $filter = null): Response {
if ($partialOnly && !$mailbox->isCached()) {
@@ -123,7 +123,7 @@ class SyncService {
$mailbox,
$this->logger,
$criteria,
- $this->messageMapper->findUidsForIds($mailbox, $knownIds),
+ $knownIds === null ? null : $this->messageMapper->findUidsForIds($mailbox, $knownIds),
!$partialOnly
);
@@ -133,7 +133,7 @@ class SyncService {
return $this->getDatabaseSyncChanges(
$account,
$mailbox,
- $knownIds,
+ $knownIds ?? [],
$query
);
}
diff --git a/tests/Integration/Framework/ImapTest.php b/tests/Integration/Framework/ImapTest.php
index c0b252fb1..1a68ad415 100644
--- a/tests/Integration/Framework/ImapTest.php
+++ b/tests/Integration/Framework/ImapTest.php
@@ -27,6 +27,7 @@ use Horde_Imap_Client_Fetch_Query;
use Horde_Imap_Client_Ids;
use Horde_Imap_Client_Socket;
use Horde_Mail_Rfc822_Address;
+use Horde_Mime_Headers_MessageId;
use Horde_Mime_Mail;
use Horde_Mime_Part;
use OCA\Mail\Account;
@@ -145,6 +146,7 @@ trait ImapTest {
$mail = new Horde_Mime_Mail();
$mail->addHeaders($headers);
+ $mail->addHeaderOb(Horde_Mime_Headers_MessageId::create());
$body = new Horde_Mime_Part();
$body->setType('text/plain');
$body->setContents($message->getBody());
diff --git a/tests/Integration/IMAP/MessageMapperTest.php b/tests/Integration/IMAP/MessageMapperTest.php
new file mode 100644
index 000000000..c1faa022c
--- /dev/null
+++ b/tests/Integration/IMAP/MessageMapperTest.php
@@ -0,0 +1,203 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @author Anna Larch <anna.larch@nextcloud.com>
+ *
+ * Mail
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Mail\Tests\Integration\IMAP;
+
+use ChristophWurst\Nextcloud\Testing\TestCase;
+use Horde_Imap_Client;
+use Horde_Imap_Client_Exception;
+use OC;
+use OCA\Mail\Account;
+use OCA\Mail\Contracts\IMailManager;
+use OCA\Mail\IMAP\MessageMapper as ImapMessageMapper;
+use OCA\Mail\Db\MessageMapper;
+use OCA\Mail\Service\Sync\SyncService;
+use OCA\Mail\Tests\Integration\Framework\ImapTest;
+use OCA\Mail\Tests\Integration\Framework\ImapTestAccount;
+
+class MessageMapperTest extends TestCase {
+ use ImapTest,
+ ImapTestAccount;
+
+ public function setUp():void {
+ parent::setUp();
+ }
+
+ public function testTagging() {
+ // First, set up account and retrieve sync token
+ $this->resetImapAccount();
+
+ $account = $this->createTestAccount();
+ /** @var SyncService $syncService */
+ $syncService = OC::$server->query(SyncService::class);
+ /** @var ImapMessageMapper $messageMapper */
+ $imapMessageMapper = OC::$server->query(ImapMessageMapper::class);
+ /** @var MessageMapper $messageMapper */
+ $messageMapper = OC::$server->query(MessageMapper::class);
+ /** @var IMailManager $mailManager */
+ $mailManager = OC::$server->query(IMailManager::class);
+ $mailBoxes = $mailManager->getMailboxes(new Account($account));
+ $inbox = null;
+ foreach ($mailBoxes as $mailBox) {
+ if ($mailBox->getName() === 'INBOX') {
+ $inbox = $mailBox;
+ break;
+ }
+ }
+
+ // Second, put a new message into the mailbox
+ $message = $this->getMessageBuilder()
+ ->from('buffington@domain.tld')
+ ->to('user@domain.tld')
+ ->finish();
+ $newUid = $this->saveMessage($inbox->getName(), $message, $account);
+
+ // now we tag this message!
+ try {
+ $imapMessageMapper->addFlag($this->getClient($account), $mailBox, [$newUid], '$label1');
+ } catch (Horde_Imap_Client_Exception $e) {
+ $this->fail('Could not tag message');
+ }
+
+ // sync
+ $syncService->syncMailbox(
+ new Account($account),
+ $inbox,
+ Horde_Imap_Client::SYNC_NEWMSGSUIDS | Horde_Imap_Client::SYNC_FLAGSUIDS | Horde_Imap_Client::SYNC_VANISHEDUIDS,
+ null,
+ false
+ );
+
+ // Let's retrieve the DB to see if we have this tag!
+ $messages = $messageMapper->findByUids($mailBox, [$newUid]);
+ $related = $messageMapper->findRelatedData($messages, $account->getUserId());
+ foreach ($related as $message) {
+ $tags = $message->getTags();
+ $this->assertEquals('$label1', $tags[0]->getImapLabel());
+ }
+
+
+ // now we untag this message!
+ try {
+ $imapMessageMapper->removeFlag($this->getClient($account), $mailBox, [$newUid], '$label1');
+ } catch (Horde_Imap_Client_Exception $e) {
+ $this->fail('Could not untag message');
+ }
+
+ // sync again
+ $syncService->syncMailbox(
+ new Account($account),
+ $inbox,
+ Horde_Imap_Client::SYNC_NEWMSGSUIDS | Horde_Imap_Client::SYNC_FLAGSUIDS | Horde_Imap_Client::SYNC_VANISHEDUIDS,
+ null,
+ true
+ );
+
+ $messages = $messageMapper->findByUids($mailBox, [$newUid]);
+ $related = $messageMapper->findRelatedData($messages, $account->getUserId());
+ foreach ($related as $message) {
+ $tags = $message->getTags();
+ $this->assertEmpty($tags);
+ }
+ }
+
+ public function testGetFlagged() {
+ // First, set up account and retrieve sync token
+ $this->resetImapAccount();
+
+ $account = $this->createTestAccount();
+ /** @var ImapMessageMapper $messageMapper */
+ $imapMessageMapper = OC::$server->query(ImapMessageMapper::class);
+ /** @var IMailManager $mailManager */
+ $mailManager = OC::$server->query(IMailManager::class);
+ $mailBoxes = $mailManager->getMailboxes(new Account($account));
+ $inbox = null;
+ foreach ($mailBoxes as $mailBox) {
+ if ($mailBox->getName() === 'INBOX') {
+ $inbox = $mailBox;
+ break;
+ }
+ }
+
+ // Put a second new message into the mailbox
+ $message = $this->getMessageBuilder()
+ ->from('buffington@domain.tld')
+ ->to('user@domain.tld')
+ ->finish();
+ $newUid = $this->saveMessage($inbox->getName(), $message, $account);
+
+
+ // Put another new message into the mailbox
+ $message = $this->getMessageBuilder()
+ ->from('fluffington@domain.tld')
+ ->to('user@domain.tld')
+ ->finish();
+ $newUid2 = $this->saveMessage($inbox->getName(), $message, $account);
+
+ // Thirdly, create a message that will not be tagged
+ $message = $this->getMessageBuilder()
+ ->from('scruffington@domain.tld')
+ ->to('user@domain.tld')
+ ->finish();
+ $this->saveMessage($inbox->getName(), $message, $account);
+
+ // now we tag this message with $label1
+ try {
+ $imapMessageMapper->addFlag($this->getClient($account), $mailBox, [$newUid], '$label1');
+ } catch (Horde_Imap_Client_Exception $e) {
+ $this->fail('Could not tag message');
+ }
+
+
+ // now we tag this and the previous message with $label2
+ try {
+ $imapMessageMapper->addFlag($this->getClient($account), $mailBox, [$newUid, $newUid2], '$label2');
+ } catch (Horde_Imap_Client_Exception $e) {
+ $this->fail('Could not tag message');
+ }
+
+ // test for labels
+ $tagged = $imapMessageMapper->getFlagged($this->getClient($account), $mailBox, '$label1');
+ $this->assertNotEmpty($tagged);
+ // are the counts correct?
+ $this->assertCount(1, $tagged);
+
+ $tagged = $imapMessageMapper->getFlagged($this->getClient($account), $mailBox, '$label2');
+ $this->assertNotEmpty($tagged);
+ $this->assertCount(2, $tagged);
+
+ // test for labels that wasn't set
+ $tagged = $imapMessageMapper->getFlagged($this->getClient($account), $mailBox, '$notAvailable');
+ $this->assertEmpty($tagged);
+
+ // test for regular flag - recent
+ $tagged = $imapMessageMapper->getFlagged($this->getClient($account), $mailBox, Horde_Imap_Client::FLAG_RECENT);
+ $this->assertNotEmpty($tagged);
+ // should return all messages
+ $this->assertCount(3, $tagged);
+ }
+
+ public function tearDown(): void {
+ $this->resetImapAccount();
+ }
+}
diff --git a/tests/Integration/Migration/MigrateImportantFromImapAndDbTest.php b/tests/Integration/Migration/MigrateImportantFromImapAndDbTest.php
new file mode 100644
index 000000000..548d63cef
--- /dev/null
+++ b/tests/Integration/Migration/MigrateImportantFromImapAndDbTest.php
@@ -0,0 +1,239 @@
+<?php
+
+/**
+ * @copyright 2021 Anna Larch <anna.larch@nextcloud.com>
+ *
+ * @author 2021 Anna Larch <anna.larch@nextcloud.com>
+ *
+ * @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\Tests\Integration\Service;
+
+use ChristophWurst\Nextcloud\Testing\TestCase;
+use Horde_Imap_Client_Exception;
+use Horde_Imap_Client_Socket;
+use OCA\Mail\Account;
+use OCA\Mail\Db\Mailbox;
+use OCA\Mail\Db\MailboxMapper;
+use OCA\Mail\IMAP\MessageMapper;
+use OCA\Mail\Db\Tag;
+use OCA\Mail\Exception\ServiceException;
+use OCA\Mail\IMAP\IMAPClientFactory;
+use OCA\Mail\Migration\MigrateImportantFromImapAndDb;
+use Psr\Log\LoggerInterface;
+
+class MigrateImportantFromImapAndDbTest extends TestCase {
+
+ /** @var MockObject */
+ private $clientFactory;
+
+ /** @var MockObject */
+ private $client;
+
+ /** @var MockObject */
+ private $messageMapper;
+
+ /** @var MockObject */
+ private $mailboxMapper;
+
+ /** @var MockObject */
+ private $logger;
+
+ /** @var MigrateImportantFromImapAndDb */
+ private $migration;
+
+ protected function setUp(): void {
+ $this->clientFactory = $this->createMock(IMAPClientFactory::class);
+ $this->client = $this->createMock(Horde_Imap_Client_Socket::class);
+ $this->messageMapper = $this->createMock(MessageMapper::class);
+ $this->mailboxMapper = $this->createMock(MailboxMapper::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->migration = new MigrateImportantFromImapAndDb(
+ $this->clientFactory,
+ $this->messageMapper,
+ $this->mailboxMapper,
+ $this->logger
+ );
+ parent::setUp();
+ }
+
+ public function testMigrateImportantOnImap() {
+ $account = $this->createMock(Account::class);
+ $mailbox = $this->createMock(Mailbox::class);
+ $uids = [1,2,3];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT);
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function testMigrateImportantOnImapNoUids() {
+ $account = $this->createMock(Account::class);
+ $mailbox = $this->createMock(Mailbox::class);
+ $uids = [];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->never())
+ ->method('addFlag');
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function testMigrateImportantOnImapExceptionGetFlagged() {
+ $account = $this->createMock(Account::class);
+ $mailbox = $this->createMock(Mailbox::class);
+ $e = new Horde_Imap_Client_Exception('');
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willThrowException($e);
+ $this->messageMapper->expects($this->never())
+ ->method('addFlag');
+ $this->logger->expects($this->never())
+ ->method('debug');
+ $this->expectException(ServiceException::class);
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function testMigrateImportantOnImapExceptionOnFlag() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setName('INBOX');
+ $e = new Horde_Imap_Client_Exception('');
+ $uids = [1,2,3,4];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT)
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not flag messages in mailbox <' . $mailbox->getId() . '>');
+ $this->expectException(ServiceException::class);
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function migrateImportantFromDb() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setId(1);
+ $uids = [1,2,3];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->mailboxMapper->expects($this->once())
+ ->method('findFlaggedImportantUids')
+ ->with($mailbox->getId())
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT);
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantFromDb($account, $mailbox);
+ }
+
+ public function testMigrateImportantFromDbNoUids() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setId(1);
+ $uids = [];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->mailboxMapper->expects($this->once())
+ ->method('findFlaggedImportantUids')
+ ->with($mailbox->getId())
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->never())
+ ->method('addFlag');
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantFromDb($account, $mailbox);
+ }
+
+ public function testMigrateImportantFromDbExceptionOnFlag() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setId(1);
+ $mailbox->setName('INBOX');
+ $e = new Horde_Imap_Client_Exception('');
+ $uids = [1,2,3];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->mailboxMapper->expects($this->once())
+ ->method('findFlaggedImportantUids')
+ ->with($mailbox->getId())
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT)
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not flag messages in mailbox <' . $mailbox->getId() . '>');
+ $this->expectException(ServiceException::class);
+
+ $this->migration->migrateImportantFromDb($account, $mailbox);
+ }
+}
diff --git a/tests/Unit/IMAP/MessageMapperTest.php b/tests/Unit/IMAP/MessageMapperTest.php
index 02625c302..80011fe20 100644
--- a/tests/Unit/IMAP/MessageMapperTest.php
+++ b/tests/Unit/IMAP/MessageMapperTest.php
@@ -30,6 +30,7 @@ use Horde_Imap_Client_Fetch_Query;
use Horde_Imap_Client_Fetch_Results;
use Horde_Imap_Client_Ids;
use Horde_Imap_Client_Socket;
+use OCA\Mail\Db\Mailbox;
use OCA\Mail\IMAP\MessageMapper;
use OCA\Mail\Model\IMAPMessage;
use PHPUnit\Framework\MockObject\MockObject;
@@ -236,4 +237,68 @@ class MessageMapperTest extends TestCase {
300
);
}
+
+ public function testGetFlagged() {
+ /** @var Horde_Imap_Client_Socket|MockObject $imapClient */
+ $imapClient = $this->createMock(Horde_Imap_Client_Socket::class);
+ $mailbox = new Mailbox();
+ $mailbox->setName('inbox');
+ $flag = '$label1';
+ $idsObject = new Horde_Imap_Client_Ids(1);
+
+ $searchResult = [
+ 'count' => 1,
+ 'match' => $idsObject,
+ 'max' => 1,
+ 'min' => 1,
+ 'relevancy' => []
+ ];
+
+ $imapClient->expects($this->once())
+ ->method('search')
+ ->willReturn($searchResult);
+
+ $result = $this->mapper->getFlagged($imapClient, $mailbox, $flag);
+ $this->assertEquals($result, [1]);
+ }
+
+ public function testGetFlaggedNoMatches() {
+ /** @var Horde_Imap_Client_Socket|MockObject $imapClient */
+ $imapClient = $this->createMock(Horde_Imap_Client_Socket::class);
+ $mailbox = new Mailbox();
+ $mailbox->setName('inbox');
+ $flag = '$label1';
+
+ $searchResult = [
+ 'count' => 0,
+ 'match' => [],
+ 'max' => 0,
+ 'min' => 0,
+ 'relevancy' => []
+ ];
+
+ $imapClient->expects($this->once())
+ ->method('search')
+ ->willReturn($searchResult);
+
+ $result = $this->mapper->getFlagged($imapClient, $mailbox, $flag);
+ $this->assertEquals($result, []);
+ }
+
+ public function testGetFlaggedSearchResultUnexpectedStructure() {
+ /** @var Horde_Imap_Client_Socket|MockObject $imapClient */
+ $imapClient = $this->createMock(Horde_Imap_Client_Socket::class);
+ $mailbox = new Mailbox();
+ $mailbox->setName('inbox');
+ $flag = '$label1';
+
+ $searchResult = [[]];
+
+ $imapClient->expects($this->once())
+ ->method('search')
+ ->willReturn($searchResult);
+
+ $result = $this->mapper->getFlagged($imapClient, $mailbox, $flag);
+ $this->assertEquals($result, []);
+ }
}
diff --git a/tests/Unit/Job/TestMigrateImportantJob.php b/tests/Unit/Job/TestMigrateImportantJob.php
new file mode 100644
index 000000000..095625065
--- /dev/null
+++ b/tests/Unit/Job/TestMigrateImportantJob.php
@@ -0,0 +1,322 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @author Anna Larch <anna.larch@nextcloud.com>
+ *
+ * Mail
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\Mail\Tests\Unit\Job;
+
+use ChristophWurst\Nextcloud\Testing\TestCase;
+use OCA\Mail\Account;
+use OCA\Mail\BackgroundJob\MigrateImportantJob;
+use OCA\Mail\Db\MailAccount;
+use OCA\Mail\Db\MailAccountMapper;
+use OCA\Mail\Db\Mailbox;
+use OCA\Mail\Db\MailboxMapper;
+use OCA\Mail\Exception\ServiceException;
+use OCA\Mail\Migration\MigrateImportantFromImapAndDb;
+use OCA\Mail\Service\MailManager;
+use OCA\Mail\Tests\Integration\Framework\ImapTest;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\IJobList;
+use PHPUnit\Framework\MockObject\MockObject;
+use Psr\Log\LoggerInterface;
+
+class TestMigrateImportantJob extends TestCase {
+ use ImapTest;
+
+ /** @var MailboxMapper|MockObject */
+ private $mailboxMapper;
+
+ /** @var MailAccountMapper|MockObject */
+ private $mailAccountMapper;
+
+ /** @var MailManager|MockObject */
+ private $mailManager;
+
+ /** @var MigrateImportantFromImapAndDb|MockObject */
+ private $migration;
+
+ /** @var LoggerInterface|MockObject */
+ private $logger;
+
+ /** @var IJobList|MockObject */
+ private $jobList;
+
+ /** @var MigrateImportantJob */
+ private $job;
+
+ /** @var [] */
+ private static $argument;
+
+ protected function setUp(): void {
+ parent::setUp();
+ $this->mailboxMapper = $this->createMock(MailboxMapper::class);
+ $this->mailAccountMapper = $this->createMock(MailAccountMapper::class);
+ $this->mailManager = $this->createMock(MailManager::class);
+ $this->migration = $this->createMock(MigrateImportantFromImapAndDb::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->jobList = $this->createMock(IJobList::class);
+
+ $this->job = new MigrateImportantJob(
+ $this->mailboxMapper,
+ $this->mailAccountMapper,
+ $this->mailManager,
+ $this->migration,
+ $this->logger,
+ $this->jobList,
+ $this->createMock(ITimeFactory::class)
+ );
+
+ self::$argument = ['mailboxId' => 1];
+ }
+
+ public function testRun() {
+ $mailbox = new Mailbox();
+ $mailbox->setId(self::$argument['mailboxId']);
+ $mailbox->setName('INBOX');
+ $mailbox->setAccountId(1);
+ $mailAccount = new MailAccount();
+ $account = new Account($mailAccount);
+
+ $this->mailboxMapper->expects($this->once())
+ ->method('findById')
+ ->with(self::$argument['mailboxId'])
+ ->willReturn($mailbox);
+ $this->mailAccountMapper->expects($this->once())
+ ->method('findById')
+ ->with($mailbox->getAccountId())
+ ->willReturn($mailAccount);
+ $this->mailManager->expects($this->once())
+ ->method('isPermflagsEnabled')
+ ->with($account, $mailbox->getName())
+ ->willReturn(true);
+ $this->migration->expects($this->once())
+ ->method('migrateImportantOnImap')
+ ->with($account, $mailbox);
+ $this->migration->expects($this->once())
+ ->method('migrateImportantFromDb')
+ ->with($account, $mailbox);
+ $this->jobList->expects($this->never())
+ ->method('remove');
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->job->run(self::$argument);
+ }
+
+ public function testRunNoMailbox() {
+ $e = new DoesNotExistException('does not exist');
+
+ $this->mailboxMapper->expects($this->once())
+ ->method('findById')
+ ->with(self::$argument['mailboxId'])
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not find mailbox <' . self::$argument['mailboxId'] . '>, removing from jobs');
+ $this->jobList->expects($this->once())
+ ->method('remove')
+ ->with(MigrateImportantJob::class, self::$argument);
+ $this->mailAccountMapper->expects($this->never())
+ ->method('findById');
+ $this->mailManager->expects($this->never())
+ ->method('isPermflagsEnabled');
+ $this->migration->expects($this->never())
+ ->method('migrateImportantOnImap');
+ $this->migration->expects($this->never())
+ ->method('migrateImportantFromDb');
+
+ $this->job->run(self::$argument);
+ }
+
+ public function testRunNoAccount() {
+ $mailbox = new Mailbox();
+ $mailbox->setId(self::$argument['mailboxId']);
+ $mailbox->setName('INBOX');
+ $mailbox->setAccountId(1);
+ $e = new DoesNotExistException('does not exist');
+
+ $this->mailboxMapper->expects($this->once())
+ ->method('findById')
+ ->with(self::$argument['mailboxId'])
+ ->willReturn($mailbox);
+ $this->mailAccountMapper->expects($this->once())
+ ->method('findById')
+ ->with($mailbox->getAccountId())
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not find account <' . $mailbox->getAccountId() . '>, removing from jobs');
+ $this->jobList->expects($this->once())
+ ->method('remove')
+ ->with(MigrateImportantJob::class, self::$argument);
+ $this->mailManager->expects($this->never())
+ ->method('isPermflagsEnabled');
+ $this->migration->expects($this->never())
+ ->method('migrateImportantOnImap');
+ $this->migration->expects($this->never())
+ ->method('migrateImportantFromDb');
+
+ $this->job->run(self::$argument);
+ }
+
+ public function testNoPermflags() {
+ $mailbox = new Mailbox();
+ $mailbox->setId(self::$argument['mailboxId']);
+ $mailbox->setName('INBOX');
+ $mailbox->setAccountId(1);
+ $mailAccount = new MailAccount();
+ $account = new Account($mailAccount);
+
+ $this->mailboxMapper->expects($this->once())
+ ->method('findById')
+ ->with(self::$argument['mailboxId'])
+ ->willReturn($mailbox);
+ $this->mailAccountMapper->expects($this->once())
+ ->method('findById')
+ ->with($mailbox->getAccountId())
+ ->willReturn($mailAccount);
+ $this->mailManager->expects($this->once())
+ ->method('isPermflagsEnabled')
+ ->with($account, $mailbox->getName())
+ ->willReturn(false);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Permflags not enabled for <' . $mailbox->getAccountId() . '>, removing from jobs');
+ $this->jobList->expects($this->once())
+ ->method('remove')
+ ->with(MigrateImportantJob::class, self::$argument);
+
+ $this->job->run(self::$argument);
+ }
+
+ public function testErrorOnMigrateOnImap() {
+ $mailbox = new Mailbox();
+ $mailbox->setId(self::$argument['mailboxId']);
+ $mailbox->setName('INBOX');
+ $mailbox->setAccountId(1);
+ $mailAccount = new MailAccount();
+ $account = new Account($mailAccount);
+ $e = new ServiceException('');
+
+ $this->mailboxMapper->expects($this->once())
+ ->method('findById')
+ ->with(self::$argument['mailboxId'])
+ ->willReturn($mailbox);
+ $this->mailAccountMapper->expects($this->once())
+ ->method('findById')
+ ->with($mailbox->getAccountId())
+ ->willReturn($mailAccount);
+ $this->mailManager->expects($this->once())
+ ->method('isPermflagsEnabled')
+ ->with($account, $mailbox->getName())
+ ->willReturn(true);
+ $this->migration->expects($this->once())
+ ->method('migrateImportantOnImap')
+ ->with($account, $mailbox)
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not flag messages on IMAP for mailbox <' . $mailbox->getId() . '>.');
+ $this->migration->expects($this->once())
+ ->method('migrateImportantFromDb')
+ ->with($account, $mailbox);
+ $this->jobList->expects($this->never())
+ ->method('remove');
+
+ $this->job->run(self::$argument);
+ }
+
+ public function testErrorOnMigrateDbToImap() {
+ $mailbox = new Mailbox();
+ $mailbox->setId(self::$argument['mailboxId']);
+ $mailbox->setName('INBOX');
+ $mailbox->setAccountId(1);
+ $mailAccount = new MailAccount();
+ $account = new Account($mailAccount);
+ $e = new ServiceException('');
+
+ $this->mailboxMapper->expects($this->once())
+ ->method('findById')
+ ->with(self::$argument['mailboxId'])
+ ->willReturn($mailbox);
+ $this->mailAccountMapper->expects($this->once())
+ ->method('findById')
+ ->with($mailbox->getAccountId())
+ ->willReturn($mailAccount);
+ $this->mailManager->expects($this->once())
+ ->method('isPermflagsEnabled')
+ ->with($account, $mailbox->getName())
+ ->willReturn(true);
+ $this->migration->expects($this->once())
+ ->method('migrateImportantOnImap')
+ ->with($account, $mailbox);
+ $this->migration->expects($this->once())
+ ->method('migrateImportantFromDb')
+ ->with($account, $mailbox)
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not flag messages from DB on IMAP for mailbox <' . $mailbox->getId() . '>.');
+ $this->jobList->expects($this->never())
+ ->method('remove');
+
+ $this->job->run(self::$argument);
+ }
+
+ public function testErrorOnOnBoth() {
+ $mailbox = new Mailbox();
+ $mailbox->setId(self::$argument['mailboxId']);
+ $mailbox->setName('INBOX');
+ $mailbox->setAccountId(1);
+ $mailAccount = new MailAccount();
+ $account = new Account($mailAccount);
+ $e = new ServiceException('');
+
+ $this->mailboxMapper->expects($this->once())
+ ->method('findById')
+ ->with(self::$argument['mailboxId'])
+ ->willReturn($mailbox);
+ $this->mailAccountMapper->expects($this->once())
+ ->method('findById')
+ ->with($mailbox->getAccountId())
+ ->willReturn($mailAccount);
+ $this->mailManager->expects($this->once())
+ ->method('isPermflagsEnabled')
+ ->with($account, $mailbox->getName())
+ ->willReturn(true);
+ $this->migration->expects($this->once())
+ ->method('migrateImportantOnImap')
+ ->with($account, $mailbox)
+ ->willThrowException($e);
+ $this->migration->expects($this->once())
+ ->method('migrateImportantFromDb')
+ ->with($account, $mailbox)
+ ->willThrowException($e);
+ $this->logger->expects($this->exactly(2))
+ ->method('debug');
+ $this->jobList->expects($this->never())
+ ->method('remove');
+
+ $this->job->run(self::$argument);
+ }
+}
diff --git a/tests/Unit/Listener/DeleteDraftListenerTest.php b/tests/Unit/Listener/DeleteDraftListenerTest.php
index 96503bdf2..fef2852f6 100644
--- a/tests/Unit/Listener/DeleteDraftListenerTest.php
+++ b/tests/Unit/Listener/DeleteDraftListenerTest.php
@@ -238,7 +238,7 @@ class DeleteDraftListenerTest extends TestCase {
->with(
$client,
$mailbox,
- $uid,
+ [$uid],
\Horde_Imap_Client::FLAG_DELETED
);
$client->expects($this->once())
diff --git a/tests/Unit/Listener/FlagRepliedMessageListenerTest.php b/tests/Unit/Listener/FlagRepliedMessageListenerTest.php
index 76433984d..20756a3d9 100644
--- a/tests/Unit/Listener/FlagRepliedMessageListenerTest.php
+++ b/tests/Unit/Listener/FlagRepliedMessageListenerTest.php
@@ -150,7 +150,7 @@ class FlagRepliedMessageListenerTest extends TestCase {
->with(
$client,
$mailbox,
- 321,
+ [321],
\Horde_Imap_Client::FLAG_ANSWERED
);
$this->logger->expects($this->never())
diff --git a/tests/Unit/Migration/MigrateImportantFromImapAndDbTest.php b/tests/Unit/Migration/MigrateImportantFromImapAndDbTest.php
new file mode 100644
index 000000000..58b799000
--- /dev/null
+++ b/tests/Unit/Migration/MigrateImportantFromImapAndDbTest.php
@@ -0,0 +1,239 @@
+<?php
+
+/**
+ * @copyright 2021 Anna Larch <anna.larch@nextcloud.com>
+ *
+ * @author 2021 Anna Larch <anna.larch@nextcloud.com>
+ *
+ * @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\Tests\Unit\Migration;
+
+use ChristophWurst\Nextcloud\Testing\TestCase;
+use Horde_Imap_Client_Exception;
+use Horde_Imap_Client_Socket;
+use OCA\Mail\Account;
+use OCA\Mail\Db\Mailbox;
+use OCA\Mail\Db\MailboxMapper;
+use OCA\Mail\IMAP\MessageMapper;
+use OCA\Mail\Db\Tag;
+use OCA\Mail\Exception\ServiceException;
+use OCA\Mail\IMAP\IMAPClientFactory;
+use OCA\Mail\Migration\MigrateImportantFromImapAndDb;
+use Psr\Log\LoggerInterface;
+
+class MigrateImportantFromImapAndDbTest extends TestCase {
+
+ /** @var MockObject */
+ private $clientFactory;
+
+ /** @var MockObject */
+ private $client;
+
+ /** @var MockObject */
+ private $messageMapper;
+
+ /** @var MockObject */
+ private $mailboxMapper;
+
+ /** @var MockObject */
+ private $logger;
+
+ /** @var MigrateImportantFromImapAndDb */
+ private $migration;
+
+ protected function setUp(): void {
+ $this->clientFactory = $this->createMock(IMAPClientFactory::class);
+ $this->client = $this->createMock(Horde_Imap_Client_Socket::class);
+ $this->messageMapper = $this->createMock(MessageMapper::class);
+ $this->mailboxMapper = $this->createMock(MailboxMapper::class);
+ $this->logger = $this->createMock(LoggerInterface::class);
+ $this->migration = new MigrateImportantFromImapAndDb(
+ $this->clientFactory,
+ $this->messageMapper,
+ $this->mailboxMapper,
+ $this->logger
+ );
+ parent::setUp();
+ }
+
+ public function testMigrateImportantOnImap() {
+ $account = $this->createMock(Account::class);
+ $mailbox = $this->createMock(Mailbox::class);
+ $uids = [1,2,3];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT);
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function testMigrateImportantOnImapNoUids() {
+ $account = $this->createMock(Account::class);
+ $mailbox = $this->createMock(Mailbox::class);
+ $uids = [];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->never())
+ ->method('addFlag');
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function testMigrateImportantOnImapExceptionGetFlagged() {
+ $account = $this->createMock(Account::class);
+ $mailbox = $this->createMock(Mailbox::class);
+ $e = new Horde_Imap_Client_Exception('');
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willThrowException($e);
+ $this->messageMapper->expects($this->never())
+ ->method('addFlag');
+ $this->logger->expects($this->never())
+ ->method('debug');
+ $this->expectException(ServiceException::class);
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function testMigrateImportantOnImapExceptionOnFlag() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setName('INBOX');
+ $e = new Horde_Imap_Client_Exception('');
+ $uids = [1,2,3];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->messageMapper->expects($this->once())
+ ->method('getFlagged')
+ ->with($this->client, $mailbox, '$important')
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT)
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not flag messages in mailbox <' . $mailbox->getId() . '>');
+ $this->expectException(ServiceException::class);
+
+ $this->migration->migrateImportantOnImap($account, $mailbox);
+ }
+
+ public function migrateImportantFromDb() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setId(1);
+ $uids = [1,2,3];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->mailboxMapper->expects($this->once())
+ ->method('findFlaggedImportantUids')
+ ->with($mailbox->getId())
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT);
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantFromDb($account, $mailbox);
+ }
+
+ public function testMigrateImportantFromDbNoUids() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setId(1);
+ $uids = [];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->mailboxMapper->expects($this->once())
+ ->method('findFlaggedImportantUids')
+ ->with($mailbox->getId())
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->never())
+ ->method('addFlag');
+ $this->logger->expects($this->never())
+ ->method('debug');
+
+ $this->migration->migrateImportantFromDb($account, $mailbox);
+ }
+
+ public function testMigrateImportantFromDbExceptionOnFlag() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setId(1);
+ $mailbox->setName('INBOX');
+ $e = new Horde_Imap_Client_Exception('');
+ $uids = [1,2,3];
+
+ $this->clientFactory->expects($this->once())
+ ->method('getClient')
+ ->with($account)
+ ->willReturn($this->client);
+ $this->mailboxMapper->expects($this->once())
+ ->method('findFlaggedImportantUids')
+ ->with($mailbox->getId())
+ ->willReturn($uids);
+ $this->messageMapper->expects($this->once())
+ ->method('addFlag')
+ ->with($this->client, $mailbox, $uids, Tag::LABEL_IMPORTANT)
+ ->willThrowException($e);
+ $this->logger->expects($this->once())
+ ->method('debug')
+ ->with('Could not flag messages in mailbox <' . $mailbox->getId() . '>');
+ $this->expectException(ServiceException::class);
+
+ $this->migration->migrateImportantFromDb($account, $mailbox);
+ }
+}
diff --git a/tests/Unit/Service/MailManagerTest.php b/tests/Unit/Service/MailManagerTest.php
index f42b586d7..3557027a1 100644
--- a/tests/Unit/Service/MailManagerTest.php
+++ b/tests/Unit/Service/MailManagerTest.php
@@ -422,7 +422,7 @@ class MailManagerTest extends TestCase {
->method('addFlag');
$this->imapMessageMapper->expects($this->once())
->method('removeFlag')
- ->with($client, $mb, 123, '\\seen');
+ ->with($client, $mb, [123], '\\seen');
$this->manager->flagMessage($account, 'INBOX', 123, 'seen', false);
}
@@ -448,7 +448,7 @@ class MailManagerTest extends TestCase {
->willReturn(['permflags' => [ "11" => "\*"] ]);
$this->imapMessageMapper->expects($this->once())
->method('addFlag')
- ->with($client, $mb, 123, Tag::LABEL_IMPORTANT);
+ ->with($client, $mb, [123], Tag::LABEL_IMPORTANT);
$account->expects($this->once())
->method('getUserId')
->willReturn('test');
@@ -476,7 +476,7 @@ class MailManagerTest extends TestCase {
->willReturn(['permflags' => [ "11" => "\*"] ]);
$this->imapMessageMapper->expects($this->once())
->method('removeFlag')
- ->with($client, $mb, 123, Tag::LABEL_IMPORTANT);
+ ->with($client, $mb, [123], Tag::LABEL_IMPORTANT);
$this->imapMessageMapper->expects($this->never())
->method('addFlag');
$account->expects($this->never())