From be4f62bd9e834b216b0518d87af82b3ce9f932ab Mon Sep 17 00:00:00 2001 From: Vidar Langseid Date: Wed, 26 Aug 2026 11:33:44 +0200 Subject: [PATCH] IBX-12339: Log a warning when notifier subscription is missing --- src/lib/Notifier/PasswordReset.php | 11 ++- src/lib/Notifier/UserInvitation.php | 11 ++- tests/lib/Notifier/PasswordResetTest.php | 83 ++++++++++++++++++++ tests/lib/Notifier/UserInvitationTest.php | 95 +++++++++++++++++++++++ 4 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 tests/lib/Notifier/PasswordResetTest.php create mode 100644 tests/lib/Notifier/UserInvitationTest.php diff --git a/src/lib/Notifier/PasswordReset.php b/src/lib/Notifier/PasswordReset.php index e86844f1b2..defdddae0c 100644 --- a/src/lib/Notifier/PasswordReset.php +++ b/src/lib/Notifier/PasswordReset.php @@ -47,9 +47,16 @@ public function __construct( public function sendMessage(User $user, string $hashKey): void { - if ($this->isNotifierConfigured()) { - $this->sendNotification($user, $hashKey); + if (!$this->isNotifierConfigured()) { + $this->logger?->warning( + 'No password reset e-mail was sent: subscribe {notification} under "ibexa.system..notifier.subscriptions" to enable it.', + ['notification' => UserPasswordReset::class] + ); + + return; } + + $this->sendNotification($user, $hashKey); } private function sendNotification(User $user, string $token): void diff --git a/src/lib/Notifier/UserInvitation.php b/src/lib/Notifier/UserInvitation.php index 0c41a96256..01166cba7d 100644 --- a/src/lib/Notifier/UserInvitation.php +++ b/src/lib/Notifier/UserInvitation.php @@ -46,9 +46,16 @@ public function __construct( public function sendInvitation(Invitation $invitation): void { - if ($this->isNotifierConfigured()) { - $this->sendNotification($invitation); + if (!$this->isNotifierConfigured()) { + $this->logger?->warning( + 'No invitation e-mail was sent: subscribe {notification} under "ibexa.system..notifier.subscriptions" to enable it.', + ['notification' => Notification\UserInvitation::class] + ); + + return; } + + $this->sendNotification($invitation); } private function sendNotification(Invitation $invitation): void diff --git a/tests/lib/Notifier/PasswordResetTest.php b/tests/lib/Notifier/PasswordResetTest.php new file mode 100644 index 0000000000..abb068eeaa --- /dev/null +++ b/tests/lib/Notifier/PasswordResetTest.php @@ -0,0 +1,83 @@ +createMock(NotificationServiceInterface::class); + $notificationService->expects(self::once())->method('send'); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::never())->method('warning'); + + $notifier = $this->createNotifier( + [UserPasswordReset::class => ['channels' => ['email']]], + $notificationService, + $logger + ); + + $notifier->sendMessage($this->createMock(User::class), 'hash-key'); + } + + public function testLogsWarningWhenNotificationIsNotSubscribed(): void + { + $notificationService = $this->createMock(NotificationServiceInterface::class); + $notificationService->expects(self::never())->method('send'); + + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects(self::once()) + ->method('warning') + ->with( + self::stringContains('notifier.subscriptions'), + ['notification' => UserPasswordReset::class] + ); + + $notifier = $this->createNotifier([], $notificationService, $logger); + + $notifier->sendMessage($this->createMock(User::class), 'hash-key'); + } + + /** + * @param array}> $subscriptions + */ + private function createNotifier( + array $subscriptions, + NotificationServiceInterface $notificationService, + LoggerInterface $logger + ): PasswordReset { + $configResolver = $this->createMock(ConfigResolverInterface::class); + $configResolver + ->method('getParameter') + ->with('notifications.subscriptions') + ->willReturn($subscriptions); + + $notifier = new PasswordReset( + $configResolver, + $this->createMock(Environment::class), + $notificationService, + $this->createMock(KernelInterface::class) + ); + $notifier->setLogger($logger); + + return $notifier; + } +} diff --git a/tests/lib/Notifier/UserInvitationTest.php b/tests/lib/Notifier/UserInvitationTest.php new file mode 100644 index 0000000000..602bfa7534 --- /dev/null +++ b/tests/lib/Notifier/UserInvitationTest.php @@ -0,0 +1,95 @@ +createMock(NotificationServiceInterface::class); + $notificationService->expects(self::once())->method('send'); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::never())->method('warning'); + + $sender = $this->createSender( + [Notification\UserInvitation::class => ['channels' => ['email']]], + $notificationService, + $logger + ); + + $sender->sendInvitation($this->createInvitation()); + } + + public function testLogsWarningWhenNotificationIsNotSubscribed(): void + { + $notificationService = $this->createMock(NotificationServiceInterface::class); + $notificationService->expects(self::never())->method('send'); + + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects(self::once()) + ->method('warning') + ->with( + self::stringContains('notifier.subscriptions'), + ['notification' => Notification\UserInvitation::class] + ); + + $sender = $this->createSender([], $notificationService, $logger); + + $sender->sendInvitation($this->createInvitation()); + } + + /** + * @param array}> $subscriptions + */ + private function createSender( + array $subscriptions, + NotificationServiceInterface $notificationService, + LoggerInterface $logger + ): UserInvitation { + $configResolver = $this->createMock(ConfigResolverInterface::class); + $configResolver + ->method('getParameter') + ->with('notifications.subscriptions') + ->willReturn($subscriptions); + + $sender = new UserInvitation( + $this->createMock(Environment::class), + $configResolver, + $notificationService, + $this->createMock(KernelInterface::class) + ); + $sender->setLogger($logger); + + return $sender; + } + + private function createInvitation(): Invitation + { + return new Invitation( + 'invitee@example.com', + 'hash', + new DateTimeImmutable('2026-01-01 00:00:00'), + 'site', + false + ); + } +}