src/Controller/FileController.php line 781

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Constant\BandTypeConstant;
  4. use App\Constant\UtilsConstant;
  5. use App\Entity\Project;
  6. use App\Services\CurlHttpClient;
  7. use DateInterval;
  8. use DateTime;
  9. use App\Services\SeoManager;
  10. use Doctrine\ORM\EntityManagerInterface;
  11. use Exception;
  12. use FOS\RestBundle\Controller\Annotations as Rest;
  13. use Liip\ImagineBundle\Imagine\Cache\CacheManager;
  14. use Symfony\Bridge\Twig\Mime\TemplatedEmail;
  15. use Symfony\Component\Asset\Package;
  16. use Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy;
  17. use Symfony\Component\Form\FormInterface;
  18. use Symfony\Component\HttpFoundation\JsonResponse;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use App\Constant\BandMemberRoleConstant;
  21. use App\Constant\FileActionConstant;
  22. use App\Constant\FilePlatformConstant;
  23. use App\Constant\FileStatusConstant;
  24. use App\Constant\FileTypeConstant;
  25. use App\Entity\BandMember;
  26. use App\Entity\FileBandMember;
  27. use App\Entity\FileReport;
  28. use App\Entity\Picture;
  29. use App\Entity\Playable;
  30. use App\Entity\User;
  31. use App\Entity\File;
  32. use App\Entity\Band;
  33. use App\Entity\Folder;
  34. use App\Form\AddDistantFileType;
  35. use App\Form\CreateFolderType;
  36. use App\Form\FileEditType;
  37. use App\Form\FileReportType;
  38. use App\Form\ShiftFileType;
  39. use App\Form\RenameFolderType;
  40. use App\Services\StorageManager;
  41. use Symfony\Component\HttpFoundation\Response;
  42. use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
  43. use Symfony\Component\Mailer\MailerInterface;
  44. use Symfony\Component\Mime\Address;
  45. use Symfony\Contracts\Translation\TranslatorInterface;
  46. class FileController extends WhiplayController
  47. {
  48.     const BAND_SHOW_ROUTE 'whiplay_band_show';
  49.     const FILES_FOLDER_ROUTE 'whiplay_files_folder';
  50.     const FILE_EDIT_ROUTE 'whiplay_file_edit';
  51.     const FILE_NAME 'file_name';
  52.     const BAND_NAME 'band_name';
  53.     /**
  54.      * Show file detail view
  55.      *
  56.      * @param Request $request
  57.      * @param File $file
  58.      * @param SeoManager $seoManager
  59.      * @return Response
  60.      */
  61.     public function show(Request $requestSeoManager $seoManagerFile $file): Response
  62.     {
  63.         preg_match('/(youtube#!)(.+)/i'$file->getUrl() ?? ''$YtUrlMatches);
  64.         if (count($YtUrlMatches) === && $YtUrlMatches[1] === 'youtube#!') {
  65.             $ogImageUrl 'https://i.ytimg.com/vi/' $YtUrlMatches[2] . '/hqdefault.jpg';
  66.         } else {
  67.             $package = new Package(new EmptyVersionStrategy());
  68.             $ogImageUrl $this->getParameter(UtilsConstant::GLOBAL_URL) .
  69.                 ($file->getPicture() instanceof Picture ?
  70.                     $file->getPicture()->getWebPath() :
  71.                     $package->getUrl('images/player/player-default.jpg'));
  72.         }
  73.         $seoManager
  74.             ->setTitleAndDescription(
  75.                 'file.show.seo.title',
  76.                 'file.show.seo.description',
  77.                 [self::FILE_NAME => htmlspecialchars($file->getName()), self::BAND_NAME => htmlspecialchars($file->getBand()->getName())]
  78.             )
  79.             ->setOgImage($ogImageUrl170170)
  80.             ->setOgType('music.song')
  81.             ->setProperty('og:audio:type''audio/vnd.facebook.bridge')
  82.             ->setProperty('music:musician'$file->getBand()->getName());
  83.         if ($file->getStatus() == FileStatusConstant::STATUS_PRIVATE) {
  84.             /** @var User $user */
  85.             $user $this->getUser();
  86.             if (!($user instanceof User)) {
  87.                 return $this->ajaxForward($request'app_login');
  88.             }
  89.             $userInBand $user->isInBand($file->getBand());
  90.             if (!$userInBand) {
  91.                 return $this->ajaxForward(
  92.                     $request,
  93.                     self::BAND_SHOW_ROUTE,
  94.                     array('id' => $file->getBand()->getId())
  95.                 );
  96.             }
  97.         }
  98.         return $this->render('File/show.html.twig', array(
  99.             'file' => $file,
  100.         ));
  101.     }
  102.     /**
  103.      * Show files and folders trash of specified band
  104.      *
  105.      * @param Request $request
  106.      * @param Band $band
  107.      * @param SeoManager $seoManager
  108.      * @return Response
  109.      */
  110.     public function trash(Request $requestSeoManager $seoManagerBand $band): Response
  111.     {
  112.         /** @var User $user */
  113.         $user $this->getUser();
  114.         $userInBand $user instanceof User && $user->isInBand($band);
  115.         if (!$userInBand) {
  116.             return $this->ajaxForward($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  117.         }
  118.         $seoManager
  119.             ->setTitleAndDescription(
  120.                 'file.trash.seo.title',
  121.                 'file.trash.seo.title',
  122.                 [self::BAND_NAME => htmlspecialchars($band->getName())]
  123.             )
  124.             ->setNoIndex();
  125.         $deletedFolders = [];
  126.         $deletedFiles = [];
  127.         foreach ($band->getFolders() as $folder) {
  128.             if ($folder->getDeleted()) {
  129.                 $deletedFolders[] = $folder;
  130.             }
  131.             /** @var File $file */
  132.             foreach ($folder->getFiles() as $file) {
  133.                 if ($file->getDeleted()) {
  134.                     $deletedFiles[] = $file;
  135.                 }
  136.             }
  137.         }
  138.         return $this->render('File/trash.html.twig', array(
  139.             'band' => $band,
  140.             'deletedFolders' => $deletedFolders,
  141.             'deletedFiles' => $deletedFiles,
  142.         ));
  143.     }
  144.     /**
  145.      * Show folder detail and files stored in it
  146.      *
  147.      * @param Request $request
  148.      * @param Folder $folder
  149.      * @param SeoManager $seoManager
  150.      * @param StorageManager $storageManager
  151.      * @param TranslatorInterface $translator
  152.      * @return Response
  153.      */
  154.     public function folder(
  155.         Request             $request,
  156.         Folder              $folder,
  157.         SeoManager          $seoManager,
  158.         StorageManager      $storageManager,
  159.         TranslatorInterface $translator
  160.     ): Response
  161.     {
  162.         $filesType $folder->getFilesType();
  163.         $band $folder->getOwner();
  164.         /** @var User $user */
  165.         $user $this->getUser();
  166.         $userInBand $user instanceof User && $user->isInBand($band);
  167.         if (!$filesType || !$userInBand) {
  168.             return $this->ajaxForward($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  169.         }
  170.         if ($band->getType() === BandTypeConstant::USER_COLLABORATION) {
  171.             return $this->ajaxForward($request'whiplay_home');
  172.         }
  173.         $seoManager
  174.             ->setTitleAndDescription(
  175.                 'file.folder.seo.title',
  176.                 'file.folder.seo.title',
  177.                 [
  178.                     'folder_name' => $translator->trans($folder->getName()),
  179.                     self::BAND_NAME => htmlspecialchars($folder->getOwner()->getName())
  180.                 ]
  181.             )
  182.             ->setNoIndex();
  183.         $returnResponse null;
  184.         $newFolder = new Folder();
  185.         $formCreateFolder $this->createForm(CreateFolderType::class, $newFolder);
  186.         $formCreateFolder->handleRequest($request);
  187.         if ($formCreateFolder->isSubmitted() && $formCreateFolder->isValid() && $user->isMemberButNotGuest($band)) {
  188.             $em $this->getDoctrine()->getManager();
  189.             $newFolder->setCreator($user);
  190.             $newFolder->setCreatedAt(new DateTime());
  191.             $newFolder->setParent($folder);
  192.             $newFolder->setOwner($band);
  193.             $em->persist($newFolder);
  194.             $band->addFolder($newFolder);
  195.             $em->persist($band);
  196.             $em->flush();
  197.             $request->setMethod('GET');
  198.             $returnResponse $this->ajaxForward($requestself::FILES_FOLDER_ROUTE, array('id' => $folder->getId()));
  199.         }
  200.         $formShiftFile $this->createForm(ShiftFileType::class);
  201.         if ($this->handleShiftForm($formShiftFile$request$folder)) {
  202.             $returnResponse $this->ajaxForward($requestself::FILES_FOLDER_ROUTE, array('id' => $folder->getId()));
  203.         }
  204.         $formRenameFolder $this->createForm(RenameFolderType::class);
  205.         if ($user->isMemberButNotGuest($band) && $this->handleRenameForm($formRenameFolder$request)) {
  206.             $returnResponse $this->ajaxForward($requestself::FILES_FOLDER_ROUTE, array('id' => $folder->getId()));
  207.         }
  208.         //FORM VIDEO
  209.         $newDistantFile = new File();
  210.         $formAddDistantFile $this->createForm(AddDistantFileType::class, $newDistantFile);
  211.         if ($this->handleVideoForm($formAddDistantFile$request$newDistantFile$folder$translator)) {
  212.             $returnResponse $this->ajaxForward($requestself::FILE_EDIT_ROUTE, array('id' => $newDistantFile->getId()));
  213.         }
  214.         if ($returnResponse !== null) {
  215.             return $returnResponse;
  216.         }
  217.         $fullUsedSize $storageManager->getStorageUsage($band);
  218.         $fullAvailableSize $storageManager->getAvailableStorage($band);
  219.         return $this->render('File/folder.html.twig', array(
  220.             'form_create_folder' => $formCreateFolder->createView(),
  221.             'form_shift_file' => $formShiftFile->createView(),
  222.             'form_rename_folder' => $formRenameFolder->createView(),
  223.             'form_add_distant_file' => $formAddDistantFile->createView(),
  224.             'band' => $band,
  225.             'currentFolder' => $folder,
  226.             'baseFolders' => $band->getBaseFolders(),
  227.             'selectedFilesType' => $filesType,
  228.             'fullAvailableSize' => $fullAvailableSize,
  229.             'fullUsedSize' => $fullUsedSize,
  230.         ));
  231.     }
  232.     /**
  233.      * Private: Handle video form from folder method
  234.      *
  235.      * @param $formAddDistantFile
  236.      * @param $request
  237.      * @param $newDistantFile
  238.      * @param $folder
  239.      * @param $translator
  240.      * @return bool
  241.      */
  242.     private function handleVideoForm($formAddDistantFile$request$newDistantFile$folder$translator): bool
  243.     {
  244.         $formAddDistantFile->handleRequest($request);
  245.         if (!$formAddDistantFile->isSubmitted() || !$formAddDistantFile->isValid()) {
  246.             return false;
  247.         }
  248.         $em $this->getDoctrine()->getManager();
  249.         if (preg_match("#^(?:https?://)?(?:www\.)?(?:youtu\.be/|youtube\.com/(?:embed/|v/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$#"$newDistantFile->getUrl(), $matches)) {
  250.             $id count($matches) > $matches[1] : '';
  251.             $newDistantFile->setUrl(FilePlatformConstant::YOUTUBE '#!' $id);
  252.             $newDistantFile->setType(FileTypeConstant::VIDEO);
  253.             $playable = new Playable();
  254.             $newDistantFile->setPlayable($playable);
  255.             $newDistantFile->setCreatedAt(new DateTime());
  256.             $newDistantFile->setFolder($folder);
  257.             $em->persist($newDistantFile);
  258.             $em->flush();
  259.             $this->toggleFileAction($newDistantFileFileActionConstant::ADDfalse);
  260.             $request->setMethod('GET');
  261.             return true;
  262.         } else {
  263.             $this->addFlash(
  264.                 'video_upload_notice',
  265.                 $translator->trans('file.folder.platform_not_found')
  266.             );
  267.         }
  268.         return false;
  269.     }
  270.     /**
  271.      * Private: Handle file shift form from folder method
  272.      *
  273.      * @param FormInterface $form
  274.      * @param Request $request
  275.      * @param Folder $folder
  276.      * @return bool
  277.      */
  278.     private function handleShiftForm(FormInterface $formRequest $requestFolder $folder): bool
  279.     {
  280.         $form->handleRequest($request);
  281.         if (!$form->isSubmitted() || !$form->isValid()) {
  282.             return false;
  283.         }
  284.         $data $form->getData();
  285.         $file $this->getDoctrine()
  286.             ->getRepository(File::class)
  287.             ->find($data['file-id']);
  288.         if (!$file || $file->getBand() !== $folder->getOwner()) {
  289.             return false;
  290.         }
  291.         $file->setFolder($folder);
  292.         $em $this->getDoctrine()->getManager();
  293.         $em->persist($file);
  294.         $em->flush();
  295.         $request->setMethod('GET');
  296.         return true;
  297.     }
  298.     /**
  299.      * Private: Handle folder rename form from folder method
  300.      *
  301.      * @param FormInterface $form
  302.      * @param Request $request
  303.      * @return bool
  304.      */
  305.     private function handleRenameForm(FormInterface $formRequest $request): bool
  306.     {
  307.         $form->handleRequest($request);
  308.         if (!$form->isSubmitted() || !$form->isValid()) {
  309.             return false;
  310.         }
  311.         $formData $form->getData();
  312.         $renamedFolder $this->getDoctrine()
  313.             ->getRepository(Folder::class)
  314.             ->find($formData['folderId']);
  315.         if (!$renamedFolder || empty($formData['newName'])) {
  316.             return false;
  317.         }
  318.         $renamedFolder->setName($formData['newName']);
  319.         $em $this->getDoctrine()->getManager();
  320.         $em->persist($renamedFolder);
  321.         $em->flush();
  322.         $request->setMethod('GET');
  323.         return true;
  324.     }
  325.     /**
  326.      * Show edition page and handle form if it's submitted
  327.      *
  328.      * @param Request $request
  329.      * @param SeoManager $seoManager
  330.      * @param TranslatorInterface $translator
  331.      * @param File $file
  332.      * @return Response
  333.      */
  334.     public function edit(
  335.         Request             $request,
  336.         SeoManager          $seoManager,
  337.         TranslatorInterface $translator,
  338.         File                $file
  339.     ): Response
  340.     {
  341.         $band $file->getBand();
  342.         if ($file->getCreatedBy() !== $this->getUser() && !$this->currentUserIsAdminOfBand($band$translator)) {
  343.             return $this->ajaxForwardToReferer($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  344.         }
  345.         if ($band->getType() === BandTypeConstant::USER_COLLABORATION) {
  346.             return $this->ajaxForward($request'whiplay_home');
  347.         }
  348.         $seoManager
  349.             ->setTitleAndDescription(
  350.                 'file.edit.seo.title',
  351.                 'file.edit.seo.title',
  352.                 [self::FILE_NAME => htmlspecialchars($file->getName()), self::BAND_NAME => htmlspecialchars($file->getBand()->getName())]
  353.             )
  354.             ->setNoIndex();
  355.         $this->addMissingBandMembersOnFile($band$file);
  356.         $em $this->getDoctrine()->getManager();
  357.         $form $this->createForm(FileEditType::class, $file, ['band' => $band]);
  358.         if (!$file->isPlayable()) {
  359.             $form->remove('playable');
  360.         }
  361.         $oldStatus $file->getStatus();
  362.         $form->handleRequest($request);
  363.         if ($form->isSubmitted() && $form->isValid()) {
  364.             if ($request->get('filePictureDelete')) {
  365.                 $em->remove($file->getPicture());
  366.                 $em->flush();
  367.                 $file->setPicture();
  368.             }
  369.             $newProjectName $form->get('newProjectName')->getData();
  370.             if ($newProjectName) {
  371.                 $newProject = new Project();
  372.                 $newProject->setName($newProjectName);
  373.                 $newProject->setBand($band);
  374.                 $em->persist($newProject);
  375.                 $band->addProject($newProject);
  376.                 $file->setProject($newProject);
  377.             }
  378.             /** @var User $user */
  379.             $user $this->getUser();
  380.             if ($file->getStatus() !== $oldStatus && $user->isInBand($file->getBand(), BandMemberRoleConstant::LEADER)) {
  381.                 $this->toggleFileAction($fileFileActionConstant::PUBLISHfalse);
  382.             }
  383.             $em->persist($file);
  384.             $em->flush();
  385.             $this->addFlash(
  386.                 UtilsConstant::NOTICE,
  387.                 $translator->trans('file.edit.saved')
  388.             );
  389.             $request->setMethod('GET');
  390.             return $this->ajaxForward($requestself::FILE_EDIT_ROUTE, array('id' => $file->getId()));
  391.         }
  392.         return $this->render('File/edit.html.twig', array(
  393.             'file' => $file,
  394.             'band' => $band,
  395.             'form' => $form->createView(),
  396.         ));
  397.     }
  398.     /**
  399.      * Private: Check all band's members and add FileBandMember without instrument if it's missing
  400.      * NOT SURE: probably to avoid an issue with form
  401.      *
  402.      * @param Band $band
  403.      * @param File $file
  404.      */
  405.     private function addMissingBandMembersOnFile(Band $bandFile $file)
  406.     {
  407.         $em $this->getDoctrine()->getManager();
  408.         $bandMembers $band->getMembers(false)->toArray();
  409.         /** @var FileBandMember[] $fileBandMembers */
  410.         $fileBandMembers $file->getBandMembers()->count() ? $file->getBandMembers()->toArray() : [];
  411.         /** @var BandMember $bandMember */
  412.         foreach ($bandMembers as $bandMember) {
  413.             $playOnMusic false;
  414.             foreach ($fileBandMembers as $fileBandMember) {
  415.                 if ($bandMember === $fileBandMember->getBandMember()) {
  416.                     $playOnMusic true;
  417.                     break;
  418.                 }
  419.             }
  420.             if ($playOnMusic === false) {
  421.                 $newFileBandMember = new FileBandMember();
  422.                 $newFileBandMember->setBandMember($bandMember);
  423.                 $newFileBandMember->setFile($file);
  424.                 $file->addBandMember($newFileBandMember);
  425.                 $em->persist($newFileBandMember);
  426.                 $em->persist($file);
  427.             }
  428.         }
  429.         $em->flush();
  430.     }
  431.     /**
  432.      * Show file report page and handle form if it's submitted
  433.      *
  434.      * @param Request $request
  435.      * @param SeoManager $seoManager
  436.      * @param TranslatorInterface $translator
  437.      * @param CurlHttpClient $httpClient
  438.      * @param MailerInterface $mailer
  439.      * @param File $file
  440.      * @return Response
  441.      * @throws TransportExceptionInterface
  442.      */
  443.     public function report(
  444.         Request             $request,
  445.         SeoManager          $seoManager,
  446.         TranslatorInterface $translator,
  447.         CurlHttpClient      $httpClient,
  448.         MailerInterface     $mailer,
  449.         File                $file
  450.     ): Response
  451.     {
  452.         $em $this->getDoctrine()->getManager();
  453.         $seoManager
  454.             ->setTitleAndDescription(
  455.                 'file.report.seo.title',
  456.                 'file.report.seo.title',
  457.                 [self::FILE_NAME => $file->getName(), self::BAND_NAME => $file->getBand()->getName()]
  458.             )
  459.             ->setNoIndex();
  460.         $report = new FileReport();
  461.         $form $this->createForm(FileReportType::class, $report);
  462.         $form->handleRequest($request);
  463.         if ($form->isSubmitted() && $form->isValid()) {
  464.             $yesterdayDateTime = new DateTime();
  465.             $yesterdayDateTime->sub(new DateInterval('P1D'));
  466.             $user $this->getUser();
  467.             $userId $user instanceof User $user->getId() : 0;
  468.             $dayReports $em->getRepository(FileReport::class)
  469.                 ->createQueryBuilder('file_report')
  470.                 ->andWhere('file_report.createdAt > :yesterday')
  471.                 ->andWhere('file_report.file = :fileId')
  472.                 ->andWhere('file_report.ip = :ip OR file_report.email = :email OR (file_report.user IS NOT NULL AND file_report.user = :userId)')
  473.                 ->setParameter('fileId'$file->getId())
  474.                 ->setParameter('ip'$request->getClientIp())
  475.                 ->setParameter('userId'$userId)
  476.                 ->setParameter('email'$report->getEmail())
  477.                 ->setParameter('yesterday'$yesterdayDateTime)
  478.                 ->getQuery()
  479.                 ->getResult();
  480.             if (count($dayReports)) {
  481.                 $this->addFlash(
  482.                     UtilsConstant::NOTICE,
  483.                     $translator->trans('file.report.wait_delay')
  484.                 );
  485.             } else {
  486.                 $data = array(
  487.                     'secret' => "0xA9e155ba26Ea705ec9A893B7553fd1Ac1Cd8b96A",
  488.                     'response' => $request->request->get('h-captcha-response')
  489.                 );
  490.                 $response $httpClient->post("https://hcaptcha.com/siteverify"$datafalse);
  491.                 $captchaData json_decode($response);
  492.                 if ($captchaData->success) {
  493.                     $recipients = array($report->getEmail(), $this->getParameter('admin_email'));
  494.                     if ($file->getCreatedBy()) {
  495.                         $recipients[] = $file->getCreatedBy()->getEmail();
  496.                     }
  497.                     $report->setUser($this->getUser());
  498.                     $report->setCreatedAt(new DateTime());
  499.                     $report->setFile($file);
  500.                     $report->setIp($request->getClientIp());
  501.                     $em->persist($report);
  502.                     $em->flush();
  503.                     $reportMail = (new TemplatedEmail())
  504.                         ->from(new Address('reports@whiplay.fr'$translator->trans('file.report.from')))
  505.                         ->to(...$recipients)
  506.                         ->subject($translator->trans('file.report.subject'))
  507.                         ->htmlTemplate('Mail/savedReport.html.twig')
  508.                         ->context([
  509.                             'report' => $report
  510.                         ]);
  511.                     $mailer->send($reportMail);
  512.                     $this->addFlash(
  513.                         UtilsConstant::NOTICE,
  514.                         $translator->trans('file.report.sent')
  515.                     );
  516.                     $request->setMethod('GET');
  517.                     if ($this->getUser()) {
  518.                         return $this->ajaxForward($request'whiplay_management_reports');
  519.                     } else {
  520.                         return $this->ajaxForward($request'whiplay_file_report', array('id' => $file->getId()));
  521.                     }
  522.                 }
  523.             }
  524.         }
  525.         return $this->render('File/report.html.twig', array(
  526.             'file' => $file,
  527.             'form' => $form->createView(),
  528.         ));
  529.     }
  530.     /**
  531.      * Restore file by setting deleted column to false
  532.      *
  533.      * @param Request $request
  534.      * @param TranslatorInterface $translator
  535.      * @param File $file
  536.      * @return Response
  537.      */
  538.     public function restore(Request $requestTranslatorInterface $translatorFile $file): Response
  539.     {
  540.         $band $file->getBand();
  541.         if (!$this->currentUserIsAdminOfBand($band$translator)) {
  542.             return $this->ajaxForwardToReferer($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  543.         }
  544.         $em $this->getDoctrine()->getManager();
  545.         $file->setDeleted(false);
  546.         $em->persist($file);
  547.         $em->flush();
  548.         $this->addFlash(
  549.             UtilsConstant::NOTICE,
  550.             $translator->trans('file.restore.restored')
  551.         );
  552.         return $this->ajaxForward($requestself::FILES_FOLDER_ROUTE, array('id' => $file->getFolder()->getId()));
  553.     }
  554.     /**
  555.      * Restore folder by setting deleted column to false
  556.      *
  557.      * @param Request $request
  558.      * @param TranslatorInterface $translator
  559.      * @param Folder $folder
  560.      * @return Response
  561.      */
  562.     public function folderRestore(Request $requestTranslatorInterface $translatorFolder $folder): Response
  563.     {
  564.         $band $folder->getOwner();
  565.         if (!$this->currentUserIsAdminOfBand($band$translator)) {
  566.             return $this->ajaxForwardToReferer($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  567.         }
  568.         $em $this->getDoctrine()->getManager();
  569.         $folder->setDeleted(false);
  570.         $em->persist($folder);
  571.         $em->flush();
  572.         $this->addFlash(
  573.             UtilsConstant::NOTICE,
  574.             $translator->trans('file.folder_restore.restored')
  575.         );
  576.         return $this->ajaxForward($requestself::FILES_FOLDER_ROUTE, array('id' => $folder->getParent()->getId()));
  577.     }
  578.     /**
  579.      * Delete file by setting deleted column to true or really delete it if reallyDelete GET param is set
  580.      *
  581.      * @param Request $request
  582.      * @param TranslatorInterface $translator
  583.      * @param File $file
  584.      * @return Response
  585.      */
  586.     public function delete(Request $requestTranslatorInterface $translatorFile $file): Response
  587.     {
  588.         $band $file->getBand();
  589.         if (!$this->currentUserIsAdminOfBand($band$translator)) {
  590.             return $this->ajaxForwardToReferer($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  591.         }
  592.         $em $this->getDoctrine()->getManager();
  593.         if ($request->query->get('reallyDelete')) {
  594.             $em->remove($file);
  595.             $em->flush();
  596.             $request->setMethod('GET');
  597.             return $this->ajaxForward($request'whiplay_files_trash', array('id' => $file->getBand()->getId()));
  598.         } else {
  599.             if ($file->getPublishAction()) {
  600.                 $em->remove($file->getPublishAction());
  601.             }
  602.             $file->setStatus(FileStatusConstant::STATUS_PRIVATE);
  603.             $file->setDeleted(true);
  604.             $em->persist($file);
  605.             $em->flush();
  606.             $this->addFlash(
  607.                 UtilsConstant::NOTICE,
  608.                 $translator->trans('file.delete.deleted')
  609.             );
  610.         }
  611.         return $this->ajaxForwardToReferer($requestself::FILES_FOLDER_ROUTE, array('id' => $file->getFolder()->getId()));
  612.     }
  613.     /**
  614.      * Delete folder by setting deleted column to true or really delete it if reallyDelete GET param is set
  615.      *
  616.      * @param Request $request
  617.      * @param TranslatorInterface $translator
  618.      * @param Folder $folder
  619.      * @return Response
  620.      */
  621.     public function folderDelete(
  622.         Request             $request,
  623.         TranslatorInterface $translator,
  624.         Folder              $folder
  625.     ): Response
  626.     {
  627.         $band $folder->getOwner();
  628.         if (!$this->currentUserIsAdminOfBand($band$translator)) {
  629.             return $this->ajaxForwardToReferer($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  630.         }
  631.         if ($request->query->get('reallyDelete')) {
  632.             $physically true;
  633.         } else {
  634.             $physically false;
  635.         }
  636.         $parentId $folder->getParent()->getId();
  637.         $em $this->getDoctrine()->getManager();
  638.         $this->deleteFolderAndChildren($folder$em$physically);
  639.         $em->flush();
  640.         if ($physically) {
  641.             $request->setMethod('GET');
  642.             return $this->ajaxForward($request'whiplay_files_trash', array('id' => $folder->getOwner()->getId()));
  643.         } else {
  644.             return $this->ajaxForward($requestself::FILES_FOLDER_ROUTE, array('id' => $parentId));
  645.         }
  646.     }
  647.     /**
  648.      * Private: Recursively delete folder and children
  649.      *
  650.      * @param Folder $folder
  651.      * @param EntityManagerInterface $em
  652.      * @param false $physically
  653.      */
  654.     private function deleteFolderAndChildren(Folder $folderEntityManagerInterface &$embool $physically false)
  655.     {
  656.         if ($physically) {
  657.             foreach ($folder->getFiles() as $file) {
  658.                 $em->remove($file);
  659.             }
  660.         }
  661.         foreach ($folder->getChildren() as $child) {
  662.             $this->deleteFolderAndChildren($child$em$physically);
  663.         }
  664.         if ($physically) {
  665.             $em->remove($folder);
  666.         } else {
  667.             $folder->setDeleted(true);
  668.         }
  669.     }
  670.     /**
  671.      * Toggle FAVORITE file action status for current user
  672.      *
  673.      * @param Request $request
  674.      * @param TranslatorInterface $translator
  675.      * @param File $file
  676.      * @return Response
  677.      */
  678.     public function favourite(Request $requestTranslatorInterface $translatorFile $file): Response
  679.     {
  680.         $band $file->getBand();
  681.         if (!$this->currentUserIsAdminOfBand($band$translator)) {
  682.             return $this->ajaxForwardToReferer($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  683.         }
  684.         $this->toggleFileAction($fileFileActionConstant::FAVORITEfalse);
  685.         return $this->ajaxForwardToReferer($request'whiplay_band_files', array('id' => $file->getBand()->getId()));
  686.     }
  687.     /**
  688.      * Toggle LIKE file action for current user
  689.      *
  690.      * @param Request $request
  691.      * @param File $file
  692.      * @return Response
  693.      */
  694.     public function like(Request $requestFile $file): Response
  695.     {
  696.         $this->toggleFileAction($fileFileActionConstant::LIKE);
  697.         return $this->ajaxForwardToReferer($request'whiplay_band_files', array('id' => $file->getBand()->getId()));
  698.     }
  699.     /**
  700.      * Toggle file status (to public or private depends on current status)
  701.      *
  702.      * @param Request $request
  703.      * @param TranslatorInterface $translator
  704.      * @param File $file
  705.      * @return Response
  706.      */
  707.     public function publish(
  708.         Request             $request,
  709.         TranslatorInterface $translator,
  710.         File                $file
  711.     ): Response
  712.     {
  713.         $band $file->getBand();
  714.         if (!$this->currentUserIsAdminOfBand($band$translator)) {
  715.             return $this->ajaxForwardToReferer($requestself::BAND_SHOW_ROUTE, array('id' => $band->getId()));
  716.         }
  717.         if ($file->getStatus() === FileStatusConstant::STATUS_PRIVATE) {
  718.             $reports $this->getDoctrine()
  719.                 ->getRepository(FileReport::class)
  720.                 ->findBy(array('file' => $file));
  721.             if (count($reports)) {
  722.                 $this->addFlash(
  723.                     UtilsConstant::NOTICE,
  724.                     $translator->trans('file.publish.reported')
  725.                 );
  726.                 return $this->ajaxForwardToReferer($request);
  727.             }
  728.             $file->setStatus(FileStatusConstant::STATUS_PUBLIC);
  729.             $this->addFlash(
  730.                 UtilsConstant::NOTICE,
  731.                 $translator->trans('file.publish.published')
  732.             );
  733.         } else {
  734.             $file->setStatus(FileStatusConstant::STATUS_PRIVATE);
  735.             $this->addFlash(
  736.                 UtilsConstant::NOTICE,
  737.                 $translator->trans('file.publish.private')
  738.             );
  739.         }
  740.         $this->toggleFileAction($fileFileActionConstant::PUBLISHfalse);
  741.         $em $this->getDoctrine()->getManager();
  742.         $em->persist($file);
  743.         $em->flush();
  744.         return $this->ajaxForwardToReferer($request);
  745.     }
  746. }