vendor/pimcore/data-hub/src/Controller/ConfigController.php line 80

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 Commercial License (PCL)
  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 PCL
  13.  */
  14. namespace Pimcore\Bundle\DataHubBundle\Controller;
  15. use Pimcore\Bundle\DataHubBundle\ConfigEvents;
  16. use Pimcore\Bundle\DataHubBundle\Configuration;
  17. use Pimcore\Bundle\DataHubBundle\Event\AdminEvents;
  18. use Pimcore\Bundle\DataHubBundle\Event\Config\SpecialEntitiesEvent;
  19. use Pimcore\Bundle\DataHubBundle\GraphQL\Service;
  20. use Pimcore\Bundle\DataHubBundle\Model\SpecialEntitySetting;
  21. use Pimcore\Bundle\DataHubBundle\Service\ExportService;
  22. use Pimcore\Bundle\DataHubBundle\Service\ImportService;
  23. use Pimcore\Bundle\DataHubBundle\WorkspaceHelper;
  24. use Pimcore\Controller\Traits\JsonHelperTrait;
  25. use Pimcore\Model\Exception\ConfigWriteException;
  26. use Pimcore\Model\User;
  27. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  28. use Symfony\Component\EventDispatcher\GenericEvent;
  29. use Symfony\Component\HttpFoundation\JsonResponse;
  30. use Symfony\Component\HttpFoundation\Request;
  31. use Symfony\Component\HttpFoundation\Response;
  32. use Symfony\Component\Routing\Annotation\Route;
  33. use Symfony\Component\Routing\RouterInterface;
  34. /**
  35.  * @Route("/admin/pimcoredatahub/config")
  36.  */
  37. class ConfigController extends \Pimcore\Controller\UserAwareController
  38. {
  39.     use JsonHelperTrait;
  40.     public const CONFIG_NAME = 'plugin_datahub_config';
  41.     /**
  42.      * @param Configuration $configuration
  43.      *
  44.      * @return array
  45.      */
  46.     private function buildItem($configuration): array
  47.     {
  48.         $type = $configuration->getType() ?: 'graphql';
  49.         $name = $configuration->getName();
  50.         return [
  51.             'id' => $name,
  52.             'text' => htmlspecialchars($name),
  53.             'type' => 'config',
  54.             'iconCls' => 'plugin_pimcore_datahub_icon_' . $type,
  55.             'expandable' => false,
  56.             'leaf' => true,
  57.             'adapter' => $type,
  58.             'writeable' => $configuration->isWriteable(),
  59.             'permissions' => [
  60.                 'delete' => $configuration->isAllowed('delete'),
  61.                 'update' => $configuration->isAllowed('update')
  62.             ]
  63.         ];
  64.     }
  65.     /**
  66.      * @Route("/list")
  67.      *
  68.      * @param Request $request
  69.      *
  70.      * @return JsonResponse
  71.      */
  72.     public function listAction(Request $request): JsonResponse
  73.     {
  74.         // check permissions
  75.         $this->checkPermission(self::CONFIG_NAME);
  76.         $list = Configuration::getList();
  77.         $event = new GenericEvent($this);
  78.         $event->setArgument('list', $list);
  79.         \Pimcore::getEventDispatcher()->dispatch($event, AdminEvents::CONFIGURATION_LIST);
  80.         $list = $event->getArgument('list');
  81.         $tree = [];
  82.         $groups = [];
  83.         /** @var Configuration $item */
  84.         foreach ($list as $item) {
  85.             if ($item->isAllowed('read')) {
  86.                 if ($item->getGroup()) {
  87.                     if (empty($groups[$item->getGroup()])) {
  88.                         $groups[$item->getGroup()] = [
  89.                             'id' => 'group_' . $item->getName(),
  90.                             'text' => htmlspecialchars($item->getGroup()),
  91.                             'expandable' => true,
  92.                             'leaf' => false,
  93.                             'allowChildren' => true,
  94.                             'iconCls' => 'pimcore_icon_folder',
  95.                             'group' => $item->getGroup(),
  96.                             'children' => []
  97.                         ];
  98.                     }
  99.                     $groups[$item->getGroup()]['children'][] = $this->buildItem($item);
  100.                 } else {
  101.                     $tree[] = $this->buildItem($item);
  102.                 }
  103.             }
  104.         }
  105.         foreach ($groups as $group) {
  106.             $tree[] = $group;
  107.         }
  108.         return $this->json($tree);
  109.     }
  110.     /**
  111.      * @Route("/delete")
  112.      *
  113.      * @param Request $request
  114.      *
  115.      * @return JsonResponse|null
  116.      *
  117.      * @throws ConfigWriteException
  118.      */
  119.     public function deleteAction(Request $request): ?JsonResponse
  120.     {
  121.         $this->checkPermission(self::CONFIG_NAME);
  122.         if ((new Configuration(null, null))->isWriteable() === false) {
  123.             throw new ConfigWriteException();
  124.         }
  125.         try {
  126.             $name = $request->get('name');
  127.             $config = Configuration::getByName($name);
  128.             if (!$config instanceof Configuration) {
  129.                 throw new \Exception('Name does not exist.');
  130.             }
  131.             if ($config->isWriteable() === false) {
  132.                 throw new ConfigWriteException();
  133.             }
  134.             if (!$config->isAllowed('delete')) {
  135.                 throw $this->createAccessDeniedHttpException();
  136.             }
  137.             WorkspaceHelper::deleteConfiguration($config);
  138.             $config->delete();
  139.             return $this->json(['success' => true]);
  140.         } catch (\Exception $e) {
  141.             return $this->json(['success' => false, 'message' => $e->getMessage()]);
  142.         }
  143.     }
  144.     /**
  145.      * @Route("/add")
  146.      *
  147.      * @param Request $request
  148.      *
  149.      * @return JsonResponse|null
  150.      *
  151.      * @throws ConfigWriteException
  152.      */
  153.     public function addAction(Request $request): ?JsonResponse
  154.     {
  155.         $this->checkPermission(self::CONFIG_NAME);
  156.         if ((new Configuration(null, null))->isWriteable() === false) {
  157.             throw new ConfigWriteException();
  158.         }
  159.         try {
  160.             $path = $request->get('path');
  161.             $name = $request->get('name');
  162.             $type = $request->get('type');
  163.             $this->checkPermissionsHasOneOf(['plugin_datahub_admin', 'plugin_datahub_adapter_' . $type]);
  164.             $config = Configuration::getByName($name);
  165.             if ($config instanceof Configuration) {
  166.                 throw new \Exception('Name already exists.');
  167.             }
  168.             $config = new Configuration($type, $path, $name);
  169.             $config->save();
  170.             return $this->json(['success' => true, 'name' => $name]);
  171.         } catch (\Exception $e) {
  172.             return $this->json(['success' => false, 'message' => $e->getMessage()]);
  173.         }
  174.     }
  175.     /**
  176.      * @Route("/clone")
  177.      *
  178.      * @param Request $request
  179.      *
  180.      * @return JsonResponse|null
  181.      */
  182.     public function cloneAction(Request $request): ?JsonResponse
  183.     {
  184.         $this->checkPermission(self::CONFIG_NAME);
  185.         try {
  186.             $name = $request->get('name');
  187.             $config = Configuration::getByName($name);
  188.             if ($config instanceof Configuration) {
  189.                 throw new \Exception('Name already exists.');
  190.             }
  191.             $originalName = $request->get('originalName');
  192.             $originalConfig = Configuration::getByName($originalName);
  193.             if (!$originalConfig) {
  194.                 throw new \Exception('Configuration not found');
  195.             }
  196.             if ($originalConfig->isWriteable() === false) {
  197.                 throw new ConfigWriteException();
  198.             }
  199.             if (!$originalConfig->isAllowed('update')) {
  200.                 throw $this->createAccessDeniedHttpException();
  201.             }
  202.             $this->checkPermissionsHasOneOf(['plugin_datahub_admin', 'plugin_datahub_adapter_' . $originalConfig->getType()]);
  203.             $originalConfig->setName($name);
  204.             $originalConfig->save();
  205.             return $this->json(['success' => true, 'name' => $name]);
  206.         } catch (\Exception $e) {
  207.             return $this->json(['success' => false, 'message' => $e->getMessage()]);
  208.         }
  209.     }
  210.     /**
  211.      * @Route("/get")
  212.      *
  213.      * @param Request $request
  214.      * @param Service $graphQlService
  215.      * @param EventDispatcherInterface $eventDispatcher
  216.      *
  217.      * @return JsonResponse
  218.      *
  219.      * @throws \Exception
  220.      */
  221.     public function getAction(Request $request, Service $graphQlService, EventDispatcherInterface $eventDispatcher): JsonResponse
  222.     {
  223.         $this->checkPermission(self::CONFIG_NAME);
  224.         $name = $request->get('name');
  225.         $configuration = Configuration::getByName($name);
  226.         if (!$configuration) {
  227.             throw new \Exception('Datahub configuration ' . $name . ' does not exist.');
  228.         }
  229.         if (!$configuration->isAllowed('read')) {
  230.             throw $this->createAccessDeniedHttpException();
  231.         }
  232.         $config = $configuration->getConfiguration();
  233.         $config['schema']['queryEntities'] = array_values($config['schema']['queryEntities'] ?? []);
  234.         $config['schema']['mutationEntities'] = array_values($config['schema']['mutationEntities'] ?? []);
  235.         $config['schema']['specialEntities'] = $config['schema']['specialEntities'] ?? [];
  236.         if (!$config['schema']['specialEntities']) {
  237.             $config['schema']['specialEntities'] = [];
  238.         }
  239.         $coreSettings = [
  240.             new SpecialEntitySetting(
  241.                 'document',
  242.                 true,
  243.                 true,
  244.                 true,
  245.                 true,
  246.                 $config['schema']['specialEntities']['document']['read'] ?? false,
  247.                 $config['schema']['specialEntities']['document']['create'] ?? false,
  248.                 $config['schema']['specialEntities']['document']['update'] ?? false,
  249.                 $config['schema']['specialEntities']['document']['delete'] ?? false
  250.             ),
  251.             new SpecialEntitySetting(
  252.                 'document_folder',
  253.                 true,
  254.                 false,
  255.                 false,
  256.                 true,
  257.                 $config['schema']['specialEntities']['document_folder']['read'] ?? false,
  258.                 $config['schema']['specialEntities']['document_folder']['create'] ?? false,
  259.                 $config['schema']['specialEntities']['document_folder']['update'] ?? false,
  260.                 $config['schema']['specialEntities']['document_folder']['delete'] ?? false
  261.             ),
  262.             new SpecialEntitySetting(
  263.                 'asset',
  264.                 true,
  265.                 true,
  266.                 true,
  267.                 true,
  268.                 $config['schema']['specialEntities']['asset']['read'] ?? false,
  269.                 $config['schema']['specialEntities']['asset']['create'] ?? false,
  270.                 $config['schema']['specialEntities']['asset']['update'] ?? false,
  271.                 $config['schema']['specialEntities']['asset']['delete'] ?? false
  272.             ),
  273.             new SpecialEntitySetting(
  274.                 'asset_folder',
  275.                 true,
  276.                 true,
  277.                 true,
  278.                 true,
  279.                 $config['schema']['specialEntities']['asset_folder']['read'] ?? false,
  280.                 $config['schema']['specialEntities']['asset_folder']['create'] ?? false,
  281.                 $config['schema']['specialEntities']['asset_folder']['update'] ?? false,
  282.                 $config['schema']['specialEntities']['asset_folder']['delete'] ?? false
  283.             ),
  284.             new SpecialEntitySetting(
  285.                 'asset_listing',
  286.                 true,
  287.                 true,
  288.                 true,
  289.                 true,
  290.                 $config['schema']['specialEntities']['asset_listing']['read'] ?? false,
  291.                 $config['schema']['specialEntities']['asset_listing']['create'] ?? false,
  292.                 $config['schema']['specialEntities']['asset_listing']['update'] ?? false,
  293.                 $config['schema']['specialEntities']['asset_listing']['delete'] ?? false
  294.             ),
  295.             new SpecialEntitySetting(
  296.                 'object_folder',
  297.                 true,
  298.                 true,
  299.                 true,
  300.                 true,
  301.                 $config['schema']['specialEntities']['object_folder']['read'] ?? false,
  302.                 $config['schema']['specialEntities']['object_folder']['create'] ?? false,
  303.                 $config['schema']['specialEntities']['object_folder']['update'] ?? false,
  304.                 $config['schema']['specialEntities']['object_folder']['delete'] ?? false
  305.             ),
  306.             new SpecialEntitySetting(
  307.                 'translation',
  308.                 true,
  309.                 false,
  310.                 false,
  311.                 false,
  312.                 $config['schema']['specialEntities']['translation_listing']['read'] ?? false,
  313.                 $config['schema']['specialEntities']['translation_listing']['create'] ?? false,
  314.                 $config['schema']['specialEntities']['translation_listing']['update'] ?? false,
  315.                 $config['schema']['specialEntities']['translation_listing']['delete'] ?? false
  316.             ),
  317.             new SpecialEntitySetting(
  318.                 'translation_listing',
  319.                 true,
  320.                 false,
  321.                 false,
  322.                 false,
  323.                 $config['schema']['specialEntities']['translation_listing']['read'] ?? false,
  324.                 $config['schema']['specialEntities']['translation_listing']['create'] ?? false,
  325.                 $config['schema']['specialEntities']['translation_listing']['update'] ?? false,
  326.                 $config['schema']['specialEntities']['translation_listing']['delete'] ?? false
  327.             )
  328.         ];
  329.         $specialSettingsEvent = new SpecialEntitiesEvent($coreSettings, $config);
  330.         $eventDispatcher->dispatch($specialSettingsEvent, ConfigEvents::SPECIAL_ENTITIES);
  331.         $finalSettings = [];
  332.         foreach ($specialSettingsEvent->getSpecialSettings() as $item) {
  333.             $finalSettings[$item->getName()] = $item;
  334.         }
  335.         $config['schema']['specialEntities'] = $specialSettingsEvent->getSpecialSettings();
  336.         //TODO we probably need this stuff only for graphql stuff
  337.         $supportedQueryDataTypes = $graphQlService->getSupportedDataObjectQueryDataTypes();
  338.         $supportedMutationDataTypes = $graphQlService->getSupportedDataObjectMutationDataTypes();
  339.         return new JsonResponse(
  340.             [
  341.                 'name' => $configuration->getName(),
  342.                 'configuration' => $config,
  343.                 'userPermissions' => [
  344.                     'update' => $configuration->isAllowed('update'),
  345.                     'delete' => $configuration->isAllowed('delete')
  346.                 ],
  347.                 'supportedGraphQLQueryDataTypes' => $supportedQueryDataTypes,
  348.                 'supportedGraphQLMutationDataTypes' => $supportedMutationDataTypes,
  349.                 'modificationDate' => $config['general']['modificationDate']
  350.             ]
  351.         );
  352.     }
  353.     /**
  354.      * @Route("/save")
  355.      *
  356.      * @param Request $request
  357.      *
  358.      * @return JsonResponse|null
  359.      */
  360.     public function saveAction(Request $request): ?JsonResponse
  361.     {
  362.         $this->checkPermission(self::CONFIG_NAME);
  363.         try {
  364.             $data = $request->get('data');
  365.             $modificationDate = $request->get('modificationDate', 0);
  366.             $dataDecoded = json_decode($data, true);
  367.             $name = $dataDecoded['general']['name'];
  368.             $config = Configuration::getByName($name);
  369.             if ($config->isWriteable() === false) {
  370.                 throw new ConfigWriteException();
  371.             }
  372.             if (!$config->isAllowed('update')) {
  373.                 throw $this->createAccessDeniedHttpException();
  374.             }
  375.             $configuration = $config->getConfiguration();
  376.             $savedModificationDate = 0;
  377.             if ($configuration && isset($configuration['general']['modificationDate'])) {
  378.                 $savedModificationDate = $configuration['general']['modificationDate'];
  379.             }
  380.             if ($modificationDate < $savedModificationDate) {
  381.                 throw new \Exception('The configuration was modified during editing, please reload the configuration and make your changes again');
  382.             }
  383.             $dataDecoded['general']['modificationDate'] = time();
  384.             $keys = ['queryEntities', 'mutationEntities'];
  385.             foreach ($keys as $key) {
  386.                 $transformedEntities = [];
  387.                 if ($dataDecoded['schema'][$key]) {
  388.                     foreach ($dataDecoded['schema'][$key] as $entity) {
  389.                         $transformedEntities[$entity['id']] = $entity;
  390.                     }
  391.                 }
  392.                 $dataDecoded['schema'][$key] = $transformedEntities;
  393.             }
  394.             if ($dataDecoded['schema']['specialEntities']) {
  395.                 $transformedEntities = [];
  396.                 foreach ($dataDecoded['schema']['specialEntities'] as $entity) {
  397.                     $transformedEntities[$entity['name']] = [
  398.                         'read' => $entity['readAllowed'],
  399.                         'create' => $entity['createAllowed'],
  400.                         'update' => $entity['updateAllowed'],
  401.                         'delete' => $entity['deleteAllowed'],
  402.                     ];
  403.                     $dataDecoded['schema']['specialEntities'] = $transformedEntities;
  404.                 }
  405.             }
  406.             if (isset($dataDecoded['security'])) {
  407.                 $dataDecoded['security']['apikey'] = explode("\n", trim($dataDecoded['security']['apikey'] ?? '', "\n"));
  408.             }
  409.             $config->setConfiguration($dataDecoded);
  410.             if ($config->isAllowed('read') && $config->isAllowed('update')) {
  411.                 $config->save();
  412.                 return $this->json(['success' => true, 'modificationDate' => $dataDecoded['general']['modificationDate']]);
  413.             } else {
  414.                 return $this->json(['success' => false, 'permissionError' => true]);
  415.             }
  416.         } catch (\Exception $e) {
  417.             return $this->json(['success' => false, 'message' => $e->getMessage()]);
  418.         }
  419.     }
  420.     /**
  421.      * @Route("/get-explorer-url")
  422.      *
  423.      * @param RouterInterface $routingService
  424.      * @param Request $request
  425.      *
  426.      * @return JsonResponse|null
  427.      *
  428.      * @throws \Exception
  429.      */
  430.     public function getExplorerUrlAction(RouterInterface $routingService, Request $request): ?JsonResponse
  431.     {
  432.         $name = $request->get('name');
  433.         $url = $routingService->generate('admin_pimcoredatahub_config', ['clientname' => $name]);
  434.         if ($url) {
  435.             return $this->json(['explorerUrl' => $url]);
  436.         } else {
  437.             throw new \Exception('unable to resolve');
  438.         }
  439.     }
  440.     /**
  441.      * @Route("/thumbnail-tree")
  442.      *
  443.      * @param Request $request
  444.      *
  445.      * @return JsonResponse
  446.      */
  447.     public function thumbnailTreeAction(Request $request)
  448.     {
  449.         $this->checkPermission('thumbnails');
  450.         $thumbnails = [];
  451.         $list = new \Pimcore\Model\Asset\Image\Thumbnail\Config\Listing();
  452.         $items = $list->load();
  453.         foreach ($items as $item) {
  454.             $thumbnails[] = [
  455.                 'id' => $item->getName(),
  456.                 'text' => $item->getName()
  457.             ];
  458.         }
  459.         return $this->jsonResponse($thumbnails);
  460.     }
  461.     /**
  462.      * @Route("/permissions-users", methods={"GET"})
  463.      *
  464.      * @param Request $request
  465.      *
  466.      * @return JsonResponse
  467.      */
  468.     public function getPermissionUsersAction(Request $request)
  469.     {
  470.         $type = $request->get('type', 'user');
  471.         $list = new User\Listing();
  472.         if ($type === 'role') {
  473.             $list = new User\Role\Listing();
  474.         }
  475.         $list->setCondition('type = ? AND id != 1', [$type]);
  476.         $list->setOrder('ASC');
  477.         $list->setOrderKey('name');
  478.         $users = [];
  479.         foreach ($list->getItems() as $user) {
  480.             if ($user->getId() && $user->getName() != 'system') {
  481.                 $users[] = [
  482.                     'id' => $user->getId(),
  483.                     'text' => $user->getName(),
  484.                     'elementType' => 'user',
  485.                 ];
  486.             }
  487.         }
  488.         return $this->jsonResponse($users);
  489.     }
  490.     /**
  491.      * @Route("/export", methods={"GET"})
  492.      *
  493.      * @param Request $request
  494.      */
  495.     public function exportConfiguration(Request $request, ExportService $exportService): Response
  496.     {
  497.         $this->checkPermission(self::CONFIG_NAME);
  498.         $name = $request->get('name');
  499.         $configuration = Configuration::getByName($name);
  500.         if (!$configuration) {
  501.             throw new \Exception('Datahub configuration ' . $name . ' does not exist.');
  502.         }
  503.         if (!$configuration->isAllowed('read')) {
  504.             throw $this->createAccessDeniedHttpException();
  505.         }
  506.         $json = $exportService->exportConfigurationJson($configuration);
  507.         $filename = sprintf(
  508.             'datahub_%s_%s_export.json',
  509.             $configuration->getType(),
  510.             $configuration->getName()
  511.         );
  512.         $response = new Response($json);
  513.         $response->headers->set('Content-type', 'application/json');
  514.         $response->headers->set('Content-Disposition', 'attachment; filename="'.$filename.'"');
  515.         return $response;
  516.     }
  517.     /**
  518.      * @Route("/import", methods={"POST"})
  519.      *
  520.      * @param Request $request
  521.      * @param ImportService $importService
  522.      */
  523.     public function importConfiguration(Request $request, ImportService $importService): JsonResponse
  524.     {
  525.         $this->checkPermission(self::CONFIG_NAME);
  526.         $json = file_get_contents($_FILES['Filedata']['tmp_name']);
  527.         $configuration = $importService->importConfigurationJson($json);
  528.         $response = $this->jsonResponse([
  529.             'success' => true,
  530.             'type' => $configuration->getType(),
  531.             'name' => $configuration->getName()
  532.         ]);
  533.         // set content-type to text/html, otherwise (when application/json is sent) chrome will complain in
  534.         // Ext.form.Action.Submit and mark the submission as failed
  535.         $response->headers->set('Content-Type', 'text/html');
  536.         return $response;
  537.     }
  538. }