mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-14 06:14:23 +00:00
342 lines
14 KiB
PHP
342 lines
14 KiB
PHP
<?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\Controller;
|
|
|
|
use Chill\MainBundle\Entity\Notification;
|
|
use Chill\MainBundle\Entity\NotificationComment;
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\MainBundle\Form\NotificationCommentType;
|
|
use Chill\MainBundle\Form\NotificationType;
|
|
use Chill\MainBundle\Notification\Exception\NotificationHandlerNotFound;
|
|
use Chill\MainBundle\Notification\NotificationHandlerManager;
|
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
|
use Chill\MainBundle\Repository\NotificationRepository;
|
|
use Chill\MainBundle\Repository\UserRepository;
|
|
use Chill\MainBundle\Security\Authorization\NotificationVoter;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
use Symfony\Component\Routing\Annotation\Route;
|
|
use Symfony\Component\Security\Core\Security;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
use function in_array;
|
|
|
|
/**
|
|
* @Route("/{_locale}/notification")
|
|
*/
|
|
class NotificationController extends AbstractController
|
|
{
|
|
public function __construct(private readonly EntityManagerInterface $em, private readonly LoggerInterface $chillLogger, private readonly LoggerInterface $logger, private readonly Security $security, private readonly NotificationRepository $notificationRepository, private readonly NotificationHandlerManager $notificationHandlerManager, private readonly PaginatorFactory $paginatorFactory, private readonly TranslatorInterface $translator, private readonly UserRepository $userRepository) {}
|
|
|
|
/**
|
|
* @Route("/create", name="chill_main_notification_create")
|
|
*/
|
|
public function createAction(Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
|
|
if (!$this->security->getUser() instanceof User) {
|
|
throw new AccessDeniedHttpException('You must be authenticated and a user to create a notification');
|
|
}
|
|
|
|
if (!$request->query->has('entityClass')) {
|
|
throw new BadRequestHttpException('Missing entityClass parameter');
|
|
}
|
|
|
|
if (!$request->query->has('entityId')) {
|
|
throw new BadRequestHttpException('missing entityId parameter');
|
|
}
|
|
|
|
$notification = new Notification();
|
|
$notification
|
|
->setRelatedEntityClass($request->query->get('entityClass'))
|
|
->setRelatedEntityId($request->query->getInt('entityId'))
|
|
->setSender($this->security->getUser());
|
|
|
|
if ($request->query->has('tos')) {
|
|
foreach ($request->query->get('tos') as $toId) {
|
|
if (null === $to = $this->userRepository->find($toId)) {
|
|
throw new NotFoundHttpException("user with id {$toId} is not found");
|
|
}
|
|
$notification->addAddressee($to);
|
|
}
|
|
}
|
|
|
|
try {
|
|
$handler = $this->notificationHandlerManager->getHandler($notification);
|
|
} catch (NotificationHandlerNotFound) {
|
|
throw new BadRequestHttpException('no handler for this notification');
|
|
}
|
|
|
|
$form = $this->createForm(NotificationType::class, $notification);
|
|
|
|
$form->handleRequest($request);
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
$this->em->persist($notification);
|
|
$this->em->flush();
|
|
|
|
$this->addFlash('success', $this->translator->trans('notification.Notification created'));
|
|
|
|
if ($request->query->has('returnPath')) {
|
|
return new RedirectResponse($request->query->get('returnPath'));
|
|
}
|
|
|
|
return $this->redirectToRoute('chill_main_homepage');
|
|
}
|
|
|
|
return $this->render('@ChillMain/Notification/create.html.twig', [
|
|
'form' => $form->createView(),
|
|
'handler' => $handler,
|
|
'notification' => $notification,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{id}/edit", name="chill_main_notification_edit")
|
|
*/
|
|
public function editAction(Notification $notification, Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted(NotificationVoter::NOTIFICATION_UPDATE, $notification);
|
|
|
|
$form = $this->createForm(NotificationType::class, $notification);
|
|
|
|
$form->handleRequest($request);
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
|
$this->em->flush();
|
|
|
|
$this->addFlash('success', $this->translator->trans('notification.Notification updated'));
|
|
|
|
if ($request->query->has('returnPath')) {
|
|
return new RedirectResponse($request->query->get('returnPath'));
|
|
}
|
|
|
|
return $this->redirectToRoute('chill_main_notification_my');
|
|
}
|
|
|
|
return $this->render('@ChillMain/Notification/edit.html.twig', [
|
|
'form' => $form->createView(),
|
|
'handler' => $this->notificationHandlerManager->getHandler($notification),
|
|
'notification' => $notification,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{id}/access_key", name="chill_main_notification_grant_access_by_access_key")
|
|
*/
|
|
public function getAccessByAccessKey(Notification $notification, Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
|
|
if (!$this->security->getUser() instanceof User) {
|
|
throw new AccessDeniedHttpException('You must be authenticated and a user to create a notification');
|
|
}
|
|
|
|
foreach (['accessKey'/* , 'email' */] as $param) {
|
|
if (!$request->query->has($param)) {
|
|
throw new BadRequestHttpException("Missing {$param} parameter");
|
|
}
|
|
}
|
|
|
|
if ($notification->getAccessKey() !== $request->query->getAlnum('accessKey')) {
|
|
throw new AccessDeniedHttpException('access key is invalid');
|
|
}
|
|
|
|
/*
|
|
desactivated due to escaped '&' in email links
|
|
if (!in_array($request->query->get('email'), $notification->getAddressesEmails(), true)) {
|
|
return (new Response('The email address is no more associated with this notification'))
|
|
->setStatusCode(Response::HTTP_FORBIDDEN);
|
|
}
|
|
*/
|
|
|
|
$notification->addAddressee($this->security->getUser());
|
|
|
|
$this->getDoctrine()->getManager()->flush();
|
|
|
|
$logMsg = '[Notification] a user is granted access to notification trough an access key';
|
|
$context = [
|
|
'notificationId' => $notification->getId(),
|
|
'email' => $request->query->get('email'),
|
|
'user' => $this->security->getUser()->getId(),
|
|
];
|
|
|
|
$this->logger->info($logMsg, $context);
|
|
$this->chillLogger->info($logMsg, $context);
|
|
|
|
return $this->redirectToRoute('chill_main_notification_show', ['id' => $notification->getId()]);
|
|
}
|
|
|
|
/**
|
|
* @Route("/inbox", name="chill_main_notification_my")
|
|
*/
|
|
public function inboxAction(): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
$currentUser = $this->security->getUser();
|
|
|
|
$notificationsNbr = $this->notificationRepository->countAllForAttendee($currentUser);
|
|
$paginator = $this->paginatorFactory->create($notificationsNbr);
|
|
|
|
$notifications = $this->notificationRepository->findAllForAttendee(
|
|
$currentUser,
|
|
$limit = $paginator->getItemsPerPage(),
|
|
$offset = $paginator->getCurrentPage()->getFirstItemNumber()
|
|
);
|
|
|
|
return $this->render('@ChillMain/Notification/list.html.twig', [
|
|
'datas' => $this->itemsForTemplate($notifications),
|
|
'notifications' => $notifications,
|
|
'paginator' => $paginator,
|
|
'step' => 'inbox',
|
|
'unreads' => $this->countUnread(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @Route("/sent", name="chill_main_notification_sent")
|
|
*/
|
|
public function sentAction(): Response
|
|
{
|
|
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
|
$currentUser = $this->security->getUser();
|
|
|
|
$notificationsNbr = $this->notificationRepository->countAllForSender($currentUser);
|
|
$paginator = $this->paginatorFactory->create($notificationsNbr);
|
|
|
|
$notifications = $this->notificationRepository->findAllForSender(
|
|
$currentUser,
|
|
$limit = $paginator->getItemsPerPage(),
|
|
$offset = $paginator->getCurrentPage()->getFirstItemNumber()
|
|
);
|
|
|
|
return $this->render('@ChillMain/Notification/list.html.twig', [
|
|
'datas' => $this->itemsForTemplate($notifications),
|
|
'notifications' => $notifications,
|
|
'paginator' => $paginator,
|
|
'step' => 'sent',
|
|
'unreads' => $this->countUnread(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @Route("/{id}/show", name="chill_main_notification_show")
|
|
*/
|
|
public function showAction(Notification $notification, Request $request): Response
|
|
{
|
|
$this->denyAccessUnlessGranted(NotificationVoter::NOTIFICATION_SEE, $notification);
|
|
|
|
if ($request->query->has('edit')) {
|
|
$commentId = $request->query->getInt('edit');
|
|
$editedComment = $notification->getComments()->filter(static fn (NotificationComment $c) => $c->getId() === $commentId)->first();
|
|
|
|
if (false === $editedComment) {
|
|
throw $this->createNotFoundException("Comment with id {$commentId} does not exists nor belong to this notification");
|
|
}
|
|
|
|
$this->denyAccessUnlessGranted(NotificationVoter::COMMENT_EDIT, $editedComment);
|
|
|
|
$editedCommentForm = $this->createForm(NotificationCommentType::class, $editedComment);
|
|
|
|
if (Request::METHOD_POST === $request->getMethod() && 'edit' === $request->request->get('form')) {
|
|
$editedCommentForm->handleRequest($request);
|
|
|
|
if ($editedCommentForm->isSubmitted() && $editedCommentForm->isValid()) {
|
|
$this->em->flush();
|
|
|
|
$this->addFlash('success', $this->translator->trans('notification.comment_updated'));
|
|
|
|
return $this->redirectToRoute('chill_main_notification_show', [
|
|
'id' => $notification->getId(),
|
|
'_fragment' => 'comment-'.$commentId,
|
|
]);
|
|
}
|
|
|
|
if ($editedCommentForm->isSubmitted() && !$editedCommentForm->isValid()) {
|
|
$this->addFlash('error', $this->translator->trans('This form contains errors'));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($this->isGranted(NotificationVoter::COMMENT_ADD, $notification)) {
|
|
$appendComment = new NotificationComment();
|
|
$appendCommentForm = $this->createForm(NotificationCommentType::class, $appendComment);
|
|
|
|
if (Request::METHOD_POST === $request->getMethod() && 'append' === $request->request->get('form')) {
|
|
$appendCommentForm->handleRequest($request);
|
|
|
|
if ($appendCommentForm->isSubmitted() && $appendCommentForm->isValid()) {
|
|
$notification->addComment($appendComment);
|
|
$this->em->persist($appendComment);
|
|
$this->em->flush();
|
|
|
|
$this->addFlash('success', $this->translator->trans('notification.comment_appended'));
|
|
|
|
return $this->redirectToRoute('chill_main_notification_show', [
|
|
'id' => $notification->getId(),
|
|
]);
|
|
}
|
|
|
|
if ($appendCommentForm->isSubmitted() && !$appendCommentForm->isValid()) {
|
|
$this->addFlash('error', $this->translator->trans('This form contains errors'));
|
|
}
|
|
}
|
|
}
|
|
|
|
$response = $this->render('@ChillMain/Notification/show.html.twig', [
|
|
'notification' => $notification,
|
|
'handler' => $this->notificationHandlerManager->getHandler($notification),
|
|
'appendCommentForm' => isset($appendCommentForm) ? $appendCommentForm->createView() : null,
|
|
'editedCommentForm' => isset($editedCommentForm) ? $editedCommentForm->createView() : null,
|
|
'editedCommentId' => $commentId ?? null,
|
|
]);
|
|
|
|
// we mark the notification as read after having computed the response
|
|
if ($this->getUser() instanceof User && !$notification->isReadBy($this->getUser())) {
|
|
$notification->markAsReadBy($this->getUser());
|
|
$this->em->flush();
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
private function countUnread(): array
|
|
{
|
|
return [
|
|
'sent' => $this->notificationRepository->countUnreadByUserWhereSender($this->security->getUser()),
|
|
'inbox' => $this->notificationRepository->countUnreadByUserWhereAddressee($this->security->getUser()),
|
|
];
|
|
}
|
|
|
|
private function itemsForTemplate(array $notifications): array
|
|
{
|
|
$templateData = [];
|
|
|
|
foreach ($notifications as $notification) {
|
|
$templateData[] = [
|
|
'template' => $this->notificationHandlerManager->getTemplate($notification),
|
|
'template_data' => $this->notificationHandlerManager->getTemplateData($notification),
|
|
'notification' => $notification,
|
|
];
|
|
}
|
|
|
|
return $templateData;
|
|
}
|
|
}
|