pimcore/lib/Pimcore/Bundle/AdminBundle/Controller/Admin/AssetController.php line 1147

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  * @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  * @license    http://www.pimcore.org/license     GPLv3 and PEL
  13.  */
  14. namespace Pimcore\Bundle\AdminBundle\Controller\Admin;
  15. use Pimcore\Controller\Configuration\TemplatePhp;
  16. use Pimcore\Controller\EventedControllerInterface;
  17. use Pimcore\Event\AdminEvents;
  18. use Pimcore\File;
  19. use Pimcore\Logger;
  20. use Pimcore\Model;
  21. use Pimcore\Model\Asset;
  22. use Pimcore\Model\Element;
  23. use Pimcore\Tool;
  24. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  25. use Symfony\Component\EventDispatcher\GenericEvent;
  26. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  27. use Symfony\Component\HttpFoundation\JsonResponse;
  28. use Symfony\Component\HttpFoundation\Request;
  29. use Symfony\Component\HttpFoundation\Response;
  30. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  31. use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
  32. use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
  33. use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
  34. use Symfony\Component\Routing\Annotation\Route;
  35. /**
  36.  * @Route("/asset")
  37.  */
  38. class AssetController extends ElementControllerBase implements EventedControllerInterface
  39. {
  40.     /**
  41.      * @var Asset\Service
  42.      */
  43.     protected $_assetService;
  44.     /**
  45.      * @Route("/get-data-by-id")
  46.      *
  47.      * @param Request $request
  48.      *
  49.      * @return JsonResponse
  50.      */
  51.     public function getDataByIdAction(Request $requestEventDispatcherInterface $eventDispatcher)
  52.     {
  53.         // check for lock
  54.         if (Element\Editlock::isLocked($request->get('id'), 'asset')) {
  55.             return $this->adminJson([
  56.                 'editlock' => Element\Editlock::getByElement($request->get('id'), 'asset')
  57.             ]);
  58.         }
  59.         Element\Editlock::lock($request->get('id'), 'asset');
  60.         $asset Asset::getById(intval($request->get('id')));
  61.         $asset = clone $asset;
  62.         if (!$asset instanceof Asset) {
  63.             return $this->adminJson(['success' => false'message' => "asset doesn't exist"]);
  64.         }
  65.         $asset->setMetadata(Asset\Service::expandMetadataForEditmode($asset->getMetadata()));
  66.         $asset->setProperties(Element\Service::minimizePropertiesForEditmode($asset->getProperties()));
  67.         //$asset->getVersions();
  68.         $asset->getScheduledTasks();
  69.         $asset->idPath Element\Service::getIdPath($asset);
  70.         $asset->userPermissions $asset->getUserPermissions();
  71.         $asset->setLocked($asset->isLocked());
  72.         $asset->setParent(null);
  73.         if ($asset instanceof Asset\Text) {
  74.             if ($asset->getFileSize() < 2000000) {
  75.                 // it doesn't make sense to show a preview for files bigger than 2MB
  76.                 $asset->data =  \ForceUTF8\Encoding::toUTF8($asset->getData());
  77.             } else {
  78.                 $asset->data false;
  79.             }
  80.         }
  81.         if ($asset instanceof Asset\Image) {
  82.             $imageInfo = [];
  83.             if ($asset->getWidth() && $asset->getHeight()) {
  84.                 $imageInfo['dimensions'] = [];
  85.                 $imageInfo['dimensions']['width'] = $asset->getWidth();
  86.                 $imageInfo['dimensions']['height'] = $asset->getHeight();
  87.             }
  88.             $exifData $asset->getEXIFData();
  89.             if (!empty($exifData)) {
  90.                 $imageInfo['exif'] = $exifData;
  91.             }
  92.             $iptcData $asset->getIPTCData();
  93.             if (!empty($iptcData)) {
  94.                 // flatten data, to be displayed in grid
  95.                 foreach ($iptcData as &$value) {
  96.                     if (is_array($value)) {
  97.                         $value implode(', '$value);
  98.                     }
  99.                 }
  100.                 $imageInfo['iptc'] = $iptcData;
  101.             }
  102.             $imageInfo['exiftoolAvailable'] = (bool) \Pimcore\Tool\Console::getExecutable('exiftool');
  103.             $asset->imageInfo $imageInfo;
  104.         }
  105.         $asset->setStream(null);
  106.         //Hook for modifying return value - e.g. for changing permissions based on object data
  107.         //data need to wrapped into a container in order to pass parameter to event listeners by reference so that they can change the values
  108.         $data object2array($asset);
  109.         $event = new GenericEvent($this, [
  110.             'data' => $data,
  111.             'asset' => $asset
  112.         ]);
  113.         $eventDispatcher->dispatch(AdminEvents::ASSET_GET_PRE_SEND_DATA$event);
  114.         $data $event->getArgument('data');
  115.         if ($asset->isAllowed('view')) {
  116.             return $this->adminJson($data);
  117.         }
  118.         return $this->adminJson(['success' => false'message' => 'missing_permission']);
  119.     }
  120.     /**
  121.      * @Route("/tree-get-childs-by-id")
  122.      *
  123.      * @param Request $request
  124.      *
  125.      * @return JsonResponse
  126.      */
  127.     public function treeGetChildsByIdAction(Request $requestEventDispatcherInterface $eventDispatcher)
  128.     {
  129.         $allParams array_merge($request->request->all(), $request->query->all());
  130.         $assets = [];
  131.         $cv false;
  132.         $asset Asset::getById($allParams['node']);
  133.         $limit intval($allParams['limit']);
  134.         if (!$allParams['limit']) {
  135.             $limit 100000000;
  136.         }
  137.         $offset intval($allParams['start']);
  138.         if ($asset->hasChildren()) {
  139.             if ($allParams['view']) {
  140.                 $cv = \Pimcore\Model\Element\Service::getCustomViewById($allParams['view']);
  141.             }
  142.             // get assets
  143.             $childsList = new Asset\Listing();
  144.             if ($this->getAdminUser()->isAdmin()) {
  145.                 $childsList->setCondition('parentId = ? '$asset->getId());
  146.             } else {
  147.                 $userIds $this->getAdminUser()->getRoles();
  148.                 $userIds[] = $this->getAdminUser()->getId();
  149.                 $childsList->setCondition('parentId = ? and
  150.                     (
  151.                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(CONCAT(path,filename),cpath)=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  152.                     or
  153.                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(cpath,CONCAT(path,filename))=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  154.                     )'$asset->getId());
  155.             }
  156.             $childsList->setLimit($limit);
  157.             $childsList->setOffset($offset);
  158.             $childsList->setOrderKey("FIELD(assets.type, 'folder') DESC, assets.filename ASC"false);
  159.             \Pimcore\Model\Element\Service::addTreeFilterJoins($cv$childsList);
  160.             $beforeListLoadEvent = new GenericEvent($this, [
  161.                 'list' => $childsList,
  162.                 'context' => $allParams
  163.             ]);
  164.             $eventDispatcher->dispatch(AdminEvents::ASSET_LIST_BEFORE_LIST_LOAD$beforeListLoadEvent);
  165.             $childsList $beforeListLoadEvent->getArgument('list');
  166.             $childs $childsList->load();
  167.             foreach ($childs as $childAsset) {
  168.                 if ($childAsset->isAllowed('list')) {
  169.                     $assets[] = $this->getTreeNodeConfig($childAsset);
  170.                 }
  171.             }
  172.         }
  173.         if ($allParams['limit']) {
  174.             return $this->adminJson([
  175.                 'offset' => $offset,
  176.                 'limit' => $limit,
  177.                 'total' => $asset->getChildAmount($this->getAdminUser()),
  178.                 'nodes' => $assets
  179.             ]);
  180.         } else {
  181.             return $this->adminJson($assets);
  182.         }
  183.     }
  184.     /**
  185.      * @Route("/add-asset")
  186.      *
  187.      * @param Request $request
  188.      *
  189.      * @return JsonResponse
  190.      */
  191.     public function addAssetAction(Request $request)
  192.     {
  193.         $res $this->addAsset($request);
  194.         return $this->adminJson(['success' => $res['success'], 'msg' => 'Success']);
  195.     }
  196.     /**
  197.      * @Route("/add-asset-compatibility")
  198.      *
  199.      * @param Request $request
  200.      *
  201.      * @return JsonResponse
  202.      */
  203.     public function addAssetCompatibilityAction(Request $request)
  204.     {
  205.         // this is a special action for the compatibility mode upload (without flash)
  206.         $res $this->addAsset($request);
  207.         $response $this->adminJson([
  208.             'success' => $res['success'],
  209.             'msg' => $res['success'] ? 'Success' 'Error',
  210.             'id' => $res['asset'] ? $res['asset']->getId() : null,
  211.             'fullpath' => $res['asset'] ? $res['asset']->getRealFullPath() : null,
  212.             'type' => $res['asset'] ? $res['asset']->getType() : null
  213.         ]);
  214.         $response->headers->set('Content-Type''text/html');
  215.         return $response;
  216.     }
  217.     /**
  218.      * @param Request $request
  219.      *
  220.      * @return array
  221.      *
  222.      * @throws \Exception
  223.      */
  224.     protected function addAsset(Request $request)
  225.     {
  226.         $success false;
  227.         if (array_key_exists('Filedata'$_FILES)) {
  228.             $filename $_FILES['Filedata']['name'];
  229.             $sourcePath $_FILES['Filedata']['tmp_name'];
  230.         } elseif ($request->get('type') == 'base64') {
  231.             $filename $request->get('filename');
  232.             $sourcePath PIMCORE_SYSTEM_TEMP_DIRECTORY '/upload-base64' uniqid() . '.tmp';
  233.             $data preg_replace('@^data:[^,]+;base64,@'''$request->get('data'));
  234.             File::put($sourcePathbase64_decode($data));
  235.         }
  236.         $parentId $request->get('parentId');
  237.         if ($request->get('dir') && $request->get('parentId')) {
  238.             // this is for uploading folders with Drag&Drop
  239.             // param "dir" contains the relative path of the file
  240.             $parent Asset::getById($request->get('parentId'));
  241.             $newPath $parent->getRealFullPath() . '/' trim($request->get('dir'), '/ ');
  242.             // check if the path is outside of the asset directory
  243.             $newRealPath PIMCORE_ASSET_DIRECTORY $newPath;
  244.             $newRealPath resolvePath($newRealPath);
  245.             if (strpos($newRealPathPIMCORE_ASSET_DIRECTORY) !== 0) {
  246.                 throw new \Exception('not allowed');
  247.             }
  248.             $maxRetries 5;
  249.             for ($retries=0$retries $maxRetries$retries++) {
  250.                 try {
  251.                     $newParent Asset\Service::createFolderByPath($newPath);
  252.                     break;
  253.                 } catch (\Exception $e) {
  254.                     if ($retries < ($maxRetries 1)) {
  255.                         $waitTime rand(100000900000); // microseconds
  256.                         usleep($waitTime); // wait specified time until we restart the transaction
  257.                     } else {
  258.                         // if the transaction still fail after $maxRetries retries, we throw out the exception
  259.                         throw $e;
  260.                     }
  261.                 }
  262.             }
  263.             $parentId $newParent->getId();
  264.         } elseif (!$request->get('parentId') && $request->get('parentPath')) {
  265.             $parent Asset::getByPath($request->get('parentPath'));
  266.             if ($parent instanceof Asset\Folder) {
  267.                 $parentId $parent->getId();
  268.             } else {
  269.                 $parentId 1;
  270.             }
  271.         } elseif (!$request->get('parentId')) {
  272.             // set the parent to the root folder
  273.             $parentId 1;
  274.         }
  275.         $filename Element\Service::getValidKey($filename'asset');
  276.         if (empty($filename)) {
  277.             throw new \Exception('The filename of the asset is empty');
  278.         }
  279.         $parentAsset Asset::getById(intval($parentId));
  280.         // check for duplicate filename
  281.         $filename $this->getSafeFilename($parentAsset->getRealFullPath(), $filename);
  282.         if ($parentAsset->isAllowed('create')) {
  283.             if (is_file($sourcePath) && filesize($sourcePath) < 1) {
  284.                 throw new \Exception('File is empty!');
  285.             } elseif (!is_file($sourcePath)) {
  286.                 throw new \Exception('Something went wrong, please check upload_max_filesize and post_max_size in your php.ini and write permissions of ' PIMCORE_PUBLIC_VAR);
  287.             }
  288.             $asset Asset::create($parentId, [
  289.                 'filename' => $filename,
  290.                 'sourcePath' => $sourcePath,
  291.                 'userOwner' => $this->getAdminUser()->getId(),
  292.                 'userModification' => $this->getAdminUser()->getId()
  293.             ]);
  294.             $success true;
  295.             @unlink($sourcePath);
  296.         } else {
  297.             Logger::debug('prevented creating asset because of missing permissions, parent asset is ' $parentAsset->getRealFullPath());
  298.         }
  299.         return [
  300.             'success' => $success,
  301.             'asset' => $asset
  302.         ];
  303.     }
  304.     /**
  305.      * @param $targetPath
  306.      * @param $filename
  307.      *
  308.      * @return string
  309.      */
  310.     protected function getSafeFilename($targetPath$filename)
  311.     {
  312.         $originalFilename $filename;
  313.         $count 1;
  314.         if ($targetPath == '/') {
  315.             $targetPath '';
  316.         }
  317.         while (true) {
  318.             if (Asset\Service::pathExists($targetPath '/' $filename)) {
  319.                 $filename str_ireplace('.' File::getFileExtension($originalFilename), '_' $count '.' File::getFileExtension($originalFilename), $originalFilename);
  320.                 $count++;
  321.             } else {
  322.                 return $filename;
  323.             }
  324.         }
  325.     }
  326.     /**
  327.      * @Route("/replace-asset")
  328.      *
  329.      * @param Request $request
  330.      *
  331.      * @return JsonResponse
  332.      *
  333.      * @throws \Exception
  334.      */
  335.     public function replaceAssetAction(Request $request)
  336.     {
  337.         $asset Asset::getById($request->get('id'));
  338.         $newFilename Element\Service::getValidKey($_FILES['Filedata']['name'], 'asset');
  339.         $mimetype Tool\Mime::detect($_FILES['Filedata']['tmp_name'], $newFilename);
  340.         $newType Asset::getTypeFromMimeMapping($mimetype$newFilename);
  341.         if ($newType != $asset->getType()) {
  342.             $translator $this->get('translator');
  343.             return $this->adminJson([
  344.                 'success'=>false,
  345.                 'message'=> sprintf($translator->trans('asset_type_change_not_allowed', [], 'admin'), $asset->getType(), $newType)
  346.             ]);
  347.         }
  348.         $stream fopen($_FILES['Filedata']['tmp_name'], 'r+');
  349.         $asset->setStream($stream);
  350.         $asset->setCustomSetting('thumbnails'null);
  351.         $asset->setUserModification($this->getAdminUser()->getId());
  352.         $newFileExt File::getFileExtension($newFilename);
  353.         $currentFileExt File::getFileExtension($asset->getFilename());
  354.         if ($newFileExt != $currentFileExt) {
  355.             $newFilename preg_replace('/\.' $currentFileExt '$/''.'.$newFileExt$asset->getFilename());
  356.             $newFilename Element\Service::getSaveCopyName('asset'$newFilename$asset->getParent());
  357.             $asset->setFilename($newFilename);
  358.         }
  359.         if ($asset->isAllowed('publish')) {
  360.             $asset->save();
  361.             $response $this->adminJson([
  362.                 'id' => $asset->getId(),
  363.                 'path' => $asset->getRealFullPath(),
  364.                 'success' => true
  365.             ]);
  366.             // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in
  367.             // Ext.form.Action.Submit and mark the submission as failed
  368.             $response->headers->set('Content-Type''text/html');
  369.             return $response;
  370.         } else {
  371.             throw new \Exception('missing permission');
  372.         }
  373.     }
  374.     /**
  375.      * @Route("/add-folder")
  376.      *
  377.      * @param Request $request
  378.      *
  379.      * @return JsonResponse
  380.      */
  381.     public function addFolderAction(Request $request)
  382.     {
  383.         $success false;
  384.         $parentAsset Asset::getById(intval($request->get('parentId')));
  385.         $equalAsset Asset::getByPath($parentAsset->getRealFullPath() . '/' $request->get('name'));
  386.         if ($parentAsset->isAllowed('create')) {
  387.             if (!$equalAsset) {
  388.                 $asset Asset::create($request->get('parentId'), [
  389.                     'filename' => $request->get('name'),
  390.                     'type' => 'folder',
  391.                     'userOwner' => $this->getAdminUser()->getId(),
  392.                     'userModification' => $this->getAdminUser()->getId()
  393.                 ]);
  394.                 $success true;
  395.             }
  396.         } else {
  397.             Logger::debug('prevented creating asset because of missing permissions');
  398.         }
  399.         return $this->adminJson(['success' => $success]);
  400.     }
  401.     /**
  402.      * @Route("/delete")
  403.      *
  404.      * @param Request $request
  405.      *
  406.      * @return JsonResponse
  407.      */
  408.     public function deleteAction(Request $request)
  409.     {
  410.         if ($request->get('type') == 'childs') {
  411.             $parentAsset Asset::getById($request->get('id'));
  412.             $list = new Asset\Listing();
  413.             $list->setCondition('path LIKE ?', [$parentAsset->getRealFullPath() . '/%']);
  414.             $list->setLimit(intval($request->get('amount')));
  415.             $list->setOrderKey('LENGTH(path)'false);
  416.             $list->setOrder('DESC');
  417.             $assets $list->load();
  418.             $deletedItems = [];
  419.             foreach ($assets as $asset) {
  420.                 /**
  421.                  * @var $asset Asset
  422.                  */
  423.                 $deletedItems[] = $asset->getRealFullPath();
  424.                 if ($asset->isAllowed('delete')) {
  425.                     $asset->delete();
  426.                 }
  427.             }
  428.             return $this->adminJson(['success' => true'deleted' => $deletedItems]);
  429.         } elseif ($request->get('id')) {
  430.             $asset Asset::getById($request->get('id'));
  431.             if ($asset->isAllowed('delete')) {
  432.                 $asset->delete();
  433.                 return $this->adminJson(['success' => true]);
  434.             }
  435.         }
  436.         return $this->adminJson(['success' => false'message' => 'missing_permission']);
  437.     }
  438.     /**
  439.      * @Route("/delete-info")
  440.      *
  441.      * @param Request $request
  442.      *
  443.      * @return JsonResponse
  444.      */
  445.     public function deleteInfoAction(Request $request)
  446.     {
  447.         $hasDependency false;
  448.         $deleteJobs = [];
  449.         $recycleJobs = [];
  450.         $totalChilds 0;
  451.         $ids $request->get('id');
  452.         $ids explode(','$ids);
  453.         foreach ($ids as $id) {
  454.             try {
  455.                 $asset Asset::getById($id);
  456.                 if (!$asset) {
  457.                     continue;
  458.                 }
  459.                 $hasDependency $asset->getDependencies()->isRequired();
  460.             } catch (\Exception $e) {
  461.                 Logger::err('failed to access asset with id: ' $id);
  462.                 continue;
  463.             }
  464.             // check for childs
  465.             if ($asset instanceof Asset) {
  466.                 $recycleJobs[] = [[
  467.                     'url' => '/admin/recyclebin/add',
  468.                     'params' => [
  469.                         'type' => 'asset',
  470.                         'id' => $asset->getId()
  471.                     ]
  472.                 ]];
  473.                 $hasChilds $asset->hasChildren();
  474.                 if (!$hasDependency) {
  475.                     $hasDependency $hasChilds;
  476.                 }
  477.                 $childs 0;
  478.                 if ($hasChilds) {
  479.                     // get amount of childs
  480.                     $list = new Asset\Listing();
  481.                     $list->setCondition('path LIKE ?', [$asset->getRealFullPath() . '/%']);
  482.                     $childs $list->getTotalCount();
  483.                     $totalChilds += $childs;
  484.                     if ($childs 0) {
  485.                         $deleteObjectsPerRequest 5;
  486.                         for ($i 0$i ceil($childs $deleteObjectsPerRequest); $i++) {
  487.                             $deleteJobs[] = [[
  488.                                 'url' => '/admin/asset/delete',
  489.                                 'params' => [
  490.                                     'step' => $i,
  491.                                     'amount' => $deleteObjectsPerRequest,
  492.                                     'type' => 'childs',
  493.                                     'id' => $asset->getId()
  494.                                 ]
  495.                             ]];
  496.                         }
  497.                     }
  498.                 }
  499.                 // the asset itself is the last one
  500.                 $deleteJobs[] = [[
  501.                     'url' => '/admin/asset/delete',
  502.                     'params' => [
  503.                         'id' => $asset->getId()
  504.                     ]
  505.                 ]];
  506.             }
  507.         }
  508.         // get the element key in case of just one
  509.         $elementKey false;
  510.         if (count($ids) === 1) {
  511.             $elementKey Asset::getById($id)->getKey();
  512.         }
  513.         $deleteJobs array_merge($recycleJobs$deleteJobs);
  514.         return $this->adminJson([
  515.             'hasDependencies' => $hasDependency,
  516.             'childs' => $totalChilds,
  517.             'deletejobs' => $deleteJobs,
  518.             'batchDelete' => count($ids) > 1,
  519.             'elementKey' => $elementKey
  520.         ]);
  521.     }
  522.     /**
  523.      * @param $element
  524.      *
  525.      * @return array
  526.      */
  527.     protected function getTreeNodeConfig($element)
  528.     {
  529.         /**
  530.          * @var $asset Asset
  531.          */
  532.         $asset $element;
  533.         $tmpAsset = [
  534.             'id' => $asset->getId(),
  535.             'text' => $asset->getFilename(),
  536.             'type' => $asset->getType(),
  537.             'path' => $asset->getRealFullPath(),
  538.             'basePath' => $asset->getRealPath(),
  539.             'locked' => $asset->isLocked(),
  540.             'lockOwner' => $asset->getLocked() ? true false,
  541.             'elementType' => 'asset',
  542.             'permissions' => [
  543.                 'remove' => $asset->isAllowed('delete'),
  544.                 'settings' => $asset->isAllowed('settings'),
  545.                 'rename' => $asset->isAllowed('rename'),
  546.                 'publish' => $asset->isAllowed('publish'),
  547.                 'view' => $asset->isAllowed('view')
  548.             ]
  549.         ];
  550.         // set type specific settings
  551.         if ($asset->getType() == 'folder') {
  552.             $tmpAsset['leaf'] = false;
  553.             $tmpAsset['expanded'] = $asset->hasNoChilds();
  554.             $tmpAsset['loaded'] = $asset->hasNoChilds();
  555.             $tmpAsset['iconCls'] = 'pimcore_icon_folder';
  556.             $tmpAsset['permissions']['create'] = $asset->isAllowed('create');
  557.             $folderThumbs = [];
  558.             $children = new Asset\Listing();
  559.             $children->setCondition('path LIKE ?', [$asset->getRealFullPath() . '/%']);
  560.             $children->setLimit(35);
  561.             foreach ($children as $child) {
  562.                 if ($child->isAllowed('view')) {
  563.                     if ($thumbnailUrl $this->getThumbnailUrl($child)) {
  564.                         $folderThumbs[] = $thumbnailUrl;
  565.                     }
  566.                 }
  567.             }
  568.             if (!empty($folderThumbs)) {
  569.                 $tmpAsset['thumbnails'] = $folderThumbs;
  570.             }
  571.         } else {
  572.             $tmpAsset['leaf'] = true;
  573.             $tmpAsset['expandable'] = false;
  574.             $tmpAsset['expanded'] = false;
  575.             $tmpAsset['iconCls'] = 'pimcore_icon_asset_default';
  576.             $fileExt File::getFileExtension($asset->getFilename());
  577.             if ($fileExt) {
  578.                 $tmpAsset['iconCls'] .= ' pimcore_icon_' File::getFileExtension($asset->getFilename());
  579.             }
  580.         }
  581.         $tmpAsset['qtipCfg'] = [
  582.             'title' => 'ID: ' $asset->getId()
  583.         ];
  584.         if ($asset->getType() == 'image') {
  585.             try {
  586.                 $tmpAsset['thumbnail'] = $this->getThumbnailUrl($asset);
  587.                 // this is for backward-compatibility, to calculate the dimensions if they are not there
  588.                 if (!$asset->getCustomSetting('imageDimensionsCalculated')) {
  589.                     $asset->save();
  590.                 }
  591.                 // we need the dimensions for the wysiwyg editors, so that they can resize the image immediately
  592.                 if ($asset->getCustomSetting('imageWidth') && $asset->getCustomSetting('imageHeight')) {
  593.                     $tmpAsset['imageWidth'] = $asset->getCustomSetting('imageWidth');
  594.                     $tmpAsset['imageHeight'] = $asset->getCustomSetting('imageHeight');
  595.                 }
  596.             } catch (\Exception $e) {
  597.                 Logger::debug('Cannot get dimensions of image, seems to be broken.');
  598.             }
  599.         } elseif ($asset->getType() == 'video') {
  600.             try {
  601.                 if (\Pimcore\Video::isAvailable()) {
  602.                     $tmpAsset['thumbnail'] = $this->getThumbnailUrl($asset);
  603.                 }
  604.             } catch (\Exception $e) {
  605.                 Logger::debug('Cannot get dimensions of video, seems to be broken.');
  606.             }
  607.         } elseif ($asset->getType() == 'document') {
  608.             try {
  609.                 // add the PDF check here, otherwise the preview layer in admin is shown without content
  610.                 if (\Pimcore\Document::isAvailable() && \Pimcore\Document::isFileTypeSupported($asset->getFilename())) {
  611.                     $tmpAsset['thumbnail'] = $this->getThumbnailUrl($asset);
  612.                 }
  613.             } catch (\Exception $e) {
  614.                 Logger::debug('Cannot get dimensions of video, seems to be broken.');
  615.             }
  616.         }
  617.         $tmpAsset['cls'] = '';
  618.         if ($asset->isLocked()) {
  619.             $tmpAsset['cls'] .= 'pimcore_treenode_locked ';
  620.         }
  621.         if ($asset->getLocked()) {
  622.             $tmpAsset['cls'] .= 'pimcore_treenode_lockOwner ';
  623.         }
  624.         return $tmpAsset;
  625.     }
  626.     /**
  627.      * @param Asset $asset
  628.      *
  629.      * @return null|string
  630.      */
  631.     protected function getThumbnailUrl(Asset $asset)
  632.     {
  633.         if ($asset instanceof Asset\Image) {
  634.             return '/admin/asset/get-image-thumbnail?id=' $asset->getId() . '&treepreview=true';
  635.         } elseif ($asset instanceof Asset\Video && \Pimcore\Video::isAvailable()) {
  636.             return '/admin/asset/get-video-thumbnail?id=' $asset->getId() . '&treepreview=true';
  637.         } elseif ($asset instanceof Asset\Document && \Pimcore\Document::isAvailable()) {
  638.             return '/admin/asset/get-document-thumbnail?id=' $asset->getId() . '&treepreview=true';
  639.         }
  640.         return null;
  641.     }
  642.     /**
  643.      * @Route("/update")
  644.      *
  645.      * @param Request $request
  646.      *
  647.      * @return JsonResponse
  648.      *
  649.      * @throws \Exception
  650.      */
  651.     public function updateAction(Request $request)
  652.     {
  653.         $success false;
  654.         $allowUpdate true;
  655.         $updateData array_merge($request->request->all(), $request->query->all());
  656.         $asset Asset::getById($request->get('id'));
  657.         if ($asset->isAllowed('settings')) {
  658.             $asset->setUserModification($this->getAdminUser()->getId());
  659.             // if the position is changed the path must be changed || also from the childs
  660.             if ($request->get('parentId')) {
  661.                 $parentAsset Asset::getById($request->get('parentId'));
  662.                 //check if parent is changed i.e. asset is moved
  663.                 if ($asset->getParentId() != $parentAsset->getId()) {
  664.                     if (!$parentAsset->isAllowed('create')) {
  665.                         throw new \Exception('Prevented moving asset - no create permission on new parent ');
  666.                     }
  667.                     $intendedPath $parentAsset->getRealPath();
  668.                     $pKey $parentAsset->getKey();
  669.                     if (!empty($pKey)) {
  670.                         $intendedPath .= $parentAsset->getKey() . '/';
  671.                     }
  672.                     $assetWithSamePath Asset::getByPath($intendedPath $asset->getKey());
  673.                     if ($assetWithSamePath != null) {
  674.                         $allowUpdate false;
  675.                     }
  676.                     if ($asset->isLocked()) {
  677.                         $allowUpdate false;
  678.                     }
  679.                 }
  680.             }
  681.             if ($allowUpdate) {
  682.                 if ($request->get('filename') != $asset->getFilename() and !$asset->isAllowed('rename')) {
  683.                     unset($updateData['filename']);
  684.                     Logger::debug('prevented renaming asset because of missing permissions ');
  685.                 }
  686.                 $asset->setValues($updateData);
  687.                 try {
  688.                     $asset->save();
  689.                     $success true;
  690.                 } catch (\Exception $e) {
  691.                     return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  692.                 }
  693.             } else {
  694.                 $msg 'prevented moving asset, asset with same path+key already exists at target location or the asset is locked. ID: ' $asset->getId();
  695.                 Logger::debug($msg);
  696.                 return $this->adminJson(['success' => $success'message' => $msg]);
  697.             }
  698.         } elseif ($asset->isAllowed('rename') && $request->get('filename')) {
  699.             //just rename
  700.             try {
  701.                 $asset->setFilename($request->get('filename'));
  702.                 $asset->save();
  703.                 $success true;
  704.             } catch (\Exception $e) {
  705.                 return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  706.             }
  707.         } else {
  708.             Logger::debug('prevented update asset because of missing permissions ');
  709.         }
  710.         return $this->adminJson(['success' => $success]);
  711.     }
  712.     /**
  713.      * @Route("/webdav{path}", requirements={"path"=".*"}, name="pimcore_admin_webdav")
  714.      *
  715.      * @param Request $request
  716.      */
  717.     public function webdavAction(Request $request)
  718.     {
  719.         $homeDir Asset::getById(1);
  720.         try {
  721.             $publicDir = new Asset\WebDAV\Folder($homeDir);
  722.             $objectTree = new Asset\WebDAV\Tree($publicDir);
  723.             $server = new \Sabre\DAV\Server($objectTree);
  724.             $server->setBaseUri('/admin/asset/webdav/');
  725.             // lock plugin
  726.             $lockBackend = new \Sabre\DAV\Locks\Backend\File(PIMCORE_SYSTEM_TEMP_DIRECTORY '/webdav-locks.dat');
  727.             $lockPlugin = new \Sabre\DAV\Locks\Plugin($lockBackend);
  728.             $server->addPlugin($lockPlugin);
  729.             // sync plugin
  730.             $server->addPlugin(new \Sabre\DAV\Sync\Plugin());
  731.             // browser plugin
  732.             $server->addPlugin(new \Sabre\DAV\Browser\Plugin());
  733.             $server->exec();
  734.         } catch (\Exception $e) {
  735.             Logger::error($e);
  736.         }
  737.         exit;
  738.     }
  739.     /**
  740.      * @Route("/save")
  741.      *
  742.      * @param Request $request
  743.      *
  744.      * @return JsonResponse
  745.      *
  746.      * @throws \Exception
  747.      */
  748.     public function saveAction(Request $request)
  749.     {
  750.         try {
  751.             $success false;
  752.             if ($request->get('id')) {
  753.                 $asset Asset::getById($request->get('id'));
  754.                 if ($asset->isAllowed('publish')) {
  755.                     // metadata
  756.                     if ($request->get('metadata')) {
  757.                         $metadata $this->decodeJson($request->get('metadata'));
  758.                         $metadata Asset\Service::minimizeMetadata($metadata);
  759.                         $asset->setMetadata($metadata);
  760.                     }
  761.                     // properties
  762.                     if ($request->get('properties')) {
  763.                         $properties = [];
  764.                         $propertiesData $this->decodeJson($request->get('properties'));
  765.                         if (is_array($propertiesData)) {
  766.                             foreach ($propertiesData as $propertyName => $propertyData) {
  767.                                 $value $propertyData['data'];
  768.                                 try {
  769.                                     $property = new Model\Property();
  770.                                     $property->setType($propertyData['type']);
  771.                                     $property->setName($propertyName);
  772.                                     $property->setCtype('asset');
  773.                                     $property->setDataFromEditmode($value);
  774.                                     $property->setInheritable($propertyData['inheritable']);
  775.                                     $properties[$propertyName] = $property;
  776.                                 } catch (\Exception $e) {
  777.                                     Logger::err("Can't add " $propertyName ' to asset ' $asset->getRealFullPath());
  778.                                 }
  779.                             }
  780.                             $asset->setProperties($properties);
  781.                         }
  782.                     }
  783.                     // scheduled tasks
  784.                     if ($request->get('scheduler')) {
  785.                         $tasks = [];
  786.                         $tasksData $this->decodeJson($request->get('scheduler'));
  787.                         if (!empty($tasksData)) {
  788.                             foreach ($tasksData as $taskData) {
  789.                                 $taskData['date'] = strtotime($taskData['date'] . ' ' $taskData['time']);
  790.                                 $task = new Model\Schedule\Task($taskData);
  791.                                 $tasks[] = $task;
  792.                             }
  793.                         }
  794.                         $asset->setScheduledTasks($tasks);
  795.                     }
  796.                     if ($request->get('data')) {
  797.                         $asset->setData($request->get('data'));
  798.                     }
  799.                     $asset->setUserModification($this->getAdminUser()->getId());
  800.                     try {
  801.                         $asset->save();
  802.                         $asset->getData();
  803.                         $success true;
  804.                     } catch (\Exception $e) {
  805.                         if ($e instanceof Element\ValidationException) {
  806.                             throw $e;
  807.                         }
  808.                         return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  809.                     }
  810.                 } else {
  811.                     Logger::debug('prevented save asset because of missing permissions ');
  812.                 }
  813.                 return $this->adminJson(['success' => $success]);
  814.             }
  815.             return $this->adminJson(false);
  816.         } catch (\Exception $e) {
  817.             Logger::log($e);
  818.             if ($e instanceof Element\ValidationException) {
  819.                 return $this->adminJson(['success' => false'type' => 'ValidationException''message' => $e->getMessage(), 'stack' => $e->getTraceAsString(), 'code' => $e->getCode()]);
  820.             }
  821.             throw $e;
  822.         }
  823.     }
  824.     /**
  825.      * @Route("/publish-version")
  826.      *
  827.      * @param Request $request
  828.      *
  829.      * @return JsonResponse
  830.      */
  831.     public function publishVersionAction(Request $request)
  832.     {
  833.         $version Model\Version::getById($request->get('id'));
  834.         $asset $version->loadData();
  835.         $currentAsset Asset::getById($asset->getId());
  836.         if ($currentAsset->isAllowed('publish')) {
  837.             try {
  838.                 $asset->setUserModification($this->getAdminUser()->getId());
  839.                 $asset->save();
  840.                 return $this->adminJson(['success' => true]);
  841.             } catch (\Exception $e) {
  842.                 return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  843.             }
  844.         }
  845.         return $this->adminJson(false);
  846.     }
  847.     /**
  848.      * @Route("/show-version")
  849.      * @TemplatePhp()
  850.      *
  851.      * @param Request $request
  852.      *
  853.      * @return Response
  854.      *
  855.      * @throws \Exception
  856.      */
  857.     public function showVersionAction(Request $request)
  858.     {
  859.         $id intval($request->get('id'));
  860.         $version Model\Version::getById($id);
  861.         $asset $version->loadData();
  862.         if ($asset->isAllowed('versions')) {
  863.             return $this->render(
  864.                 'PimcoreAdminBundle:Admin/Asset:showVersion' ucfirst($asset->getType()) . '.html.php',
  865.                 ['asset' => $asset]
  866.             );
  867.         } else {
  868.             throw new \Exception('Permission denied, version id [' $id ']');
  869.         }
  870.     }
  871.     /**
  872.      * @Route("/download")
  873.      *
  874.      * @param Request $request
  875.      *
  876.      * @return BinaryFileResponse
  877.      */
  878.     public function downloadAction(Request $request)
  879.     {
  880.         $asset Asset::getById($request->get('id'));
  881.         if ($asset->isAllowed('view')) {
  882.             $response = new BinaryFileResponse($asset->getFileSystemPath());
  883.             $response->headers->set('Content-Type'$asset->getMimetype());
  884.             $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT$asset->getFilename());
  885.             return $response;
  886.         }
  887.     }
  888.     /**
  889.      * @Route("/download-image-thumbnail")
  890.      *
  891.      * @param Request $request
  892.      *
  893.      * @return BinaryFileResponse
  894.      */
  895.     public function downloadImageThumbnailAction(Request $request)
  896.     {
  897.         $image Asset\Image::getById($request->get('id'));
  898.         if (!$image->isAllowed('view')) {
  899.             throw new \Exception('not allowed to view thumbnail');
  900.         }
  901.         $config null;
  902.         if ($request->get('config')) {
  903.             $config $this->decodeJson($request->get('config'));
  904.         } elseif ($request->get('type')) {
  905.             $predefined = [
  906.                 'web' => [
  907.                     'resize_mode' => 'scaleByWidth',
  908.                     'width' => 3500,
  909.                     'dpi' => 72,
  910.                     'format' => 'JPEG',
  911.                     'quality' => 85
  912.                 ],
  913.                 'print' => [
  914.                     'resize_mode' => 'scaleByWidth',
  915.                     'width' => 6000,
  916.                     'dpi' => 300,
  917.                     'format' => 'JPEG',
  918.                     'quality' => 95
  919.                 ],
  920.                 'office' => [
  921.                     'resize_mode' => 'scaleByWidth',
  922.                     'width' => 1190,
  923.                     'dpi' => 144,
  924.                     'format' => 'JPEG',
  925.                     'quality' => 90
  926.                 ],
  927.             ];
  928.             $config $predefined[$request->get('type')];
  929.         }
  930.         if ($config) {
  931.             $thumbnailConfig = new Asset\Image\Thumbnail\Config();
  932.             $thumbnailConfig->setName('pimcore-download-' $image->getId() . '-' md5($request->get('config')));
  933.             if ($config['resize_mode'] == 'scaleByWidth') {
  934.                 $thumbnailConfig->addItem('scaleByWidth', [
  935.                     'width' => $config['width']
  936.                 ]);
  937.             } elseif ($config['resize_mode'] == 'scaleByHeight') {
  938.                 $thumbnailConfig->addItem('scaleByHeight', [
  939.                     'height' => $config['height']
  940.                 ]);
  941.             } else {
  942.                 $thumbnailConfig->addItem('resize', [
  943.                     'width' => $config['width'],
  944.                     'height' => $config['height']
  945.                 ]);
  946.             }
  947.             $thumbnailConfig->setQuality($config['quality']);
  948.             $thumbnailConfig->setFormat($config['format']);
  949.             if ($thumbnailConfig->getFormat() == 'JPEG') {
  950.                 $thumbnailConfig->setPreserveMetaData(true);
  951.                 if (empty($config['quality'])) {
  952.                     $thumbnailConfig->setPreserveColor(true);
  953.                 }
  954.             }
  955.             $thumbnail $image->getThumbnail($thumbnailConfig);
  956.             $thumbnailFile $thumbnail->getFileSystemPath();
  957.             $exiftool = \Pimcore\Tool\Console::getExecutable('exiftool');
  958.             if ($thumbnailConfig->getFormat() == 'JPEG' && $exiftool && isset($config['dpi']) && $config['dpi']) {
  959.                 \Pimcore\Tool\Console::exec($exiftool ' -overwrite_original -xresolution=' $config['dpi'] . ' -yresolution=' $config['dpi'] . ' -resolutionunit=inches ' escapeshellarg($thumbnailFile));
  960.             }
  961.             $downloadFilename str_replace(
  962.                 '.' File::getFileExtension($image->getFilename()),
  963.                 '.' $thumbnail->getFileExtension(),
  964.                 $image->getFilename()
  965.             );
  966.             $downloadFilename strtolower($downloadFilename);
  967.             clearstatcache();
  968.             $response = new BinaryFileResponse($thumbnailFile);
  969.             $response->headers->set('Content-Type'$thumbnail->getMimeType());
  970.             $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT$downloadFilename);
  971.             $this->addThumbnailCacheHeaders($response);
  972.             $response->deleteFileAfterSend(true);
  973.             return $response;
  974.         }
  975.     }
  976.     /**
  977.      * @Route("/get-image-thumbnail")
  978.      *
  979.      * @param Request $request
  980.      *
  981.      * @return BinaryFileResponse|JsonResponse
  982.      */
  983.     public function getImageThumbnailAction(Request $request)
  984.     {
  985.         $fileinfo $request->get('fileinfo');
  986.         $image Asset\Image::getById(intval($request->get('id')));
  987.         if (!$image->isAllowed('view')) {
  988.             throw new \Exception('not allowed to view thumbnail');
  989.         }
  990.         $thumbnail null;
  991.         if ($request->get('thumbnail')) {
  992.             $thumbnail $image->getThumbnailConfig($request->get('thumbnail'));
  993.         }
  994.         if (!$thumbnail) {
  995.             if ($request->get('config')) {
  996.                 $thumbnail $image->getThumbnailConfig($this->decodeJson($request->get('config')));
  997.             } else {
  998.                 $thumbnail $image->getThumbnailConfig(array_merge($request->request->all(), $request->query->all()));
  999.             }
  1000.         } else {
  1001.             // no high-res images in admin mode (editmode)
  1002.             // this is mostly because of the document's image editable, which doesn't know anything about the thumbnail
  1003.             // configuration, so the dimensions would be incorrect (double the size)
  1004.             $thumbnail->setHighResolution(1);
  1005.         }
  1006.         $format strtolower($thumbnail->getFormat());
  1007.         if ($format == 'source' || $format == 'print') {
  1008.             $thumbnail->setFormat('PNG');
  1009.         }
  1010.         if ($request->get('treepreview')) {
  1011.             $thumbnail Asset\Image\Thumbnail\Config::getPreviewConfig();
  1012.         }
  1013.         if ($request->get('cropPercent')) {
  1014.             $thumbnail->addItemAt(0'cropPercent', [
  1015.                 'width' => $request->get('cropWidth'),
  1016.                 'height' => $request->get('cropHeight'),
  1017.                 'y' => $request->get('cropTop'),
  1018.                 'x' => $request->get('cropLeft')
  1019.             ]);
  1020.             $hash md5(Tool\Serialize::serialize(array_merge($request->request->all(), $request->query->all())));
  1021.             $thumbnail->setName($thumbnail->getName() . '_auto_' $hash);
  1022.         }
  1023.         $thumbnail $image->getThumbnail($thumbnail);
  1024.         if ($fileinfo) {
  1025.             return $this->adminJson([
  1026.                 'width' => $thumbnail->getWidth(),
  1027.                 'height' => $thumbnail->getHeight()]);
  1028.         }
  1029.         $thumbnailFile $thumbnail->getFileSystemPath();
  1030.         $response = new BinaryFileResponse($thumbnailFile);
  1031.         $response->headers->set('Content-Type'$thumbnail->getMimeType());
  1032.         $response->headers->set('Access-Control-Allow-Origin''*');
  1033.         $this->addThumbnailCacheHeaders($response);
  1034.         return $response;
  1035.     }
  1036.     /**
  1037.      * @Route("/get-video-thumbnail")
  1038.      *
  1039.      * @param Request $request
  1040.      *
  1041.      * @return BinaryFileResponse
  1042.      */
  1043.     public function getVideoThumbnailAction(Request $request)
  1044.     {
  1045.         if ($request->get('id')) {
  1046.             $video Asset::getById(intval($request->get('id')));
  1047.         } elseif ($request->get('path')) {
  1048.             $video Asset::getByPath($request->get('path'));
  1049.         }
  1050.         if (!$video->isAllowed('view')) {
  1051.             throw new \Exception('not allowed to view thumbnail');
  1052.         }
  1053.         $thumbnail array_merge($request->request->all(), $request->query->all());
  1054.         if ($request->get('treepreview')) {
  1055.             $thumbnail Asset\Image\Thumbnail\Config::getPreviewConfig();
  1056.         }
  1057.         $time null;
  1058.         if ($request->get('time')) {
  1059.             $time intval($request->get('time'));
  1060.         }
  1061.         if ($request->get('settime')) {
  1062.             $video->removeCustomSetting('image_thumbnail_asset');
  1063.             $video->setCustomSetting('image_thumbnail_time'$time);
  1064.             $video->save();
  1065.         }
  1066.         $image null;
  1067.         if ($request->get('image')) {
  1068.             $image Asset::getById(intval($request->get('image')));
  1069.         }
  1070.         if ($request->get('setimage') && $image) {
  1071.             $video->removeCustomSetting('image_thumbnail_time');
  1072.             $video->setCustomSetting('image_thumbnail_asset'$image->getId());
  1073.             $video->save();
  1074.         }
  1075.         $thumb $video->getImageThumbnail($thumbnail$time$image);
  1076.         $thumbnailFile $thumb->getFileSystemPath();
  1077.         $response = new BinaryFileResponse($thumbnailFile);
  1078.         $response->headers->set('Content-type''image/' File::getFileExtension($thumbnailFile));
  1079.         $this->addThumbnailCacheHeaders($response);
  1080.         return $response;
  1081.     }
  1082.     /**
  1083.      * @Route("/get-document-thumbnail")
  1084.      *
  1085.      * @param Request $request
  1086.      *
  1087.      * @return BinaryFileResponse
  1088.      */
  1089.     public function getDocumentThumbnailAction(Request $request)
  1090.     {
  1091.         $document Asset::getById(intval($request->get('id')));
  1092.         if (!$document->isAllowed('view')) {
  1093.             throw new \Exception('not allowed to view thumbnail');
  1094.         }
  1095.         $thumbnail Asset\Image\Thumbnail\Config::getByAutoDetect(array_merge($request->request->all(), $request->query->all()));
  1096.         $format strtolower($thumbnail->getFormat());
  1097.         if ($format == 'source') {
  1098.             $thumbnail->setFormat('jpeg'); // default format for documents is JPEG not PNG (=too big)
  1099.         }
  1100.         if ($request->get('treepreview')) {
  1101.             $thumbnail Asset\Image\Thumbnail\Config::getPreviewConfig();
  1102.         }
  1103.         $page 1;
  1104.         if (is_numeric($request->get('page'))) {
  1105.             $page = (int)$request->get('page');
  1106.         }
  1107.         $thumb $document->getImageThumbnail($thumbnail$page);
  1108.         $thumbnailFile $thumb->getFileSystemPath();
  1109.         $format 'png';
  1110.         $response = new BinaryFileResponse($thumbnailFile);
  1111.         $response->headers->set('Content-type''image/' $format);
  1112.         $this->addThumbnailCacheHeaders($response);
  1113.         return $response;
  1114.     }
  1115.     /**
  1116.      * @param Response $response
  1117.      */
  1118.     protected function addThumbnailCacheHeaders(Response $response)
  1119.     {
  1120.         $lifetime 300;
  1121.         $date = new \DateTime('now');
  1122.         $date->add(new \DateInterval('PT' $lifetime 'S'));
  1123.         $response->setMaxAge($lifetime);
  1124.         $response->setPublic();
  1125.         $response->setExpires($date);
  1126.         $response->headers->set('Pragma''');
  1127.     }
  1128.     /**
  1129.      * @Route("/get-preview-document")
  1130.      * @TemplatePhp()
  1131.      *
  1132.      * @param Request $request
  1133.      *
  1134.      * @return array
  1135.      */
  1136.     public function getPreviewDocumentAction(Request $request)
  1137.     {
  1138.         $asset Asset::getById($request->get('id'));
  1139.         if (!$asset->isAllowed('view')) {
  1140.             throw new \Exception('not allowed to preview');
  1141.         }
  1142.         return ['asset' => $asset];
  1143.     }
  1144.     /**
  1145.      * @Route("/get-preview-video")
  1146.      * @TemplatePhp()
  1147.      *
  1148.      * @param Request $request
  1149.      *
  1150.      * @return Response
  1151.      */
  1152.     public function getPreviewVideoAction(Request $request)
  1153.     {
  1154.         $asset Asset::getById($request->get('id'));
  1155.         if (!$asset->isAllowed('view')) {
  1156.             throw new \Exception('not allowed to preview');
  1157.         }
  1158.         $previewData = ['asset' => $asset];
  1159.         $config Asset\Video\Thumbnail\Config::getPreviewConfig();
  1160.         $thumbnail $asset->getThumbnail($config, ['mp4']);
  1161.         if ($thumbnail) {
  1162.             $previewData['asset'] = $asset;
  1163.             $previewData['thumbnail'] = $thumbnail;
  1164.             if ($thumbnail['status'] == 'finished') {
  1165.                 return $this->render(
  1166.                     'PimcoreAdminBundle:Admin/Asset:getPreviewVideoDisplay.html.php',
  1167.                     $previewData
  1168.                 );
  1169.             } else {
  1170.                 return $this->render(
  1171.                     'PimcoreAdminBundle:Admin/Asset:getPreviewVideoError.html.php',
  1172.                     $previewData
  1173.                 );
  1174.             }
  1175.         } else {
  1176.             return $this->render(
  1177.                 'PimcoreAdminBundle:Admin/Asset:getPreviewVideoError.html.php',
  1178.                 $previewData
  1179.             );
  1180.         }
  1181.     }
  1182.     /**
  1183.      * @Route("/image-editor")
  1184.      *
  1185.      * @param Request $request
  1186.      * @TemplatePhp()
  1187.      *
  1188.      * @return array
  1189.      */
  1190.     public function imageEditorAction(Request $request)
  1191.     {
  1192.         $asset Asset::getById($request->get('id'));
  1193.         if (!$asset->isAllowed('view')) {
  1194.             throw new \Exception('not allowed to preview');
  1195.         }
  1196.         return ['asset' => $asset];
  1197.     }
  1198.     /**
  1199.      * @Route("/image-editor-save")
  1200.      *
  1201.      * @param Request $request
  1202.      *
  1203.      * @return JsonResponse
  1204.      */
  1205.     public function imageEditorSaveAction(Request $request)
  1206.     {
  1207.         $asset Asset::getById($request->get('id'));
  1208.         if (!$asset->isAllowed('publish')) {
  1209.             throw new \Exception('not allowed to publish');
  1210.         }
  1211.         $data $request->get('dataUri');
  1212.         $data substr($datastrpos($data','));
  1213.         $data base64_decode($data);
  1214.         $asset->setData($data);
  1215.         $asset->setUserModification($this->getAdminUser()->getId());
  1216.         $asset->save();
  1217.         return $this->adminJson(['success' => true]);
  1218.     }
  1219.     /**
  1220.      * @Route("/get-folder-content-preview")
  1221.      *
  1222.      * @param Request $request
  1223.      *
  1224.      * @return JsonResponse
  1225.      */
  1226.     public function getFolderContentPreviewAction(Request $requestEventDispatcherInterface $eventDispatcher)
  1227.     {
  1228.         $allParams array_merge($request->request->all(), $request->query->all());
  1229.         $filterPrepareEvent = new GenericEvent($this, [
  1230.             'requestParams' => $allParams
  1231.         ]);
  1232.         $eventDispatcher->dispatch(AdminEvents::ASSET_LIST_BEFORE_FILTER_PREPARE$filterPrepareEvent);
  1233.         $allParams $filterPrepareEvent->getArgument('requestParams');
  1234.         $folder Asset::getById($allParams['id']);
  1235.         $start 0;
  1236.         $limit 10;
  1237.         if ($allParams['limit']) {
  1238.             $limit $allParams['limit'];
  1239.         }
  1240.         if ($allParams['start']) {
  1241.             $start $allParams['start'];
  1242.         }
  1243.         $conditionFilters = [];
  1244.         $list = new Asset\Listing();
  1245.         $conditionFilters[] = 'path LIKE ' . ($folder->getRealFullPath() == '/' "'/%'" $list->quote($folder->getRealFullPath() . '/%')) ." AND type != 'folder'";
  1246.         if (!$this->getAdminUser()->isAdmin()) {
  1247.             $userIds $this->getAdminUser()->getRoles();
  1248.             $userIds[] = $this->getAdminUser()->getId();
  1249.             $conditionFilters[] .= ' (
  1250.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(CONCAT(path, filename),cpath)=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1251.                                                     OR
  1252.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(cpath,CONCAT(path, filename))=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1253.                                                  )';
  1254.         }
  1255.         $condition implode(' AND '$conditionFilters);
  1256.         $list->setCondition($condition);
  1257.         $list->setLimit($limit);
  1258.         $list->setOffset($start);
  1259.         $list->setOrderKey('filename');
  1260.         $list->setOrder('asc');
  1261.         $beforeListLoadEvent = new GenericEvent($this, [
  1262.             'list' => $list,
  1263.             'context' => $allParams
  1264.         ]);
  1265.         $eventDispatcher->dispatch(AdminEvents::ASSET_LIST_BEFORE_LIST_LOAD$beforeListLoadEvent);
  1266.         $list $beforeListLoadEvent->getArgument('list');
  1267.         $list->load();
  1268.         $assets = [];
  1269.         foreach ($list as $asset) {
  1270.             $thumbnailMethod '';
  1271.             if ($asset instanceof Asset\Image) {
  1272.                 $thumbnailMethod 'getThumbnail';
  1273.             } elseif ($asset instanceof Asset\Video && \Pimcore\Video::isAvailable()) {
  1274.                 $thumbnailMethod 'getImageThumbnail';
  1275.             } elseif ($asset instanceof Asset\Document && \Pimcore\Document::isAvailable()) {
  1276.                 $thumbnailMethod 'getImageThumbnail';
  1277.             }
  1278.             if (!empty($thumbnailMethod)) {
  1279.                 $filenameDisplay $asset->getFilename();
  1280.                 if (strlen($filenameDisplay) > 32) {
  1281.                     $filenameDisplay substr($filenameDisplay025) . '...' . \Pimcore\File::getFileExtension($filenameDisplay);
  1282.                 }
  1283.                 // Like for treeGetChildsByIdAction, so we respect isAllowed method which can be extended (object DI) for custom permissions, so relying only users_workspaces_asset is insufficient and could lead security breach
  1284.                 if ($asset->isAllowed('list')) {
  1285.                     $assets[] = [
  1286.                         'id' => $asset->getId(),
  1287.                         'type' => $asset->getType(),
  1288.                         'filename' => $asset->getFilename(),
  1289.                         'filenameDisplay' => $filenameDisplay,
  1290.                         'url' => '/admin/asset/get-' $asset->getType() . '-thumbnail?id=' $asset->getId() . '&treepreview=true',
  1291.                         'idPath' => $data['idPath'] = Element\Service::getIdPath($asset)
  1292.                     ];
  1293.                 }
  1294.             }
  1295.         }
  1296.         // We need to temporary use data key to be compatible with the ASSET_LIST_AFTER_LIST_LOAD global event
  1297.         $result = ['data' => $assets'success' => true'total' => $list->getTotalCount()];
  1298.         $afterListLoadEvent = new GenericEvent($this, [
  1299.             'list' => $result,
  1300.             'context' => $allParams
  1301.         ]);
  1302.         $eventDispatcher->dispatch(AdminEvents::ASSET_LIST_AFTER_LIST_LOAD$afterListLoadEvent);
  1303.         $result $afterListLoadEvent->getArgument('list');
  1304.         // Here we revert to assets key
  1305.         return $this->adminJson(['assets' => $result['data'], 'success' => $result['success'], 'total' => $result['total']]);
  1306.     }
  1307.     /**
  1308.      * @Route("/copy-info")
  1309.      *
  1310.      * @param Request $request
  1311.      *
  1312.      * @return JsonResponse
  1313.      */
  1314.     public function copyInfoAction(Request $request)
  1315.     {
  1316.         $transactionId time();
  1317.         $pasteJobs = [];
  1318.         Tool\Session::useSession(function (AttributeBagInterface $session) use ($transactionId) {
  1319.             $session->set($transactionId, []);
  1320.         }, 'pimcore_copy');
  1321.         if ($request->get('type') == 'recursive') {
  1322.             $asset Asset::getById($request->get('sourceId'));
  1323.             // first of all the new parent
  1324.             $pasteJobs[] = [[
  1325.                 'url' => '/admin/asset/copy',
  1326.                 'params' => [
  1327.                     'sourceId' => $request->get('sourceId'),
  1328.                     'targetId' => $request->get('targetId'),
  1329.                     'type' => 'child',
  1330.                     'transactionId' => $transactionId,
  1331.                     'saveParentId' => true
  1332.                 ]
  1333.             ]];
  1334.             if ($asset->hasChildren()) {
  1335.                 // get amount of children
  1336.                 $list = new Asset\Listing();
  1337.                 $list->setCondition('path LIKE ?', [$asset->getRealFullPath() . '/%']);
  1338.                 $list->setOrderKey('LENGTH(path)'false);
  1339.                 $list->setOrder('ASC');
  1340.                 $childIds $list->loadIdList();
  1341.                 if (count($childIds) > 0) {
  1342.                     foreach ($childIds as $id) {
  1343.                         $pasteJobs[] = [[
  1344.                             'url' => '/admin/asset/copy',
  1345.                             'params' => [
  1346.                                 'sourceId' => $id,
  1347.                                 'targetParentId' => $request->get('targetId'),
  1348.                                 'sourceParentId' => $request->get('sourceId'),
  1349.                                 'type' => 'child',
  1350.                                 'transactionId' => $transactionId
  1351.                             ]
  1352.                         ]];
  1353.                     }
  1354.                 }
  1355.             }
  1356.         } elseif ($request->get('type') == 'child' || $request->get('type') == 'replace') {
  1357.             // the object itself is the last one
  1358.             $pasteJobs[] = [[
  1359.                 'url' => '/admin/asset/copy',
  1360.                 'params' => [
  1361.                     'sourceId' => $request->get('sourceId'),
  1362.                     'targetId' => $request->get('targetId'),
  1363.                     'type' => $request->get('type'),
  1364.                     'transactionId' => $transactionId
  1365.                 ]
  1366.             ]];
  1367.         }
  1368.         return $this->adminJson([
  1369.             'pastejobs' => $pasteJobs
  1370.         ]);
  1371.     }
  1372.     /**
  1373.      * @Route("/copy")
  1374.      *
  1375.      * @param Request $request
  1376.      *
  1377.      * @return JsonResponse
  1378.      */
  1379.     public function copyAction(Request $request)
  1380.     {
  1381.         $success false;
  1382.         $sourceId intval($request->get('sourceId'));
  1383.         $source Asset::getById($sourceId);
  1384.         $session Tool\Session::get('pimcore_copy');
  1385.         $sessionBag $session->get($request->get('transactionId'));
  1386.         $targetId intval($request->get('targetId'));
  1387.         if ($request->get('targetParentId')) {
  1388.             $sourceParent Asset::getById($request->get('sourceParentId'));
  1389.             // this is because the key can get the prefix "_copy" if the target does already exists
  1390.             if ($sessionBag['parentId']) {
  1391.                 $targetParent Asset::getById($sessionBag['parentId']);
  1392.             } else {
  1393.                 $targetParent Asset::getById($request->get('targetParentId'));
  1394.             }
  1395.             $targetPath preg_replace('@^' $sourceParent->getRealFullPath() . '@'$targetParent '/'$source->getRealPath());
  1396.             $target Asset::getByPath($targetPath);
  1397.         } else {
  1398.             $target Asset::getById($targetId);
  1399.         }
  1400.         if ($target->isAllowed('create')) {
  1401.             $source Asset::getById($sourceId);
  1402.             if ($source != null) {
  1403.                 if ($request->get('type') == 'child') {
  1404.                     $newAsset $this->_assetService->copyAsChild($target$source);
  1405.                     // this is because the key can get the prefix "_copy" if the target does already exists
  1406.                     if ($request->get('saveParentId')) {
  1407.                         $sessionBag['parentId'] = $newAsset->getId();
  1408.                     }
  1409.                 } elseif ($request->get('type') == 'replace') {
  1410.                     $this->_assetService->copyContents($target$source);
  1411.                 }
  1412.                 $session->set($request->get('transactionId'), $sessionBag);
  1413.                 Tool\Session::writeClose();
  1414.                 $success true;
  1415.             } else {
  1416.                 Logger::debug('prevended copy/paste because asset with same path+key already exists in this location');
  1417.             }
  1418.         } else {
  1419.             Logger::error('could not execute copy/paste because of missing permissions on target [ ' $targetId ' ]');
  1420.             return $this->adminJson(['error' => false'message' => 'missing_permission']);
  1421.         }
  1422.         Tool\Session::writeClose();
  1423.         return $this->adminJson(['success' => $success]);
  1424.     }
  1425.     /**
  1426.      * @Route("/download-as-zip-jobs")
  1427.      *
  1428.      * @param Request $request
  1429.      *
  1430.      * @return JsonResponse
  1431.      */
  1432.     public function downloadAsZipJobsAction(Request $request)
  1433.     {
  1434.         $jobId uniqid();
  1435.         $filesPerJob 5;
  1436.         $jobs = [];
  1437.         $asset Asset::getById($request->get('id'));
  1438.         if ($asset->isAllowed('view')) {
  1439.             $parentPath $asset->getRealFullPath();
  1440.             if ($asset->getId() == 1) {
  1441.                 $parentPath '';
  1442.             }
  1443.             $db = \Pimcore\Db::get();
  1444.             $conditionFilters = [];
  1445.             $conditionFilters[] .= 'path LIKE ' $db->quote($parentPath '/%') .' AND type != ' $db->quote('folder');
  1446.             if (!$this->getAdminUser()->isAdmin()) {
  1447.                 $userIds $this->getAdminUser()->getRoles();
  1448.                 $userIds[] = $this->getAdminUser()->getId();
  1449.                 $conditionFilters[] .= ' (
  1450.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(CONCAT(path, filename),cpath)=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1451.                                                     OR
  1452.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(cpath,CONCAT(path, filename))=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1453.                                                  )';
  1454.             }
  1455.             $condition implode(' AND '$conditionFilters);
  1456.             $assetList = new Asset\Listing();
  1457.             $assetList->setCondition($condition);
  1458.             $assetList->setOrderKey('LENGTH(path)'false);
  1459.             $assetList->setOrder('ASC');
  1460.             for ($i 0$i ceil($assetList->getTotalCount() / $filesPerJob); $i++) {
  1461.                 $jobs[] = [[
  1462.                     'url' => '/admin/asset/download-as-zip-add-files',
  1463.                     'params' => [
  1464.                         'id' => $asset->getId(),
  1465.                         'offset' => $i $filesPerJob,
  1466.                         'limit' => $filesPerJob,
  1467.                         'jobId' => $jobId
  1468.                     ]
  1469.                 ]];
  1470.             }
  1471.         }
  1472.         return $this->adminJson([
  1473.             'success' => true,
  1474.             'jobs' => $jobs,
  1475.             'jobId' => $jobId
  1476.         ]);
  1477.     }
  1478.     /**
  1479.      * @Route("/download-as-zip-add-files")
  1480.      *
  1481.      * @param Request $request
  1482.      *
  1483.      * @return JsonResponse
  1484.      */
  1485.     public function downloadAsZipAddFilesAction(Request $request)
  1486.     {
  1487.         $zipFile PIMCORE_SYSTEM_TEMP_DIRECTORY '/download-zip-' $request->get('jobId') . '.zip';
  1488.         $asset Asset::getById($request->get('id'));
  1489.         $success false;
  1490.         if ($asset->isAllowed('view')) {
  1491.             $zip = new \ZipArchive();
  1492.             if (!is_file($zipFile)) {
  1493.                 $zipState $zip->open($zipFile, \ZipArchive::CREATE);
  1494.             } else {
  1495.                 $zipState $zip->open($zipFile);
  1496.             }
  1497.             if ($zipState === true) {
  1498.                 $parentPath $asset->getRealFullPath();
  1499.                 if ($asset->getId() == 1) {
  1500.                     $parentPath '';
  1501.                 }
  1502.                 $db = \Pimcore\Db::get();
  1503.                 $conditionFilters = [];
  1504.                 $conditionFilters[] .= "type != 'folder' AND path LIKE " $db->quote($parentPath '/%');
  1505.                 if (!$this->getAdminUser()->isAdmin()) {
  1506.                     $userIds $this->getAdminUser()->getRoles();
  1507.                     $userIds[] = $this->getAdminUser()->getId();
  1508.                     $conditionFilters[] .= ' (
  1509.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(CONCAT(path, filename),cpath)=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1510.                                                     OR
  1511.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(cpath,CONCAT(path, filename))=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1512.                                                  )';
  1513.                 }
  1514.                 $condition implode(' AND '$conditionFilters);
  1515.                 $assetList = new Asset\Listing();
  1516.                 $assetList->setCondition($condition);
  1517.                 $assetList->setOrderKey('LENGTH(path) ASC, id ASC'false);
  1518.                 $assetList->setOffset((int)$request->get('offset'));
  1519.                 $assetList->setLimit((int)$request->get('limit'));
  1520.                 foreach ($assetList->load() as $a) {
  1521.                     if ($a->isAllowed('view')) {
  1522.                         if (!$a instanceof Asset\Folder) {
  1523.                             // add the file with the relative path to the parent directory
  1524.                             $zip->addFile($a->getFileSystemPath(), preg_replace('@^' preg_quote($asset->getRealPath(), '@') . '@i'''$a->getRealFullPath()));
  1525.                         }
  1526.                     }
  1527.                 }
  1528.                 $zip->close();
  1529.                 $success true;
  1530.             }
  1531.         }
  1532.         return $this->adminJson([
  1533.             'success' => $success
  1534.         ]);
  1535.     }
  1536.     /**
  1537.      * @Route("/download-as-zip")
  1538.      *
  1539.      * @param Request $request
  1540.      *
  1541.      * @return BinaryFileResponse
  1542.      * Download all assets contained in the folder with parameter id as ZIP file.
  1543.      * The suggested filename is either [folder name].zip or assets.zip for the root folder.
  1544.      */
  1545.     public function downloadAsZipAction(Request $request)
  1546.     {
  1547.         $asset Asset::getById($request->get('id'));
  1548.         $zipFile PIMCORE_SYSTEM_TEMP_DIRECTORY '/download-zip-' $request->get('jobId') . '.zip';
  1549.         $suggestedFilename $asset->getFilename();
  1550.         if (empty($suggestedFilename)) {
  1551.             $suggestedFilename 'assets';
  1552.         }
  1553.         $response = new BinaryFileResponse($zipFile);
  1554.         $response->headers->set('Content-Type''application/zip');
  1555.         $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT$suggestedFilename '.zip');
  1556.         $response->deleteFileAfterSend(true);
  1557.         return $response;
  1558.     }
  1559.     /**
  1560.      * @Route("/import-zip")
  1561.      *
  1562.      * @param Request $request
  1563.      *
  1564.      * @return Response
  1565.      */
  1566.     public function importZipAction(Request $request)
  1567.     {
  1568.         $jobId uniqid();
  1569.         $filesPerJob 5;
  1570.         $jobs = [];
  1571.         $asset Asset::getById($request->get('parentId'));
  1572.         if (!$asset->isAllowed('create')) {
  1573.             throw new \Exception('not allowed to create');
  1574.         }
  1575.         $zipFile PIMCORE_SYSTEM_TEMP_DIRECTORY '/' $jobId '.zip';
  1576.         copy($_FILES['Filedata']['tmp_name'], $zipFile);
  1577.         $zip = new \ZipArchive;
  1578.         if ($zip->open($zipFile) === true) {
  1579.             $jobAmount ceil($zip->numFiles $filesPerJob);
  1580.             for ($i 0$i $jobAmount$i++) {
  1581.                 $jobs[] = [[
  1582.                     'url' => '/admin/asset/import-zip-files',
  1583.                     'params' => [
  1584.                         'parentId' => $asset->getId(),
  1585.                         'offset' => $i $filesPerJob,
  1586.                         'limit' => $filesPerJob,
  1587.                         'jobId' => $jobId,
  1588.                         'last' => (($i 1) >= $jobAmount) ? 'true' ''
  1589.                     ]
  1590.                 ]];
  1591.             }
  1592.             $zip->close();
  1593.         }
  1594.         // here we have to use this method and not the JSON action helper ($this->_helper->json()) because this will add
  1595.         // Content-Type: application/json which fires a download window in most browsers, because this is a normal POST
  1596.         // request and not XHR where the content-type doesn't matter
  1597.         $responseJson $this->encodeJson([
  1598.             'success' => true,
  1599.             'jobs' => $jobs,
  1600.             'jobId' => $jobId
  1601.         ]);
  1602.         return new Response($responseJson);
  1603.     }
  1604.     /**
  1605.      * @Route("/import-zip-files")
  1606.      *
  1607.      * @param Request $request
  1608.      *
  1609.      * @return JsonResponse
  1610.      */
  1611.     public function importZipFilesAction(Request $request)
  1612.     {
  1613.         $jobId $request->get('jobId');
  1614.         $limit = (int)$request->get('limit');
  1615.         $offset = (int)$request->get('offset');
  1616.         $importAsset Asset::getById($request->get('parentId'));
  1617.         $zipFile PIMCORE_SYSTEM_TEMP_DIRECTORY '/' $jobId '.zip';
  1618.         $tmpDir PIMCORE_SYSTEM_TEMP_DIRECTORY '/zip-import';
  1619.         if (!is_dir($tmpDir)) {
  1620.             File::mkdir($tmpDir0777true);
  1621.         }
  1622.         $zip = new \ZipArchive;
  1623.         if ($zip->open($zipFile) === true) {
  1624.             for ($i $offset$i < ($offset $limit); $i++) {
  1625.                 $path $zip->getNameIndex($i);
  1626.                 if ($path !== false) {
  1627.                     if ($zip->extractTo($tmpDir '/'$path)) {
  1628.                         $tmpFile $tmpDir '/' preg_replace('@^/@'''$path);
  1629.                         $filename Element\Service::getValidKey(basename($path), 'asset');
  1630.                         $relativePath '';
  1631.                         if (dirname($path) != '.') {
  1632.                             $relativePath dirname($path);
  1633.                         }
  1634.                         $parentPath $importAsset->getRealFullPath() . '/' preg_replace('@^/@'''$relativePath);
  1635.                         $parent Asset\Service::createFolderByPath($parentPath);
  1636.                         // check for duplicate filename
  1637.                         $filename $this->getSafeFilename($parent->getRealFullPath(), $filename);
  1638.                         if ($parent->isAllowed('create')) {
  1639.                             $asset Asset::create($parent->getId(), [
  1640.                                 'filename' => $filename,
  1641.                                 'sourcePath' => $tmpFile,
  1642.                                 'userOwner' => $this->getAdminUser()->getId(),
  1643.                                 'userModification' => $this->getAdminUser()->getId()
  1644.                             ]);
  1645.                             @unlink($tmpFile);
  1646.                         } else {
  1647.                             Logger::debug('prevented creating asset because of missing permissions');
  1648.                         }
  1649.                     }
  1650.                 }
  1651.             }
  1652.             $zip->close();
  1653.         }
  1654.         if ($request->get('last')) {
  1655.             unlink($zipFile);
  1656.         }
  1657.         return $this->adminJson([
  1658.             'success' => true
  1659.         ]);
  1660.     }
  1661.     /**
  1662.      * @Route("/import-server")
  1663.      *
  1664.      * @param Request $request
  1665.      *
  1666.      * @return JsonResponse
  1667.      */
  1668.     public function importServerAction(Request $request)
  1669.     {
  1670.         $success true;
  1671.         $filesPerJob 5;
  1672.         $jobs = [];
  1673.         $importDirectory str_replace('/fileexplorer'PIMCORE_PROJECT_ROOT$request->get('serverPath'));
  1674.         if (is_dir($importDirectory)) {
  1675.             $files rscandir($importDirectory '/');
  1676.             $count count($files);
  1677.             $jobFiles = [];
  1678.             for ($i 0$i $count$i++) {
  1679.                 if (is_dir($files[$i])) {
  1680.                     continue;
  1681.                 }
  1682.                 $jobFiles[] = preg_replace('@^' preg_quote($importDirectory'@') . '@'''$files[$i]);
  1683.                 if (count($jobFiles) >= $filesPerJob || $i >= ($count 1)) {
  1684.                     $jobs[] = [[
  1685.                         'url' => '/admin/asset/import-server-files',
  1686.                         'params' => [
  1687.                             'parentId' => $request->get('parentId'),
  1688.                             'serverPath' => $importDirectory,
  1689.                             'files' => implode('::'$jobFiles)
  1690.                         ]
  1691.                     ]];
  1692.                     $jobFiles = [];
  1693.                 }
  1694.             }
  1695.         }
  1696.         return $this->adminJson([
  1697.             'success' => $success,
  1698.             'jobs' => $jobs
  1699.         ]);
  1700.     }
  1701.     /**
  1702.      * @Route("/import-server-files")
  1703.      *
  1704.      * @param Request $request
  1705.      *
  1706.      * @return JsonResponse
  1707.      */
  1708.     public function importServerFilesAction(Request $request)
  1709.     {
  1710.         $assetFolder Asset::getById($request->get('parentId'));
  1711.         $serverPath $request->get('serverPath');
  1712.         $files explode('::'$request->get('files'));
  1713.         foreach ($files as $file) {
  1714.             $absolutePath $serverPath $file;
  1715.             if (is_file($absolutePath)) {
  1716.                 $relFolderPath str_replace('\\''/'dirname($file));
  1717.                 $folder Asset\Service::createFolderByPath($assetFolder->getRealFullPath() . $relFolderPath);
  1718.                 $filename basename($file);
  1719.                 // check for duplicate filename
  1720.                 $filename Element\Service::getValidKey($filename'asset');
  1721.                 $filename $this->getSafeFilename($folder->getRealFullPath(), $filename);
  1722.                 if ($assetFolder->isAllowed('create')) {
  1723.                     $asset Asset::create($folder->getId(), [
  1724.                         'filename' => $filename,
  1725.                         'sourcePath' => $absolutePath,
  1726.                         'userOwner' => $this->getAdminUser()->getId(),
  1727.                         'userModification' => $this->getAdminUser()->getId()
  1728.                     ]);
  1729.                 } else {
  1730.                     Logger::debug('prevented creating asset because of missing permissions ');
  1731.                 }
  1732.             }
  1733.         }
  1734.         return $this->adminJson([
  1735.             'success' => true
  1736.         ]);
  1737.     }
  1738.     /**
  1739.      * @Route("/import-url")
  1740.      *
  1741.      * @param Request $request
  1742.      *
  1743.      * @return JsonResponse
  1744.      *
  1745.      * @throws \Exception
  1746.      */
  1747.     public function importUrlAction(Request $request)
  1748.     {
  1749.         $success true;
  1750.         $data Tool::getHttpData($request->get('url'));
  1751.         $filename basename($request->get('url'));
  1752.         $parentId $request->get('id');
  1753.         $parentAsset Asset::getById(intval($parentId));
  1754.         $filename Element\Service::getValidKey($filename'asset');
  1755.         $filename $this->getSafeFilename($parentAsset->getRealFullPath(), $filename);
  1756.         if (empty($filename)) {
  1757.             throw new \Exception('The filename of the asset is empty');
  1758.         }
  1759.         // check for duplicate filename
  1760.         $filename $this->getSafeFilename($parentAsset->getRealFullPath(), $filename);
  1761.         if ($parentAsset->isAllowed('create')) {
  1762.             $asset Asset::create($parentId, [
  1763.                 'filename' => $filename,
  1764.                 'data' => $data,
  1765.                 'userOwner' => $this->getAdminUser()->getId(),
  1766.                 'userModification' => $this->getAdminUser()->getId()
  1767.             ]);
  1768.             $success true;
  1769.         } else {
  1770.             Logger::debug('prevented creating asset because of missing permissions');
  1771.         }
  1772.         return $this->adminJson(['success' => $success]);
  1773.     }
  1774.     /**
  1775.      * @Route("/clear-thumbnail")
  1776.      *
  1777.      * @param Request $request
  1778.      *
  1779.      * @return JsonResponse
  1780.      */
  1781.     public function clearThumbnailAction(Request $request)
  1782.     {
  1783.         $success false;
  1784.         if ($asset Asset::getById($request->get('id'))) {
  1785.             if (method_exists($asset'clearThumbnails')) {
  1786.                 if (!$asset->isAllowed('publish')) {
  1787.                     throw new \Exception('not allowed to publish');
  1788.                 }
  1789.                 $asset->clearThumbnails(true); // force clear
  1790.                 $asset->save();
  1791.                 $success true;
  1792.             }
  1793.         }
  1794.         return $this->adminJson(['success' => $success]);
  1795.     }
  1796.     /**
  1797.      * @Route("/grid-proxy")
  1798.      *
  1799.      * @param Request $request
  1800.      *
  1801.      * @return JsonResponse
  1802.      */
  1803.     public function gridProxyAction(Request $requestEventDispatcherInterface $eventDispatcher)
  1804.     {
  1805.         $allParams array_merge($request->request->all(), $request->query->all());
  1806.         $filterPrepareEvent = new GenericEvent($this, [
  1807.             'requestParams' => $allParams
  1808.         ]);
  1809.         $eventDispatcher->dispatch(AdminEvents::ASSET_LIST_BEFORE_FILTER_PREPARE$filterPrepareEvent);
  1810.         $allParams $filterPrepareEvent->getArgument('requestParams');
  1811.         if ($allParams['data']) {
  1812.             if ($allParams['xaction'] == 'update') {
  1813.                 //TODO probably not needed
  1814.             }
  1815.         } else {
  1816.             $db = \Pimcore\Db::get();
  1817.             // get list of objects
  1818.             $folder Asset::getById($allParams['folderId']);
  1819.             $start 0;
  1820.             $limit 20;
  1821.             $orderKey 'id';
  1822.             $order 'ASC';
  1823.             if ($allParams['limit']) {
  1824.                 $limit $allParams['limit'];
  1825.             }
  1826.             if ($allParams['start']) {
  1827.                 $start $allParams['start'];
  1828.             }
  1829.             $sortingSettings = \Pimcore\Bundle\AdminBundle\Helper\QueryParams::extractSortingSettings($allParams);
  1830.             if ($sortingSettings['orderKey']) {
  1831.                 $orderKey $sortingSettings['orderKey'];
  1832.                 if ($orderKey == 'fullpath') {
  1833.                     $orderKey = ['path''filename'];
  1834.                 }
  1835.                 $order $sortingSettings['order'];
  1836.             }
  1837.             $list = new Asset\Listing();
  1838.             $conditionFilters = [];
  1839.             if ($allParams['only_direct_children'] == 'true') {
  1840.                 $conditionFilters[] = 'parentId = ' $folder->getId();
  1841.             } else {
  1842.                 $conditionFilters[] = 'path LIKE ' . ($folder->getRealFullPath() == '/' "'/%'" $list->quote($folder->getRealFullPath() . '/%'));
  1843.             }
  1844.             $conditionFilters[] = "type != 'folder'";
  1845.             $filterJson $allParams['filter'];
  1846.             if ($filterJson) {
  1847.                 $filters $this->decodeJson($filterJson);
  1848.                 foreach ($filters as $filter) {
  1849.                     $operator '=';
  1850.                     $filterField $filter['property'];
  1851.                     $filterOperator $filter['operator'];
  1852.                     $filterType $filter['type'];
  1853.                     if ($filterType == 'string') {
  1854.                         $operator 'LIKE';
  1855.                     } elseif ($filterType == 'numeric') {
  1856.                         if ($filterOperator == 'lt') {
  1857.                             $operator '<';
  1858.                         } elseif ($filterOperator == 'gt') {
  1859.                             $operator '>';
  1860.                         } elseif ($filterOperator == 'eq') {
  1861.                             $operator '=';
  1862.                         }
  1863.                     } elseif ($filterType == 'date') {
  1864.                         if ($filterOperator == 'lt') {
  1865.                             $operator '<';
  1866.                         } elseif ($filterOperator == 'gt') {
  1867.                             $operator '>';
  1868.                         } elseif ($filterOperator == 'eq') {
  1869.                             $operator '=';
  1870.                         }
  1871.                         $filter['value'] = strtotime($filter['value']);
  1872.                     } elseif ($filterType == 'list') {
  1873.                         $operator '=';
  1874.                     } elseif ($filterType == 'boolean') {
  1875.                         $operator '=';
  1876.                         $filter['value'] = (int) $filter['value'];
  1877.                     }
  1878.                     // system field
  1879.                     $value $filter['value'];
  1880.                     if ($operator == 'LIKE') {
  1881.                         $value '%' $value '%';
  1882.                     }
  1883.                     $field '`' $filterField '` ';
  1884.                     if ($filterField == 'fullpath') {
  1885.                         $field 'CONCAT(path,filename)';
  1886.                     }
  1887.                     $conditionFilters[] =  $field $operator ' ' $db->quote($value);
  1888.                 }
  1889.             }
  1890.             if (!$this->getAdminUser()->isAdmin()) {
  1891.                 $userIds $this->getAdminUser()->getRoles();
  1892.                 $userIds[] = $this->getAdminUser()->getId();
  1893.                 $conditionFilters[] .= ' (
  1894.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(CONCAT(path, filename),cpath)=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1895.                                                     OR
  1896.                                                     (select list from users_workspaces_asset where userId in (' implode(','$userIds) . ') and LOCATE(cpath,CONCAT(path, filename))=1  ORDER BY LENGTH(cpath) DESC LIMIT 1)=1
  1897.                                                  )';
  1898.             }
  1899.             $condition implode(' AND '$conditionFilters);
  1900.             $list->setCondition($condition);
  1901.             $list->setLimit($limit);
  1902.             $list->setOffset($start);
  1903.             $list->setOrder($order);
  1904.             $list->setOrderKey($orderKey);
  1905.             $beforeListLoadEvent = new GenericEvent($this, [
  1906.                 'list' => $list,
  1907.                 'context' => $allParams
  1908.             ]);
  1909.             $eventDispatcher->dispatch(AdminEvents::ASSET_LIST_BEFORE_LIST_LOAD$beforeListLoadEvent);
  1910.             $list $beforeListLoadEvent->getArgument('list');
  1911.             $list->load();
  1912.             $assets = [];
  1913.             foreach ($list->getAssets() as $asset) {
  1914.                 /** @var $asset Asset */
  1915.                 $filename PIMCORE_ASSET_DIRECTORY '/' $asset->getRealFullPath();
  1916.                 $size = @filesize($filename);
  1917.                 // Like for treeGetChildsByIdAction, so we respect isAllowed method which can be extended (object DI) for custom permissions, so relying only users_workspaces_asset is insufficient and could lead security breach
  1918.                 if ($asset->isAllowed('list')) {
  1919.                     $assets[] = [
  1920.                         'id' => $asset->getid(),
  1921.                         'type' => $asset->getType(),
  1922.                         'fullpath' => $asset->getRealFullPath(),
  1923.                         'creationDate' => $asset->getCreationDate(),
  1924.                         'modificationDate' => $asset->getModificationDate(),
  1925.                         'size' => formatBytes($size),
  1926.                         'idPath' => $data['idPath'] = Element\Service::getIdPath($asset)
  1927.                     ];
  1928.                 }
  1929.             }
  1930.             $result = ['data' => $assets'success' => true'total' => $list->getTotalCount()];
  1931.             $afterListLoadEvent = new GenericEvent($this, [
  1932.                 'list' => $result,
  1933.                 'context' => $allParams
  1934.             ]);
  1935.             $eventDispatcher->dispatch(AdminEvents::ASSET_LIST_AFTER_LIST_LOAD$afterListLoadEvent);
  1936.             $result $afterListLoadEvent->getArgument('list');
  1937.             return $this->adminJson($result);
  1938.         }
  1939.     }
  1940.     /**
  1941.      * @Route("/get-text")
  1942.      *
  1943.      * @param Request $request
  1944.      *
  1945.      * @return JsonResponse
  1946.      */
  1947.     public function getTextAction(Request $request)
  1948.     {
  1949.         $asset Asset::getById($request->get('id'));
  1950.         if (!$asset->isAllowed('view')) {
  1951.             throw new \Exception('not allowed to view');
  1952.         }
  1953.         $page $request->get('page');
  1954.         if ($asset instanceof Asset\Document) {
  1955.             $text $asset->getText($page);
  1956.         }
  1957.         return $this->adminJson(['success' => 'true''text' => $text]);
  1958.     }
  1959.     /**
  1960.      * @param FilterControllerEvent $event
  1961.      */
  1962.     public function onKernelController(FilterControllerEvent $event)
  1963.     {
  1964.         $isMasterRequest $event->isMasterRequest();
  1965.         if (!$isMasterRequest) {
  1966.             return;
  1967.         }
  1968.         $this->checkActionPermission($event'assets', [
  1969.             'getImageThumbnailAction''getVideoThumbnailAction''getDocumentThumbnailAction'
  1970.         ]);
  1971.         $this->_assetService = new Asset\Service($this->getAdminUser());
  1972.     }
  1973.     /**
  1974.      * @param FilterResponseEvent $event
  1975.      */
  1976.     public function onKernelResponse(FilterResponseEvent $event)
  1977.     {
  1978.         // nothing to do
  1979.     }
  1980. }