vendor/shopware/core/Framework/Store/Api/StoreController.php line 172

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core\Framework\Store\Api;
  3. use GuzzleHttp\Exception\ClientException;
  4. use GuzzleHttp\Exception\ConnectException;
  5. use Shopware\Core\Framework\Api\Context\AdminApiSource;
  6. use Shopware\Core\Framework\Api\Context\Exception\InvalidContextSourceException;
  7. use Shopware\Core\Framework\Api\Context\Exception\InvalidContextSourceUserException;
  8. use Shopware\Core\Framework\Context;
  9. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  12. use Shopware\Core\Framework\Feature;
  13. use Shopware\Core\Framework\Log\Package;
  14. use Shopware\Core\Framework\Plugin\PluginEntity;
  15. use Shopware\Core\Framework\Plugin\PluginManagementService;
  16. use Shopware\Core\Framework\Routing\Annotation\Since;
  17. use Shopware\Core\Framework\Store\Exception\CanNotDownloadPluginManagedByComposerException;
  18. use Shopware\Core\Framework\Store\Exception\StoreApiException;
  19. use Shopware\Core\Framework\Store\Exception\StoreInvalidCredentialsException;
  20. use Shopware\Core\Framework\Store\Exception\StoreNotAvailableException;
  21. use Shopware\Core\Framework\Store\Exception\StoreTokenMissingException;
  22. use Shopware\Core\Framework\Store\Services\AbstractExtensionDataProvider;
  23. use Shopware\Core\Framework\Store\Services\StoreClient;
  24. use Shopware\Core\Framework\Validation\DataBag\QueryDataBag;
  25. use Shopware\Core\System\User\UserEntity;
  26. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  27. use Symfony\Component\HttpFoundation\JsonResponse;
  28. use Symfony\Component\HttpFoundation\Request;
  29. use Symfony\Component\HttpFoundation\Response;
  30. use Symfony\Component\Routing\Annotation\Route;
  31. /**
  32.  * @internal
  33.  * @Route(defaults={"_routeScope"={"api"}})
  34.  */
  35. #[Package('merchant-services')]
  36. class StoreController extends AbstractController
  37. {
  38.     private StoreClient $storeClient;
  39.     private EntityRepositoryInterface $pluginRepo;
  40.     private PluginManagementService $pluginManagementService;
  41.     private AbstractExtensionDataProvider $extensionDataProvider;
  42.     private EntityRepositoryInterface $userRepository;
  43.     public function __construct(
  44.         StoreClient $storeClient,
  45.         EntityRepositoryInterface $pluginRepo,
  46.         PluginManagementService $pluginManagementService,
  47.         EntityRepositoryInterface $userRepository,
  48.         AbstractExtensionDataProvider $extensionDataProvider
  49.     ) {
  50.         $this->storeClient $storeClient;
  51.         $this->pluginRepo $pluginRepo;
  52.         $this->pluginManagementService $pluginManagementService;
  53.         $this->userRepository $userRepository;
  54.         $this->extensionDataProvider $extensionDataProvider;
  55.     }
  56.     /**
  57.      * @deprecated tag:v6.5.0 - Will be removed without replacement
  58.      *
  59.      * @Since("6.0.0.0")
  60.      * @Route("/api/_action/store/ping", name="api.custom.store.ping", methods={"GET"})
  61.      */
  62.     public function pingStoreAPI(): Response
  63.     {
  64.         Feature::triggerDeprecationOrThrow(
  65.             'v6.5.0.0',
  66.             'Route "api.custom.store.ping" is deprecated and will be removed without replacement.'
  67.         );
  68.         try {
  69.             $this->storeClient->ping();
  70.         } catch (ClientException ConnectException $exception) {
  71.             throw new StoreNotAvailableException();
  72.         }
  73.         return new Response();
  74.     }
  75.     /**
  76.      * @Since("6.0.0.0")
  77.      * @Route("/api/_action/store/login", name="api.custom.store.login", methods={"POST"})
  78.      */
  79.     public function login(Request $requestContext $context): JsonResponse
  80.     {
  81.         $shopwareId $request->request->get('shopwareId');
  82.         $password $request->request->get('password');
  83.         if (!\is_string($shopwareId) || !\is_string($password)) {
  84.             throw new StoreInvalidCredentialsException();
  85.         }
  86.         try {
  87.             $this->storeClient->loginWithShopwareId($shopwareId$password$context);
  88.         } catch (ClientException $exception) {
  89.             throw new StoreApiException($exception);
  90.         }
  91.         return new JsonResponse();
  92.     }
  93.     /**
  94.      * @Since("6.0.0.0")
  95.      * @Route("/api/_action/store/checklogin", name="api.custom.store.checklogin", methods={"POST"})
  96.      */
  97.     public function checkLogin(Context $context): Response
  98.     {
  99.         try {
  100.             // Throws StoreTokenMissingException if no token is present
  101.             $this->getUserStoreToken($context);
  102.             $userInfo $this->storeClient->userInfo($context);
  103.             return new JsonResponse([
  104.                 'userInfo' => $userInfo,
  105.             ]);
  106.         } catch (StoreTokenMissingException|ClientException $exception) {
  107.             return new JsonResponse([
  108.                 'userInfo' => null,
  109.             ]);
  110.         }
  111.     }
  112.     /**
  113.      * @Since("6.0.0.0")
  114.      * @Route("/api/_action/store/logout", name="api.custom.store.logout", methods={"POST"})
  115.      */
  116.     public function logout(Context $context): Response
  117.     {
  118.         $context->scope(Context::SYSTEM_SCOPE, function ($context): void {
  119.             $this->userRepository->update([['id' => $context->getSource()->getUserId(), 'storeToken' => null]], $context);
  120.         });
  121.         return new Response();
  122.     }
  123.     /**
  124.      * @deprecated tag:v6.5.0 Unused method will be removed
  125.      * @Since("6.0.0.0")
  126.      * @Route("/api/_action/store/licenses", name="api.custom.store.licenses", methods={"GET"})
  127.      */
  128.     public function getLicenseList(Context $context): JsonResponse
  129.     {
  130.         Feature::triggerDeprecationOrThrow(
  131.             'v6.5.0.0',
  132.             Feature::deprecatedMethodMessage(__CLASS____METHOD__'v6.5.0.0')
  133.         );
  134.         try {
  135.             $licenseList $this->storeClient->getLicenseList($context);
  136.         } catch (ClientException $exception) {
  137.             throw new StoreApiException($exception);
  138.         }
  139.         return new JsonResponse([
  140.             'items' => $licenseList,
  141.             'total' => \count($licenseList),
  142.         ]);
  143.     }
  144.     /**
  145.      * @Since("6.0.0.0")
  146.      * @Route("/api/_action/store/updates", name="api.custom.store.updates", methods={"GET"})
  147.      */
  148.     public function getUpdateList(Context $context): JsonResponse
  149.     {
  150.         $extensions $this->extensionDataProvider->getInstalledExtensions($contextfalse);
  151.         try {
  152.             $updatesList $this->storeClient->getExtensionUpdateList($extensions$context);
  153.         } catch (ClientException $exception) {
  154.             throw new StoreApiException($exception);
  155.         }
  156.         return new JsonResponse([
  157.             'items' => $updatesList,
  158.             'total' => \count($updatesList),
  159.         ]);
  160.     }
  161.     /**
  162.      * @deprecated tag:v6.5.0 - Will be removed, use ExtensionStoreActionsController::downloadExtension() instead
  163.      * @Since("6.0.0.0")
  164.      * @Route("/api/_action/store/download", name="api.custom.store.download", methods={"GET"})
  165.      */
  166.     public function downloadPlugin(QueryDataBag $queryDataBagContext $context): JsonResponse
  167.     {
  168.         Feature::triggerDeprecationOrThrow(
  169.             'v6.5.0.0',
  170.             Feature::deprecatedMethodMessage(__CLASS____METHOD__'v6.5.0.0''ExtensionStoreActionsController::downloadExtension()')
  171.         );
  172.         $pluginName = (string) $queryDataBag->get('pluginName');
  173.         $criteria = new Criteria();
  174.         $criteria->addFilter(new EqualsFilter('plugin.name'$pluginName));
  175.         /** @var PluginEntity|null $plugin */
  176.         $plugin $this->pluginRepo->search($criteria$context)->first();
  177.         if ($plugin !== null && $plugin->getManagedByComposer()) {
  178.             throw new CanNotDownloadPluginManagedByComposerException('can not downloads plugins managed by composer from store api');
  179.         }
  180.         try {
  181.             $data $this->storeClient->getDownloadDataForPlugin($pluginName$context);
  182.         } catch (ClientException $exception) {
  183.             throw new StoreApiException($exception);
  184.         }
  185.         $this->pluginManagementService->downloadStorePlugin($data$context);
  186.         return new JsonResponse(nullResponse::HTTP_OK);
  187.     }
  188.     /**
  189.      * @Since("6.0.0.0")
  190.      * @Route("/api/_action/store/license-violations", name="api.custom.store.license-violations", methods={"POST"})
  191.      */
  192.     public function getLicenseViolations(Request $requestContext $context): JsonResponse
  193.     {
  194.         $extensions $this->extensionDataProvider->getInstalledExtensions($contextfalse);
  195.         $indexedExtensions = [];
  196.         foreach ($extensions as $extension) {
  197.             $name $extension->getName();
  198.             $indexedExtensions[$name] = [
  199.                 'name' => $name,
  200.                 'version' => $extension->getVersion(),
  201.                 'active' => $extension->getActive(),
  202.             ];
  203.         }
  204.         try {
  205.             $violations $this->storeClient->getLicenseViolations($context$indexedExtensions$request->getHost());
  206.         } catch (ClientException $exception) {
  207.             throw new StoreApiException($exception);
  208.         }
  209.         return new JsonResponse([
  210.             'items' => $violations,
  211.             'total' => \count($violations),
  212.         ]);
  213.     }
  214.     /**
  215.      * @Since("6.0.0.0")
  216.      * @Route("/api/_action/store/plugin/search", name="api.action.store.plugin.search", methods={"POST"})
  217.      */
  218.     public function searchPlugins(Request $requestContext $context): Response
  219.     {
  220.         $extensions $this->extensionDataProvider->getInstalledExtensions($contextfalse);
  221.         try {
  222.             $this->storeClient->checkForViolations($context$extensions$request->getHost());
  223.         } catch (\Exception $e) {
  224.         }
  225.         return new JsonResponse([
  226.             'total' => $extensions->count(),
  227.             'items' => $extensions,
  228.         ]);
  229.     }
  230.     protected function getUserStoreToken(Context $context): string
  231.     {
  232.         $contextSource $context->getSource();
  233.         if (!$contextSource instanceof AdminApiSource) {
  234.             throw new InvalidContextSourceException(AdminApiSource::class, \get_class($contextSource));
  235.         }
  236.         $userId $contextSource->getUserId();
  237.         if ($userId === null) {
  238.             throw new InvalidContextSourceUserException(\get_class($contextSource));
  239.         }
  240.         /** @var UserEntity|null $user */
  241.         $user $this->userRepository->search(new Criteria([$userId]), $context)->first();
  242.         if ($user === null) {
  243.             throw new StoreTokenMissingException();
  244.         }
  245.         $storeToken $user->getStoreToken();
  246.         if ($storeToken === null) {
  247.             throw new StoreTokenMissingException();
  248.         }
  249.         return $storeToken;
  250.     }
  251. }