em = $em; $this->logger = $logger; $this->chillLogger = $chillLogger; $this->security = $security; $this->notificationRepository = $notificationRepository; $this->notificationHandlerManager = $notificationHandlerManager; $this->paginatorFactory = $paginatorFactory; $this->translator = $translator; $this->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 $e) { 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 function (NotificationComment $c) use ($commentId) { return $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; } }