Resolve "Notification aux groupes utilisateurs"

This commit is contained in:
2026-03-16 14:08:35 +00:00
parent 81193376a4
commit dd429ca02a
13 changed files with 562 additions and 48 deletions

View File

@@ -0,0 +1,187 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Tests\Notification\Email\NotificationEmailHandler;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserGroup;
use Chill\MainBundle\Notification\Email\NotificationEmailHandlers\SendImmediateNotificationEmailHandler;
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendImmediateNotificationEmailMessage;
use Chill\MainBundle\Notification\Email\NotificationMailer;
use Chill\MainBundle\Repository\NotificationRepository;
use Chill\MainBundle\Repository\UserGroupRepository;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Psr\Log\NullLogger;
/**
* @internal
*
* @coversNothing
*/
class SendImmediateNotificationEmailHandlerTest extends TestCase
{
use ProphecyTrait;
private $notificationRepository;
private $userRepository;
private $userGroupRepository;
private $notificationMailer;
private SendImmediateNotificationEmailHandler $handler;
protected function setUp(): void
{
$this->notificationRepository = $this->prophesize(NotificationRepository::class);
$this->userRepository = $this->prophesize(UserRepositoryInterface::class);
$this->userGroupRepository = $this->prophesize(UserGroupRepository::class);
$this->notificationMailer = $this->prophesize(NotificationMailer::class);
$this->handler = new SendImmediateNotificationEmailHandler(
$this->notificationRepository->reveal(),
$this->userRepository->reveal(),
$this->userGroupRepository->reveal(),
$this->notificationMailer->reveal(),
new NullLogger()
);
}
public function testInvokeWithUserAddressee(): void
{
$notificationId = 123;
$userId = 456;
$notification = $this->prophesize(Notification::class);
$notification->getId()->willReturn($notificationId);
$user = $this->prophesize(User::class);
$user->getId()->willReturn($userId);
$message = new SendImmediateNotificationEmailMessage($notification->reveal(), $user->reveal());
$this->notificationRepository->find($notificationId)->willReturn($notification->reveal());
$this->userRepository->find($userId)->willReturn($user->reveal());
$this->notificationMailer->sendEmailToAddressee($notification->reveal(), $user->reveal())
->shouldBeCalledOnce();
($this->handler)($message);
}
public function testInvokeWithUserGroupAddressee(): void
{
$notificationId = 123;
$userGroupId = 789;
$notification = $this->prophesize(Notification::class);
$notification->getId()->willReturn($notificationId);
$userGroup = $this->prophesize(UserGroup::class);
$userGroup->getId()->willReturn($userGroupId);
$message = new SendImmediateNotificationEmailMessage($notification->reveal(), $userGroup->reveal());
$this->notificationRepository->find($notificationId)->willReturn($notification->reveal());
$this->userGroupRepository->find($userGroupId)->willReturn($userGroup->reveal());
$this->notificationMailer->sendEmailToAddressee($notification->reveal(), $userGroup->reveal())
->shouldBeCalledOnce();
($this->handler)($message);
}
public function testInvokeThrowsExceptionWhenNotificationNotFound(): void
{
$notificationId = 123;
$userId = 456;
$notification = $this->prophesize(Notification::class);
$notification->getId()->willReturn($notificationId);
$user = $this->prophesize(User::class);
$user->getId()->willReturn($userId);
$message = new SendImmediateNotificationEmailMessage($notification->reveal(), $user->reveal());
$this->notificationRepository->find($notificationId)->willReturn(null);
$this->userRepository->find($userId)->willReturn($user->reveal());
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf('Notification with ID %s not found', $notificationId));
($this->handler)($message);
}
public function testInvokeThrowsExceptionWhenUserNotFound(): void
{
$notificationId = 123;
$userId = 456;
$notification = $this->prophesize(Notification::class);
$notification->getId()->willReturn($notificationId);
$user = $this->prophesize(User::class);
$user->getId()->willReturn($userId);
$message = new SendImmediateNotificationEmailMessage($notification->reveal(), $user->reveal());
$this->notificationRepository->find($notificationId)->willReturn($notification->reveal());
$this->userRepository->find($userId)->willReturn(null);
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf('User with ID %s or user group with id %s not found', $userId, ''));
($this->handler)($message);
}
public function testInvokeThrowsExceptionWhenUserGroupNotFound(): void
{
$notificationId = 123;
$userGroupId = 789;
$notification = $this->prophesize(Notification::class);
$notification->getId()->willReturn($notificationId);
$userGroup = $this->prophesize(UserGroup::class);
$userGroup->getId()->willReturn($userGroupId);
$message = new SendImmediateNotificationEmailMessage($notification->reveal(), $userGroup->reveal());
$this->notificationRepository->find($notificationId)->willReturn($notification->reveal());
$this->userGroupRepository->find($userGroupId)->willReturn(null);
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf('User with ID %s or user group with id %s not found', '', $userGroupId));
($this->handler)($message);
}
public function testInvokeRethrowsExceptionWhenMailerFails(): void
{
$notificationId = 123;
$userId = 456;
$notification = $this->prophesize(Notification::class);
$notification->getId()->willReturn($notificationId);
$user = $this->prophesize(User::class);
$user->getId()->willReturn($userId);
$message = new SendImmediateNotificationEmailMessage($notification->reveal(), $user->reveal());
$this->notificationRepository->find($notificationId)->willReturn($notification->reveal());
$this->userRepository->find($userId)->willReturn($user->reveal());
$exception = new \Exception('Mailer error');
$this->notificationMailer->sendEmailToAddressee($notification->reveal(), $user->reveal())
->willThrow($exception);
$this->expectException(\Exception::class);
$this->expectExceptionMessage('Mailer error');
($this->handler)($message);
}
}

View File

@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Tests\Notification\Email;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserGroup;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Twig\Environment;
/**
* @internal
*
* @coversNothing
*/
class NotificationMailTwigContentTest extends KernelTestCase
{
private Environment $twig;
protected function setUp(): void
{
self::bootKernel();
$this->twig = $this->getContainer()->get('twig');
}
/**
* @dataProvider provideContent
*/
public function testContent(string $template, array $args): void
{
$actual = $this->twig->render($template, $args);
self::assertIsString($actual);
}
public static function provideContent(): iterable
{
$notification = new Notification();
$notification->setMessage('test message');
$notification->setSender(new User());
$class = new \ReflectionClass($notification);
$method = $class->getProperty('id');
$method->setValue($notification, 1);
$txt = '@ChillMain/Notification/email_non_system_notification_content.txt.twig';
$md = '@ChillMain/Notification/email_non_system_notification_content.md.twig';
$user = new User();
$user->setLocale('fr');
$user->setLabel('test');
$userGroup = new UserGroup();
$userGroup->setLabel(['fr' => 'test user group']);
foreach ([$md, $txt] as $template) {
yield 'test with a user for '.$template => [$template, ['notification' => $notification, 'dest' => $user]];
yield 'test with a group for '.$template => [$template, ['notification' => $notification, 'dest' => $userGroup]];
}
}
}

View File

@@ -9,11 +9,12 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
namespace Notification\Email;
namespace Chill\MainBundle\Tests\Notification\Email;
use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\NotificationComment;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserGroup;
use Chill\MainBundle\Notification\Email\NotificationMailer;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\PostPersistEventArgs;
@@ -64,13 +65,22 @@ class NotificationMailerTest extends TestCase
// a mail only to user1 and user3 should have been sent
$mailer->send(Argument::that(function (Email $email) {
foreach ($email->getTo() as $address) {
if ('user1@foo.com' === $address->getAddress() || 'user3@foo.com' === $address->getAddress()) {
if ('user1@foo.com' === $address->getAddress()) {
return true;
}
}
return false;
}))->shouldBeCalledTimes(2);
}))->shouldBeCalledTimes(1);
$mailer->send(Argument::that(function (Email $email) {
foreach ($email->getTo() as $address) {
if ('user3@foo.com' === $address->getAddress()) {
return true;
}
}
return false;
}))->shouldBeCalledTimes(1);
$objectManager = $this->prophesize(EntityManagerInterface::class);
@@ -121,7 +131,83 @@ class NotificationMailerTest extends TestCase
* @throws \ReflectionException
* @throws Exception
*/
public function testProcessNotificationForAddresseeWithImmediateEmailPreference(): void
public function testPostPersistNotificationToGroup(): void
{
// Create a real notification entity
$notification = new Notification();
$notification->setType('test_notification_type');
// Use reflection to set the ID since it's normally generated by the database
$reflectionNotification = new \ReflectionClass(Notification::class);
$idProperty = $reflectionNotification->getProperty('id');
$idProperty->setValue($notification, 123);
// Create a real user entity
$user = new User();
$user->setEmail('user@example.com');
$userGroup = new UserGroup();
$userGroup->addUser($user);
$notification->addAddressee($userGroup);
// Use reflection to set the ID since it's normally generated by the database
$reflectionUser = new \ReflectionClass($user);
$idProperty = $reflectionUser->getProperty('id');
$idProperty->setValue($user, 456);
$reflectionUser = new \ReflectionClass($userGroup);
$idProperty = $reflectionUser->getProperty('id');
$idProperty->setValue($userGroup, 789);
// Set notification flags for the user
$user->setNotificationImmediately('test_notification_type', true);
$messageBus = $this->prophesize(MessageBusInterface::class);
$messageBus->dispatch(Argument::that(fn (SendImmediateNotificationEmailMessage $message) => 123 === $message->getNotificationId() && 456 === $message->getUserId() && null === $message->getUserGroupId()))->willReturn(new Envelope(new \stdClass()))->shouldBeCalled();
$messageBus->dispatch(Argument::that(fn (SendImmediateNotificationEmailMessage $message) => 123 === $message->getNotificationId() && null === $message->getUserId() && 789 === $message->getUserGroupId()))->willReturn(new Envelope(new \stdClass()))->shouldBeCalled();
$notificationMailer = $this->buildNotificationMailer(null, $messageBus->reveal());
$notificationMailer->postPersistNotification($notification, new PostPersistEventArgs($notification, $this->prophesize(EntityManagerInterface::class)->reveal()));
}
/**
* @throws \ReflectionException
* @throws Exception
*/
public function testPostPersistNotificationWithImmediateEmailPreference(): void
{
// Create a real notification entity
$notification = new Notification();
$notification->setType('test_notification_type');
// Use reflection to set the ID since it's normally generated by the database
$reflectionNotification = new \ReflectionClass(Notification::class);
$idProperty = $reflectionNotification->getProperty('id');
$idProperty->setValue($notification, 123);
// Create a real user entity
$user = new User();
$user->setEmail('user@example.com');
$notification->addAddressee($user);
// Use reflection to set the ID since it's normally generated by the database
$reflectionUser = new \ReflectionClass(User::class);
$idProperty = $reflectionUser->getProperty('id');
$idProperty->setValue($user, 456);
// Set notification flags for the user
$user->setNotificationImmediately('test_notification_type', true);
$messageBus = $this->prophesize(MessageBusInterface::class);
$messageBus->dispatch(Argument::that(fn (SendImmediateNotificationEmailMessage $message) => 123 === $message->getNotificationId() && 456 === $message->getUserId() && null === $message->getUserGroupId()))->willReturn(new Envelope(new \stdClass()))->shouldBeCalled();
$notificationMailer = $this->buildNotificationMailer(null, $messageBus->reveal());
$notificationMailer->postPersistNotification($notification, new PostPersistEventArgs($notification, $this->prophesize(EntityManagerInterface::class)->reveal()));
}
public function testPostPersistNotificationWithDailyDigestPreference(): void
{
// Create a real notification entity
$notification = new Notification();
@@ -136,6 +222,11 @@ class NotificationMailerTest extends TestCase
// Create a real user entity
$user = new User();
$user->setEmail('user@example.com');
// Set notification flags for the user
$user->setNotificationImmediately('test_notification_type', false);
$user->setNotificationDailyDigest('test_notification_type', true);
$notification->addAddressee($user);
// Use reflection to set the ID since it's normally generated by the database
$reflectionUser = new \ReflectionClass(User::class);
@@ -143,23 +234,15 @@ class NotificationMailerTest extends TestCase
$idProperty->setAccessible(true);
$idProperty->setValue($user, 456);
// Set notification flags for the user
$user->setNotificationImmediately('test_notification_type', true);
$messageBus = $this->prophesize(MessageBusInterface::class);
$messageBus->dispatch(Argument::that(fn (SendImmediateNotificationEmailMessage $message) => 123 === $message->getNotificationId() && 456 === $message->getUserId() && null === $message->getUserGroupId()))->willReturn(new Envelope(new \stdClass()))->shouldNotBeCalled();
$messageBus = $this->createMock(MessageBusInterface::class);
$messageBus->expects($this->once())
->method('dispatch')
->with($this->callback(fn (SendImmediateNotificationEmailMessage $message) => 123 === $message->getNotificationId()
&& 456 === $message->getAddresseeId()))
->willReturn(new Envelope(new \stdClass()));
$notificationMailer = $this->buildNotificationMailer(
null,
$messageBus->reveal()
);
$mailer = $this->buildNotificationMailer(null, $messageBus);
// Call the method that processes notifications
$reflection = new \ReflectionClass(NotificationMailer::class);
$method = $reflection->getMethod('processNotificationForAddressee');
$method->setAccessible(true);
$method->invoke($mailer, $notification, $user);
$notificationMailer->postPersistNotification($notification, new PostPersistEventArgs($notification, $this->prophesize(EntityManagerInterface::class)->reveal()));
}
public function testSendDailyDigest(): void
@@ -250,6 +333,108 @@ class NotificationMailerTest extends TestCase
$notificationMailer->sendDailyDigest($user, $notifications);
}
public function testSendEmailToAddresseeUser(): void
{
$user = new User();
$user->setEmail('user@example.com');
$notification = new Notification();
$notification->setSender(new User());
$notification->setTitle('Notification 1');
$notification->setType('test_notification_type');
$notification->addAddressee($user);
$mailer = $this->prophesize(MailerInterface::class);
$mailer->send(Argument::that(function ($arg) {
if (!$arg instanceof Email) {
return false;
}
if ('Notification 1' !== $arg->getSubject()) {
return false;
}
foreach ($arg->getTo() as $address) {
if ('user@example.com' === $address->getAddress()) {
return true;
}
}
return false;
}))->shouldBeCalledOnce();
$notificationMailer = $this->buildNotificationMailer($mailer->reveal());
$notificationMailer->sendEmailToAddressee($notification, $user);
}
public function testSendEmailToAddresseeGroup(): void
{
$userGroup = new UserGroup();
$userGroup->setEmail('user@example.com');
$notification = new Notification();
$notification->setSender(new User());
$notification->setTitle('Notification 1');
$notification->setType('test_notification_type');
$notification->addAddressee($userGroup);
$mailer = $this->prophesize(MailerInterface::class);
$mailer->send(Argument::that(function ($arg) {
if (!$arg instanceof Email) {
return false;
}
if ('Notification 1' !== $arg->getSubject()) {
return false;
}
foreach ($arg->getTo() as $address) {
if ('user@example.com' === $address->getAddress()) {
return true;
}
}
return false;
}))->shouldBeCalledOnce();
$notificationMailer = $this->buildNotificationMailer($mailer->reveal());
$notificationMailer->sendEmailToAddressee($notification, $userGroup);
}
public function testSendEmailToAddresseeGroupWithNoAddress(): void
{
$userGroup = new UserGroup();
$notification = new Notification();
$notification->setSender(new User());
$notification->setTitle('Notification 1');
$notification->setType('test_notification_type');
$notification->addAddressee($userGroup);
$mailer = $this->prophesize(MailerInterface::class);
$mailer->send(Argument::any())->shouldNotBeCalled();
$notificationMailer = $this->buildNotificationMailer($mailer->reveal());
$notificationMailer->sendEmailToAddressee($notification, $userGroup);
}
public function testSendEmailToAddresseeUserWithNoAddress(): void
{
$user = new User();
$notification = new Notification();
$notification->setSender(new User());
$notification->setTitle('Notification 1');
$notification->setType('test_notification_type');
$notification->addAddressee($user);
$mailer = $this->prophesize(MailerInterface::class);
$mailer->send(Argument::any())->shouldNotBeCalled();
$notificationMailer = $this->buildNotificationMailer($mailer->reveal());
$notificationMailer->sendEmailToAddressee($notification, $user);
}
private function buildNotificationMailer(
?MailerInterface $mailer = null,
?MessageBusInterface $messageBus = null,