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:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2020-02-03 16:51:51 +0300
committerChristoph Wurst <christoph@winzerhof-wurst.at>2020-02-03 22:24:27 +0300
commit6d2d36a1982f851aead5acb7a861601e7881ccae (patch)
treecff597c6126f2e6d0fcff1be88d29f98ca5399cb
parent70962a95ac6bf61079976c13380d809ef754ef6a (diff)
Detect missing mailbox cache and block access to messages
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
-rw-r--r--lib/Contracts/IMailSearch.php2
-rw-r--r--lib/Controller/FoldersController.php7
-rwxr-xr-xlib/Controller/MessagesController.php13
-rw-r--r--lib/Db/Mailbox.php12
-rw-r--r--lib/Db/MailboxMapper.php14
-rw-r--r--lib/Exception/ClientException.php5
-rw-r--r--lib/Exception/MailboxLockedException.php (renamed from lib/Exception/ConcurrentSyncException.php)13
-rw-r--r--lib/Exception/MailboxNotCachedException.php8
-rw-r--r--lib/Http/JsonResponse.php13
-rw-r--r--lib/Http/Middleware/ErrorMiddleware.php4
-rw-r--r--lib/Service/Search/MailSearch.php11
-rw-r--r--lib/Service/SyncService.php116
-rw-r--r--src/components/FolderContent.vue49
-rw-r--r--src/service/MessageService.js24
-rw-r--r--src/store/actions.js5
-rw-r--r--tests/Unit/Controller/MessagesControllerTest.php6
-rw-r--r--tests/Unit/Service/MailSearchTest.php45
17 files changed, 244 insertions, 103 deletions
diff --git a/lib/Contracts/IMailSearch.php b/lib/Contracts/IMailSearch.php
index 43299907c..ac2a82d3b 100644
--- a/lib/Contracts/IMailSearch.php
+++ b/lib/Contracts/IMailSearch.php
@@ -24,6 +24,7 @@
namespace OCA\Mail\Contracts;
use OCA\Mail\Account;
+use OCA\Mail\Exception\ClientException;
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\Model\IMAPMessage;
@@ -36,6 +37,7 @@ interface IMailSearch {
* @param string|null $cursor
*
* @return IMAPMessage[]
+ * @throws ClientException
* @throws ServiceException
*/
public function findMessages(Account $account, string $mailboxName, ?string $filter, ?int $cursor): array;
diff --git a/lib/Controller/FoldersController.php b/lib/Controller/FoldersController.php
index 3caa7c051..96442b68f 100644
--- a/lib/Controller/FoldersController.php
+++ b/lib/Controller/FoldersController.php
@@ -26,6 +26,7 @@ declare(strict_types=1);
namespace OCA\Mail\Controller;
use Horde_Imap_Client;
+use OCA\Mail\Exception\ClientException;
use OCA\Mail\Exception\MailboxNotCachedException;
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\Service\SyncService;
@@ -102,10 +103,12 @@ class FoldersController extends Controller {
* @param string $folderId
* @param string $syncToken
* @param int[] $uids
+ *
* @return JSONResponse
+ * @throws ClientException
* @throws ServiceException
*/
- public function sync(int $accountId, string $folderId, array $uids = []): JSONResponse {
+ public function sync(int $accountId, string $folderId, array $uids = [], bool $init = false): JSONResponse {
$account = $this->accountService->find($this->currentUserId, $accountId);
if (empty($accountId) || empty($folderId) || !is_array($uids)) {
@@ -120,7 +123,7 @@ class FoldersController extends Controller {
array_map(function($uid) {
return (int) $uid;
}, $uids),
- true
+ !$init
);
} catch (MailboxNotCachedException $e) {
return new JSONResponse(null, Http::STATUS_PRECONDITION_REQUIRED);
diff --git a/lib/Controller/MessagesController.php b/lib/Controller/MessagesController.php
index 7e075621e..9a6fc82de 100755
--- a/lib/Controller/MessagesController.php
+++ b/lib/Controller/MessagesController.php
@@ -33,6 +33,7 @@ namespace OCA\Mail\Controller;
use Exception;
use OCA\Mail\Contracts\IMailManager;
use OCA\Mail\Contracts\IMailSearch;
+use OCA\Mail\Exception\ClientException;
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\Http\AttachmentDownloadResponse;
use OCA\Mail\Http\HtmlResponse;
@@ -40,7 +41,6 @@ use OCA\Mail\Model\IMAPMessage;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\IMailBox;
use OCA\Mail\Service\ItineraryService;
-use OCA\Mail\Service\SyncService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
@@ -70,9 +70,6 @@ class MessagesController extends Controller {
/** @var ItineraryService */
private $itineraryService;
- /** @var SyncService */
- private $syncService;
-
/** @var string */
private $currentUserId;
@@ -108,7 +105,6 @@ class MessagesController extends Controller {
IMailManager $mailManager,
IMailSearch $mailSearch,
ItineraryService $itineraryService,
- SyncService $syncService,
string $UserId,
$userFolder,
ILogger $logger,
@@ -121,7 +117,6 @@ class MessagesController extends Controller {
$this->mailManager = $mailManager;
$this->mailSearch = $mailSearch;
$this->itineraryService = $itineraryService;
- $this->syncService = $syncService;
$this->currentUserId = $UserId;
$this->userFolder = $userFolder;
$this->logger = $logger;
@@ -141,6 +136,7 @@ class MessagesController extends Controller {
* @param string $filter
*
* @return JSONResponse
+ * @throws ClientException
* @throws ServiceException
*/
public function index(int $accountId, string $folderId, int $cursor = null, string $filter = null): JSONResponse {
@@ -150,11 +146,6 @@ class MessagesController extends Controller {
return new JSONResponse(null, Http::STATUS_FORBIDDEN);
}
- $this->syncService->ensurePopulated(
- $account,
- base64_decode($folderId)
- );
-
$this->logger->debug("loading messages of folder <$folderId>");
return new JSONResponse(
diff --git a/lib/Db/Mailbox.php b/lib/Db/Mailbox.php
index c09b3981a..772ad641e 100644
--- a/lib/Db/Mailbox.php
+++ b/lib/Db/Mailbox.php
@@ -127,4 +127,16 @@ class Mailbox extends Entity {
return $this->getName();
}
+ public function isCached(): bool {
+ return $this->getSyncNewToken() !== null
+ && $this->getSyncChangedToken() !== null
+ && $this->getSyncVanishedToken() !== null;
+ }
+
+ public function hasLocks(): bool {
+ return $this->getSyncNewLock() !== null
+ || $this->getSyncChangedLock() !== null
+ || $this->getSyncVanishedLock() !== null;
+ }
+
}
diff --git a/lib/Db/MailboxMapper.php b/lib/Db/MailboxMapper.php
index 3acbde53b..6fcb527c5 100644
--- a/lib/Db/MailboxMapper.php
+++ b/lib/Db/MailboxMapper.php
@@ -24,7 +24,7 @@
namespace OCA\Mail\Db;
use OCA\Mail\Account;
-use OCA\Mail\Exception\ConcurrentSyncException;
+use OCA\Mail\Exception\MailboxLockedException;
use OCA\Mail\Exception\ServiceException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
@@ -109,7 +109,7 @@ class MailboxMapper extends QBMapper {
}
/**
- * @throws ConcurrentSyncException
+ * @throws MailboxLockedException
*/
private function lockForSync(Mailbox $mailbox, string $attr, ?int $lock): int {
$now = $this->timeFactory->getTime();
@@ -117,7 +117,7 @@ class MailboxMapper extends QBMapper {
if ($lock !== null
&& $lock > ($now - 5 * 60)) {
// Another process is syncing
- throw new ConcurrentSyncException($mailbox->getId() . ' is already being synced');
+ throw MailboxLockedException::from($mailbox);
}
$query = $this->db->getQueryBuilder();
@@ -130,14 +130,14 @@ class MailboxMapper extends QBMapper {
if ($query->execute() === 0) {
// Another process just started syncing
- throw new ConcurrentSyncException();
+ throw MailboxLockedException::from($mailbox);
}
return $now;
}
/**
- * @throws ConcurrentSyncException
+ * @throws MailboxLockedException
*/
public function lockForNewSync(Mailbox $mailbox): void {
$mailbox->setSyncNewLock(
@@ -146,7 +146,7 @@ class MailboxMapper extends QBMapper {
}
/**
- * @throws ConcurrentSyncException
+ * @throws MailboxLockedException
*/
public function lockForChangeSync(Mailbox $mailbox): void {
$mailbox->setSyncChangedLock(
@@ -155,7 +155,7 @@ class MailboxMapper extends QBMapper {
}
/**
- * @throws ConcurrentSyncException
+ * @throws MailboxLockedException
*/
public function lockForVanishedSync(Mailbox $mailbox): void {
$mailbox->setSyncVanishedLock(
diff --git a/lib/Exception/ClientException.php b/lib/Exception/ClientException.php
index b2f212512..3619ee04d 100644
--- a/lib/Exception/ClientException.php
+++ b/lib/Exception/ClientException.php
@@ -27,7 +27,12 @@ declare(strict_types=1);
namespace OCA\Mail\Exception;
use Exception;
+use OCP\AppFramework\Http;
class ClientException extends Exception {
+ public function getHttpCode(): int {
+ return Http::STATUS_BAD_REQUEST;
+ }
+
}
diff --git a/lib/Exception/ConcurrentSyncException.php b/lib/Exception/MailboxLockedException.php
index 7cc91136d..8f66e50af 100644
--- a/lib/Exception/ConcurrentSyncException.php
+++ b/lib/Exception/MailboxLockedException.php
@@ -23,8 +23,17 @@
namespace OCA\Mail\Exception;
-use Exception;
+use OCA\Mail\Db\Mailbox;
+use OCP\AppFramework\Http;
-class ConcurrentSyncException extends Exception {
+class MailboxLockedException extends ClientException {
+
+ public static function from(Mailbox $mailbox): self {
+ return new self($mailbox->getId() . ' is already being synced');
+ }
+
+ public function getHttpCode(): int {
+ return Http::STATUS_CONFLICT;
+ }
}
diff --git a/lib/Exception/MailboxNotCachedException.php b/lib/Exception/MailboxNotCachedException.php
index 37242b1ad..728700c92 100644
--- a/lib/Exception/MailboxNotCachedException.php
+++ b/lib/Exception/MailboxNotCachedException.php
@@ -2,6 +2,12 @@
namespace OCA\Mail\Exception;
-class MailboxNotCachedException extends ServiceException {
+use OCA\Mail\Db\Mailbox;
+
+class MailboxNotCachedException extends ClientException {
+
+ public static function from(Mailbox $mailbox): self {
+ return new self("mailbox {$mailbox->getId()} is not cached");
+ }
}
diff --git a/lib/Http/JsonResponse.php b/lib/Http/JsonResponse.php
index c647e5089..8c5cc9396 100644
--- a/lib/Http/JsonResponse.php
+++ b/lib/Http/JsonResponse.php
@@ -25,6 +25,7 @@ declare(strict_types=1);
namespace OCA\Mail\Http;
+use OCA\Mail\Exception\ClientException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse as Base;
use Throwable;
@@ -40,7 +41,7 @@ use function get_class;
class JsonResponse extends Base {
public function __construct($data = [],
- int $statusCode = Http::STATUS_OK) {
+ int $statusCode = Http::STATUS_OK) {
parent::__construct($data, $statusCode);
$this->addHeader('x-mail-response', 'true');
@@ -68,6 +69,16 @@ class JsonResponse extends Base {
);
}
+ public static function failWith(ClientException $exception): self {
+ return self::fail(
+ [
+ 'message' => $exception->getMessage(),
+ 'type' => get_class($exception),
+ ],
+ $exception->getHttpCode()
+ );
+ }
+
public static function error(string $message,
int $status = Http::STATUS_INTERNAL_SERVER_ERROR,
array $data = [],
diff --git a/lib/Http/Middleware/ErrorMiddleware.php b/lib/Http/Middleware/ErrorMiddleware.php
index 07fd4130e..3890faaa6 100644
--- a/lib/Http/Middleware/ErrorMiddleware.php
+++ b/lib/Http/Middleware/ErrorMiddleware.php
@@ -76,9 +76,7 @@ class ErrorMiddleware extends Middleware {
}
if ($exception instanceof ClientException) {
- return JsonResponse::fail([
- 'message' => $exception->getMessage()
- ]);
+ return JsonResponse::failWith($exception);
}
if ($exception instanceof DoesNotExistException) {
diff --git a/lib/Service/Search/MailSearch.php b/lib/Service/Search/MailSearch.php
index 1927af9aa..290f1fb1c 100644
--- a/lib/Service/Search/MailSearch.php
+++ b/lib/Service/Search/MailSearch.php
@@ -30,6 +30,9 @@ use OCA\Mail\Db\Mailbox;
use OCA\Mail\Db\MailboxMapper;
use OCA\Mail\Db\Message;
use OCA\Mail\Db\MessageMapper;
+use OCA\Mail\Exception\ClientException;
+use OCA\Mail\Exception\MailboxLockedException;
+use OCA\Mail\Exception\MailboxNotCachedException;
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\IMAP\Search\Provider as ImapSearchProvider;
use OCP\AppFramework\Db\DoesNotExistException;
@@ -71,6 +74,7 @@ class MailSearch implements IMailSearch {
* @param string|null $cursor
*
* @return Message[]
+ * @throws ClientException
* @throws ServiceException
*/
public function findMessages(Account $account,
@@ -83,6 +87,13 @@ class MailSearch implements IMailSearch {
throw new ServiceException('Mailbox does not exist', 0, $e);
}
+ if ($mailbox->hasLocks()) {
+ throw MailboxLockedException::from($mailbox);
+ }
+ if (!$mailbox->isCached()) {
+ throw MailboxNotCachedException::from($mailbox);
+ }
+
$query = $this->filterStringParser->parse($filter);
if ($cursor !== null) {
$query->setCursor($cursor);
diff --git a/lib/Service/SyncService.php b/lib/Service/SyncService.php
index 6a084a575..b99caf1c3 100644
--- a/lib/Service/SyncService.php
+++ b/lib/Service/SyncService.php
@@ -32,7 +32,8 @@ use OCA\Mail\Db\MailboxMapper;
use OCA\Mail\Db\Message;
use OCA\Mail\Db\MessageMapper;
use OCA\Mail\Db\MessageMapper as DatabaseMessageMapper;
-use OCA\Mail\Exception\ConcurrentSyncException;
+use OCA\Mail\Exception\ClientException;
+use OCA\Mail\Exception\MailboxLockedException;
use OCA\Mail\Exception\MailboxNotCachedException;
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\IMAP\IMAPClientFactory;
@@ -51,6 +52,57 @@ use function array_map;
class SyncService {
+ /**
+ * @param int[] $knownUids
+ *
+ * @throws ClientException
+ * @throws ServiceException
+ */
+ private function sync(Account $account,
+ Mailbox $mailbox,
+ int $criteria,
+ array $knownUids = null,
+ bool $force = false): Response {
+ if ($mailbox->getSelectable() === false) {
+ return new Response();
+ }
+
+ if ($criteria & Horde_Imap_Client::SYNC_NEWMSGSUIDS) {
+ $this->mailboxMapper->lockForNewSync($mailbox);
+ }
+ if ($criteria & Horde_Imap_Client::SYNC_FLAGSUIDS) {
+ $this->mailboxMapper->lockForChangeSync($mailbox);
+ }
+ if ($criteria & Horde_Imap_Client::SYNC_VANISHEDUIDS) {
+ $this->mailboxMapper->lockForVanishedSync($mailbox);
+ }
+
+ try {
+ if ($force
+ || $mailbox->getSyncNewToken() === null
+ || $mailbox->getSyncChangedToken() === null
+ || $mailbox->getSyncVanishedToken() === null) {
+ $response = $this->runInitialSync($account, $mailbox);
+ } else {
+ $response = $this->runPartialSync($account, $mailbox, $criteria, $knownUids);
+ }
+ } catch (Throwable $e) {
+ throw new ServiceException('Sync failed', 0, $e);
+ } finally {
+ if ($criteria & Horde_Imap_Client::SYNC_VANISHEDUIDS) {
+ $this->mailboxMapper->unlockFromVanishedSync($mailbox);
+ }
+ if ($criteria & Horde_Imap_Client::SYNC_FLAGSUIDS) {
+ $this->mailboxMapper->unlockFromChangedSync($mailbox);
+ }
+ if ($criteria & Horde_Imap_Client::SYNC_NEWMSGSUIDS) {
+ $this->mailboxMapper->unlockFromNewSync($mailbox);
+ }
+ }
+
+ return $response;
+ }
+
/** @var DatabaseMessageMapper */
private $dbMapper;
@@ -94,6 +146,7 @@ class SyncService {
}
/**
+ * @throws ClientException
* @throws ServiceException
*/
public function syncAccount(Account $account,
@@ -113,6 +166,7 @@ class SyncService {
/**
* @param int[] $knownUids
*
+ * @throws ClientException
* @throws ServiceException
*/
public function syncMailbox(Account $account,
@@ -123,8 +177,8 @@ class SyncService {
try {
$mb = $this->mailboxMapper->find($account, $mailbox);
- if ($partialOnly && $mb->getSyncNewToken() === null) {
- throw new MailboxNotCachedException();
+ if ($partialOnly && !$mb->isCached()) {
+ throw MailboxNotCachedException::from($mb);
}
return $this->sync(
@@ -158,7 +212,7 @@ class SyncService {
$this->mailboxMapper->lockForVanishedSync($mb);
$this->runInitialSync($account, $mb);
- } catch (ConcurrentSyncException $e) {
+ } catch (MailboxLockedException $e) {
// Fine, then we don't have to do it
} finally {
$this->mailboxMapper->unlockFromNewSync($mb);
@@ -168,60 +222,6 @@ class SyncService {
}
/**
- * @param int[] $knownUids
- *
- * @throws ServiceException
- */
- private function sync(Account $account,
- Mailbox $mailbox,
- int $criteria,
- array $knownUids = null,
- bool $force = false): Response {
- if ($mailbox->getSelectable() === false) {
- return new Response();
- }
-
- try {
- if ($criteria & Horde_Imap_Client::SYNC_NEWMSGSUIDS) {
- $this->mailboxMapper->lockForNewSync($mailbox);
- }
- if ($criteria & Horde_Imap_Client::SYNC_FLAGSUIDS) {
- $this->mailboxMapper->lockForChangeSync($mailbox);
- }
- if ($criteria & Horde_Imap_Client::SYNC_VANISHEDUIDS) {
- $this->mailboxMapper->lockForVanishedSync($mailbox);
- }
- } catch (ConcurrentSyncException $e) {
- throw new ServiceException('Another sync is in progress for ' . $mailbox->getId(), 0, $e);
- }
-
- try {
- if ($force
- || $mailbox->getSyncNewToken() === null
- || $mailbox->getSyncChangedToken() === null
- || $mailbox->getSyncVanishedToken() === null) {
- $response = $this->runInitialSync($account, $mailbox);
- } else {
- $response = $this->runPartialSync($account, $mailbox, $criteria, $knownUids);
- }
- } catch (Throwable $e) {
- throw new ServiceException('Sync failed', 0, $e);
- } finally {
- if ($criteria & Horde_Imap_Client::SYNC_VANISHEDUIDS) {
- $this->mailboxMapper->unlockFromVanishedSync($mailbox);
- }
- if ($criteria & Horde_Imap_Client::SYNC_FLAGSUIDS) {
- $this->mailboxMapper->unlockFromChangedSync($mailbox);
- }
- if ($criteria & Horde_Imap_Client::SYNC_NEWMSGSUIDS) {
- $this->mailboxMapper->unlockFromNewSync($mailbox);
- }
- }
-
- return $response;
- }
-
- /**
* @throws ServiceException
*/
private function runInitialSync(Account $account, Mailbox $mailbox): Response {
diff --git a/src/components/FolderContent.vue b/src/components/FolderContent.vue
index 78a5abdb3..23baf2631 100644
--- a/src/components/FolderContent.vue
+++ b/src/components/FolderContent.vue
@@ -2,10 +2,12 @@
<AppContent>
<AppDetailsToggle v-if="showMessage" @close="hideMessage" />
<div id="app-content-wrapper">
+ <Error v-if="error" :error="t('mail', 'Could not open mailbox')" message="" />
+ <Loading v-else-if="loadingEnvelopes" :hint="t('mail', 'Loading messages')" />
<Loading
- v-if="loading"
+ v-else-if="loadingCacheInitialization"
:hint="t('mail', 'Loading messages')"
- :slow-hint="t('mail', 'This can take a bit longer when the mailbox is accessed for the first time.')"
+ :slow-hint="t('mail', 'Indexing your messages. This can take a bit longer for larger mailboxes.')"
/>
<template v-else>
<EnvelopeList
@@ -29,6 +31,7 @@ import isMobile from '@nextcloud/vue/dist/Mixins/isMobile'
import AppDetailsToggle from './AppDetailsToggle'
import EnvelopeList from './EnvelopeList'
+import Error from './Error'
import Loading from './Loading'
import Logger from '../logger'
import Message from './Message'
@@ -41,6 +44,7 @@ export default {
AppContent,
AppDetailsToggle,
EnvelopeList,
+ Error,
Loading,
Message,
NewMessageDetail,
@@ -59,7 +63,9 @@ export default {
},
data() {
return {
- loading: true,
+ error: false,
+ loadingEnvelopes: true,
+ loadingCacheInitialization: false,
searchQuery: undefined,
alive: false,
}
@@ -94,7 +100,7 @@ export default {
$route(to, from) {
if (to.name === 'folder') {
// Navigate (back) to the folder view -> (re)fetch data
- this.fetchData()
+ this.loadEnvelopes()
}
},
},
@@ -103,14 +109,31 @@ export default {
new OCA.Search(this.searchProxy, this.clearSearchProxy)
- this.fetchData()
+ this.loadEnvelopes()
},
beforeDestroy() {
this.alive = false
},
methods: {
- fetchData() {
- this.loading = true
+ initializeCache() {
+ this.loadingCacheInitialization = true
+ this.error = false
+
+ this.$store
+ .dispatch('syncEnvelopes', {
+ accountId: this.account.id,
+ folderId: this.folder.id,
+ init: true,
+ })
+ .then(() => {
+ this.loadingCacheInitialization = false
+
+ return this.loadEnvelopes()
+ })
+ },
+ loadEnvelopes() {
+ this.loadingEnvelopes = true
+ this.error = false
this.$store
.dispatch('fetchEnvelopes', {
@@ -122,7 +145,7 @@ export default {
const envelopes = this.envelopes
Logger.debug('envelopes fetched', envelopes)
- this.loading = false
+ this.loadingEnvelopes = false
if (!this.isMobile && this.$route.name !== 'message' && envelopes.length > 0) {
// Show first message
@@ -140,6 +163,14 @@ export default {
})
}
})
+ .catch(error => {
+ if (error.name === 'MailboxNotCachedException') {
+ this.loadingEnvelopes = false
+
+ return this.initializeCache()
+ }
+ this.error = {}
+ })
},
hideMessage() {
this.$router.replace({
@@ -163,7 +194,7 @@ export default {
search(query) {
this.searchQuery = query
- this.fetchData()
+ this.loadEnvelopes()
},
clearSearch() {
this.searchQuery = undefined
diff --git a/src/service/MessageService.js b/src/service/MessageService.js
index 0b2861a70..9e2fdbfac 100644
--- a/src/service/MessageService.js
+++ b/src/service/MessageService.js
@@ -1,8 +1,17 @@
import {generateUrl} from '@nextcloud/router'
import axios from '@nextcloud/axios'
+import logger from '../logger'
import {parseErrorResponse} from '../http/ErrorResponseParser'
+export class MailboxNotCachedException extends Error {
+ constructor(message) {
+ super(message)
+ this.name = 'MailboxNotCachedException'
+ this.message = message
+ }
+}
+
export function fetchEnvelopes(accountId, folderId, query, cursor) {
const url = generateUrl('/apps/mail/api/accounts/{accountId}/folders/{folderId}/messages', {
accountId,
@@ -22,9 +31,21 @@ export function fetchEnvelopes(accountId, folderId, query, cursor) {
params: params,
})
.then(resp => resp.data)
+ .catch(error => {
+ if (
+ error.response &&
+ error.response.status === 400 &&
+ 'x-mail-response' in error.response.headers &&
+ error.response.data.data.type === 'OCA\\Mail\\Exception\\MailboxNotCachedException'
+ ) {
+ logger.debug(`mailbox ${folderId} of account ${accountId} is not cached`)
+ throw new MailboxNotCachedException()
+ }
+ throw error
+ })
}
-export function syncEnvelopes(accountId, folderId, uids) {
+export function syncEnvelopes(accountId, folderId, uids, init = false) {
const url = generateUrl('/apps/mail/api/accounts/{accountId}/folders/{folderId}/sync', {
accountId,
folderId,
@@ -34,6 +55,7 @@ export function syncEnvelopes(accountId, folderId, uids) {
.get(url, {
params: {
uids,
+ init,
},
})
.then(resp => resp.data)
diff --git a/src/store/actions.js b/src/store/actions.js
index ca5e4a321..4c09f1343 100644
--- a/src/store/actions.js
+++ b/src/store/actions.js
@@ -334,7 +334,7 @@ export default {
return envelopes
})
},
- syncEnvelopes({commit, getters, dispatch}, {accountId, folderId}) {
+ syncEnvelopes({commit, getters, dispatch}, {accountId, folderId, init = false}) {
const folder = getters.getFolder(accountId, folderId)
if (folder.isUnified) {
@@ -350,6 +350,7 @@ export default {
dispatch('syncEnvelopes', {
accountId: account.id,
folderId: folder.id,
+ init,
})
)
)
@@ -359,7 +360,7 @@ export default {
const uids = getters.getEnvelopes(accountId, folderId).map(env => env.id)
- return syncEnvelopes(accountId, folderId, uids).then(syncData => {
+ return syncEnvelopes(accountId, folderId, uids, init).then(syncData => {
const unifiedFolder = getters.getUnifiedFolder(folder.specialRole)
syncData.newMessages.forEach(envelope => {
diff --git a/tests/Unit/Controller/MessagesControllerTest.php b/tests/Unit/Controller/MessagesControllerTest.php
index 0b215c557..1178a03c4 100644
--- a/tests/Unit/Controller/MessagesControllerTest.php
+++ b/tests/Unit/Controller/MessagesControllerTest.php
@@ -38,7 +38,6 @@ use OCA\Mail\Model\Message;
use OCA\Mail\Service\AccountService;
use OCA\Mail\Service\ItineraryService;
use OCA\Mail\Service\MailManager;
-use OCA\Mail\Service\SyncService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\ContentSecurityPolicy;
@@ -72,9 +71,6 @@ class MessagesControllerTest extends TestCase {
/** @var ItineraryService|MockObject */
private $itineraryService;
- /** @var SyncService|MockObject */
- private $syncService;
-
/** @var string */
private $userId;
@@ -120,7 +116,6 @@ class MessagesControllerTest extends TestCase {
$this->mailManager = $this->createMock(IMailManager::class);
$this->mailSearch = $this->createMock(IMailSearch::class);
$this->itineraryService = $this->createMock(ItineraryService::class);
- $this->syncService = $this->createMock(SyncService::class);
$this->userId = 'john';
$this->userFolder = $this->createMock(Folder::class);
$this->request = $this->createMock(Request::class);
@@ -145,7 +140,6 @@ class MessagesControllerTest extends TestCase {
$this->mailManager,
$this->mailSearch,
$this->itineraryService,
- $this->syncService,
$this->userId,
$this->userFolder,
$this->logger,
diff --git a/tests/Unit/Service/MailSearchTest.php b/tests/Unit/Service/MailSearchTest.php
index 2b5006ef4..410ef372d 100644
--- a/tests/Unit/Service/MailSearchTest.php
+++ b/tests/Unit/Service/MailSearchTest.php
@@ -27,8 +27,11 @@ use ChristophWurst\Nextcloud\Testing\TestCase;
use Horde_Imap_Client_Fetch_Results;
use Horde_Imap_Client_Socket;
use OCA\Mail\Account;
+use OCA\Mail\Db\Mailbox;
use OCA\Mail\Db\MailboxMapper;
use OCA\Mail\Db\MessageMapper;
+use OCA\Mail\Exception\MailboxLockedException;
+use OCA\Mail\Exception\MailboxNotCachedException;
use OCA\Mail\IMAP\IMAPClientFactory;
use OCA\Mail\IMAP\Search\Provider;
use OCA\Mail\Service\Search\FilterStringParser;
@@ -74,8 +77,50 @@ class MailSearchTest extends TestCase {
);
}
+ public function testFindMessagesNotCached() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setSyncNewToken('abc');
+ $mailbox->setSyncChangedToken('def');
+ $this->mailboxMapper->expects($this->once())
+ ->method('find')
+ ->willReturn($mailbox);
+ $this->expectException(MailboxNotCachedException::class);
+
+ $messages = $this->search->findMessages(
+ $account,
+ 'INBOX',
+ null,
+ null
+ );
+ }
+
+ public function testFindMessagesLocked() {
+ $account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setSyncNewLock(123);
+ $this->mailboxMapper->expects($this->once())
+ ->method('find')
+ ->willReturn($mailbox);
+ $this->expectException(MailboxLockedException::class);
+
+ $messages = $this->search->findMessages(
+ $account,
+ 'INBOX',
+ null,
+ null
+ );
+ }
+
public function testNoFindMessages() {
$account = $this->createMock(Account::class);
+ $mailbox = new Mailbox();
+ $mailbox->setSyncNewToken('abc');
+ $mailbox->setSyncChangedToken('def');
+ $mailbox->setSyncVanishedToken('ghi');
+ $this->mailboxMapper->expects($this->once())
+ ->method('find')
+ ->willReturn($mailbox);
$messages = $this->search->findMessages(
$account,