mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-10 16:55:00 +00:00
Compare commits
14 Commits
389-displa
...
330-notifi
Author | SHA1 | Date | |
---|---|---|---|
f88f1f1859 | |||
e6cbba8c63 | |||
c2782be56a | |||
cf391d60fe | |||
acad9d1553 | |||
0a19255a22 | |||
bef5dcce14 | |||
33540f58d7 | |||
cf780b6e36 | |||
c9c565809a | |||
c917c42789 | |||
1c426f560e | |||
5ee8a6bc82 | |||
47cf83ef93
|
@@ -46,7 +46,7 @@ stages:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
stage: Composer install
|
stage: Composer install
|
||||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
image: chill/base-image:8.3-edge
|
||||||
before_script:
|
before_script:
|
||||||
- composer config -g cache-dir "$(pwd)/.cache"
|
- composer config -g cache-dir "$(pwd)/.cache"
|
||||||
script:
|
script:
|
||||||
@@ -61,7 +61,7 @@ build:
|
|||||||
|
|
||||||
code_style:
|
code_style:
|
||||||
stage: Tests
|
stage: Tests
|
||||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
image: chill/base-image:8.3-edge
|
||||||
script:
|
script:
|
||||||
- php-cs-fixer fix --dry-run -v --show-progress=none
|
- php-cs-fixer fix --dry-run -v --show-progress=none
|
||||||
cache:
|
cache:
|
||||||
@@ -74,7 +74,7 @@ code_style:
|
|||||||
|
|
||||||
phpstan_tests:
|
phpstan_tests:
|
||||||
stage: Tests
|
stage: Tests
|
||||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
image: chill/base-image:8.3-edge
|
||||||
variables:
|
variables:
|
||||||
COMPOSER_MEMORY_LIMIT: 3G
|
COMPOSER_MEMORY_LIMIT: 3G
|
||||||
before_script:
|
before_script:
|
||||||
@@ -91,7 +91,7 @@ phpstan_tests:
|
|||||||
|
|
||||||
rector_tests:
|
rector_tests:
|
||||||
stage: Tests
|
stage: Tests
|
||||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
image: chill/base-image:8.3-edge
|
||||||
before_script:
|
before_script:
|
||||||
- bin/console cache:clear --env=dev
|
- bin/console cache:clear --env=dev
|
||||||
script:
|
script:
|
||||||
@@ -132,7 +132,7 @@ lint:
|
|||||||
|
|
||||||
unit_tests:
|
unit_tests:
|
||||||
stage: Tests
|
stage: Tests
|
||||||
image: gitea.champs-libres.be/chill-project/chill-skeleton-basic/base-image:php82
|
image: chill/base-image:8.3-edge
|
||||||
variables:
|
variables:
|
||||||
COMPOSER_MEMORY_LIMIT: 3G
|
COMPOSER_MEMORY_LIMIT: 3G
|
||||||
before_script:
|
before_script:
|
||||||
|
@@ -12,3 +12,7 @@ framework:
|
|||||||
adapter: cache.adapter.redis
|
adapter: cache.adapter.redis
|
||||||
public: false
|
public: false
|
||||||
default_lifetime: 300
|
default_lifetime: 300
|
||||||
|
cache.daily_notifications:
|
||||||
|
adapter: cache.adapter.redis
|
||||||
|
public: true
|
||||||
|
default_lifetime: 90000 # 25 hours
|
||||||
|
@@ -45,6 +45,27 @@ framework:
|
|||||||
|
|
||||||
auto_setup: false
|
auto_setup: false
|
||||||
|
|
||||||
|
immediate_email:
|
||||||
|
dsn: '%env(MESSENGER_TRANSPORT_DSN)%/priority'
|
||||||
|
options:
|
||||||
|
queue_name: immediate_notifications
|
||||||
|
exchange:
|
||||||
|
name: notifications
|
||||||
|
type: direct
|
||||||
|
retry_strategy:
|
||||||
|
max_retries: 3
|
||||||
|
delay: 1000
|
||||||
|
multiplier: 2
|
||||||
|
|
||||||
|
daily_email:
|
||||||
|
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
|
||||||
|
options:
|
||||||
|
queue_name: daily_notifications
|
||||||
|
exchange:
|
||||||
|
name: notifications
|
||||||
|
type: direct
|
||||||
|
# No automatic consumption - handled by cron job
|
||||||
|
|
||||||
routing:
|
routing:
|
||||||
# routes added by chill-bundles recipes
|
# routes added by chill-bundles recipes
|
||||||
'Chill\CalendarBundle\Messenger\Message\CalendarRangeMessage': async
|
'Chill\CalendarBundle\Messenger\Message\CalendarRangeMessage': async
|
||||||
@@ -61,6 +82,9 @@ framework:
|
|||||||
'Chill\MainBundle\Workflow\Messenger\PostSignatureStateChangeMessage': priority
|
'Chill\MainBundle\Workflow\Messenger\PostSignatureStateChangeMessage': priority
|
||||||
'Chill\MainBundle\Workflow\Messenger\PostPublicViewMessage': async
|
'Chill\MainBundle\Workflow\Messenger\PostPublicViewMessage': async
|
||||||
'Chill\MainBundle\Service\Workflow\CancelStaleWorkflowMessage': async
|
'Chill\MainBundle\Service\Workflow\CancelStaleWorkflowMessage': async
|
||||||
|
'Chill\MainBundle\Notification\Email\SendImmediateNotificationEmailMessage': immediate_email
|
||||||
|
'Chill\MainBundle\Notification\Email\ScheduleDailyNotificationEmailMessage': daily_email
|
||||||
|
'Chill\MainBundle\Notification\Email\SendDailyDigestMessage': daily_email
|
||||||
# end of routes added by chill-bundles recipes
|
# end of routes added by chill-bundles recipes
|
||||||
# Route your messages to the transports
|
# Route your messages to the transports
|
||||||
# 'App\Message\YourMessage': async
|
# 'App\Message\YourMessage': async
|
||||||
|
@@ -11,8 +11,10 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Controller;
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
use Chill\MainBundle\Entity\Notification;
|
use Chill\MainBundle\Entity\Notification;
|
||||||
use Chill\MainBundle\Entity\NotificationComment;
|
use Chill\MainBundle\Entity\NotificationComment;
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
use Chill\MainBundle\Form\NotificationCommentType;
|
use Chill\MainBundle\Form\NotificationCommentType;
|
||||||
use Chill\MainBundle\Form\NotificationType;
|
use Chill\MainBundle\Form\NotificationType;
|
||||||
use Chill\MainBundle\Notification\Exception\NotificationHandlerNotFound;
|
use Chill\MainBundle\Notification\Exception\NotificationHandlerNotFound;
|
||||||
@@ -22,6 +24,9 @@ use Chill\MainBundle\Repository\NotificationRepository;
|
|||||||
use Chill\MainBundle\Repository\UserRepository;
|
use Chill\MainBundle\Repository\UserRepository;
|
||||||
use Chill\MainBundle\Security\Authorization\NotificationVoter;
|
use Chill\MainBundle\Security\Authorization\NotificationVoter;
|
||||||
use Chill\MainBundle\Security\ChillSecurity;
|
use Chill\MainBundle\Security\ChillSecurity;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
@@ -53,11 +58,29 @@ class NotificationController extends AbstractController
|
|||||||
throw new BadRequestHttpException('missing entityId parameter');
|
throw new BadRequestHttpException('missing entityId parameter');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$notificationType = '';
|
||||||
|
|
||||||
|
switch ($request->query->get('entityClass')) {
|
||||||
|
case Activity::class:
|
||||||
|
$notificationType = NotificationFlagEnum::ACTIVITY;
|
||||||
|
break;
|
||||||
|
case AccompanyingPeriod::class:
|
||||||
|
$notificationType = NotificationFlagEnum::ACC_COURSE;
|
||||||
|
break;
|
||||||
|
case AccompanyingPeriodWork::class:
|
||||||
|
$notificationType = NotificationFlagEnum::ACC_COURSE_WORK;
|
||||||
|
break;
|
||||||
|
case AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument::class:
|
||||||
|
$notificationType = NotificationFlagEnum::ACC_COURSE_WORK_EVAL_DOC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$notification = new Notification();
|
$notification = new Notification();
|
||||||
$notification
|
$notification
|
||||||
->setRelatedEntityClass($request->query->get('entityClass'))
|
->setRelatedEntityClass($request->query->get('entityClass'))
|
||||||
->setRelatedEntityId($request->query->getInt('entityId'))
|
->setRelatedEntityId($request->query->getInt('entityId'))
|
||||||
->setSender($this->security->getUser());
|
->setSender($this->security->getUser())
|
||||||
|
->setType($notificationType);
|
||||||
|
|
||||||
$tos = $request->query->all('tos');
|
$tos = $request->query->all('tos');
|
||||||
|
|
||||||
|
@@ -11,14 +11,12 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Controller;
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
use Chill\MainBundle\Form\UserPhonenumberType;
|
use Chill\MainBundle\Form\UserProfileType;
|
||||||
use Chill\MainBundle\Security\ChillSecurity;
|
use Chill\MainBundle\Security\ChillSecurity;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\Form\FormInterface;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
@@ -41,16 +39,21 @@ final class UserProfileController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$user = $this->security->getUser();
|
$user = $this->security->getUser();
|
||||||
$editForm = $this->createPhonenumberEditForm($user);
|
$editForm = $this->createForm(UserProfileType::class, $user);
|
||||||
|
|
||||||
|
$editForm->get('notificationFlags')->setData($user->getNotificationFlags());
|
||||||
|
|
||||||
|
$editForm->add('submit', SubmitType::class);
|
||||||
$editForm->handleRequest($request);
|
$editForm->handleRequest($request);
|
||||||
|
|
||||||
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||||
$phonenumber = $editForm->get('phonenumber')->getData();
|
$notificationFlagsData = $editForm->get('notificationFlags')->getData();
|
||||||
|
$user->setNotificationFlags($notificationFlagsData);
|
||||||
|
|
||||||
$user->setPhonenumber($phonenumber);
|
$em = $this->managerRegistry->getManager();
|
||||||
|
$em->persist($user);
|
||||||
$this->managerRegistry->getManager()->flush();
|
$em->flush();
|
||||||
$this->addFlash('success', $this->translator->trans('user.profile.Phonenumber successfully updated!'));
|
$this->addFlash('success', $this->translator->trans('user.profile.Profile successfully updated!'));
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_main_user_profile');
|
return $this->redirectToRoute('chill_main_user_profile');
|
||||||
}
|
}
|
||||||
@@ -60,13 +63,4 @@ final class UserProfileController extends AbstractController
|
|||||||
'form' => $editForm->createView(),
|
'form' => $editForm->createView(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createPhonenumberEditForm(UserInterface $user): FormInterface
|
|
||||||
{
|
|
||||||
return $this->createForm(
|
|
||||||
UserPhonenumberType::class,
|
|
||||||
$user,
|
|
||||||
)
|
|
||||||
->add('submit', SubmitType::class, ['label' => $this->translator->trans('Save')]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ namespace Chill\MainBundle\Entity;
|
|||||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
@@ -24,7 +25,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
|||||||
#[ORM\Index(name: 'chill_main_notification_related_entity_idx', columns: ['relatedentityclass', 'relatedentityid'])]
|
#[ORM\Index(name: 'chill_main_notification_related_entity_idx', columns: ['relatedentityclass', 'relatedentityid'])]
|
||||||
class Notification implements TrackUpdateInterface
|
class Notification implements TrackUpdateInterface
|
||||||
{
|
{
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false)]
|
#[ORM\Column(type: Types::TEXT, nullable: false)]
|
||||||
private string $accessKey;
|
private string $accessKey;
|
||||||
|
|
||||||
private array $addedAddresses = [];
|
private array $addedAddresses = [];
|
||||||
@@ -41,7 +42,7 @@ class Notification implements TrackUpdateInterface
|
|||||||
*
|
*
|
||||||
* @var array|string[]
|
* @var array|string[]
|
||||||
*/
|
*/
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, options: ['default' => '[]', 'jsonb' => true])]
|
#[ORM\Column(type: Types::JSON, options: ['default' => '[]', 'jsonb' => true])]
|
||||||
private array $addressesEmails = [];
|
private array $addressesEmails = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,21 +61,21 @@ class Notification implements TrackUpdateInterface
|
|||||||
#[ORM\OrderBy(['createdAt' => \Doctrine\Common\Collections\Criteria::ASC])]
|
#[ORM\OrderBy(['createdAt' => \Doctrine\Common\Collections\Criteria::ASC])]
|
||||||
private Collection $comments;
|
private Collection $comments;
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE)]
|
#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
|
||||||
private \DateTimeImmutable $date;
|
private \DateTimeImmutable $date;
|
||||||
|
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\GeneratedValue]
|
#[ORM\GeneratedValue]
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
#[ORM\Column(type: Types::INTEGER)]
|
||||||
private ?int $id = null;
|
private ?int $id = null;
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT)]
|
#[ORM\Column(type: Types::TEXT)]
|
||||||
private string $message = '';
|
private string $message = '';
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
#[ORM\Column(type: Types::STRING, length: 255)]
|
||||||
private string $relatedEntityClass = '';
|
private string $relatedEntityClass = '';
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
|
#[ORM\Column(type: Types::INTEGER)]
|
||||||
private int $relatedEntityId;
|
private int $relatedEntityId;
|
||||||
|
|
||||||
private array $removedAddresses = [];
|
private array $removedAddresses = [];
|
||||||
@@ -84,7 +85,7 @@ class Notification implements TrackUpdateInterface
|
|||||||
private ?User $sender = null;
|
private ?User $sender = null;
|
||||||
|
|
||||||
#[Assert\NotBlank(message: 'notification.Title must be defined')]
|
#[Assert\NotBlank(message: 'notification.Title must be defined')]
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, options: ['default' => ''])]
|
#[ORM\Column(type: Types::TEXT, options: ['default' => ''])]
|
||||||
private string $title = '';
|
private string $title = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,12 +95,15 @@ class Notification implements TrackUpdateInterface
|
|||||||
#[ORM\JoinTable(name: 'chill_main_notification_addresses_unread')]
|
#[ORM\JoinTable(name: 'chill_main_notification_addresses_unread')]
|
||||||
private Collection $unreadBy;
|
private Collection $unreadBy;
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE)]
|
#[ORM\Column(type: Types::DATETIME_IMMUTABLE)]
|
||||||
private ?\DateTimeImmutable $updatedAt = null;
|
private ?\DateTimeImmutable $updatedAt = null;
|
||||||
|
|
||||||
#[ORM\ManyToOne(targetEntity: User::class)]
|
#[ORM\ManyToOne(targetEntity: User::class)]
|
||||||
private ?User $updatedBy = null;
|
private ?User $updatedBy = null;
|
||||||
|
|
||||||
|
#[ORM\Column(name: 'type', type: Types::STRING, nullable: true, enumType: NotificationFlagEnum::class)]
|
||||||
|
private NotificationFlagEnum $type;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->addressees = new ArrayCollection();
|
$this->addressees = new ArrayCollection();
|
||||||
@@ -389,4 +393,16 @@ class Notification implements TrackUpdateInterface
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setType(NotificationFlagEnum $type): self
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): NotificationFlagEnum
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
23
src/Bundle/ChillMainBundle/Entity/NotificationFlagEnum.php
Normal file
23
src/Bundle/ChillMainBundle/Entity/NotificationFlagEnum.php
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?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\Entity;
|
||||||
|
|
||||||
|
enum NotificationFlagEnum: string
|
||||||
|
{
|
||||||
|
case REFERRER_ACC_COURSE = 'referrer-acc-course-notif';
|
||||||
|
case PERSON_MOVE = 'person-move-notif';
|
||||||
|
case ACC_COURSE = 'acc-course-notif';
|
||||||
|
case WORKFLOW_TRANS = 'workflow-trans-notif';
|
||||||
|
case ACC_COURSE_WORK = 'acc-course-work-notif';
|
||||||
|
case ACC_COURSE_WORK_EVAL_DOC = 'acc-course-work-eval-doc-notif';
|
||||||
|
case ACTIVITY = 'activity-notif';
|
||||||
|
}
|
@@ -116,6 +116,9 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
|||||||
#[PhonenumberConstraint]
|
#[PhonenumberConstraint]
|
||||||
private ?PhoneNumber $phonenumber = null;
|
private ?PhoneNumber $phonenumber = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, nullable: false, options: ['default' => '[]', 'jsonb' => true])]
|
||||||
|
private $notificationFlags = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User constructor.
|
* User constructor.
|
||||||
*/
|
*/
|
||||||
@@ -613,4 +616,24 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getNotificationFlags(): array
|
||||||
|
{
|
||||||
|
return $this->notificationFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNotificationFlags(array $notificationFlags)
|
||||||
|
{
|
||||||
|
$this->notificationFlags = $notificationFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNotificationFlagData(string $flag): array
|
||||||
|
{
|
||||||
|
return $this->notificationFlags[$flag] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNotificationFlagData(string $flag, array $data): void
|
||||||
|
{
|
||||||
|
$this->notificationFlags[$flag] = $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,78 @@
|
|||||||
|
<?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\Form\DataMapper;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\DataMapperInterface;
|
||||||
|
|
||||||
|
final readonly class NotificationFlagDataMapper implements DataMapperInterface
|
||||||
|
{
|
||||||
|
private array $notificationFlagProviders;
|
||||||
|
|
||||||
|
public function __construct(array $notificationFlagProviders)
|
||||||
|
{
|
||||||
|
$this->notificationFlagProviders = $notificationFlagProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mapDataToForms($viewData, $forms): void
|
||||||
|
{
|
||||||
|
if (null === $viewData) {
|
||||||
|
$viewData = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$formsArray = iterator_to_array($forms);
|
||||||
|
|
||||||
|
foreach ($this->notificationFlagProviders as $flagProvider) {
|
||||||
|
$flag = $flagProvider->getFlag();
|
||||||
|
|
||||||
|
if (isset($formsArray[$flag])) {
|
||||||
|
$flagForm = $formsArray[$flag];
|
||||||
|
|
||||||
|
$immediateEmailChecked = in_array('immediate-email', $viewData[$flag] ?? []);
|
||||||
|
$dailyEmailChecked = in_array('daily-email', $viewData[$flag] ?? []);
|
||||||
|
|
||||||
|
if ($flagForm->has('immediate_email')) {
|
||||||
|
$flagForm->get('immediate_email')->setData($immediateEmailChecked);
|
||||||
|
}
|
||||||
|
if ($flagForm->has('daily_email')) {
|
||||||
|
$flagForm->get('daily_email')->setData($dailyEmailChecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mapFormsToData($forms, &$viewData): void
|
||||||
|
{
|
||||||
|
$formsArray = iterator_to_array($forms);
|
||||||
|
$viewData = [];
|
||||||
|
|
||||||
|
foreach ($this->notificationFlagProviders as $flagProvider) {
|
||||||
|
$flag = $flagProvider->getFlag();
|
||||||
|
|
||||||
|
if (isset($formsArray[$flag])) {
|
||||||
|
$flagForm = $formsArray[$flag];
|
||||||
|
$viewData[$flag] = [];
|
||||||
|
|
||||||
|
if ($flagForm['immediate_email']->getData()) {
|
||||||
|
$viewData[$flag][] = 'immediate-email';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($flagForm['daily_email']->getData()) {
|
||||||
|
$viewData[$flag][] = 'daily-email';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($viewData[$flag])) {
|
||||||
|
$viewData[$flag][] = 'no-email';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,62 @@
|
|||||||
|
<?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\Form\Type;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Form\DataMapper\NotificationFlagDataMapper;
|
||||||
|
use Chill\MainBundle\Notification\NotificationFlagManager;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class NotificationFlagsType extends AbstractType
|
||||||
|
{
|
||||||
|
private array $notificationFlagProviders;
|
||||||
|
|
||||||
|
public function __construct(NotificationFlagManager $notificationFlagManager)
|
||||||
|
{
|
||||||
|
$this->notificationFlagProviders = $notificationFlagManager->getAllNotificationFlagProviders();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder->setDataMapper(new NotificationFlagDataMapper($this->notificationFlagProviders));
|
||||||
|
|
||||||
|
foreach ($this->notificationFlagProviders as $flagProvider) {
|
||||||
|
$flag = $flagProvider->getFlag();
|
||||||
|
$builder->add($flag, FormType::class, [
|
||||||
|
'label' => $flagProvider->getLabel(),
|
||||||
|
'required' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$builder->get($flag)
|
||||||
|
->add('immediate_email', CheckboxType::class, [
|
||||||
|
'label' => false,
|
||||||
|
'required' => false,
|
||||||
|
'mapped' => false, // Keep this here for the individual checkboxes
|
||||||
|
])
|
||||||
|
->add('daily_email', CheckboxType::class, [
|
||||||
|
'label' => false,
|
||||||
|
'required' => false,
|
||||||
|
'mapped' => false, // Keep this here for the individual checkboxes
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
41
src/Bundle/ChillMainBundle/Form/UserProfileType.php
Normal file
41
src/Bundle/ChillMainBundle/Form/UserProfileType.php
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<?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\Form;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
||||||
|
use Chill\MainBundle\Form\Type\NotificationFlagsType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class UserProfileType extends AbstractType
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('phonenumber', ChillPhoneNumberType::class, [
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
->add('notificationFlags', NotificationFlagsType::class, [
|
||||||
|
'label' => false,
|
||||||
|
'mapped' => false,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => \Chill\MainBundle\Entity\User::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,70 @@
|
|||||||
|
<?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\Notification\Email\NotificationEmailHandlers;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationEmailMessage;
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendDailyDigestMessage;
|
||||||
|
use Psr\Cache\InvalidArgumentException;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
|
use Symfony\Component\Messenger\Stamp\DelayStamp;
|
||||||
|
use Symfony\Contracts\Cache\CacheInterface;
|
||||||
|
|
||||||
|
readonly class ScheduleDailyNotificationEmailHandler
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private CacheInterface $dailyNotificationsCache,
|
||||||
|
private MessageBusInterface $messageBus,
|
||||||
|
private LoggerInterface $logger,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __invoke(ScheduleDailyNotificationEmailMessage $message): void
|
||||||
|
{
|
||||||
|
$userId = $message->getAddresseeId();
|
||||||
|
$notificationId = $message->getNotificationId();
|
||||||
|
|
||||||
|
// Store notification in cache grouped by user
|
||||||
|
$cacheKey = "daily_notifications_user_{$userId}";
|
||||||
|
$existingNotifications = $this->dailyNotificationsCache->get($cacheKey, function () {
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
$existingNotifications[] = $notificationId;
|
||||||
|
|
||||||
|
$this->dailyNotificationsCache->get($cacheKey, function () use ($existingNotifications) {
|
||||||
|
return $existingNotifications;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Only send the daily digest message if this is the first notification for today otherwise it already exists
|
||||||
|
if (1 === count($existingNotifications)) {
|
||||||
|
$digestMessage = new SendDailyDigestMessage($userId);
|
||||||
|
|
||||||
|
// Calculate delay until next 9 AM
|
||||||
|
$now = new \DateTimeImmutable();
|
||||||
|
$nextNineAM = $now->modify('tomorrow 09:00');
|
||||||
|
$delay = $nextNineAM->getTimestamp() - $now->getTimestamp();
|
||||||
|
|
||||||
|
$this->messageBus->dispatch($digestMessage, [
|
||||||
|
new DelayStamp($delay * 1000),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->info('[ScheduleDailyNotificationEmailHandler] Added notification to daily cache', [
|
||||||
|
'notification_id' => $notificationId,
|
||||||
|
'user_id' => $userId,
|
||||||
|
'total_pending' => count($existingNotifications),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
<?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\Notification\Email\NotificationEmailHandlers;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendDailyDigestMessage;
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationMailer;
|
||||||
|
use Chill\MainBundle\Repository\NotificationRepository;
|
||||||
|
use Chill\MainBundle\Repository\UserRepository;
|
||||||
|
use Psr\Cache\InvalidArgumentException;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Contracts\Cache\CacheInterface;
|
||||||
|
|
||||||
|
#[AsMessageHandler]
|
||||||
|
class SendDailyDigestHandler
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly CacheInterface $dailyNotificationsCache,
|
||||||
|
private readonly NotificationRepository $notificationRepository,
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
|
private readonly NotificationMailer $notificationMailer,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function __invoke(SendDailyDigestMessage $message): void
|
||||||
|
{
|
||||||
|
$userId = $message->getUserId();
|
||||||
|
$cacheKey = "daily_notifications_user_{$userId}";
|
||||||
|
|
||||||
|
$notificationIds = $this->dailyNotificationsCache->get($cacheKey, []);
|
||||||
|
|
||||||
|
if (empty($notificationIds)) {
|
||||||
|
$this->logger->info('[SendDailyDigestHandler] No notifications found for user', [
|
||||||
|
'user_id' => $userId,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->userRepository->find($userId);
|
||||||
|
$notifications = $this->notificationRepository->findBy(['id' => $notificationIds]);
|
||||||
|
|
||||||
|
if ($user && !empty($notifications)) {
|
||||||
|
$this->notificationMailer->sendDailyDigest($user, $notifications);
|
||||||
|
|
||||||
|
// Clear the cache after sending
|
||||||
|
$this->dailyNotificationsCache->delete($cacheKey);
|
||||||
|
|
||||||
|
$this->logger->info('[SendDailyDigestHandler] Sent daily digest', [
|
||||||
|
'user_id' => $userId,
|
||||||
|
'notification_count' => count($notifications),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,68 @@
|
|||||||
|
<?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\Notification\Email\NotificationEmailHandlers;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendImmediateNotificationEmailMessage;
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationMailer;
|
||||||
|
use Chill\MainBundle\Repository\NotificationRepository;
|
||||||
|
use Chill\MainBundle\Repository\UserRepository;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||||
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
||||||
|
|
||||||
|
#[AsMessageHandler]
|
||||||
|
class SendImmediateNotificationEmailHandler
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly NotificationRepository $notificationRepository,
|
||||||
|
private readonly UserRepository $userRepository,
|
||||||
|
private readonly NotificationMailer $notificationMailer,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws TransportExceptionInterface
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function __invoke(SendImmediateNotificationEmailMessage $message): void
|
||||||
|
{
|
||||||
|
$notification = $this->notificationRepository->find($message->getNotificationId());
|
||||||
|
$addressee = $this->userRepository->find($message->getAddresseeId());
|
||||||
|
|
||||||
|
if (null === $notification) {
|
||||||
|
$this->logger->error('[SendImmediateNotificationEmailHandler] Notification not found', [
|
||||||
|
'notification_id' => $message->getNotificationId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $addressee) {
|
||||||
|
$this->logger->error('[SendImmediateNotificationEmailHandler] Addressee not found', [
|
||||||
|
'addressee_id' => $message->getAddresseeId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->notificationMailer->sendEmailToAddressee($notification, $addressee);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error('[SendImmediateNotificationEmailHandler] Failed to send email', [
|
||||||
|
'notification_id' => $message->getNotificationId(),
|
||||||
|
'addressee_id' => $message->getAddresseeId(),
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
<?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\Notification\Email\NotificationEmailMessages;
|
||||||
|
|
||||||
|
readonly class ScheduleDailyNotificationEmailMessage
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private int $notificationId,
|
||||||
|
private int $addresseeId,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getNotificationId(): int
|
||||||
|
{
|
||||||
|
return $this->notificationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddresseeId(): int
|
||||||
|
{
|
||||||
|
return $this->addresseeId;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,24 @@
|
|||||||
|
<?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\Notification\Email\NotificationEmailMessages;
|
||||||
|
|
||||||
|
class SendDailyDigestMessage
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly int $userId,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getUserId(): int
|
||||||
|
{
|
||||||
|
return $this->userId;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
<?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\Notification\Email\NotificationEmailMessages;
|
||||||
|
|
||||||
|
readonly class SendImmediateNotificationEmailMessage
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private int $notificationId,
|
||||||
|
private int $addresseeId,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getNotificationId(): int
|
||||||
|
{
|
||||||
|
return $this->notificationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAddresseeId(): int
|
||||||
|
{
|
||||||
|
return $this->addresseeId;
|
||||||
|
}
|
||||||
|
}
|
@@ -13,6 +13,8 @@ namespace Chill\MainBundle\Notification\Email;
|
|||||||
|
|
||||||
use Chill\MainBundle\Entity\Notification;
|
use Chill\MainBundle\Entity\Notification;
|
||||||
use Chill\MainBundle\Entity\NotificationComment;
|
use Chill\MainBundle\Entity\NotificationComment;
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationEmailMessage;
|
||||||
|
use Chill\MainBundle\Notification\Email\NotificationEmailMessages\SendImmediateNotificationEmailMessage;
|
||||||
use Doctrine\ORM\Event\PostPersistEventArgs;
|
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
@@ -20,11 +22,12 @@ use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
|||||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||||
use Symfony\Component\Mailer\MailerInterface;
|
use Symfony\Component\Mailer\MailerInterface;
|
||||||
use Symfony\Component\Mime\Email;
|
use Symfony\Component\Mime\Email;
|
||||||
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
class NotificationMailer
|
readonly class NotificationMailer
|
||||||
{
|
{
|
||||||
public function __construct(private readonly MailerInterface $mailer, private readonly LoggerInterface $logger, private readonly TranslatorInterface $translator) {}
|
public function __construct(private MailerInterface $mailer, private LoggerInterface $logger, private MessageBusInterface $messageBus, private readonly TranslatorInterface $translator) {}
|
||||||
|
|
||||||
public function postPersistComment(NotificationComment $comment, PostPersistEventArgs $eventArgs): void
|
public function postPersistComment(NotificationComment $comment, PostPersistEventArgs $eventArgs): void
|
||||||
{
|
{
|
||||||
@@ -80,38 +83,152 @@ class NotificationMailer
|
|||||||
|
|
||||||
private function sendNotificationEmailsToAddresses(Notification $notification): void
|
private function sendNotificationEmailsToAddresses(Notification $notification): void
|
||||||
{
|
{
|
||||||
|
if (null === $notification->getType()) {
|
||||||
|
$this->logger->warning('[NotificationMailer] Notification has no type, skipping email processing', [
|
||||||
|
'notification_id' => $notification->getId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($notification->getAddressees() as $addressee) {
|
foreach ($notification->getAddressees() as $addressee) {
|
||||||
if (null === $addressee->getEmail()) {
|
if (null === $addressee->getEmail()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($notification->isSystem()) {
|
$this->processNotificationForAddressee($notification, $addressee);
|
||||||
$email = new Email();
|
}
|
||||||
$email
|
}
|
||||||
->text($notification->getMessage());
|
|
||||||
} else {
|
|
||||||
$email = new TemplatedEmail();
|
|
||||||
$email
|
|
||||||
->textTemplate('@ChillMain/Notification/email_non_system_notification_content.fr.md.twig')
|
|
||||||
->context([
|
|
||||||
'notification' => $notification,
|
|
||||||
'dest' => $addressee,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private function processNotificationForAddressee(Notification $notification, $addressee): void
|
||||||
|
{
|
||||||
|
$notificationFlags = $addressee->getNotificationFlags();
|
||||||
|
$notificationType = $notification->getType();
|
||||||
|
|
||||||
|
$emailPreference = $notificationFlags[$notificationType->value] ?? null;
|
||||||
|
|
||||||
|
match ($emailPreference) {
|
||||||
|
'immediate-email' => $this->scheduleImmediateEmail($notification, $addressee),
|
||||||
|
'daily-email' => $this->scheduleDailyEmail($notification, $addressee),
|
||||||
|
default => $this->logger->debug('[NotificationMailer] No email preference set for notification type', [
|
||||||
|
'notification_id' => $notification->getId(),
|
||||||
|
'addressee_email' => $addressee->getEmail(),
|
||||||
|
'notification_type' => $notificationType->value,
|
||||||
|
'preference' => $emailPreference,
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function scheduleImmediateEmail(Notification $notification, $addressee): void
|
||||||
|
{
|
||||||
|
$message = new SendImmediateNotificationEmailMessage(
|
||||||
|
$notification->getId(),
|
||||||
|
$addressee->getId()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->messageBus->dispatch($message);
|
||||||
|
|
||||||
|
$this->logger->info('[NotificationMailer] Scheduled immediate email', [
|
||||||
|
'notification_id' => $notification->getId(),
|
||||||
|
'addressee_email' => $addressee->getEmail(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function scheduleDailyEmail(Notification $notification, $addressee): void
|
||||||
|
{
|
||||||
|
$message = new ScheduleDailyNotificationEmailMessage(
|
||||||
|
$notification->getId(),
|
||||||
|
$addressee->getId()
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->messageBus->dispatch($message);
|
||||||
|
|
||||||
|
$this->logger->info('[NotificationMailer] Scheduled daily email', [
|
||||||
|
'notification_id' => $notification->getId(),
|
||||||
|
'addressee_email' => $addressee->getEmail(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sends the email but is now called by the immediate notification email message handler.
|
||||||
|
*
|
||||||
|
* @throws TransportExceptionInterface
|
||||||
|
*/
|
||||||
|
public function sendEmailToAddressee(Notification $notification, $addressee): void
|
||||||
|
{
|
||||||
|
if (null === $addressee->getEmail()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($notification->isSystem()) {
|
||||||
|
$email = new Email();
|
||||||
|
$email->text($notification->getMessage());
|
||||||
|
} else {
|
||||||
|
$email = new TemplatedEmail();
|
||||||
$email
|
$email
|
||||||
->subject($notification->getTitle())
|
->textTemplate('@ChillMain/Notification/email_non_system_notification_content.fr.md.twig')
|
||||||
->to($addressee->getEmail());
|
->context([
|
||||||
|
'notification' => $notification,
|
||||||
try {
|
'dest' => $addressee,
|
||||||
$this->mailer->send($email);
|
|
||||||
} catch (TransportExceptionInterface $e) {
|
|
||||||
$this->logger->warning('[NotificationMailer] could not send an email notification', [
|
|
||||||
'to' => $addressee->getEmail(),
|
|
||||||
'error_message' => $e->getMessage(),
|
|
||||||
'error_trace' => $e->getTraceAsString(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$email
|
||||||
|
->subject($notification->getTitle())
|
||||||
|
->to($addressee->getEmail());
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->mailer->send($email);
|
||||||
|
$this->logger->info('[NotificationMailer] Email sent successfully', [
|
||||||
|
'notification_id' => $notification->getId(),
|
||||||
|
'addressee_email' => $addressee->getEmail(),
|
||||||
|
]);
|
||||||
|
} catch (TransportExceptionInterface $e) {
|
||||||
|
$this->logger->warning('[NotificationMailer] Could not send an email notification', [
|
||||||
|
'to' => $addressee->getEmail(),
|
||||||
|
'notification_id' => $notification->getId(),
|
||||||
|
'error_message' => $e->getMessage(),
|
||||||
|
'error_trace' => $e->getTraceAsString(),
|
||||||
|
]);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send daily digest email with multiple notifications to a user.
|
||||||
|
* @throws TransportExceptionInterface
|
||||||
|
*/
|
||||||
|
public function sendDailyDigest($user, array $notifications): void
|
||||||
|
{
|
||||||
|
if (null === $user->getEmail() || empty($notifications)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$email = new TemplatedEmail();
|
||||||
|
$email
|
||||||
|
->textTemplate('@ChillMain/Notification/email_daily_digest.fr.md.twig')
|
||||||
|
->context([
|
||||||
|
'user' => $user,
|
||||||
|
'notifications' => $notifications,
|
||||||
|
'notification_count' => count($notifications),
|
||||||
|
])
|
||||||
|
->subject($this->translator->trans('notification.Daily Notification Digest'))
|
||||||
|
->to($user->getEmail());
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->mailer->send($email);
|
||||||
|
$this->logger->info('[NotificationMailer] Daily digest email sent successfully', [
|
||||||
|
'user_email' => $user->getEmail(),
|
||||||
|
'notification_count' => count($notifications),
|
||||||
|
]);
|
||||||
|
} catch (TransportExceptionInterface $e) {
|
||||||
|
$this->logger->warning('[NotificationMailer] Could not send daily digest email', [
|
||||||
|
'to' => $user->getEmail(),
|
||||||
|
'notification_count' => count($notifications),
|
||||||
|
'error_message' => $e->getMessage(),
|
||||||
|
'error_trace' => $e->getTraceAsString(),
|
||||||
|
]);
|
||||||
|
throw $e; // Re-throw so the message handler can handle the failure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
|
||||||
|
class AccompanyingCourseNotificationFlagProvider implements NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFlag(): string
|
||||||
|
{
|
||||||
|
return NotificationFlagEnum::ACC_COURSE->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface
|
||||||
|
{
|
||||||
|
return new TranslatableMessage('notification.flags.acc-course');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
|
||||||
|
class AccompanyingCourseWorkEvalDocNotificationFlagProvider implements NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFlag(): string
|
||||||
|
{
|
||||||
|
return NotificationFlagEnum::ACC_COURSE_WORK_EVAL_DOC->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface
|
||||||
|
{
|
||||||
|
return new TranslatableMessage('notification.flags.acc-course-work-eval-doc');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
|
||||||
|
class AccompanyingCourseWorkNotificationFlagProvider implements NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFlag(): string
|
||||||
|
{
|
||||||
|
return NotificationFlagEnum::ACC_COURSE_WORK->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface
|
||||||
|
{
|
||||||
|
return new TranslatableMessage('notification.flags.acc-course-work');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
|
||||||
|
class ActivityNotificationFlagProvider implements NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFlag(): string
|
||||||
|
{
|
||||||
|
return NotificationFlagEnum::ACTIVITY->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface
|
||||||
|
{
|
||||||
|
return new TranslatableMessage('notification.flags.activity');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
|
||||||
|
class DesignatedReferrerNotificationFlagProvider implements NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFlag(): string
|
||||||
|
{
|
||||||
|
return NotificationFlagEnum::REFERRER_ACC_COURSE->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface
|
||||||
|
{
|
||||||
|
return new TranslatableMessage('notification.flags.referrer-acc-course');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,23 @@
|
|||||||
|
<?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\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
|
||||||
|
|
||||||
|
#[AutoconfigureTag('chill_main.notification_flag_provider')]
|
||||||
|
interface NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
public function getFlag(): string;
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface;
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
|
||||||
|
class PersonAddressMoveNotificationFlagProvider implements NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFlag(): string
|
||||||
|
{
|
||||||
|
return NotificationFlagEnum::PERSON_MOVE->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface
|
||||||
|
{
|
||||||
|
return new TranslatableMessage('notification.flags.person-address-move');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Notification\FlagProviders;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
|
|
||||||
|
class WorkflowTransitionNotificationFlagProvider implements NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFlag(): string
|
||||||
|
{
|
||||||
|
return NotificationFlagEnum::WORKFLOW_TRANS->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabel(): TranslatableInterface
|
||||||
|
{
|
||||||
|
return new TranslatableMessage('notification.flags.workflow-trans');
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
<?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\Notification;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Notification\FlagProviders\NotificationFlagProviderInterface;
|
||||||
|
|
||||||
|
final readonly class NotificationFlagManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<NotificationFlagProviderInterface>
|
||||||
|
*/
|
||||||
|
private array $notificationFlagProviders;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
iterable $notificationFlagProviders,
|
||||||
|
) {
|
||||||
|
$this->notificationFlagProviders = iterator_to_array($notificationFlagProviders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllNotificationFlagProviders(): array
|
||||||
|
{
|
||||||
|
return $this->notificationFlagProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNotificationFlagProviderByLabel(string $label): ?NotificationFlagProviderInterface
|
||||||
|
{
|
||||||
|
foreach ($this->notificationFlagProviders as $provider) {
|
||||||
|
if ($provider->getLabel() == $label) {
|
||||||
|
return $provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,18 @@
|
|||||||
|
# Résumé quotidien des notifications
|
||||||
|
|
||||||
|
Bonjour {{ user.name ?? user.email }},
|
||||||
|
|
||||||
|
Voici vos {{ notification_count }} notification{% if notification_count > 1 %}s{% endif %} du jour :
|
||||||
|
|
||||||
|
{% for notification in notifications %}
|
||||||
|
## {{ notification.title }}
|
||||||
|
|
||||||
|
{{ notification.message }}
|
||||||
|
|
||||||
|
Vous pouvez visualiser la notification et y répondre ici:
|
||||||
|
|
||||||
|
{{ absolute_url(path('chill_main_notification_show', {'_locale': 'fr', 'id': notification.id }, false)) }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
--
|
||||||
|
Le logiciel Chill
|
@@ -45,6 +45,32 @@
|
|||||||
{{ form_start(form) }}
|
{{ form_start(form) }}
|
||||||
{{ form_row(form.phonenumber) }}
|
{{ form_row(form.phonenumber) }}
|
||||||
|
|
||||||
|
<h2 class="mb-4">{{ 'user.profile.notification_preferences'|trans }}</h2>
|
||||||
|
<table class="table table-bordered border-dark align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'notification.flags.type'|trans }}</th>
|
||||||
|
<th>{{ 'notification.flags.preferences.immediate_email'|trans }}</th>
|
||||||
|
<th>{{ 'notification.flags.preferences.daily_email'|trans }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for flag in form.notificationFlags %}
|
||||||
|
<tr>
|
||||||
|
<td class="col-sm-6">
|
||||||
|
<label>{{ form_label(flag) }}</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ form_widget(flag.immediate_email) }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ form_widget(flag.daily_email) }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
{{ form_widget(form.submit, { 'attr': { 'class': 'btn btn-save' } } ) }}
|
{{ form_widget(form.submit, { 'attr': { 'class': 'btn btn-save' } } ) }}
|
||||||
|
@@ -12,6 +12,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\MainBundle\Workflow\EventSubscriber;
|
namespace Chill\MainBundle\Workflow\EventSubscriber;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\Notification;
|
use Chill\MainBundle\Entity\Notification;
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Entity\UserGroup;
|
use Chill\MainBundle\Entity\UserGroup;
|
||||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
||||||
@@ -125,7 +126,8 @@ class NotificationOnTransition implements EventSubscriberInterface
|
|||||||
->setRelatedEntityClass(EntityWorkflow::class)
|
->setRelatedEntityClass(EntityWorkflow::class)
|
||||||
->setTitle($this->engine->render('@ChillMain/Workflow/workflow_notification_on_transition_completed_title.fr.txt.twig', $context))
|
->setTitle($this->engine->render('@ChillMain/Workflow/workflow_notification_on_transition_completed_title.fr.txt.twig', $context))
|
||||||
->setMessage($this->engine->render('@ChillMain/Workflow/workflow_notification_on_transition_completed_content.fr.txt.twig', $context))
|
->setMessage($this->engine->render('@ChillMain/Workflow/workflow_notification_on_transition_completed_content.fr.txt.twig', $context))
|
||||||
->addAddressee($subscriber);
|
->addAddressee($subscriber)
|
||||||
|
->setType(NotificationFlagEnum::WORKFLOW_TRANS);
|
||||||
$this->entityManager->persist($notification);
|
$this->entityManager->persist($notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -139,6 +139,11 @@ services:
|
|||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
|
|
||||||
|
Chill\MainBundle\Form\DataMapper\NotificationFlagDataMapper:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
Chill\MainBundle\Form\UserProfileType: ~
|
||||||
Chill\MainBundle\Form\AbsenceType: ~
|
Chill\MainBundle\Form\AbsenceType: ~
|
||||||
Chill\MainBundle\Form\DataMapper\RegroupmentDataMapper: ~
|
Chill\MainBundle\Form\DataMapper\RegroupmentDataMapper: ~
|
||||||
Chill\MainBundle\Form\RegroupmentType: ~
|
Chill\MainBundle\Form\RegroupmentType: ~
|
||||||
|
@@ -12,6 +12,10 @@ services:
|
|||||||
arguments:
|
arguments:
|
||||||
$routeParameters: '%chill_main.notifications%'
|
$routeParameters: '%chill_main.notifications%'
|
||||||
|
|
||||||
|
Chill\MainBundle\Notification\NotificationFlagManager:
|
||||||
|
arguments:
|
||||||
|
$notificationFlagProviders: !tagged_iterator chill_main.notification_flag_provider
|
||||||
|
|
||||||
Chill\MainBundle\Notification\NotificationHandlerManager:
|
Chill\MainBundle\Notification\NotificationHandlerManager:
|
||||||
arguments:
|
arguments:
|
||||||
$handlers: !tagged_iterator chill_main.notification_handler
|
$handlers: !tagged_iterator chill_main.notification_handler
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Main;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
final class Version20250610102953 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add notification flags property to User';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE users ADD notificationFlags JSONB DEFAULT '[]' NOT NULL
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE users DROP notificationFlags
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\Main;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20250618115938 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add type property to notifications';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE chill_main_notification ADD type VARCHAR(255)
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE chill_main_notification DROP type
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
}
|
@@ -51,9 +51,10 @@ Label: Nom
|
|||||||
user:
|
user:
|
||||||
profile:
|
profile:
|
||||||
title: Mon profil
|
title: Mon profil
|
||||||
Phonenumber successfully updated!: Numéro de téléphone mis à jour!
|
Profile successfully updated!: Votre profil a été mis à jour!
|
||||||
no job: Pas de métier assigné
|
no job: Pas de métier assigné
|
||||||
no scope: Pas de cercle assigné
|
no scope: Pas de cercle assigné
|
||||||
|
notification_preferences: Préférences pour mes notifications
|
||||||
|
|
||||||
user_group:
|
user_group:
|
||||||
inactive: Inactif
|
inactive: Inactif
|
||||||
@@ -715,6 +716,21 @@ notification:
|
|||||||
mark_as_read: Marquer comme lu
|
mark_as_read: Marquer comme lu
|
||||||
mark_as_unread: Marquer comme non-lu
|
mark_as_unread: Marquer comme non-lu
|
||||||
|
|
||||||
|
flags:
|
||||||
|
type: Type de notification
|
||||||
|
referrer-acc-course: Notification lors de la désignation comme référent
|
||||||
|
acc-course-work-eval-doc: Notification sur un document d'évaluation
|
||||||
|
acc-course-work: Notification sur un action d'accompagnement
|
||||||
|
activity: Notification sur un échange
|
||||||
|
acc-course: Notification sur un parcours d'accompagnement
|
||||||
|
person-address-move: Notification lors que l'usager qui localise un parcours a déménagé
|
||||||
|
person: Notification sur un usager
|
||||||
|
workflow-trans: Notification sur une transition d'un workflow
|
||||||
|
preferences:
|
||||||
|
immediate_email: Recevoir un email immédiatement
|
||||||
|
daily_email: Recevoir un récapitulatif quotidien
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export:
|
export:
|
||||||
address_helper:
|
address_helper:
|
||||||
|
@@ -13,6 +13,7 @@ namespace Chill\PersonBundle\AccompanyingPeriod\Events;
|
|||||||
|
|
||||||
use Chill\MainBundle\Entity\Address;
|
use Chill\MainBundle\Entity\Address;
|
||||||
use Chill\MainBundle\Entity\Notification;
|
use Chill\MainBundle\Entity\Notification;
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
use Chill\MainBundle\Notification\NotificationPersisterInterface;
|
use Chill\MainBundle\Notification\NotificationPersisterInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Event\Person\PersonAddressMoveEvent;
|
use Chill\PersonBundle\Event\Person\PersonAddressMoveEvent;
|
||||||
@@ -65,7 +66,8 @@ class PersonAddressMoveEventSubscriber implements EventSubscriberInterface
|
|||||||
->setMessage($this->engine->render('@ChillPerson/AccompanyingPeriod/notification_location_user_on_period_has_moved.fr.txt.twig', [
|
->setMessage($this->engine->render('@ChillPerson/AccompanyingPeriod/notification_location_user_on_period_has_moved.fr.txt.twig', [
|
||||||
'oldPersonLocation' => $person,
|
'oldPersonLocation' => $person,
|
||||||
'period' => $period,
|
'period' => $period,
|
||||||
]));
|
]))
|
||||||
|
->setType(NotificationFlagEnum::PERSON_MOVE);
|
||||||
|
|
||||||
$this->notificationPersister->persist($notification);
|
$this->notificationPersister->persist($notification);
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\PersonBundle\AccompanyingPeriod\Events;
|
namespace Chill\PersonBundle\AccompanyingPeriod\Events;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\Notification;
|
use Chill\MainBundle\Entity\Notification;
|
||||||
|
use Chill\MainBundle\Entity\NotificationFlagEnum;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Notification\NotificationPersisterInterface;
|
use Chill\MainBundle\Notification\NotificationPersisterInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
@@ -73,7 +74,8 @@ class UserRefEventSubscriber implements EventSubscriberInterface
|
|||||||
'accompanyingCourse' => $period,
|
'accompanyingCourse' => $period,
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
->addAddressee($period->getUser());
|
->addAddressee($period->getUser())
|
||||||
|
->setType(NotificationFlagEnum::REFERRER_ACC_COURSE);
|
||||||
|
|
||||||
$this->notificationPersister->persist($notification);
|
$this->notificationPersister->persist($notification);
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,15 @@
|
|||||||
"config/routes/annotations.yaml"
|
"config/routes/annotations.yaml"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"doctrine/deprecations": {
|
||||||
|
"version": "1.1",
|
||||||
|
"recipe": {
|
||||||
|
"repo": "github.com/symfony/recipes",
|
||||||
|
"branch": "main",
|
||||||
|
"version": "1.0",
|
||||||
|
"ref": "87424683adc81d7dc305eefec1fced883084aab9"
|
||||||
|
}
|
||||||
|
},
|
||||||
"doctrine/doctrine-bundle": {
|
"doctrine/doctrine-bundle": {
|
||||||
"version": "2.13",
|
"version": "2.13",
|
||||||
"recipe": {
|
"recipe": {
|
||||||
|
Reference in New Issue
Block a user