From c0a93345dc4e90fc3a8ac2aae9bba8d3e836e7a3 Mon Sep 17 00:00:00 2001 From: Anna Larch Date: Tue, 19 May 2026 13:02:05 +0200 Subject: [PATCH] fix(MailQueueHandler): check enable_email toggle before sending queued emails The admin Enable notification emails toggle was only checked when queuing new emails. The sendEmails() background job had no knowledge of it and would send all queued entries regardless. Adds an early-return guard using IAppConfig::getValueString() at the top of sendEmails(), consistent with the checks in UserSettings. The queue is left intact so pending notifications can be delivered if the admin re-enables emails. AI-Assisted-By: Claude Sonnet 4.6 Signed-off-by: Anna Larch --- lib/AppInfo/Application.php | 2 ++ lib/MailQueueHandler.php | 6 ++++++ tests/MailQueueHandlerTest.php | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 19c4f47ef..312aab673 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -31,6 +31,7 @@ use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\DB\Events\AddMissingIndicesEvent; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IDateTimeFormatter; use OCP\IDBConnection; @@ -117,6 +118,7 @@ public function register(IRegistrationContext $context): void { $c->get(IFactory::class), $c->get(IManager::class), $c->get(IValidator::class), + $c->get(IAppConfig::class), $c->get(IConfig::class), $c->get(LoggerInterface::class), $c->get(Data::class), diff --git a/lib/MailQueueHandler.php b/lib/MailQueueHandler.php index 3da47f717..ff2fddc17 100644 --- a/lib/MailQueueHandler.php +++ b/lib/MailQueueHandler.php @@ -11,6 +11,7 @@ use OCP\Activity\IManager; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Defaults; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IDateTimeFormatter; use OCP\IDBConnection; @@ -51,6 +52,7 @@ public function __construct( protected IFactory $lFactory, protected IManager $activityManager, protected IValidator $richObjectValidator, + protected IAppConfig $appConfig, protected IConfig $config, protected LoggerInterface $logger, protected Data $data, @@ -70,6 +72,10 @@ public function __construct( * @return int Number of users we sent an email to */ public function sendEmails(int $limit, int $sendTime, bool $forceSending = false, ?int $restrictEmails = null): int { + if (!$this->appConfig->getValueBool('activity', 'enable_email', true)) { + return 0; + } + // Get all users which should receive an email $affectedUsers = $this->getAffectedUsers($limit, $sendTime, $forceSending, $restrictEmails); if (empty($affectedUsers)) { diff --git a/tests/MailQueueHandlerTest.php b/tests/MailQueueHandlerTest.php index 91a658138..a86ebdca8 100644 --- a/tests/MailQueueHandlerTest.php +++ b/tests/MailQueueHandlerTest.php @@ -34,6 +34,7 @@ use OCA\Activity\UserSettings; use OCP\Activity\IEvent; use OCP\Activity\IManager; +use OCP\IAppConfig; use OCP\IConfig; use OCP\IDateTimeFormatter; use OCP\IDBConnection; @@ -65,6 +66,7 @@ class MailQueueHandlerTest extends TestCase { protected IFactory&MockObject $lFactory; protected IManager&MockObject $activityManager; protected IValidator&MockObject $richObjectValidator; + protected IAppConfig&MockObject $appConfig; protected IConfig&MockObject $config; protected MockObject&LoggerInterface $logger; @@ -81,6 +83,7 @@ protected function setUp(): void { $app = self::getUniqueID('MailQueueHandlerTest', 10); $this->userManager = $this->createMock(IUserManager::class); $this->lFactory = $this->createMock(IFactory::class); + $this->appConfig = $this->createMock(IAppConfig::class); $this->config = $this->createMock(IConfig::class); $this->logger = $this->createMock(LoggerInterface::class); $this->dateTimeFormatter = $this->createMock(IDateTimeFormatter::class); @@ -141,6 +144,7 @@ protected function setUp(): void { $this->lFactory, $this->activityManager, $this->richObjectValidator, + $this->appConfig, $this->config, $this->logger, $this->data, @@ -300,6 +304,10 @@ public function testSendEmailToUser(): void { public function testSendEmailsDeletesQueueOnMailerFailure(): void { $maxTime = 200; + $this->appConfig->method('getValueBool') + ->with('activity', 'enable_email', true) + ->willReturn(true); + $template = $this->createMock(IEMailTemplate::class); $this->mailer->method('createEMailTemplate') ->willReturn($template); @@ -340,6 +348,10 @@ public function testSendEmailsDeletesQueueOnMailerFailure(): void { public function testSendEmailsDeletesQueueOnSendReturnFalse(): void { $maxTime = 200; + $this->appConfig->method('getValueBool') + ->with('activity', 'enable_email', true) + ->willReturn(true); + $template = $this->createMock(IEMailTemplate::class); $this->mailer->method('createEMailTemplate') ->willReturn($template); @@ -370,6 +382,27 @@ public function testSendEmailsDeletesQueueOnSendReturnFalse(): void { } } + public function testSendEmailsSkipsWhenAdminEmailDisabled(): void { + $maxTime = 200; + + $this->appConfig->method('getValueBool') + ->with('activity', 'enable_email', true) + ->willReturn(false); + + $this->mailer->expects($this->never()) + ->method('send'); + + $result = $this->mailQueueHandler->sendEmails(3, $maxTime); + + $this->assertSame(0, $result); + + // Queue must be untouched so emails can be sent if admin re-enables the toggle + foreach (['user1', 'user2', 'user3'] as $user) { + [$data,] = self::invokePrivate($this->mailQueueHandler, 'getItemsForUser', [$user, $maxTime]); + $this->assertNotEmpty($data, "Queue entries for $user must survive when email is globally disabled"); + } + } + /** * @param array $users * @param int $maxTime