vendor/pimcore/pimcore/bundles/AdminBundle/Controller/Admin/AssetController.php line 1274

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