Merge pull request #3367 from nextcloud/enhancement/threads-api

Add a REST resource to fetch a thread
This commit is contained in:
Christoph Wurst 2020-07-17 18:57:57 +02:00 коммит произвёл GitHub
Родитель e380adfc02 24d268d107
Коммит 0a7b961520
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 115 добавлений и 24 удалений

Просмотреть файл

@ -104,6 +104,11 @@ return [
'url' => '/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/html',
'verb' => 'GET'
],
[
'name' => 'messages#getThread',
'url' => '/api/accounts/{accountId}/message/{id}/thread',
'verb' => 'GET'
],
[
'name' => 'messages#setFlags',
'url' => '/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/flags',

Просмотреть файл

@ -85,6 +85,14 @@ interface IMailManager {
*/
public function getMessage(Account $account, string $mailbox, int $id, bool $loadBody = false): IMAPMessage;
/**
* @param Account $account
* @param int $messageId database message ID
*
* @return IMAPMessage[]
*/
public function getThread(Account $account, int $messageId): array;
/**
* @param Account $sourceAccount
* @param string $sourceFolderId

Просмотреть файл

@ -234,6 +234,23 @@ class MessagesController extends Controller {
return new JSONResponse($json);
}
/**
* @NoAdminRequired
* @NoCSRFRequired
* @TrapError
*
* @param int $accountId
* @param string $folderId
*
* @return JSONResponse
* @throws ClientException
*/
public function getThread(int $accountId, int $id): JSONResponse {
$account = $this->accountService->find($this->currentUserId, $accountId);
return new JSONResponse($this->mailManager->getThread($account, $id));
}
/**
* @NoAdminRequired
* @TrapError

Просмотреть файл

@ -339,6 +339,41 @@ class MessageMapper extends QBMapper {
$query->execute();
}
/**
* @param Account $account
* @param int $messageId
*
* @return Message[]
*/
public function findThread(Account $account, int $messageId): array {
$qb = $this->db->getQueryBuilder();
$subQb1 = $this->db->getQueryBuilder();
$subQb2 = $this->db->getQueryBuilder();
$mailboxIdsQuery = $subQb1
->select('id')
->from('mail_mailboxes')
->where($qb->expr()->eq('account_id', $qb->createNamedParameter($account->getId(), IQueryBuilder::PARAM_INT)));
$threadRootIdsQuery = $subQb2
->select('thread_root_id')
->from($this->getTableName())
->where(
$qb->expr()->eq('id', $qb->createNamedParameter($messageId, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT)
);
$selectMessages = $qb
->select('*')
->from($this->getTableName())
->where(
$qb->expr()->isNotNull('thread_root_id'),
$qb->expr()->in('thread_root_id', $qb->createFunction($threadRootIdsQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY),
$qb->expr()->in('mailbox_id', $qb->createFunction($mailboxIdsQuery->getSQL()), IQueryBuilder::PARAM_INT_ARRAY)
)
->orderBy('sent_at', 'desc');
return $this->findRecipients($this->findEntities($selectMessages));
}
/**
* @param Mailbox $mailbox
* @param SearchQuery $query

Просмотреть файл

@ -30,6 +30,7 @@ use OCA\Mail\Account;
use OCA\Mail\Contracts\IMailManager;
use OCA\Mail\Db\Mailbox;
use OCA\Mail\Db\MailboxMapper;
use OCA\Mail\Db\MessageMapper as DbMessageMapper;
use OCA\Mail\Events\BeforeMessageDeletedEvent;
use OCA\Mail\Events\MessageDeletedEvent;
use OCA\Mail\Events\MessageFlaggedEvent;
@ -40,7 +41,7 @@ use OCA\Mail\IMAP\FolderMapper;
use OCA\Mail\IMAP\FolderStats;
use OCA\Mail\IMAP\IMAPClientFactory;
use OCA\Mail\IMAP\MailboxSync;
use OCA\Mail\IMAP\MessageMapper;
use OCA\Mail\IMAP\MessageMapper as ImapMessageMapper;
use OCA\Mail\Model\IMAPMessage;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\EventDispatcher\IEventDispatcher;
@ -74,8 +75,11 @@ class MailManager implements IMailManager {
/** @var FolderMapper */
private $folderMapper;
/** @var MessageMapper */
private $messageMapper;
/** @var ImapMessageMapper */
private $imapMessageMapper;
/** @var DbMessageMapper */
private $dbMessageMapper;
/** @var IEventDispatcher */
private $eventDispatcher;
@ -84,13 +88,15 @@ class MailManager implements IMailManager {
MailboxMapper $mailboxMapper,
MailboxSync $mailboxSync,
FolderMapper $folderMapper,
MessageMapper $messageMapper,
ImapMessageMapper $messageMapper,
DbMessageMapper $dbMessageMapper,
IEventDispatcher $eventDispatcher) {
$this->imapClientFactory = $imapClientFactory;
$this->mailboxMapper = $mailboxMapper;
$this->mailboxSync = $mailboxSync;
$this->folderMapper = $folderMapper;
$this->messageMapper = $messageMapper;
$this->imapMessageMapper = $messageMapper;
$this->dbMessageMapper = $dbMessageMapper;
$this->eventDispatcher = $eventDispatcher;
}
@ -151,7 +157,7 @@ class MailManager implements IMailManager {
$mailbox = $this->mailboxMapper->find($account, $mailbox);
try {
return $this->messageMapper->find(
return $this->imapMessageMapper->find(
$client,
$mailbox->getName(),
$id,
@ -162,6 +168,10 @@ class MailManager implements IMailManager {
}
}
public function getThread(Account $account, int $messageId): array {
return $this->dbMessageMapper->findThread($account, $messageId);
}
/**
* @param Account $account
* @param string $mb
@ -176,7 +186,7 @@ class MailManager implements IMailManager {
$client = $this->imapClientFactory->getClient($account);
try {
return $this->messageMapper->getSource(
return $this->imapMessageMapper->getSource(
$client,
$mailbox,
$id
@ -240,13 +250,13 @@ class MailManager implements IMailManager {
if ($mailboxId === $trashMailbox->getName()) {
// Delete inside trash -> expunge
$this->messageMapper->expunge(
$this->imapMessageMapper->expunge(
$this->imapClientFactory->getClient($account),
$sourceMailbox->getName(),
$messageId
);
} else {
$this->messageMapper->move(
$this->imapMessageMapper->move(
$this->imapClientFactory->getClient($account),
$sourceMailbox->getName(),
$messageId,
@ -276,13 +286,13 @@ class MailManager implements IMailManager {
int $messageId): void {
$client = $this->imapClientFactory->getClient($account);
$this->messageMapper->move($client, $sourceFolderId, $messageId, $destFolderId);
$this->imapMessageMapper->move($client, $sourceFolderId, $messageId, $destFolderId);
}
public function markFolderAsRead(Account $account, string $folderId): void {
$client = $this->imapClientFactory->getClient($account);
$this->messageMapper->markAllRead($client, $folderId);
$this->imapMessageMapper->markAllRead($client, $folderId);
}
public function flagMessage(Account $account, string $mailbox, int $uid, string $flag, bool $value): void {
@ -298,9 +308,9 @@ class MailManager implements IMailManager {
try {
foreach ($imapFlags as $imapFlag) {
if ($value) {
$this->messageMapper->addFlag($client, $mb, $uid, $imapFlag);
$this->imapMessageMapper->addFlag($client, $mb, $uid, $imapFlag);
} else {
$this->messageMapper->removeFlag($client, $mb, $uid, $imapFlag);
$this->imapMessageMapper->removeFlag($client, $mb, $uid, $imapFlag);
}
}
} catch (Horde_Imap_Client_Exception $e) {

Просмотреть файл

@ -28,6 +28,7 @@ use Horde_Imap_Client_Socket;
use OCA\Mail\Account;
use OCA\Mail\Db\Mailbox;
use OCA\Mail\Db\MailboxMapper;
use OCA\Mail\Db\MessageMapper as DbMessageMapper;
use OCA\Mail\Events\BeforeMessageDeletedEvent;
use OCA\Mail\Exception\ServiceException;
use OCA\Mail\Folder;
@ -35,7 +36,7 @@ use OCA\Mail\IMAP\FolderMapper;
use OCA\Mail\IMAP\FolderStats;
use OCA\Mail\IMAP\IMAPClientFactory;
use OCA\Mail\IMAP\MailboxSync;
use OCA\Mail\IMAP\MessageMapper;
use OCA\Mail\IMAP\MessageMapper as ImapMessageMapper;
use OCA\Mail\Service\MailManager;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\EventDispatcher\IEventDispatcher;
@ -55,8 +56,11 @@ class MailManagerTest extends TestCase {
/** @var FolderMapper|MockObject */
private $folderMapper;
/** @var MessageMapper|MockObject */
private $messageMapper;
/** @var ImapMessageMapper|MockObject */
private $imapMessageMapper;
/** @var DbMessageMapper|MockObject */
private $dbMessageMapper;
/** @var IEventDispatcher|MockObject */
private $eventDispatcher;
@ -70,7 +74,8 @@ class MailManagerTest extends TestCase {
$this->imapClientFactory = $this->createMock(IMAPClientFactory::class);
$this->mailboxMapper = $this->createMock(MailboxMapper::class);
$this->folderMapper = $this->createMock(FolderMapper::class);
$this->messageMapper = $this->createMock(MessageMapper::class);
$this->imapMessageMapper = $this->createMock(ImapMessageMapper::class);
$this->dbMessageMapper = $this->createMock(DbMessageMapper::class);
$this->mailboxSync = $this->createMock(MailboxSync::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
@ -79,7 +84,8 @@ class MailManagerTest extends TestCase {
$this->mailboxMapper,
$this->mailboxSync,
$this->folderMapper,
$this->messageMapper,
$this->imapMessageMapper,
$this->dbMessageMapper,
$this->eventDispatcher
);
}
@ -219,7 +225,7 @@ class MailManagerTest extends TestCase {
$this->imapClientFactory->expects($this->once())
->method('getClient')
->willReturn($client);
$this->messageMapper->expects($this->once())
$this->imapMessageMapper->expects($this->once())
->method('move')
->with(
$client,
@ -256,7 +262,7 @@ class MailManagerTest extends TestCase {
$this->imapClientFactory->expects($this->once())
->method('getClient')
->willReturn($client);
$this->messageMapper->expects($this->once())
$this->imapMessageMapper->expects($this->once())
->method('expunge')
->with(
$client,
@ -277,9 +283,9 @@ class MailManagerTest extends TestCase {
$this->imapClientFactory->expects($this->once())
->method('getClient')
->willReturn($client);
$this->messageMapper->expects($this->never())
$this->imapMessageMapper->expects($this->never())
->method('addFlag');
$this->messageMapper->expects($this->never())
$this->imapMessageMapper->expects($this->never())
->method('removeFlag');
$this->manager->flagMessage($account, 'INBOX', 123, 'important', true);
@ -296,12 +302,22 @@ class MailManagerTest extends TestCase {
->method('find')
->with($account, 'INBOX')
->willReturn($mb);
$this->messageMapper->expects($this->never())
$this->imapMessageMapper->expects($this->never())
->method('addFlag');
$this->messageMapper->expects($this->once())
$this->imapMessageMapper->expects($this->once())
->method('removeFlag')
->with($client, $mb, 123, '\\seen');
$this->manager->flagMessage($account, 'INBOX', 123, 'seen', false);
}
public function testGetThread(): void {
$account = $this->createMock(Account::class);
$messageId = 123;
$this->dbMessageMapper->expects($this->once())
->method('findThread')
->with($account, $messageId);
$this->manager->getThread($account, $messageId);
}
}