diff --git a/lib/Controller/MessagesController.php b/lib/Controller/MessagesController.php index 6e1ebfc533..cf35456cd5 100755 --- a/lib/Controller/MessagesController.php +++ b/lib/Controller/MessagesController.php @@ -45,6 +45,8 @@ use OCP\Files\GenericFileException; use OCP\Files\IMimeTypeDetector; use OCP\Files\NotPermittedException; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IL10N; use OCP\IRequest; use OCP\IURLGenerator; @@ -74,7 +76,8 @@ class MessagesController extends Controller { private SnoozeService $snoozeService; private AiIntegrationsService $aiIntegrationService; - public function __construct(string $appName, + public function __construct( + string $appName, IRequest $request, AccountService $accountService, IMailManager $mailManager, @@ -94,7 +97,9 @@ public function __construct(string $appName, IDkimService $dkimService, IUserPreferences $preferences, SnoozeService $snoozeService, - AiIntegrationsService $aiIntegrationService) { + AiIntegrationsService $aiIntegrationService, + private ICacheFactory $cacheFactory, + ) { parent::__construct($appName, $request); $this->accountService = $accountService; $this->mailManager = $mailManager; @@ -218,6 +223,9 @@ public function getBody(int $id): JSONResponse { return new JSONResponse([], Http::STATUS_FORBIDDEN); } + $cacheInstance = $this->getCacheForAccount($account->getId()); + $imapMessageCacheKey = 'message_' . $id; + $client = $this->clientFactory->getClient($account); try { $imapMessage = $this->mailManager->getImapMessage( @@ -226,6 +234,11 @@ public function getBody(int $id): JSONResponse { $mailbox, $message->getUid(), true ); + + if ($imapMessage->hasHtmlMessage()) { + $cacheInstance->set($imapMessageCacheKey, $imapMessage->getHtmlBody($id), 600); + } + $json = $imapMessage->getFullMessage($id); } finally { $client->logout(); @@ -571,21 +584,28 @@ public function getHtmlBody(int $id, bool $plain = false): Response { ); } - $client = $this->clientFactory->getClient($account); - try { - $html = $this->mailManager->getImapMessage( - $client, - $account, - $mailbox, - $message->getUid(), - true - )->getHtmlBody( - $id - ); - } finally { - $client->logout(); + $cacheInstance = $this->getCacheForAccount($account->getId()); + $imapMessageCacheKey = 'message_' . $id; + + $html = $cacheInstance->get($imapMessageCacheKey); + if ($html === null) { + $client = $this->clientFactory->getClient($account); + try { + $html = $this->mailManager->getImapMessage( + $client, + $account, + $mailbox, + $message->getUid(), + true + )->getHtmlBody( + $id + ); + } finally { + $client->logout(); + } } + $htmlResponse = $plain ? HtmlResponse::plain($html) : HtmlResponse::withResizer( @@ -1001,4 +1021,8 @@ private function attachmentIsImage(array $attachment): bool { private function attachmentIsCalendarEvent(array $attachment): bool { return in_array($attachment['mime'], ['text/calendar', 'application/ics'], true); } + + private function getCacheForAccount(int $accountId): ICache { + return $this->cacheFactory->createDistributed('mail_account_' . $accountId); + } } diff --git a/lib/Model/IMAPMessage.php b/lib/Model/IMAPMessage.php index 566b652d5f..ec7cdd95e0 100644 --- a/lib/Model/IMAPMessage.php +++ b/lib/Model/IMAPMessage.php @@ -137,6 +137,10 @@ public static function generateMessageId(): string { return Horde_Mime_Headers_MessageId::create('nextcloud-mail-generated')->value; } + public function hasHtmlMessage(): bool { + return $this->hasHtmlMessage; + } + /** * @return int */ diff --git a/tests/Unit/Controller/MessagesControllerTest.php b/tests/Unit/Controller/MessagesControllerTest.php index 73d7b0c08d..49a41440f8 100644 --- a/tests/Unit/Controller/MessagesControllerTest.php +++ b/tests/Unit/Controller/MessagesControllerTest.php @@ -13,6 +13,7 @@ use ChristophWurst\Nextcloud\Testing\TestCase; use Horde_Imap_Client_Socket; use OC\AppFramework\Http\Request; +use OC\Memcache\NullCache; use OC\Security\CSP\ContentSecurityPolicyNonceManager; use OCA\Mail\Account; use OCA\Mail\Attachment; @@ -48,6 +49,7 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\Files\Folder; use OCP\Files\IMimeTypeDetector; +use OCP\ICacheFactory; use OCP\IL10N; use OCP\IRequest; use OCP\IURLGenerator; @@ -130,6 +132,8 @@ class MessagesControllerTest extends TestCase { /** @var MockObject|AiIntegrationsService */ private $aiIntegrationsService; + private ICacheFactory&MockObject $cacheFactory; + protected function setUp(): void { parent::setUp(); @@ -155,6 +159,10 @@ protected function setUp(): void { $this->userPreferences = $this->createMock(IUserPreferences::class); $this->snoozeService = $this->createMock(SnoozeService::class); $this->aiIntegrationsService = $this->createMock(AiIntegrationsService::class); + $this->cacheFactory = $this->createMock(ICacheFactory::class); + + $this->cacheFactory->method('createDistributed') + ->willReturn(new NullCache()); $timeFactory = $this->createMocK(ITimeFactory::class); $timeFactory->expects($this->any()) @@ -185,6 +193,7 @@ protected function setUp(): void { $this->userPreferences, $this->snoozeService, $this->aiIntegrationsService, + $this->cacheFactory, ); $this->account = $this->createMock(Account::class); @@ -1241,6 +1250,7 @@ public function testNeedsTranslationNoUser() { $this->userPreferences, $this->snoozeService, $this->aiIntegrationsService, + $this->cacheFactory, ); $actualResponse = $controller->needsTranslation(100);