src/PromemoriaBundle/Controller/ApiController.php line 119

Open in your IDE?
  1. <?php
  2. namespace App\PromemoriaBundle\Controller;
  3. use Pimcore\Db;
  4. use Pimcore\File;
  5. use Pimcore\Tool;
  6. use Pimcore\Model\User;
  7. use Pimcore\Security\User\User as UserAdmin;
  8. use Pimcore\Model\Asset;
  9. use Pimcore\Tool\Session;
  10. use Pimcore\Event\AdminEvents;
  11. use Pimcore\Tool\Authentication;
  12. use Pimcore\Controller\FrontendController;
  13. use Pimcore\Bundle\AdminBundle\Controller\Admin;
  14. use Pimcore\Controller\Configuration\ResponseHeader;
  15. use Pimcore\Event\Admin\Login\LoginCredentialsEvent;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpFoundation\Response;
  18. use Symfony\Component\Routing\Annotation\Route;
  19. use Symfony\Component\HttpFoundation\JsonResponse;
  20. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  21. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  22. use Symfony\Component\HttpFoundation\StreamedResponse;
  23. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  24. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  25. use Pimcore\Model\Asset\Folder;
  26. class ApiController extends FrontendController
  27. {
  28.        /**
  29.      * @Route("/promemoria/api/login", methods={"POST"})
  30.      * @param Request $request
  31.      *
  32.      * @return JsonResponse
  33.      */
  34.     public function login(Request $request)
  35.     {
  36.         $response = new Response();
  37.         $response->setStatusCode(401);
  38.         $data json_decode($request->getContent());
  39.         if (!empty($data->username) &&  !empty($data->password)) {
  40.             $credentials = [
  41.                 'username' => $data->username,
  42.                 'password' => $data->password
  43.             ];
  44.             $event = new LoginCredentialsEvent($request$credentials);
  45.             try {
  46.                 $this->dispatcher->dispatch(AdminEvents::LOGIN_CREDENTIALS$event);
  47.             } catch (\Throwable $th) {
  48.             }
  49.             $pimcoreUser Authentication::authenticatePlaintext($data->username$data->password);
  50.             if ($pimcoreUser) {
  51.                 return Session::useSession(function (AttributeBagInterface $adminSession) use ($pimcoreUser) {
  52.                     $user = new UserAdmin($pimcoreUser);
  53.                     Session::regenerateId();
  54.                     $adminSession->set('user'$pimcoreUser);
  55.                     $adminSession->set('2fa_required'true);
  56.                     return $this->json(['ok' => true'user' => array(
  57.                         'id' => $pimcoreUser->getId(),
  58.                         'firstname' => $pimcoreUser->getFirstname(),
  59.                         'lastname' => $pimcoreUser->getLastname(),
  60.                         'email' => $pimcoreUser->getEmail(),
  61.                         'roles' => $user->getRoles()
  62.                     )]);
  63.                 });
  64.             }
  65.         }
  66.         return $response;
  67.     }
  68.     /**
  69.      * @Route("/promemoria/api/logout", methods={"POST", "GET"})
  70.      *
  71.      * @return JsonResponse
  72.      */
  73.     public function logout()
  74.     {
  75.         return $this->redirectToRoute('pimcore_admin_logout');
  76.     }
  77.     /**
  78.      * @Route("/promemoria/api/get-audio-thumbnail", methods={"GET"})
  79.      *
  80.      * @param Request $request
  81.      *
  82.      * @return BinaryFileResponse
  83.      */
  84.     public function getAudioThumbnail(Request $request)
  85.     {
  86.         $tmpfname tempnam("/tmp""audio.png");
  87.         file_put_contents($tmpfnamefile_get_contents("https://dummyimage.com/170x170/3e3e3e/ffffff.png&text=audio"));
  88.         $response = new BinaryFileResponse($tmpfname);
  89.         $this->addThumbnailCacheHeaders($response);
  90.         return $response;
  91.     }
  92.     /**
  93.      * @Route("/promemoria/api/get-image-thumbnail", methods={"GET"})
  94.      *
  95.      * @param Request $request
  96.      *
  97.      * @return BinaryFileResponse|StreamedResponse
  98.      */
  99.     public function getImageThumbnail(Request $request)
  100.     {
  101.         $id $request->get('id');
  102.         if(!$this->checkHash($id)){
  103.             $response = new Response();
  104.             $response->setStatusCode(401);
  105.             return $response;
  106.         }
  107.         $image Asset\Image::getById(intval($id));
  108.         $thumb $this->getThumb($image$request->get('version''thumbnail'));
  109.         return $this->responseThumbnail($thumb);
  110.     }
  111.     /**
  112.      * @Route("/promemoria/api/get-video-thumbnail", methods={"GET"})
  113.      *
  114.      * @param Request $request
  115.      *
  116.      * @return BinaryFileResponse|StreamedResponse
  117.      */
  118.     public function getVideoThumbnail(Request $request)
  119.     {
  120.         $id $request->get('id');
  121.         if(!$this->checkHash($id)){
  122.             $response = new Response();
  123.             $response->setStatusCode(401);
  124.             return $response;
  125.         }
  126.         $video Asset\Video::getById(intval($id));
  127.         $thumb $video->getImageThumbnail(Asset\Image\Thumbnail\Config::getPreviewConfig());
  128.         return $this->responseThumbnail($thumb);
  129.     }
  130.     /**
  131.      * @Route("/promemoria/api/get-document-thumbnail", methods={"GET"})
  132.      *
  133.      * @param Request $request
  134.      *
  135.      * @return BinaryFileResponse|StreamedResponse
  136.      */
  137.     public function getDocumentThumbnail(Request $request)
  138.     {
  139.         $id $request->get('id');
  140.         if(!$this->checkHash($id)){
  141.             $response = new Response();
  142.             $response->setStatusCode(401);
  143.             return $response;
  144.         }
  145.         $document Asset\Document::getById(intval($id));
  146.         $thumb = new Asset\Document\ImageThumbnail($documentAsset\Image\Thumbnail\Config::getPreviewConfig(), 1);
  147.         return $this->responseThumbnail($thumb);
  148.     }
  149.     /**
  150.      * @Route("/promemoria/api/get-video-preview", methods={"GET"})
  151.      *
  152.      * @param Request $request
  153.      *
  154.      * @return BinaryFileResponse
  155.      */
  156.     public function getVideoPreview(Request $request)
  157.     {
  158.         $response = new Response();
  159.         $response->setStatusCode(400);
  160.         $id $request->get('id');
  161.         if(!$this->checkHash($id)){
  162.             $response->setStatusCode(401);
  163.             return $response;
  164.         }
  165.         $asset Asset::getById(intval($id));
  166.         if(!empty($asset) && $asset->getType()=='video'){
  167.             $thumbnail $asset->getThumbnail(Asset\Video\Thumbnail\Config::getPreviewConfig(), ['mp4']);
  168.             $storagePath $asset->getRealPath() . '/' preg_replace('@^' preg_quote($asset->getPath(), '@') . '@'''urldecode($thumbnail['formats']['mp4']));
  169.             $storage \Pimcore\Tool\Storage::get('thumbnail');
  170.             if ($storage->fileExists($storagePath)) {
  171.                 $fs $storage->fileSize($storagePath);
  172.                 $stream $storage->readStream($storagePath);
  173.                 return new StreamedResponse(function () use ($stream) {
  174.                     fpassthru($stream);
  175.                 }, 200, [
  176.                     'Content-Type' => 'video/mp4',
  177.                     'Content-Length' => $fs,
  178.                     'Accept-Ranges' => 'bytes',
  179.                 ]);
  180.             } else {
  181.                 $response->setStatusCode(204);
  182.             }
  183.         }
  184.         return $response;
  185.     }
  186.     /**
  187.      * @param Response $response
  188.      */
  189.     protected function responseThumbnail($thumb)
  190.     {
  191.         $stream $thumb->getStream();
  192.         if ($stream) {
  193.             $response = new StreamedResponse(function () use ($stream) {
  194.                 fpassthru($stream);
  195.             }, 200, [
  196.                 'Content-Type' => 'image/' $thumb->getFileExtension(),
  197.             ]);
  198.         } else {
  199.             $response = new BinaryFileResponse(PIMCORE_PATH '/bundles/AdminBundle/public/img/filetype-not-supported.svg');
  200.         }
  201.         $this->addThumbnailCacheHeaders($response);
  202.         return $response;
  203.     }
  204.     /**
  205.      * @Route("/promemoria/api/download-as-zip", methods={"GET"})
  206.      *
  207.      * @param Request $request
  208.      *
  209.      * @return BinaryFileResponse
  210.      */
  211.     public function downloadAsZip(Request $request)
  212.     {
  213.         $name $request->get('name''');
  214.         $version $request->get('version''original');
  215.         $watermarked $request->get('watermarked'0);
  216.         $zipName = ($name ?: 'collection-' time()) . '.zip';
  217.         $zipFile tempnam("/tmp"$zipName);
  218.         $zip = new \ZipArchive();
  219.         $zipState $zip->open($zipFile\ZipArchive::CREATE);
  220.         $selectedIds $request->get('selectedIds''');
  221.         if (strlen($selectedIds) > && $zipState === true) {
  222.             $conditionFilters = [];
  223.             $selectedIds explode(','$selectedIds);
  224.             $ids = [];
  225.             foreach ($selectedIds as $id) {
  226.                 if(!$this->checkHash($id)){
  227.                     $response = new Response();
  228.                     $response->setStatusCode(401);
  229.                     return $response;
  230.                 }
  231.                 $ids[] = intval($id);
  232.             }
  233.             $conditionFilters[] = 'id IN (' implode(','$ids) . ')';
  234.             $conditionFilters[] .= "type != 'folder'";
  235.             $condition implode(' AND '$conditionFilters);
  236.             $assetList = new Asset\Listing();
  237.             $assetList->setCondition($condition);
  238.             $assetList->setOrderKey('LENGTH(path) ASC, id ASC'false);
  239.             $assetList->setOffset((int)$request->get('offset'));
  240.             $assetList->setLimit((int)$request->get('limit'));
  241.             foreach ($assetList->load() as $a) {
  242.                 if (!$a instanceof Asset\Folder) {
  243.                     if($a instanceof Asset\Image){
  244.                         $a $this->getThumb($a$watermarked $version "no_watermark"$version === 'original');
  245.                     }
  246.                     if ($a instanceof Asset\Image\Thumbnail) {
  247.                         $dir_prefix '/var/www/html/public/var/tmp/thumbnails';
  248.                         $pathReference $a->getPathReference();
  249.                         //serve per generare la thumb nel caso non esista
  250.                         $fileContent Tool\Storage::get('thumbnail')->read($pathReference['storagePath']);
  251.                         $path urldecode($a->getPath());
  252.                     } else {
  253.                         $dir_prefix '/var/www/html/public/var/assets';
  254.                         $path $a->getRealFullPath();
  255.                     }
  256.                     $zip->addFile($dir_prefix.$pathbasename($path));
  257.                 }
  258.             }
  259.             $zip->close();
  260.             $response = new BinaryFileResponse($zipFile);
  261.             $response->headers->set('Content-Type''application/zip');
  262.             $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT$zipName);
  263.             $response->deleteFileAfterSend(true);
  264.             return $response;
  265.         }
  266.         return $this->json(['error' => true]);
  267.     }
  268.     /**
  269.      * @Route("/promemoria/api/getShortToken", methods={"GET"})
  270.      * @param Request $request
  271.      *
  272.      * @return JsonResponse
  273.      */
  274.     public function getShortToken(Request $request)
  275.     {
  276.         $response = new Response();
  277.         $response->setStatusCode(400);
  278.         $db \Pimcore\Db::get();
  279.         $jwtToken $request->get('jwtToken');
  280.         $this->clearExpiredShortUrls();
  281.         if (!empty($jwtToken)) {
  282.             $generatedToken substr(md5(uniqid(mt_rand(), true)), 08);
  283.             $db->insert('promemoria_shorturl', [
  284.                 'jwtToken' => $jwtToken,
  285.                 'shortToken' => $generatedToken
  286.             ]);
  287.             return $this->json(['shortToken' => $generatedToken]);
  288.         }
  289.         return $response;
  290.     }
  291.     /**
  292.      * @Route("/promemoria/api/getJwtToken", methods={"GET"})
  293.      * @param Request $request
  294.      *
  295.      * @return JsonResponse
  296.      */
  297.     public function getJwtToken(Request $request)
  298.     {
  299.         $response = new Response();
  300.         $response->setStatusCode(400);
  301.         $db \Pimcore\Db::get();
  302.         $shortToken $request->get('shortToken');
  303.         $this->clearExpiredShortUrls();
  304.         if (!empty($shortToken)) {
  305.             $res $db->fetchRow("SELECT jwtToken FROM promemoria_shorturl WHERE shortToken = " $db->quote($shortToken));
  306.             return $this->json(['jwtToken' => $res['jwtToken']]);
  307.         }
  308.         return $response;
  309.     }
  310.     /**
  311.      * @Route("/promemoria/api/changePassword", methods={"POST"})
  312.      * @param Request $request
  313.      *
  314.      * @return JsonResponse
  315.      */
  316.     public function changePassword(Request $request)
  317.     {
  318.         $response = new Response();
  319.         $response->setStatusCode(401);
  320.         $data json_decode($request->getContent());
  321.         $newPassword $data->password;
  322.         $pimcoreUser Authentication::authenticateSession();
  323.         if(empty($pimcoreUser)){
  324.             return $response;
  325.         }
  326.         if (!empty($pimcoreUser) && !empty($newPassword)) {
  327.             $pimcoreUser->setPassword(Authentication::getPasswordHash($pimcoreUser->getUsername(), $newPassword));
  328.             $pimcoreUser->save();
  329.             return $this->json(['message' => 'Password changed']);
  330.         }
  331.         return $response;
  332.     }
  333.     /**
  334.      * @Route("/promemoria/api/getUserList", methods={"POST"}))
  335.      * @param Request $request
  336.      *
  337.      * @return JsonResponse
  338.      */
  339.     public function getUserList(Request $request)
  340.     {
  341.         $pimcoreUser Authentication::authenticateSession();
  342.         if(empty($pimcoreUser)){
  343.             $response = new Response();
  344.             $response->setStatusCode(401);
  345.             return $response;
  346.         }
  347.         $db \Pimcore\Db::get();
  348.         $query = <<<QUERY
  349.         SELECT u.id as user_id, u.name as user_name, u.firstname as fname, u.lastname as lname, u.email, r.id as role_id, r.name as role
  350.         FROM users u
  351.         INNER JOIN users r ON u.type = 'user' and u.roles = r.id and u.roles != '' and u.active = 1
  352.         order by u.name asc
  353. QUERY;
  354.         return $this->json(['users' => $db->executeQuery($query)->fetchAll()]);
  355.     }
  356.     /**
  357.     * @Route("/promemoria/api/getRoleList", methods={"POST"}))
  358.     * @param Request $request
  359.     *
  360.     * @return JsonResponse
  361.     */
  362.     public function getRoleList(Request $request)
  363.     {
  364.         $pimcoreUser Authentication::authenticateSession();
  365.         if(empty($pimcoreUser)){
  366.             $response = new Response();
  367.             $response->setStatusCode(401);
  368.             return $response;
  369.         }
  370.         $db \Pimcore\Db::get();
  371.         $query = <<<QUERY
  372.         SELECT u.id as role_id, u.name as name
  373.         FROM users u
  374.         WHERE
  375.         u.type = 'role'
  376.         order by u.name asc
  377. QUERY;
  378.         return $this->json(['roles' => $db->executeQuery($query)->fetchAll()]);
  379.     }
  380.     /**
  381.      * @Route("/promemoria/api/upsertUser", methods={"POST"})
  382.      * @param Request $request
  383.      *
  384.      * @return JsonResponse
  385.      */
  386.     public function upsertUser(Request $request)
  387.     {
  388.         $pimcoreUser Authentication::authenticateSession();
  389.         if(empty($pimcoreUser)){
  390.             $response = new Response();
  391.             $response->setStatusCode(401);
  392.             return $response;
  393.         }
  394.         $userAdmin = new UserAdmin($pimcoreUser);
  395.         if(!in_array("ROLE_PIMCORE_ADMIN"$userAdmin->getRoles())
  396.             && !in_array("ROLE_MANAGER"$userAdmin->getRoles())){
  397.             $response = new Response();
  398.             $response->setStatusCode(401);
  399.             return $response;
  400.         }
  401.         $data json_decode($request->getContent());
  402.         $user = new User();
  403.         if(!empty($data->user_id)){
  404.             $user User::getById($data->user_id);
  405.         }
  406.         $user->setParentid(0);
  407.         $user->setUsername($data->user_name);
  408.         $user->setFirstname($data->fname);
  409.         $user->setLastname($data->lname);
  410.         $user->setEmail($data->email);
  411.         $user->setActive($data->active);
  412.         $user->setLanguage("it");
  413.         if(!empty($data->password)){
  414.             $user->setPassword(Authentication::getPasswordHash($data->user_name$data->password));
  415.         }
  416.         $user->setRoles($data->role_id);
  417.         $user->save();
  418.         return $this->json(['message' => 'User updated']);
  419.     }
  420.     /**
  421.      * @Route("/promemoria/api/deleteUser", methods={"POST"})
  422.      * @param Request $request
  423.      *
  424.      * @return JsonResponse
  425.      */
  426.     public function deleteUser(Request $request)
  427.     {
  428.         $pimcoreUser Authentication::authenticateSession();
  429.         if(empty($pimcoreUser)){
  430.             $response = new Response();
  431.             $response->setStatusCode(401);
  432.             return $response;
  433.         }
  434.         $data json_decode($request->getContent());
  435.         $user User::getById($data->user_id);
  436.         $userAdmin = new UserAdmin($user);
  437.         if(in_array("ROLE_PIMCORE_ADMIN"$userAdmin->getRoles())){
  438.             $response = new Response();
  439.             $response->setStatusCode(401);
  440.             return $response;
  441.         }
  442.         $user->delete();
  443.         return $this->json(['message' => 'User deleted']);
  444.     }
  445.     
  446.     /**
  447.      * @Route("/promemoria/api/diario", methods={"POST"})
  448.      * @param Request $request
  449.      *
  450.      * @return JsonResponse
  451.      */
  452.     public function diario(Request $request) {
  453.         $token $request->get("token");
  454.         $config \App\PromemoriaBundle\PromemoriaBundle::getConfig();
  455.         if (!empty($config["googleRecaptchaSecretKey"]) && !empty($token)) {
  456.             $verifyResponse file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' $config["googleRecaptchaSecretKey"] . '&response=' $token);
  457.             $responseData json_decode($verifyResponse);
  458.             if (!$responseData->success || $responseData->score 0.5) {
  459.                 $response = new Response();
  460.                 $response->setStatusCode(401);
  461.                 return $response;
  462.             }
  463.             $pimcoreUsername "website";
  464.             $pimcoreId 0;
  465.         } else {
  466.             $pimcoreUser Authentication::authenticateSession();
  467.             if (empty($pimcoreUser)) {
  468.                 $email $request->get("email");
  469.                 if (empty($email)) {
  470.                     $response = new Response();
  471.                     $response->setStatusCode(401);
  472.                     return $response;
  473.                 } else {
  474.                     $pimcoreUsername $email;
  475.                     $pimcoreId 0;
  476.                 }
  477.             } else {
  478.                 $pimcoreUsername $pimcoreUser->getUsername();
  479.                 $pimcoreId $pimcoreUser->getId();
  480.             }
  481.         }
  482.         $assetFolderName "diarioCollezionista";
  483.         $parentBuca "/" $assetFolderName "/";
  484.         $rootFolder Folder::getByPath("/" $assetFolderName);
  485. // Create root folder if it doesn’t exist
  486.         if (!$rootFolder) {
  487.             $rootFolder = new Folder();
  488.             $rootFolder->setParentId(1); // Root folder in Pimcore
  489.             $rootFolder->setKey($assetFolderName);
  490.             $rootFolder->save();
  491.         }
  492.         $diarioNoteId $request->get("diarioNoteId");
  493.         $inventrio $request->get("inventrio");
  494.         $title $request->get("title");
  495.         $parentPath1 $parentBuca $inventrio;
  496.         $parentPath2 $parentPath1 "/" $title;
  497.         $parentAsset1 \Pimcore\Model\Asset::getByPath($parentPath1);
  498.         $parentAsset2 \Pimcore\Model\Asset::getByPath($parentPath2);
  499. // Create or get first-level folder (/diarioCollezionista/inventrio)
  500.         if (!$parentAsset1) {
  501.             $parent1 \Pimcore\Model\Asset::getByPath($parentBuca);
  502.             $parentAsset1 $this->createFolder($inventrio$parent1->getId(), 'asset');
  503.         }
  504. //  Handle second-level folder (title)
  505.         $folderId null// initialize
  506.         if (!$parentAsset2) {
  507.             $parent2 \Pimcore\Model\Asset::getByPath($parentPath1);
  508.             if (empty($diarioNoteId) || $diarioNoteId === 'UNDEFINED' || $diarioNoteId === 'undefined') {
  509.                 // Case 1: No diarioNoteId ? Create a new folder
  510.                 $parentAsset2 $this->createFolder($title$parent2->getId(), 'asset');
  511.                 $folderId $parentAsset2->getId();
  512.             } else {
  513.                 // Case 2: diarioNoteId exists ? rename existing folder to new title
  514.                 $existingAsset \Pimcore\Model\Asset::getById($diarioNoteId);
  515.                 if ($existingAsset instanceof \Pimcore\Model\Asset) {
  516.                     // Rename only if name is different
  517.                     if ($existingAsset->getKey() !== $title) {
  518.                         $existingAsset->setKey($title); 
  519.                         $existingAsset->save();
  520.                     }
  521.                     $parentAsset2 $existingAsset;
  522.                     $folderId $existingAsset->getId();
  523.                 } else {
  524.                     // fallback: diarioNoteId invalid ? create new folder
  525.                     $parentAsset2 $this->createFolder($title$parent2->getId(), 'asset');
  526.                     $folderId $parentAsset2->getId();
  527.                 }
  528.             }
  529.         } else {
  530.             // folder already exists by path
  531.             $folderId $parentAsset2->getId();
  532.         }
  533. //  Handle file uploads
  534.         $fields json_decode($request->get("fields"), true);
  535.         $values = [];
  536.         $assetIds = [];
  537.         if (is_array($fields)) {
  538.             foreach ($fields as $key => $typeField) {
  539.                 if (in_array($typeField, ["file""image"])) {
  540.                     $files $request->files->get($key);
  541.                     if (!empty($files)) {
  542.                         $files is_array($files) ? $files : [$files];
  543.                         foreach ($files as $file) {
  544.                             $newAsset $this->createAsset($parentAsset2$file);
  545.                             $values[] = $newAsset;
  546.                             if ($newAsset instanceof \Pimcore\Model\Asset) {
  547.                                 $assetIds[] = $newAsset->getId() . "-" .
  548.                                         substr(md5($newAsset->getId() . md5(getenv("dotenv_suffix"))), 08);
  549.                             }
  550.                         }
  551.                     }
  552.                 }
  553.             }
  554.         }
  555. //  Return JSON Response
  556.         return $this->json([
  557.                     "status" => true,
  558.                     "assetIds" => $assetIds,
  559.                     "folderId" => $folderId
  560.         ]);
  561.     }
  562.     /**
  563.      * @Route("/promemoria/api/diarioDeleteMedia", methods={"POST"})
  564.      * @param Request $request
  565.      *
  566.      * @return JsonResponse
  567.      */
  568.     public function diarioDeleteMedia(Request $request) {
  569.         $token $request->get("token");
  570.         $config \App\PromemoriaBundle\PromemoriaBundle::getConfig();
  571.         if (!empty($config["googleRecaptchaSecretKey"]) && !empty($token)) {
  572.             $verifyResponse file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' $config["googleRecaptchaSecretKey"] . '&response=' $token);
  573.             $responseData json_decode($verifyResponse);
  574.             if (!$responseData->success || $responseData->score 0.5) {
  575.                 $response = new Response();
  576.                 $response->setStatusCode(401);
  577.                 return $response;
  578.             }
  579.             $pimcoreUsername "website";
  580.             $pimcoreId 0;
  581.         } else {
  582.             $pimcoreUser Authentication::authenticateSession();
  583.             if (empty($pimcoreUser)) {
  584.                 $email $request->get("email");
  585.                 if (empty($email)) {
  586.                     $response = new Response();
  587.                     $response->setStatusCode(401);
  588.                     return $response;
  589.                 } else {
  590.                     $pimcoreUsername $email;
  591.                     $pimcoreId 0;
  592.                 }
  593.             } else {
  594.                 $pimcoreUsername $pimcoreUser->getUsername();
  595.                 $pimcoreId $pimcoreUser->getId();
  596.             }
  597.         }
  598.         $parentBuca "/diarioCollezionista/";
  599.         $inventrio trim($request->get("inventrio"));
  600.         $title trim($request->get("title"));
  601.         $imageName trim($request->get("imageName"));
  602.         // ? Basic input validation
  603.         if (empty($inventrio) || empty($title)) {
  604.             return $this->json([
  605.                         "status" => false,
  606.                         "message" => "Missing required parameters: inventrio or title."
  607.             ]);
  608.         }
  609.         //  Build asset path
  610.         if ($imageName === 'deleteAll') {
  611.             $assetPath $parentBuca $inventrio "/" $title;
  612.         } else {
  613.             if (empty($imageName)) {
  614.                 return $this->json([
  615.                             "status" => false,
  616.                             "message" => "Image name cannot be empty unless deleteAll is specified."
  617.                 ]);
  618.             }
  619.             $assetPath $parentBuca $inventrio "/" $title "/" $imageName;
  620.         }
  621.         // Normalize path (ensure leading slash)
  622.         $assetPath "/" ltrim($assetPath"/");
  623.         // Security check: only allow under parentBuca
  624.         if (strpos($assetPath$parentBuca) !== 0) {
  625.             return $this->json([
  626.                         "status" => false,
  627.                         "message" => "Invalid path. Deletion outside parent folder is not allowed."
  628.             ]);
  629.         }
  630.         // ? Check if asset exists
  631.         $asset2 \Pimcore\Model\Asset::getByPath($assetPath);
  632.         if (!$asset2 instanceof \Pimcore\Model\Asset) {
  633.             return $this->json([
  634.                         "status" => false,
  635.                         "message" => "Asset not found at path: " $assetPath
  636.             ]);
  637.         }
  638.         try {
  639.             if ($imageName === 'deleteAll') {
  640.                 if ($asset2 instanceof \Pimcore\Model\Asset\Folder) {
  641.                     // just delete the folder recursively
  642.                     $mediaId $asset2->getId();
  643.                     $asset2->delete();
  644.                     return $this->json([
  645.                                 "status" => true,
  646.                                 "message" => "Asset Folder Successfully.",
  647.                                 "mediaId" => $mediaId "-" substr(md5($mediaId md5(getenv("dotenv_suffix"))), 08)
  648.                     ]);
  649.                 } else {
  650.                     return $this->json([
  651.                                 "status" => false,
  652.                                 "message" => "Target is not a folder."
  653.                     ]);
  654.                 }
  655.             } else {
  656.                 // delete a single asset
  657.                 $mediaId $asset2->getId();
  658.                 $asset2->delete();
  659.                 // check if parent folder is now empty ? delete it too
  660.                 $parentFolder $asset2->getParent();
  661.                 if ($parentFolder instanceof \Pimcore\Model\Asset\Folder && count($parentFolder->getChildren()) === 0) {
  662.                     $parentFolder->delete();
  663.                 }
  664.                 return $this->json([
  665.                             "status" => true,
  666.                             "message" => "Asset Deleted Successfully.",
  667.                             "mediaId" => $mediaId "-" substr(md5($mediaId md5(getenv("dotenv_suffix"))), 08)
  668.                 ]);
  669.             }
  670.         } catch (\Exception $e) {
  671.             \Pimcore\Log\Simple::log("asset_delete_error"$e->getMessage());
  672.             return $this->json([
  673.                         "status" => false,
  674.                         "message" => "Error deleting asset: " $e->getMessage()
  675.             ]);
  676.         }
  677.     }
  678.     /**
  679.      * @Route("/promemoria/api/buca", methods={"POST"})
  680.      * @param Request $request
  681.      *
  682.      * @return JsonResponse
  683.      */
  684.     public function buca(Request $request)
  685.     {
  686.         $token $request->get("token");
  687.         $config \App\PromemoriaBundle\PromemoriaBundle::getConfig();
  688.         if(!empty($config["googleRecaptchaSecretKey"]) && !empty($token)){
  689.             $verifyResponse file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' $config["googleRecaptchaSecretKey"] . '&response=' $token);
  690.             $responseData json_decode($verifyResponse);
  691.             if (!$responseData->success || $responseData->score 0.5) {
  692.                 $response = new Response();
  693.                 $response->setStatusCode(401);
  694.                 return $response;
  695.             }
  696.             $pimcoreUsername "website";
  697.             $pimcoreId 0;
  698.         }else{
  699.             $pimcoreUser Authentication::authenticateSession();
  700.             if(empty($pimcoreUser)){
  701.                 $email $request->get("email");
  702.                 if(empty($email)){
  703.                     $response = new Response();
  704.                     $response->setStatusCode(401);
  705.                     return $response;
  706.                 }else{
  707.                     $pimcoreUsername $email;
  708.                     $pimcoreId 0;
  709.                 }
  710.             }else{
  711.                 $pimcoreUsername $pimcoreUser->getUsername();
  712.                 $pimcoreId $pimcoreUser->getId();
  713.             }
  714.         }
  715.         // crezione folder utente se non esiste
  716.         $parentBuca "/Buca/";
  717.         $parentPath $parentBuca $pimcoreUsername;
  718.         $parentAsset \Pimcore\Model\Asset::getByPath($parentPath);
  719.         if(!$parentAsset){
  720.             $parent \Pimcore\Model\Asset::getByPath($parentBuca);
  721.             $parentAsset $this->createFolder($pimcoreUsername$parent->getId(), 'asset');
  722.         }
  723.         $parentObject \Pimcore\Model\DataObject::getByPath($parentPath);
  724.         if(!$parentObject){
  725.             $parent \Pimcore\Model\DataObject::getByPath($parentBuca);
  726.             $parentObject $this->createFolder($pimcoreUsername$parent->getId());
  727.         }
  728.         // creazione oggetto e media
  729.         $separatore "$";
  730.         $classe "\Pimcore\Model\DataObject\\" $request->get("class");
  731.         $fields json_decode($request->get("fields"), TRUE);
  732.         $obj = new $classe();
  733.         $obj->setParentId($parentObject->getId());
  734.         foreach ($fields as $key => $typeField) {
  735.             $fieldDefiniton $obj->getClass()->getFieldDefinition($key);
  736.             $type $fieldDefiniton $fieldDefiniton->getFieldtype() : "localizedfield";
  737.             $type strpos($key$separatore) !== FALSE "block" $type;
  738.             if(in_array($typeField,["file","image"])){
  739.                 $files $request->files->get($key);
  740.                 $didascalie $request->get($key "Didascalia");
  741.                 if(!empty($files)){
  742.                     $isMultiple is_array($files);
  743.                     $files $isMultiple $files : [$files];
  744.                     $values = [];
  745.                     if($typeField === "image"){
  746.                         foreach ($files as $index => $file) {
  747.                             $advancedImage = new \Pimcore\Model\DataObject\Data\Hotspotimage();
  748.                             $advancedImage->setImage($this->createAsset($parentAsset$file"image"));
  749.                             $values[] = $advancedImage;
  750.                         }
  751.                         $values = new \Pimcore\Model\DataObject\Data\ImageGallery($values);
  752.                     }else{
  753.                         foreach ($files as $index => $file) {
  754.                             $values[] = $this->createAsset($parentAsset$file);
  755.                         }
  756.                     }
  757.                     $obj->{"set" ucfirst($key)}($isMultiple $values $values[0]);
  758.                 }
  759.             }else {
  760.                 $val $request->get($key);
  761.                 if(!empty($val)){
  762.                     switch($typeField){
  763.                         case "link":
  764.                             $link = new \Pimcore\Model\DataObject\Data\Link();
  765.                             $link->setText("Link");
  766.                             $link->setPath($val);
  767.                             $val $link;
  768.                             break;
  769.                         case 'date':
  770.                             $val \Carbon\Carbon::createFromFormat('Y-m-d'$val);
  771.                             break;
  772.                     }
  773.                     switch($type){
  774.                         case "video":
  775.                             $video = new \Pimcore\Model\DataObject\Data\Video();
  776.                             $video->setType("youtube");
  777.                             $video->setData($val);
  778.                             $result preg_match("/(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&]+(?=\?)|(?<=v=)[^&]+|(?<=youtu.be\/)[^&]+/"$val$matches);
  779.                             if($result){
  780.                                 $video->setType("youtube");
  781.                                 $video->setData($matches[0]);
  782.                             }
  783.                             $result preg_match("/(?<=vimeo.com\/)[^&]+/"$val$matches);
  784.                             if($result){
  785.                                 $video->setType("vimeo");
  786.                                 $video->setData($matches[0]);
  787.                             }
  788.                             $obj->{"set" ucfirst($key)}($video);
  789.                             break;
  790.                         case "block":
  791.                             list ($keyContainer$keyMeta) = explode($separatore$key);
  792.                             $metadata = [];
  793.                             $metadata[$keyMeta] = new \Pimcore\Model\DataObject\Data\BlockElement($keyMeta$typeField$val);
  794.                             $obj->{"set" ucfirst($keyContainer)}([$metadata]);
  795.                             break;
  796.                         case "localizedfield":
  797.                             $obj->{"set" ucfirst($key)}($val'it');
  798.                             break;
  799.                         case "multiselect":
  800.                             $obj->{"set" ucfirst($key)}([$val]);
  801.                             break;
  802.                         default:
  803.                             $obj->{"set" ucfirst($key)}($val);
  804.                             break;
  805.                     }
  806.                     if($key === 'dcTitle'){
  807.                         $obj->setKey(\Pimcore\Model\Element\Service::getValidKey($val'object'));
  808.                     }
  809.                 }
  810.             }
  811.         }
  812.         $obj->setUserOwner($pimcoreId);
  813.         $obj->setUserModification($pimcoreId);
  814.         $obj->save();
  815.         $tags $request->get("tags");
  816.         if(!empty($tags)){
  817.             \Pimcore\Model\Element\Tag::setTagsForElement('object'$obj->getId(), array_map(function($id){
  818.                 return \Pimcore\Model\Element\Tag::getById($id);
  819.             }, $tags));
  820.         }
  821.         return $this->json(["status" =>  true ]);
  822.     }
  823.     /**
  824.      * @Route("/promemoria/api/bucaSelect", methods={"POST"})
  825.      * @param Request $request
  826.      *
  827.      * @return JsonResponse
  828.      */
  829.     public function bucaSelect(Request $request)
  830.     {
  831.         $pimcoreUser Authentication::authenticateSession();
  832.         if(empty($pimcoreUser)){
  833.             $response = new Response();
  834.             $response->setStatusCode(401);
  835.             return $response;
  836.         }
  837.         $data json_decode($request->getContent());
  838.         $classe "\Pimcore\Model\DataObject\\" $data->class;
  839.         $obj = new $classe();
  840.         $fieldDefiniton $obj->getClass()->getFieldDefinition($data->field);
  841.         return $this->json($fieldDefiniton->getOptions());
  842.     }
  843.      /**
  844.      * @Route("/promemoria/api/bucaTags", methods={"POST"})
  845.      * @param Request $request
  846.      *
  847.      * @return JsonResponse
  848.      */
  849.     public function bucaTags(Request $request)
  850.     {
  851.         $pimcoreUser Authentication::authenticateSession();
  852.         if(empty($pimcoreUser)){
  853.             $response = new Response();
  854.             $response->setStatusCode(401);
  855.             return $response;
  856.         }
  857.         $data json_decode($request->getContent());
  858.         $tagList = new \Pimcore\Model\Element\Tag\Listing();
  859.         $tagList->setCondition("parentId = ?"$data->parentId);
  860.         $tagList->setOrderKey("id");
  861.         $tags = [];
  862.         foreach ($tagList->load() as $tag) {
  863.             $tags[] = [
  864.                 "id" => $tag->getId(),
  865.                 "label" => $tag->getName()
  866.             ];
  867.         }
  868.         return $this->json($tags);
  869.     }
  870.     /**
  871.      * @Route("/promemoria/api/check-email", methods={"POST"}))
  872.      * @param Request $request
  873.      *
  874.      * @return JsonResponse
  875.      */
  876.     public function checkEmail(Request $request)
  877.     {
  878.         $response = new Response();
  879.         $response->setStatusCode(400);
  880.         $data json_decode($request->getContent());
  881.         if(empty($data->email)){
  882.             return $response;
  883.         }
  884.         $user false;
  885.         $entries = new \Pimcore\Model\User\Listing();
  886.         $entries->setLimit(1);
  887.         $entries->setCondition("email LIKE ?", [$data->email]);
  888.         foreach ($entries as $entry) {
  889.             $user $entry;
  890.             return $this->json([
  891.                 'status' => true
  892.             ]);
  893.         }
  894.         return $response;
  895.     }
  896.     /**
  897.      * @Route("/promemoria/api/change-reset-password", methods={"POST"}))
  898.      * @param Request $request
  899.      *
  900.      * @return JsonResponse
  901.      */
  902.     public function changeResetPassword(Request $request)
  903.     {
  904.         $response = new Response();
  905.         $response->setStatusCode(400);
  906.         $data json_decode($request->getContent());
  907.         if(empty($data->email) || empty($data->password)){
  908.             return $response;
  909.         }
  910.         $entries = new \Pimcore\Model\User\Listing();
  911.         $entries->setLimit(1);
  912.         $entries->setCondition("email LIKE ?", [$data->email]);
  913.         foreach ($entries as $entry) {
  914.             $user $entry;
  915.             $user->setPassword(Authentication::getPasswordHash($user->getUsername(), $data->password));
  916.             $user->save();
  917.             return $this->json([
  918.                 'status' => true
  919.             ]);
  920.         }
  921.         return $response;
  922.     }
  923.     /* PRIVATE */
  924.     private function clearExpiredShortUrls()
  925.     {
  926.         $db \Pimcore\Db::get();
  927.         $db->deleteWhere('promemoria_shorturl''insertDate < NOW() - INTERVAL 1 WEEK');
  928.     }
  929.     private function createFolder($name$parent$type 'object'){
  930.         $folder $type === 'object' ? new \Pimcore\Model\DataObject\Folder() : new \Pimcore\Model\Asset\Folder();
  931.         $folder->setParentId($parent);
  932.         $type === 'object'  $folder->setKey($name) : $folder->setFilename($name);
  933.         $folder->save();
  934.         return $folder;
  935.     }
  936.     private function createAsset($parentAsset$file$type=""){
  937.         $newAsset $type ? new \Pimcore\Model\Asset\Image() : new \Pimcore\Model\Asset();
  938.         $newAsset->setFilename($this->checkFileAndRename($parentAsset->getFullPath(), $file->getClientOriginalName()));
  939.         $newAsset->setData(file_get_contents($file->getPathname()));
  940.         $newAsset->setParent($parentAsset);
  941.         $newAsset->save();
  942.         return $newAsset;
  943.     }
  944.     private function checkFileAndRename($parentPath$filename){
  945.         $path_parts pathinfo($filename);
  946.         $i 1;
  947.         while(\Pimcore\Model\Asset::getByPath($parentPath "/" $filename)){
  948.             $filename $path_parts['filename'] . "_$i." $path_parts['extension'];
  949.             $i++;
  950.         }
  951.         return $filename;
  952.     }
  953.     private function getThumb($image$type$original=false){
  954.         $thumb $this->getThumbnail($image"watermarked_" $type);
  955.         if(!$thumb || empty($thumb->getConfig())) {
  956.             $thumb $this->getThumbnail($image$type);
  957.         }
  958.         if(!$thumb || empty($thumb->getConfig())){
  959.             if($original) return $image;
  960.             $thumb $this->getThumbnail($imageAsset\Image\Thumbnail\Config::getPreviewConfig());
  961.         }
  962.         return $thumb;
  963.     }
  964.     private function getThumbnail($image$type){
  965.         try{
  966.             return $image->getThumbnail($type);
  967.         }catch(\Exception $err){
  968.             return null;
  969.         }
  970.     }
  971.     private function addThumbnailCacheHeaders(Response $response)
  972.     {
  973.        $lifetime 300;
  974.         $date = new \DateTime('now');
  975.         $date->add(new \DateInterval('PT' $lifetime 'S'));
  976.         $response->setMaxAge($lifetime);
  977.         $response->setPublic();
  978.         $response->setExpires($date);
  979.         $response->headers->set('Access-Control-Allow-Origin''*');
  980.     }
  981.     private function checkHash($id){
  982.         list($id$hash) = explode("-"$id);
  983.         return $hash === substr(md5($id md5(getenv("dotenv_suffix"))), 08);
  984.     }
  985. }