src/Controller/Api/ApiPublicationController.php line 379

Open in your IDE?
  1. <?php
  2. /**
  3.  * ApiPublicationController.php.
  4.  */
  5. namespace App\Controller\Api;
  6. use App\Entity\Entrance;
  7. use App\Entity\MessageTarget;
  8. use App\Entity\PublicMessage;
  9. use App\Entity\PublicPage;
  10. use App\Entity\Residence;
  11. use App\Entity\ThinClient;
  12. use App\Entity\Video;
  13. use App\Service\FrontService;
  14. use App\Service\ThinClientService;
  15. use App\Utils\BrowserNotificationSender;
  16. use App\Utils\MediaManager;
  17. use Doctrine\Common\Collections\ArrayCollection;
  18. use Doctrine\Persistence\ManagerRegistry;
  19. use FOS\RestBundle\Controller\AbstractFOSRestController;
  20. use FOS\RestBundle\Controller\Annotations as Rest;
  21. use FOS\RestBundle\Controller\Annotations\Delete;
  22. use FOS\RestBundle\Controller\Annotations\Get;
  23. use FOS\RestBundle\Controller\Annotations\Post;
  24. use FOS\RestBundle\View\View;
  25. use Liip\ImagineBundle\Imagine\Cache\CacheManager;
  26. use Psr\Log\LoggerInterface;
  27. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  28. use Symfony\Component\HttpFoundation\Request;
  29. use Symfony\Component\HttpFoundation\Response;
  30. use Symfony\Component\Routing\Annotation\Route;
  31. /**
  32.  * Api controller for public pages and public messages management.
  33.  */
  34. #[Route(path: '/api')]
  35. class ApiPublicationController extends AbstractFOSRestController
  36. {
  37.     public function __construct(private readonly ManagerRegistry $doctrine)
  38.     {
  39.     }
  40.     /**
  41.      * @Rest\View()
  42.      * @Rest\Put("/messages")
  43.      */
  44.     public function editPublicMessage(Request $request, ThinClientService $thinClientService)
  45.     {
  46.         $msgRequest = json_decode($request->getContent(), true);
  47.         $em = $this->doctrine->getManager();
  48.         $publicMessage = $this->doctrine
  49.       ->getRepository(PublicMessage::class)
  50.       ->find($msgRequest['message_id']);
  51.         if (empty($publicMessage)) {
  52.             return \FOS\RestBundle\View\View::create(['message' => 'Message not found'], Response::HTTP_NOT_FOUND);
  53.         }
  54.         $publicMessage->setSubject($msgRequest['subject']);
  55.         $publicMessage->setContent($msgRequest['content']);
  56.         $publicMessage->setImportant($msgRequest['important']);
  57.         $inComingStartDisplayDate = $msgRequest['start_display_date'];
  58.         $publicMessage->setStartDisplayDate(new \DateTime("@$inComingStartDisplayDate"));
  59.         if ($msgRequest['stop_display_date']) {
  60.             $inComingStopDisplayDate = $msgRequest['stop_display_date'];
  61.             $publicMessage->setStopDisplayDate(new \DateTime("@$inComingStopDisplayDate"));
  62.         }
  63.         // --- réinitialisation des messages targets
  64.         foreach ($publicMessage->getMessageTargets() as $mt) {
  65.             $entrance = $mt->getEntrance();
  66.             $residence = $mt->getResidence();
  67.             if (null !== $entrance) {
  68.                 if (!in_array($entrance->getId(), $msgRequest['message_targets']['entrances'])) {
  69.                     // --- V2 :
  70.                     $entrance->refreshUpdateToken();
  71.                     // --- V3 :
  72.                     $thinClientService->updateEntranceToken($entrance, 'messages');
  73.                     $thinClientService->updateEntranceToken($entrance, 'launcher_grid');
  74.                     $em->persist($entrance);
  75.                 }
  76.             } elseif (null !== $residence) {
  77.                 if (!in_array($residence->getId(), $msgRequest['message_targets']['residences'])) {
  78.                     // --- V2 :
  79.                     $residence->refreshAllUpdateToken();
  80.                 }
  81.                 // --- V3 :
  82.                 $thinClientService->updateResidenceToken($mt->getResidence(), 'messages');
  83.                 $thinClientService->updateResidenceToken($mt->getResidence(), 'launcher_grid');
  84.                 $em->persist($residence);
  85.             }
  86.             $publicMessage->removeMessageTarget($mt);
  87.             $em->remove($mt);
  88.         }
  89.         foreach ($msgRequest['message_targets']['residences'] as $residenceId) {
  90.             $residence = $this->doctrine
  91.         ->getRepository(Residence::class)
  92.         ->find($residenceId);
  93.             $messageTarget = new MessageTarget();
  94.             $messageTarget->setPublicMessage($publicMessage);
  95.             $messageTarget->setResidence($residence);
  96.             $publicMessage->addMessageTarget($messageTarget);
  97.             // --- V2 :
  98.             $residence->refreshAllUpdateToken();
  99.             // --- V3 :
  100.             $thinClientService->updateResidenceToken($residence, 'messages');
  101.             $thinClientService->updateResidenceToken($residence, 'launcher_grid');
  102.             $em->persist($residence);
  103.             $em->persist($messageTarget);
  104.         }
  105.         foreach ($msgRequest['message_targets']['entrances'] as $entranceId) {
  106.             $entrance = $this->doctrine
  107.         ->getRepository(Entrance::class)
  108.         ->find($entranceId);
  109.             $messageTarget = new MessageTarget();
  110.             $messageTarget->setPublicMessage($publicMessage);
  111.             $messageTarget->setEntrance($entrance);
  112.             $publicMessage->addMessageTarget($messageTarget);
  113.             // --- V2 :
  114.             $entrance->refreshUpdateToken();
  115.             // --- V3 :
  116.             $thinClientService->updateEntranceToken($entrance, 'messages');
  117.             $thinClientService->updateEntranceToken($entrance, 'launcher_grid');
  118.             $em->persist($entrance);
  119.             $em->persist($messageTarget);
  120.         }
  121.         $em->persist($publicMessage);
  122.         $em->flush();
  123.         $response = [];
  124.         $response['message'] = $publicMessage;
  125.         return new View($response, Response::HTTP_CREATED);
  126.     }
  127.     /**
  128.      * @Get("/publications/{typeProperty}/{propertyId}")
  129.      *
  130.      * @param $typeProperty string Property type : 'entrance' or 'residence'
  131.      * @param $propertyId integer Property identifier
  132.      * @throws \Exception
  133.      */
  134.     #[IsGranted('ROLE_VIEW_PROPERTIES')]
  135.     public function getPublicationsForProperty($typeProperty, $propertyId, MediaManager $mediaManager, CacheManager $imagineCacheManager, LoggerInterface $logger): View
  136.     {
  137.         try {
  138.             if (!in_array($typeProperty, ['entrance', 'residence'])) {
  139.                 throw new \Exception("Invalid typeProperty (must be 'entrance', 'residence')", 1);
  140.             }
  141.             $property = $this->doctrine->getRepository('\App\Entity\\'.ucfirst((string) $typeProperty))->find($propertyId);
  142.             if (null === $property) {
  143.                 return new View("This {$typeProperty} does not exist", Response::HTTP_NOT_FOUND);
  144.             }
  145.             $publicPages = $property->getPublicationsToDisplay('publicPages');
  146.             foreach ($publicPages as $page) {
  147.                 $page->setPreviewUrl($mediaManager->getServerUrl($page->getPreviewName()));
  148.                 $thumb = $imagineCacheManager->getBrowserPath($page->getPreviewName(), 'page_preview_medium');
  149.                 $page->setPreviewThumb($thumb);
  150.             }
  151.             $publicMessages = $property->getPublicationsToDisplay('publicMessages');
  152.             $socialAds = $property->getPublicationsToDisplay('socialAds');
  153.             return new View([
  154.           'publicMessages' => $publicMessages,
  155.           'socialAds' => $socialAds,
  156.           'publicPages' => $publicPages,
  157.       ], Response::HTTP_OK);
  158.         } catch (\Exception $e) {
  159.             $logger->error($e->getMessage(), $e->getTrace());
  160.             return new View("Echec : {$e->getMessage()}", Response::HTTP_UNPROCESSABLE_ENTITY);
  161.         }
  162.     }
  163.     /**
  164.      * Return the current important publicMessage of the attached entrance.
  165.      *
  166.      * @Get("/important/message")
  167.      */
  168.     #[IsGranted('ROLE_FRONT_ACCESS')]
  169.     public function getEntranceImportantMessage(): View
  170.     {
  171.         try {
  172.             if (!$this->getUser()->hasGroup('GROUP_RESIDENT')) {
  173.                 throw new \Exception('Only residents can access this endpoint', 1);
  174.             }
  175.             $entrance = $this->getUser()->getApartment()->getEntrance();
  176.             $messagePrios = $entrance->getPublicationsToDisplay('publicMessages')->filter(fn(PublicMessage $publicMessage) => $publicMessage->getImportant());
  177.             $messagePrio = false;
  178.             if ($messagePrios->count() > 0) {
  179.                 $messagePrio = $messagePrios->first();
  180.                 $messagePrio->setSender(null); // Pas terrible, mais ça évite de faire tout un micmac de groupes de sérialisation
  181.             }
  182.             return new View($messagePrio, Response::HTTP_OK);
  183.         } catch (\Exception $e) {
  184.             return new View('Echec : '.$e->getMessage(), Response::HTTP_UNPROCESSABLE_ENTITY);
  185.         }
  186.     }
  187.     /**
  188.      * Return current user uploaded videos.
  189.      *
  190.      * @Get("/videos")
  191.      */
  192.     #[IsGranted('ROLE_PUBLICPAGE_VIDEO')]
  193.     public function getUserVideos(): View
  194.     {
  195.         $repo = $this->doctrine->getManager()->getRepository(Video::class);
  196.         $videos = $repo->findBy(['uploader' => $this->getUser()]);
  197.         return new View($videos);
  198.     }
  199.     /**
  200.      * @Post("/delete/{typePublication}/{idPublication}")
  201.      *
  202.      * @param $typePublication string Publication type : 'publicMessage', 'publicPage' or 'socialad'
  203.      * @param $idPublication integer Publication identifier
  204.      */
  205.     #[IsGranted('ROLE_FRONT_ACCESS')]
  206.     public function deletePublication($typePublication, $idPublication, BrowserNotificationSender $notificationSender, FrontService $frontService, ThinClientService $thinClientService, \Symfony\Contracts\Translation\TranslatorInterface $translator): View
  207.     {
  208.         try {
  209.             if (!in_array($typePublication, ['publicMessage', 'publicPage', 'socialad'])) {
  210.                 throw new \Exception("Invalid typePublication (must be 'publicMessage' or 'publicPage");
  211.             }
  212.             if ('socialad' === $typePublication) {
  213.                 return $frontService->deleteSocialAd($idPublication, $this->getUser());
  214.             }
  215.             if (!$this->getUser()->hasRole('ROLE_PUBLICPAGE')) {
  216.                 return new View('Denied access', Response::HTTP_FORBIDDEN);
  217.             }
  218.             if (empty($idPublication) || ($idPublication != intval($idPublication))) {
  219.                 throw new \Exception('Veuillez spécifier la publication à supprimer');
  220.             }
  221.             $targetPublication = $this->doctrine->getRepository('\App\Entity\\'.ucfirst((string) $typePublication))->find($idPublication);
  222.             if (null === $targetPublication) {
  223.                 throw new \Exception('Publication introuvable');
  224.             }
  225.             if ('publicPage' === $typePublication) {
  226.                 if ($targetPublication->getCreator() !== $this->getUser() && !$this->getUser()->hasRole('ROLE_PUBLICPAGE')) {
  227.                     throw new \Exception("Seul l'auteur d'une publication peut la supprimer!", 1);
  228.                 }
  229.             }
  230.             if ('publicMessage' === $typePublication) {
  231.                 if ($targetPublication->getSender() !== $this->getUser() && !$this->getUser()->hasRole('ROLE_PUBLICMESSAGE')) {
  232.                     throw new \Exception("Seul l'auteur d'une publication peut la supprimer!", 1);
  233.                 }
  234.             }
  235.             $em = $this->doctrine->getManager();
  236.             // Update-token of message target
  237.             if ('publicMessage' == $typePublication) {
  238.                 $dataType = 'messages';
  239.             } elseif ('publicPage' == $typePublication) {
  240.                 $dataType = 'pages';
  241.             }
  242.             $targetResidences = new ArrayCollection();
  243.             foreach ($targetPublication->getMessageTargets() as $mt) {
  244.                 $entrance = $mt->getEntrance();
  245.                 $residence = $mt->getResidence();
  246.                 if (null !== $entrance) {
  247.                     $entrance->refreshUpdateToken();
  248.                     $em->persist($entrance);
  249.                     // --- V3 :
  250.                     $thinClientService->updateEntranceToken($entrance, $dataType);
  251.                     if ('messages' == $dataType) {
  252.                         $thinClientService->updateEntranceToken($entrance, 'launcher_grid');
  253.                     }
  254.                     if (!$targetResidences->contains($mt->getEntrance()->getResidence())) {
  255.                         $targetResidences->add($mt->getEntrance()->getResidence());
  256.                     }
  257.                 } elseif (null !== $residence) {
  258.                     $residence->refreshAllUpdateToken();
  259.                     $em->persist($residence);
  260.                     // --- V3 :
  261.                     $thinClientService->updateResidenceToken($residence, $dataType);
  262.                     if ('messages' == $dataType) {
  263.                         $thinClientService->updateResidenceToken($residence, 'launcher_grid');
  264.                     }
  265.                     if (!$targetResidences->contains($mt->getResidence())) {
  266.                         $targetResidences->add($mt->getResidence());
  267.                     }
  268.                 }
  269.             }
  270.             /* OK --> delete publication and associations */
  271.             foreach ($targetPublication->getMessageTargets() as $messageTarget) {
  272.                 $em->remove($messageTarget);
  273.             }
  274.             foreach ($targetPublication->getModerationEvents() as $moderationEvent) {
  275.                 $em->remove($moderationEvent);
  276.             }
  277.             $em->remove($targetPublication);
  278.             $em->flush();
  279.             // --- Notification management :
  280.             $landlords = new ArrayCollection();
  281.             foreach ($targetResidences as $targetResidence) {
  282.                 foreach ($targetResidence->getAffectedLandlordsByRole('ROLE_MODERATOR') as $landlord) {
  283.                     $landlords->add($landlord);
  284.                 }
  285.             }
  286.             $notificationSender->sendMultipleNotifications(
  287.                 $landlords,
  288.                 BrowserNotificationSender::TYPE_PUBLIC_CONTENT_DELETED,
  289.                 $this->getUser()
  290.             );
  291.             return new View($translator->trans('publications.deleted'), Response::HTTP_ACCEPTED);
  292.         } catch (\Exception $e) {
  293.             return new View("Echec : {$e->getMessage()}", Response::HTTP_UNPROCESSABLE_ENTITY);
  294.         }
  295.     }
  296.     /**
  297.      * @Delete("videos/delete/{id}")
  298.      *
  299.      * @param int $id id de l'entité vidéo
  300.      */
  301.     #[IsGranted('ROLE_PUBLICPAGE_VIDEO')]
  302.     public function deleteVideo($id, MediaManager $mm): View
  303.     {
  304.         $video = $this->doctrine->getRepository(Video::class)->find($id);
  305.         if (null === $video) {
  306.             return new View('This video does not exist', Response::HTTP_NOT_FOUND);
  307.         }
  308.         $em = $this->doctrine->getManager();
  309.         $mm->deleteObject($video->getVideoName());
  310.         if (Video::STATUS_UPLOADING === $video->getVideoStatus() && null !== $video->getUploadId()) {
  311.             $mm->abortMultipartUpload($video->getVideoName(), $video->getUploadId());
  312.         } elseif (Video::STATUS_READY !== $video->getVideoStatus()) {
  313.             $mm->deleteObject($video->getVideoName());
  314.         } else {
  315.             $mm->deleteObject($video->getVideoName());
  316.         }
  317.         $em->remove($video);
  318.         $em->flush();
  319.         return new View('Video has been deleted', Response::HTTP_OK);
  320.     }
  321.     /**
  322.      * Return publication.
  323.      *
  324.      * @Get("/get/publication/{id}/{token}")
  325.      *
  326.      * @param int    $id    id publication
  327.      * @param string $token thinclient token
  328.      */
  329.     public function getPublicationById($id, $token, MediaManager $mediaManager)
  330.     {
  331.         $em = $this->doctrine->getManager();
  332.         /** @var Thinclient $thinclient */
  333.         $thinclient = $em->getRepository(ThinClient::class)->findOneBySoftwareId($token);
  334.         if (null === $thinclient) {
  335.             return new View(['Le client n\'existe pas'], Response::HTTP_NOT_FOUND);
  336.         }
  337.         /** @var PublicPage $publication */
  338.         $publication = $em->getRepository(PublicPage::class)->findOneBy(['id' => $id]);
  339.         if (null === $publication) {
  340.             return new View(['La publication n\'existe pas'], Response::HTTP_NOT_FOUND);
  341.         }
  342.         return $mediaManager->generateObjectResponse($publication->getPreviewName());
  343.     }
  344. }