src/Controller/WebController.php line 76

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by PhpStorm.
  4.  * User: rostandnj
  5.  * Date: 25/3/19
  6.  * Time: 11:42 AM
  7.  */
  8. namespace App\Controller;
  9. use App\Entity\ActeurExterne;
  10. use App\Entity\Article;
  11. use App\Entity\Boite;
  12. use App\Entity\Bordereau;
  13. use App\Entity\CadreClassement;
  14. use App\Entity\Comment;
  15. use App\Entity\Courrier;
  16. use App\Entity\CourrierCollaborateur;
  17. use App\Entity\Courtier;
  18. use App\Entity\DemandeArchive;
  19. use App\Entity\Document;
  20. use App\Entity\Dossier;
  21. use App\Entity\Etagere;
  22. use App\Entity\News;
  23. use App\Entity\PieceJointe;
  24. use App\Entity\Priorite;
  25. use App\Entity\Rayon;
  26. use App\Entity\RegisterItem;
  27. use App\Entity\RegleConservation;
  28. use App\Entity\Role;
  29. use App\Entity\Salle;
  30. use App\Entity\Save;
  31. use App\Entity\Service;
  32. use App\Entity\Statut;
  33. use App\Entity\Tache;
  34. use App\Entity\TypeConfidentialite;
  35. use App\Entity\TypeCourrier;
  36. use App\Entity\TypeDossier;
  37. use App\Entity\TypeTache;
  38. use App\Entity\User;
  39. use App\Entity\Workgroup;
  40. use Firebase\JWT\JWT;
  41. use Firebase\JWT\Key;
  42. use Knp\Component\Pager\PaginatorInterface;
  43. use phpDocumentor\Reflection\Types\Null_;
  44. use Psr\Log\LoggerInterface;
  45. use Symfony\Component\HttpFoundation\JsonResponse;
  46. use Symfony\Component\HttpFoundation\Response;
  47. use Symfony\Component\HttpFoundation\Request;
  48. use Symfony\Component\DependencyInjection\ContainerInterface;
  49. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  50. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  51. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  52. use App\Twig\AppExtension;
  53. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  54. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  55. use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
  56. use Doctrine\ORM\EntityManagerInterface;
  57. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  58. use Symfony\Component\Security\Core\Security;
  59. class WebController extends AbstractController implements LogginInterfaceController
  60. {
  61.     private $mycontainer;
  62.     private $locale;
  63.     private $session;
  64.     private $extension;
  65.     private $currentUser;
  66.     private EntityManagerInterface $em;
  67.     private Security $security;
  68.     /**
  69.      * WebController constructor.
  70.      */
  71.     public function __construct(ContainerInterface $c,SessionInterface $s,EntityManagerInterface $em, Security $security)
  72.     {
  73.         $this->currentUser =null;
  74.         $this->extension = new AppExtension($c);
  75.         $this->session = $s;
  76.         $this->mycontainer = $c;
  77.         $this->locale="fr";
  78.         $this->em=$em;
  79.         $this->security = $security;
  80.         $lang = $this->mycontainer->get("request_stack")->getCurrentRequest()->cookies->get("lang");
  81.         if(in_array($lang,["fr","en"])) {
  82.             $this->mycontainer->get('translator')->setLocale($lang);
  83.             $this->locale = $lang;
  84.         }else{
  85.             $this->mycontainer->get('translator')->setLocale($this->locale);
  86.         }
  87.         $this->currentUser = $this->security->getUser();
  88.         $tab=[];
  89.         if($this->currentUser !==NULL)
  90.         {
  91.             if($this->currentUser->getType() == 1)
  92.             {
  93.                 $roles = $this->em->getRepository(Role::class)->findBy(array("isActive"=>true));
  94.             }
  95.             else
  96.             {
  97.                 $roles = $this->currentUser->getUserRoles();
  98.             }
  99.             foreach ($roles as $r)
  100.             {
  101.                 $tab[]=$r->getCode();
  102.             }
  103.         }
  104.         $res = $this->mycontainer->get("user_manager")->getSystemInfo();
  105.         $this->session->set('AppData',$res["data"]);
  106.         $this->session->set('roles',$tab);
  107.     }
  108.     private function testRole($role): bool
  109.     {
  110.         if ($this->currentUser === "anon.") {
  111.             return false;
  112.         }
  113.         if ($this->currentUser->getType() == 1) {
  114.             return true;
  115.         }
  116.         $userRoles = $this->currentUser->getUserRoles();
  117.         $serviceRoles = $this->currentUser->getService()->getRoles();
  118.         $roles = array_merge(
  119.             is_array($userRoles) ? $userRoles : $userRoles->toArray(),
  120.             is_array($serviceRoles) ? $serviceRoles : $serviceRoles->toArray()
  121.         );
  122.         foreach ($roles as $r) {
  123.             if ($r->getCode() === $role) {
  124.                 return true;
  125.             }
  126.         }
  127.         return false;
  128.     }
  129.     public function home(Request $request)
  130.     {
  131.         if($this->currentUser !== NULL) return $this->redirectToRoute('web_app_dashboard');
  132.         return $this->render('login.html.twig');
  133.     }
  134.     public function welcome(Request $request)
  135.     {
  136.         if($this->currentUser!=NULL) return $this->redirectToRoute('web_app_dashboard');
  137.         return $this->render('welcome.html.twig');
  138.     }
  139.     public function dashboard(Request $request)
  140.     {
  141.         //var_dump($this->currentUser->getType());
  142.         if($this->currentUser === NULL){
  143.             return $this->redirectToRoute('api_home');
  144.         }
  145.         $save = $this->em->getRepository(Save::class)->findBy(array("isActive"=>true),array("id"=>"DESC"),1,0);
  146.         $req = $this->em->getRepository(DemandeArchive::class)->findBy(array("isActive"=>true));
  147.         $dossiers = $this->em->getRepository(Dossier::class)->findBy(array("isActive"=>true));
  148.         $simple=0;
  149.         foreach ($dossiers as $d)
  150.         {
  151.             if($d->getStatut()==1) {
  152.                 $simple++;
  153.             }
  154.         }
  155.         $months=[];
  156.         $label=[];
  157.         $value=[];
  158.         for ($i = 0; $i <= 7; $i++)
  159.         {
  160.             $months[date("Y-m", strtotime( date( 'Y-m-01' )." -$i months"))] =0 ;
  161.         }
  162.         foreach ($dossiers as $d)
  163.         {
  164.             //var_dump($d->getDate()->format("Y-m"));
  165.             if(array_key_exists($d->getDate()->format("Y-m"),$months))
  166.             {
  167.                 $months[$d->getDate()->format("Y-m")]++;
  168.             }
  169.         }
  170.         foreach ($months as $key=>$val)
  171.         {
  172.             $label[]=$key;
  173.             $value[]=$val;
  174.         }
  175.         $totalReq = count($req);
  176.         $totalDone=0;
  177.         $date=$this->mycontainer->get('translator')->trans("no_save");
  178.         foreach ($req as $r)
  179.         {
  180.             if($r->getStatut()>1)
  181.             {
  182.                 $totalDone++;
  183.             }
  184.         }
  185.         if($totalDone>0)
  186.         {
  187.             $totalDone = round($totalDone/$totalReq,2)*100;
  188.         }
  189.         if(count($save)>0)
  190.         {
  191.             $date = $save[0]->getDate()->format("d/m/Y h:i:s");
  192.         }
  193.         return $this->render('dashboard.html.twig',["dossiers"=>$simple,"demande"=>$totalDone,"date"=>$date,"label"=>$label,"value"=>$value]);
  194.     }
  195.     public function organigramme(Request $request)
  196.     {
  197.         if(!$this->testRole('M_ORG')) return $this->redirectToRoute('web_app_dashboard');
  198.         $services = $this->em->getRepository(Service::class)->findBy(array("isActive"=>true,"service"=>null),array("id"=>"ASC"));
  199.         return $this->render('organigramme.html.twig',["services"=>$services]);
  200.     }
  201.     public function systeme(Request $request)
  202.     {
  203.         if(!$this->testRole('AD_S1')) return $this->redirectToRoute('web_app_dashboard');
  204.         $res = $this->mycontainer->get("user_manager")->getSystemInfo();
  205.         return $this->render('systeme.html.twig',["system"=>$res["data"]]);
  206.     }
  207.     public function service(Request $request)
  208.     {
  209.         if(!$this->testRole('AD_S2')) return $this->redirectToRoute('web_app_dashboard');
  210.         $services = $this->em->getRepository(Service::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  211.         $roles = $this->em->getRepository(Role::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  212.         $cadres = $this->em->getRepository(CadreClassement::class)->findBy(["isActive"=>true],["niveau"=>"ASC"]);
  213.         $cadresLevel = $this->em->getRepository(CadreClassement::class)->findOneExampleOfEachLevel();
  214.         $levels = [];
  215.         foreach ($cadresLevel as $c){
  216.             $levels[]= $c->getNiveau();
  217.         }
  218.         if(count($levels) === 0){
  219.             $levels[]=1;
  220.         }
  221.         else{
  222.             if(max($levels)<5){
  223.                 $levels[]=max($levels) + 1;
  224.             }
  225.         }
  226.         return $this->render('service.html.twig',["services"=>$services,'roles'=>$roles,"cadres"=>$cadres, 'niveaux'=>$levels]);
  227.     }
  228.     public function utilisateur(Request $request)
  229.     {
  230.         if(!$this->testRole('AD_S3')) return $this->redirectToRoute('web_app_dashboard');
  231.         $services = $this->em->getRepository(Service::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  232.         $users = $this->em->getRepository(User::class)->loadAllUsers(1000,0);
  233.         $roles = $this->em->getRepository(Role::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  234.         return $this->render('utilisateur.html.twig',["services"=>$services,"users"=>$users,'roles'=>$roles]);
  235.     }
  236.     public function workgroup(Request $request)
  237.     {
  238.         if(!$this->testRole('AD_S4')) return $this->redirectToRoute('web_app_dashboard');
  239.         $wkgs = $this->em->getRepository(Workgroup::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  240.         return $this->render('workgroup.html.twig',["wkgs"=>$wkgs,]);
  241.     }
  242.     public function journal(Request $request)
  243.     {
  244.         if(!$this->testRole('AD_H1')) return $this->redirectToRoute('web_app_dashboard');
  245.         //$this->session->getFlashBag()->add('notice','hello');
  246.         return $this->render('journal.html.twig');
  247.     }
  248.     public function sauvegarde(Request $request)
  249.     {
  250.         if(!$this->testRole('AD_S1')) return $this->redirectToRoute('web_app_dashboard');
  251.         $all = $this->em->getRepository(Save::class)->findBy(array("isActive"=>true),array("id"=>"DESC"));
  252.         $todaydb = $this->em->getRepository(Save::class)->findForTodayDb();
  253.         $todayar = $this->em->getRepository(Save::class)->findForTodayArchive();
  254.         $today=[];
  255.         foreach ($todaydb as $t)
  256.         {
  257.             $today[]=$t;
  258.         }
  259.         foreach ($todayar as $t)
  260.         {
  261.             $today[]=$t;
  262.         }
  263.         return $this->render('sauvegarde.html.twig',["all"=>$all,"today"=>$today]);
  264.     }
  265.     public function profile(Request $request): Response
  266.     {
  267.         return $this->render('profile.html.twig');
  268.     }
  269.     public function support(Request $request): Response
  270.     {
  271.         $news = $this->em->getRepository(News::class)->findBy(array("isActive"=>true,"status"=>true));
  272.         return $this->render('support.html.twig',["faq"=>$news]);
  273.     }
  274.     public function upload(Request $request)
  275.     {
  276.         $file = $request->files;
  277.         return new Response();
  278.     }
  279.     public function readFile(Request $request,$name)
  280.     {
  281.         if($this->currentUser === NULL) return $this->redirectToRoute('api_home');
  282.         $fu = $this->mycontainer->get('upload_service');
  283.         $res = $fu->getFileBinary($name);
  284.         if($res['error']==true) return new Response('file not found'.$name,401);
  285.         if(!in_array($name,['man.png', 'woman.png'])){
  286.             $original = $this->mycontainer->get('user_manager')->getFile(['name'=>$name]);
  287.             if($original !== null && !in_array(explode('/',$original['type'])[0],['image','pdf'])){
  288.                 $resp = new BinaryFileResponse($res["data"]);
  289.                 $resp->setContentDisposition(
  290.                     ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  291.                     $original['nom']
  292.                 );
  293.                 return $resp;
  294.             }
  295.         }
  296.         return new BinaryFileResponse($res["data"]);
  297.     }
  298.     public function showNotif(Request $request,$id): \Symfony\Component\HttpFoundation\RedirectResponse
  299.     {
  300.         $status = $this->em->getRepository(Statut::class)->findOneBy(array('id' =>$id, 'user' =>$this->currentUser));
  301.         if($status === null) return $this->redirectToRoute("web_app_dashboard");
  302.         if($status->getStatut()==0)
  303.         {
  304.             $status->setStatut(1);
  305.             $this->em->persist($status);
  306.             $this->em->flush();
  307.         }
  308.         if(in_array($status->getNotification()->getCode(),[30,31,33,35,36,37,38,39])){
  309.             return $this->redirectToRoute("web_my_mail");
  310.         }
  311.         switch ($status->getNotification()->getCode())
  312.         {
  313.             case 0:
  314.                 return $this->redirectToRoute("web_app_demandes_validation");
  315.                 break;
  316.             case 2:
  317.                 return $this->redirectToRoute("web_app_demandes");
  318.                 break;
  319.             case 3:
  320.                 return $this->redirectToRoute("web_app_demandes");
  321.             case 11:
  322.             case 12:
  323.             case 10:
  324.                 return $this->redirectToRoute("web_my_drive_share");
  325.             case 32:
  326.                 return $this->redirectToRoute("web_my_mail_internal");
  327.             case 40:
  328.                 return $this->redirectToRoute("web_forum_display_subject",["slug"=>$status->getNotification()->getArticle()->getSlug()]);
  329.             default:
  330.                 return $this->redirectToRoute("web_app_dashboard");
  331.                 break;
  332.         }
  333.     }
  334.     public function news(Request $request)
  335.     {
  336.         if(!$this->testRole('AD_A3')) return $this->redirectToRoute('web_app_dashboard');
  337.         $news = $this->em->getRepository(News::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  338.         return $this->render('news.html.twig',["news"=>$news]);
  339.     }
  340.     public function myWorkgroup(Request $request)
  341.     {
  342.         $groups= $this->mycontainer->get('user_manager')->userWorkgroups();
  343.         return $this->render('my_groups.html.twig',["wkgs"=>$groups]);
  344.     }
  345.     public function myDrive(Request $request)
  346.     {
  347.         if($this->currentUser ==='anon.') return $this->redirectToRoute('web_app_dashboard');
  348.         $res = $this->mycontainer->get('user_manager')->driveStat();
  349.         return $this->render('my_drive.html.twig',['stat'=>$res['data']]);
  350.     }
  351.     public function mySharedDrive(Request $request)
  352.     {
  353.         if($this->currentUser ==='anon.') return $this->redirectToRoute('web_app_dashboard');
  354.         $res = $this->mycontainer->get('user_manager')->driveSharedStat();
  355.         return $this->render('my_drive_share.html.twig',['stat'=>$res['data']]);
  356.     }
  357.     public function ocr(Request $request): Response
  358.     {
  359.         return $this->render('ocr.html.twig',[]);
  360.     }
  361.     public function priorite(Request $request)
  362.     {
  363.         if(!$this->testRole('ADMI4')) return $this->redirectToRoute('web_app_dashboard');
  364.         $priorites = $this->em->getRepository(Priorite::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  365.         return $this->render('priorite.html.twig',["priorites"=>$priorites,]);
  366.     }
  367.     public function acteurExterne(Request $request)
  368.     {
  369.         if(!$this->testRole('AD_S3')) return $this->redirectToRoute('web_app_dashboard');
  370.         $acteurs = $this->em->getRepository(ActeurExterne::class)->findBy(array("isActive"=>true),array("nom"=>"ASC"));
  371.         return $this->render('acteur.html.twig',["acteurs"=>$acteurs]);
  372.     }
  373.     public function signature(Request $request)
  374.     {
  375.         if($this->currentUser === NULL) return $this->redirectToRoute('api_home');
  376.         $fu = $this->mycontainer->get('upload_service');
  377.         $res = $fu->userFolder($this->currentUser->getId());
  378.         return $this->render('signature.html.twig',["status"=>$fu->getSignature($this->currentUser->getId()),'files'=>$res['files'],'signed'=>$res['signed']]);
  379.     }
  380.     public function diffusion(Request $request)
  381.     {
  382.         if($this->currentUser === NULL) return $this->redirectToRoute('api_home');
  383.         if(!$this->testRole('M_LDD')) return $this->redirectToRoute('web_app_dashboard');
  384.         $users = $this->em->getRepository(User::class)->loadAllUsersExecptAdmin();
  385.         $services = $this->em->getRepository(Service::class)->findBy(array("isActive"=>true),array("id"=>"ASC"));
  386.         $userWithPhone = [];
  387.         foreach ($users as $u){
  388.             if($u->getTelephone()!== null && strlen($u->getTelephone())>=9 ){
  389.                 $userWithPhone[] = $u->toArray();
  390.             }
  391.         }
  392.         return $this->render('diffusion.html.twig',["users"=>$userWithPhone,'services'=>$services]);
  393.     }
  394.     public function readFileUser(Request $request,$name)
  395.     {
  396.         if($this->currentUser === NULL) return $this->redirectToRoute('api_home');
  397.         $fu = $this->mycontainer->get('upload_service');
  398.         $res = $fu->getFileBinaryUser($name,$this->currentUser->getId());
  399.         if($res['error']) return new Response('file not found',404);
  400.         if(!in_array($name,['man.png', 'woman.png'])){
  401.             $original = $this->mycontainer->get('user_manager')->getFile(['name'=>$name]);
  402.             if($original !== null && !in_array(explode('/',$original['type'])[0],['image','pdf'])){
  403.                 $resp = new BinaryFileResponse($res["data"]);
  404.                 $resp->setContentDisposition(
  405.                     ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  406.                     $original['nom']
  407.                 );
  408.                 return $resp;
  409.             }
  410.         }
  411.         return new BinaryFileResponse($res["data"]);
  412.     }
  413.     public function readFileUserSignature(Request $request,$name)
  414.     {
  415.         if($this->currentUser === NULL) return $this->redirectToRoute('api_home');
  416.         $fu = $this->mycontainer->get('upload_service');
  417.         $res = $fu->getFileBinaryUserSignature($name,$this->currentUser->getId());
  418.         if($res['error']) return new Response('file not found',404);
  419.         if(!in_array($name,['man.png', 'woman.png'])){
  420.             $original = $this->mycontainer->get('user_manager')->getFile(['name'=>$name]);
  421.             if($original !== null && !in_array(explode('/',$original['type'])[0],['image','pdf'])){
  422.                 $resp = new BinaryFileResponse($res["data"]);
  423.                 $resp->setContentDisposition(
  424.                     ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  425.                     $original['nom']
  426.                 );
  427.                 return $resp;
  428.             }
  429.         }
  430.         return new BinaryFileResponse($res["data"]);
  431.     }
  432.     public function forum(Request $request, PaginatorInterface $paginator){
  433.         $query = $request->query->get('keywords');
  434.         $page = $request->query->getInt('page', 1);
  435.         $limit = 20;
  436.         if($query !== null && strlen($query)>0){
  437.             $res = $this->mycontainer->get("user_manager")->simpleSearchArticle( ["keywords"=>$query]);
  438.             $entities2 = $res["data"];
  439.         }else{
  440.             $entities2 = $this->em->getRepository(Article::class)->findBy(['isActive'=>true],['id'=>'DESC']);
  441.         }
  442.         $articles = $paginator->paginate(
  443.             $entities2,$page, $limit
  444.         );
  445.         //$this->siteInfo['date_now'] =new \DateTime();
  446.         return $this->render('forum.html.twig', ['articles'=>$articles]);
  447.     }
  448.     public function displaySubject(Request $request, $slug){
  449.         $article = $this->em->getRepository(Article::class)->findOneBy(['slug'=>$slug]);
  450.         if($article === null){
  451.             $this->addFlash('notice',$this->mycontainer->get('translator')->trans("subject not found"));
  452.             return $this->redirectToRoute('web_forum');
  453.         }
  454.         $comments = $this->em->getRepository(Comment::class)->findBy(['article'=>$article,'isActive'=>true],['id'=>'DESC']);
  455.         $commentsArray = [];
  456.         foreach ($comments as $n){
  457.             $commentsArray[] = $n->toArray();
  458.         }
  459.         $recents = $this->em->getRepository(Article::class)->findRecentExcept($article->getId());
  460.         return $this->render('forum_display_subject.html.twig', ['article'=>$article,'comments'=>$commentsArray,'recents'=>$recents]);
  461.     }
  462.     public function webmail(Request $request): Response
  463.     {
  464.         return $this->render('webmail.html.twig');
  465.     }
  466.     public function videoConference(Request $request): Response
  467.     {
  468.         return $this->render('video_conference_modal.html.twig');
  469.     }
  470.     public function editWord(string $filename): Response
  471.     {
  472.         $payload = [
  473.             "document" => [
  474.                 "fileType" => "docx",
  475.                 "key" => uniqid(),
  476.                 "title" => $filename,
  477.                 "url" => "http://symfony/files/".$filename
  478.             ],
  479.             "editorConfig" => [
  480.                 "mode" => "edit",
  481.                 "user" => [
  482.                     "id" => $this->getUser()->getId(),
  483.                     "name" => $this->getUser()->getUserIdentifier()
  484.                 ],
  485.                 "callbackUrl" => "http://symfony/onlyoffice/callback"
  486.             ]
  487.         ];
  488.         $token = JWT::encode($payload, $this->mycontainer->getParameter('app.only_office_jwt_secret'), 'HS256');
  489.         return $this->render('office/edit.html.twig', [
  490.             'onlyofficeUrl' =>  $this->mycontainer->getParameter('app.only_office_url'),
  491.             'config' => json_encode($payload),
  492.             'token' => $token
  493.         ]);
  494.     }
  495.     public function tempFileOLDNOSECURE(string $name): Response
  496.     {
  497.         $path = sys_get_temp_dir().'/'.$name;
  498.         if (!file_exists($path)) {
  499.             throw $this->createNotFoundException();
  500.         }
  501.         return new BinaryFileResponse($path);
  502.     }
  503.     public function tempFile(string $name, Request $request): ?BinaryFileResponse
  504.     {
  505.         // 1️⃣ Extract JWT from Authorization header
  506.         $authHeader = $request->headers->get('Authorization');
  507.          if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) {
  508.              throw new AccessDeniedHttpException('Missing JWT token');
  509.          }
  510.         $jwt = substr($authHeader, 7);
  511.         try {
  512.             $payload = JWT::decode(
  513.                 $jwt,
  514.                 new Key($this->getParameter('app.only_office_jwt_secret'), 'HS256')
  515.             );
  516.         } catch (\Exception $e) {
  517.             throw new AccessDeniedHttpException('Invalid JWT token');
  518.         }
  519.         ;
  520.         /*if (
  521.              empty($payload->file->tmp_name)
  522.              || $payload->file->tmp_name !== $name
  523.          ) {
  524.              throw new AccessDeniedHttpException(json_encode($payload));
  525.          }*/
  526.         /*return new BinaryFileResponse(
  527.              $filePath,
  528.              200,
  529.              [
  530.                  'Content-Type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  531.                  'Content-Disposition' => 'inline; filename="' . basename($name) . '"',
  532.              ]
  533.          );*/
  534.         $filePath = sys_get_temp_dir() . '/' . $name;
  535.         if (!is_file($filePath)) {
  536.             throw new NotFoundHttpException('File not found');
  537.         }
  538.          return new BinaryFileResponse($filePath);
  539.     }
  540.     public function onlyOfficeCallbackOLD(Request $request, $id,$tmp_file,  LoggerInterface $logger): JsonResponse
  541.     {
  542.         $data = json_decode($request->getContent(), true);
  543.         // Status 2 = document closed, ready to save
  544.         // Status 6 = forcesave while editing
  545.         if (!in_array($data['status'], [2, 6])) {
  546.             $logger->info('OnlyOffice callback: ignoring status ' . $data['status']);
  547.             return new JsonResponse(['error' => 0]);
  548.         }
  549.         $logger->info("OnlyOffice callback: start callback");
  550.         $logger->info("OnlyOffice callback: file url ". $data['url']);
  551.         $doc = $this->em->getRepository(Document::class)->findOneBy(['id'=>$id,'isActive'=>true]);
  552.         if($doc === null){
  553.             //document_not_found
  554.             $logger->info('OnlyOffice callback: document not found');
  555.             return new JsonResponse(['error' => 2]);
  556.         }
  557.         /*$filePath = sys_get_temp_dir() . '/' . $tmp_file;
  558.         if (!is_file($filePath)) {
  559.             throw new NotFoundHttpException('File not found');
  560.         }*/
  561.         // 1️⃣ Télécharger fichier modifié
  562.         $updatedContent = file_get_contents($data['url']);
  563.         $logger->info("OnlyOffice callback: file downloaded ");
  564.         // 2️⃣ Chiffrement
  565.         $encrypted = $this->mycontainer->get('hash_service')->encrypt($updatedContent);
  566.         $logger->info("OnlyOffice callback: file crypted ");
  567.         $fic = $doc->getFichier();
  568.         // 3️⃣ Sauvegarde
  569.         $path = $fic->getPath();
  570. // Separate filename and extension
  571.         $info = pathinfo($path);
  572.         $filename = $info['filename']; // without extension
  573.         $extension = $info['extension'];
  574. // Check if filename already has a version (_v<number>)
  575.        /* if (preg_match('/^(.*)_v(\d+)$/', $filename, $matches)) {
  576.             $baseName = $matches[1];
  577.             $version  = (int)$matches[2] + 1;
  578.         } else {
  579.             $baseName = $filename;
  580.             $version  = 1;
  581.         }
  582.         $newName = $baseName . '_v' . $version . '.' . $extension;
  583. */
  584.         $newName = $path;
  585.         $encryptedPath = $this->mycontainer->get('upload_service')->getTargetDirectory().'/'.$newName;
  586.         $logger->info("OnlyOffice callback: file encryptedPath ".$encryptedPath);
  587.         file_put_contents($encryptedPath, $encrypted);
  588.         // 4️⃣ Nettoyage temp (only when document is closed, not on forcesave)
  589.         if ($data['status'] === 2) {
  590.             @unlink(sys_get_temp_dir().'/'.$tmp_file);
  591.         }
  592.         $fic->setPath($newName);
  593.         $this->em->persist($fic);
  594.         $this->em->flush();
  595.         return new JsonResponse(['error' => 0],200);
  596.     }
  597.     public function onlyOfficeCallback(
  598.         Request $request,
  599.         int $id,
  600.         string $tmp_file,
  601.         LoggerInterface $logger
  602.     ): JsonResponse
  603.     {
  604.         $rawBody = $request->getContent();
  605.         $data = json_decode($rawBody, true);
  606.         // 1️⃣ Verify JWT token from OnlyOffice
  607.         $jwtSecret = $this->mycontainer->getParameter('app.only_office_jwt_secret');
  608.         $authHeader = $request->headers->get('Authorization');
  609.         if ($authHeader && str_starts_with($authHeader, 'Bearer ')) {
  610.             // JWT in Authorization header
  611.             $token = substr($authHeader, 7);
  612.             try {
  613.                 $decoded = JWT::decode($token, new Key($jwtSecret, 'HS256'));
  614.                 // Deep convert stdClass to array
  615.                 $data = json_decode(json_encode($decoded), true);
  616.                 // OnlyOffice sends the actual callback data inside 'payload' field
  617.                 if (isset($data['payload'])) {
  618.                     $data = $data['payload'];
  619.                 }
  620.                 $logger->info('OnlyOffice callback: JWT decoded from Authorization header', ['data' => $data]);
  621.             } catch (\Exception $e) {
  622.                 $logger->error('OnlyOffice callback: JWT verification failed', ['error' => $e->getMessage()]);
  623.                 return new JsonResponse(['error' => 1], 403);
  624.             }
  625.         } elseif (isset($data['token'])) {
  626.             // JWT in request body
  627.             try {
  628.                 $decoded = JWT::decode($data['token'], new Key($jwtSecret, 'HS256'));
  629.                 $data = json_decode(json_encode($decoded), true);
  630.                 // OnlyOffice sends the actual callback data inside 'payload' field
  631.                 if (isset($data['payload'])) {
  632.                     $data = $data['payload'];
  633.                 }
  634.                 $logger->info('OnlyOffice callback: JWT decoded from request body', ['data' => $data]);
  635.             } catch (\Exception $e) {
  636.                 $logger->error('OnlyOffice callback: JWT verification failed', ['error' => $e->getMessage()]);
  637.                 return new JsonResponse(['error' => 1], 403);
  638.             }
  639.         } else {
  640.             $logger->warning('OnlyOffice callback: No JWT token provided');
  641.             // If no JWT is sent, proceed without verification (for testing only)
  642.         }
  643.         $logger->info('OnlyOffice callback received', [
  644.             'status' => $data['status'] ?? 'unknown',
  645.             'doc_id' => $id,
  646.             'has_url' => !empty($data['url']),
  647.             'users' => $data['users'] ?? [],
  648.             'key' => $data['key'] ?? 'no-key'
  649.         ]);
  650.         // Status codes:
  651.         // 0 - no document with the key identifier could be found
  652.         // 1 - document is being edited
  653.         // 2 - document is ready for saving (final save on close)
  654.         // 3 - document saving error has occurred
  655.         // 4 - document is closed with no changes
  656.         // 6 - document is being edited, but the current user is not editing (forcesave)
  657.         // 7 - error has occurred while force saving
  658.         $status = $data['status'] ?? 0;
  659.         // Handle status 1, 4: no action needed
  660.         if (in_array($status, [1, 4])) {
  661.             $logger->info('OnlyOffice callback: no save needed for status ' . $status);
  662.             $response = ['error' => 0];
  663.             $responseToken = JWT::encode($response, $jwtSecret, 'HS256');
  664.             return new JsonResponse(['error' => 0, 'token' => $responseToken]);
  665.         }
  666.         // Handle errors
  667.         if (in_array($status, [0, 3])) {
  668.             $logger->error('OnlyOffice callback: error status ' . $status, $data);
  669.             $response = ['error' => 1];
  670.             $responseToken = JWT::encode($response, $jwtSecret, 'HS256');
  671.             return new JsonResponse(['error' => 1, 'token' => $responseToken]);
  672.         }
  673.         // Handle forcesave error (status 7) - acknowledge but don't treat as critical
  674.         if ($status === 7) {
  675.             $logger->warning('OnlyOffice callback: forcesave error (status 7)', [
  676.                 'doc_id' => $id,
  677.                 'forcesavetype' => $data['forcesavetype'] ?? 'unknown',
  678.                 'users' => $data['users'] ?? []
  679.             ]);
  680.             // Return success to prevent OnlyOffice from repeatedly retrying
  681.             $response = ['error' => 0];
  682.             $responseToken = JWT::encode($response, $jwtSecret, 'HS256');
  683.             return new JsonResponse(['error' => 0, 'token' => $responseToken]);
  684.         }
  685.         // Handle saves (status 2 = final save, status 6 = forcesave during co-editing)
  686.         if (!in_array($status, [2, 6])) {
  687.             $logger->info('OnlyOffice callback: ignoring status ' . $status);
  688.             $response = ['error' => 0];
  689.             $responseToken = JWT::encode($response, $jwtSecret, 'HS256');
  690.             return new JsonResponse(['error' => 0, 'token' => $responseToken]);
  691.         }
  692.         $doc = $this->em->getRepository(Document::class)
  693.             ->findOneBy(['id' => $id, 'isActive' => true]);
  694.         if (!$doc) {
  695.             $logger->warning('OnlyOffice callback: document not found');
  696.             return new JsonResponse(['error' => 2]);
  697.         }
  698.         if (empty($data['url'])) {
  699.             $logger->error('OnlyOffice callback: no URL provided in callback data', ['data' => $data]);
  700.             $response = ['error' => 1];
  701.             $responseToken = JWT::encode($response, $jwtSecret, 'HS256');
  702.             return new JsonResponse(['error' => 1, 'token' => $responseToken]);
  703.         }
  704.         $logger->info("OnlyOffice callback: downloading file from URL " . $data['url']);
  705.         // 1️⃣ Download the content from OnlyOffice
  706.         $finalContent = @file_get_contents($data['url']);
  707.         if ($finalContent === false) {
  708.             $error = error_get_last();
  709.             $logger->error('OnlyOffice callback: failed to download file', [
  710.                 'url' => $data['url'],
  711.                 'error' => $error['message'] ?? 'unknown error',
  712.                 'doc_id' => $id
  713.             ]);
  714.             $response = ['error' => 1];
  715.             $responseToken = JWT::encode($response, $jwtSecret, 'HS256');
  716.             return new JsonResponse(['error' => 1, 'token' => $responseToken]);
  717.         }
  718.         // 2️⃣ Encrypt the content
  719.         $encrypted = $this->mycontainer->get('hash_service')->encrypt($finalContent);
  720.         // 3️⃣ Save encrypted content atomically
  721.         $fic  = $doc->getFichier();
  722.         $encryptedPath = $this->mycontainer->get('upload_service')->getTargetDirectory() . '/' . $fic->getPath();
  723.         $tmpEncrypted = $encryptedPath . '.tmp';
  724.         file_put_contents($tmpEncrypted, $encrypted);
  725.         rename($tmpEncrypted, $encryptedPath);
  726.         // 4️⃣ Update file size
  727.         $newSize = filesize($encryptedPath);
  728.         $fic->setTaille($newSize);
  729.         // 5️⃣ Only update dateCreation on FINAL save (status 2), not on forcesave (status 6)
  730.         // This ensures all users share the same document key during co-editing
  731.         if ($status === 2) {
  732.             $d = new \DateTime();
  733.             $fic->setDateCreation($d);  // Update to trigger new document key on next open
  734.             $doc->setDateModification($d);
  735.             $doc->setFichier($fic);
  736.             @unlink(sys_get_temp_dir() . '/' . $tmp_file);
  737.             $logger->info("OnlyOffice callback: temp file removed and version updated");
  738.         }
  739.         $this->em->persist($doc);
  740.         $logger->info("OnlyOffice callback: file encrypted and saved successfully (status: {$status}, size: {$newSize})");
  741.         $this->em->flush();
  742.         // 5️⃣ Return JWT-signed response (required when JWT is enabled)
  743.         $response = ['error' => 0];
  744.         $responseToken = JWT::encode($response, $jwtSecret, 'HS256');
  745.         return new JsonResponse([
  746.             'error' => 0,
  747.             'token' => $responseToken
  748.         ]);
  749.     }
  750.     public function openProject(Request $request)
  751.     {
  752.         if($this->currentUser === 'anon.') return $this->redirectToRoute('api_home');
  753.         return $this->render('open_project.html.twig',[
  754.         ]);
  755.     }
  756. }