From 7f220cd3912ed9bead187f0f7b0e876c0d7da947 Mon Sep 17 00:00:00 2001 From: Alex Zamponi <562324+alexz707@users.noreply.github.com> Date: Fri, 26 Jan 2024 10:16:47 +0100 Subject: [PATCH 01/11] Add Api Platform Bundle --- src/PimcoreStudioApiBundle.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PimcoreStudioApiBundle.php b/src/PimcoreStudioApiBundle.php index bb1ca3391..1d54351ab 100644 --- a/src/PimcoreStudioApiBundle.php +++ b/src/PimcoreStudioApiBundle.php @@ -13,14 +13,16 @@ namespace Pimcore\Bundle\StudioApiBundle; +use ApiPlatform\Symfony\Bundle\ApiPlatformBundle; use Pimcore\Bundle\EnterpriseSubscriptionToolsBundle\Bundle\EnterpriseBundleInterface; use Pimcore\Bundle\EnterpriseSubscriptionToolsBundle\PimcoreEnterpriseSubscriptionToolsBundle; use Pimcore\Extension\Bundle\AbstractPimcoreBundle; use Pimcore\Extension\Bundle\Installer\InstallerInterface; +use Pimcore\HttpKernel\Bundle\DependentBundleInterface; use Pimcore\HttpKernel\BundleCollection\BundleCollection; class PimcoreStudioApiBundle extends AbstractPimcoreBundle implements - EnterpriseBundleInterface + EnterpriseBundleInterface, DependentBundleInterface { private const ENTERPRISE_BUNDLE_LICENSE_ID = 'xLicensex'; @@ -50,6 +52,7 @@ public function getInstaller(): ?InstallerInterface public static function registerDependentBundles(BundleCollection $collection): void { $collection->addBundle(new PimcoreEnterpriseSubscriptionToolsBundle()); + $collection->addBundle(new ApiPlatformBundle()); } public function getBundleLicenseId(): string From a821a5bf018385ac9c5d4642826236c728abae4f Mon Sep 17 00:00:00 2001 From: Alex Zamponi <562324+alexz707@users.noreply.github.com> Date: Fri, 26 Jan 2024 11:16:26 +0100 Subject: [PATCH 02/11] Add POC elements --- config/api_platform/resources/asset.yaml | 31 +++++ config/api_platform/resources/user.yaml | 19 +++ config/pimcore/routing.yaml | 4 + config/serialization/asset.yaml | 64 ++++++++++ config/serialization/user.yaml | 4 + config/services.yaml | 9 +- .../PimcoreStudioApiExtension.php | 69 +++++++++++ src/Dto/ResetPasswordRequest.php | 17 +++ src/Serializer/AssetNormalizer.php | 53 ++++++++ src/State/AssetProvider.php | 33 +++++ src/State/ResetPasswordProcessor.php | 114 ++++++++++++++++++ 11 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 config/api_platform/resources/asset.yaml create mode 100644 config/api_platform/resources/user.yaml create mode 100644 config/pimcore/routing.yaml create mode 100644 config/serialization/asset.yaml create mode 100644 config/serialization/user.yaml create mode 100644 src/DependencyInjection/PimcoreStudioApiExtension.php create mode 100644 src/Dto/ResetPasswordRequest.php create mode 100644 src/Serializer/AssetNormalizer.php create mode 100644 src/State/AssetProvider.php create mode 100644 src/State/ResetPasswordProcessor.php diff --git a/config/api_platform/resources/asset.yaml b/config/api_platform/resources/asset.yaml new file mode 100644 index 000000000..77d1edbd4 --- /dev/null +++ b/config/api_platform/resources/asset.yaml @@ -0,0 +1,31 @@ +resources: + Pimcore\Model\Asset: + provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider + normalizationContext: + groups: ['get'] + denormalizationContext: + groups: ['set'] + properties: + id: + identifier: true + parentId: ~ + type: ~ + data: ~ + fullPath: ~ + + Pimcore\Model\Asset\Image: + provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider + properties: + id: + identifier: true + normalizationContext: + groups: ['get'] + denormalizationContext: + groups: ['set'] + + Pimcore\Model\Asset\Image\Thumbnail: + provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider + normalizationContext: + groups: ['get'] + denormalizationContext: + groups: ['set'] diff --git a/config/api_platform/resources/user.yaml b/config/api_platform/resources/user.yaml new file mode 100644 index 000000000..a78d2be1e --- /dev/null +++ b/config/api_platform/resources/user.yaml @@ -0,0 +1,19 @@ +resources: + Pimcore\Model\User: + operations: + ApiPlatform\Metadata\Post: + status: 202 + processor: Pimcore\Bundle\StudioApiBundle\State\ResetPasswordProcessor + input: Pimcore\Bundle\StudioApiBundle\Dto\ResetPasswordRequest + output: false + uriTemplate: '/users/reset-password' +# ApiPlatform\Metadata\Get: +# controller: ApiPlatform\Action\NotFoundAction +# read: false +# output: false + + + normalizationContext: + groups: [ 'get' ] + denormalizationContext: + groups: [ 'set' ] \ No newline at end of file diff --git a/config/pimcore/routing.yaml b/config/pimcore/routing.yaml new file mode 100644 index 000000000..f6b934190 --- /dev/null +++ b/config/pimcore/routing.yaml @@ -0,0 +1,4 @@ +api_platform: + resource: . + type: api_platform + prefix: /api \ No newline at end of file diff --git a/config/serialization/asset.yaml b/config/serialization/asset.yaml new file mode 100644 index 000000000..8cf84b184 --- /dev/null +++ b/config/serialization/asset.yaml @@ -0,0 +1,64 @@ +Pimcore\Model\Asset: + attributes: + id: + groups: ['get', 'bla:read'] + parentId: + groups: ['get'] + type: + groups: ['get'] + filename: + groups: ['get'] + path: + groups: ['get'] + mimetype: + groups: ['get'] + creationDate: + groups: ['get'] + modificationDate: + groups: ['get'] + userOwner: + groups: ['get'] + userModification: + groups: ['get'] + properties: + groups: ['get'] + versions: + groups: ['get'] + metadata: + groups: ['get'] + locked: + groups: ['get'] + customSettings: + groups: ['get'] + hasMetaData: + groups: ['get'] + dependencies: + groups: ['get'] + scheduledTasks: + groups: ['get'] + versionCount: + groups: ['get'] + fullPath: + groups: ['get'] + +Pimcore\Model\Asset\Image: + attributes: + thumbnail: + groups: ['get'] + format: + groups: ['get'] + dimensions: + groups: ['get'] + width: + groups: [ 'get' ] + height: + groups: [ 'get' ] + +Pimcore\Model\Asset\Image\Thumbnail: + attributes: + path: + groups: ['get'] + imageTag: + groups: ['get'] + media: + groups: ['get'] \ No newline at end of file diff --git a/config/serialization/user.yaml b/config/serialization/user.yaml new file mode 100644 index 000000000..4346a156a --- /dev/null +++ b/config/serialization/user.yaml @@ -0,0 +1,4 @@ +Pimcore\Bundle\StudioApiBundle\Dto\ResetPasswordRequest: + attributes: + username: + groups: ['get', 'set'] \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index 8c98cca77..6561874e7 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -17,4 +17,11 @@ services: Pimcore\Bundle\StudioApiBundle\Controller\: resource: '../src/Controller' public: true - tags: [ 'controller.service_arguments' ] \ No newline at end of file + tags: [ 'controller.service_arguments' ] + + Pimcore\Bundle\StudioApiBundle\State\AssetProvider: ~ + Pimcore\Bundle\StudioApiBundle\State\ResetPasswordProcessor: ~ + + Pimcore\Bundle\StudioApiBundle\Serializer\AssetNormalizer: + tags: + - { name: 'serializer.normalizer' } \ No newline at end of file diff --git a/src/DependencyInjection/PimcoreStudioApiExtension.php b/src/DependencyInjection/PimcoreStudioApiExtension.php new file mode 100644 index 000000000..bf642d874 --- /dev/null +++ b/src/DependencyInjection/PimcoreStudioApiExtension.php @@ -0,0 +1,69 @@ +processConfiguration($configuration, $configs); + + // Load services and configuration + $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../../config')); + $loader->load('services.yaml'); + + // Set default serializer mapping if not provided in the app's config + if (!isset($config['serializer']['mapping']['paths'])) { + $config['serializer']['mapping']['paths'] = [__DIR__ . '/../../config/serialization']; + } + + // Pass the configuration to the custom normalizer + $container->setParameter('pimcore_studio_api.serializer.mapping.paths', $config['serializer']['mapping']['paths']); + } + + public function prepend(ContainerBuilder $container): void + { + $apiPlatformConfig = [ + "mapping"=>[ + "paths"=> [ + __DIR__ . '/../../config/api_platform/' + ] + ] + ]; + $container->prependExtensionConfig('api_platform', $apiPlatformConfig); + } +} \ No newline at end of file diff --git a/src/Dto/ResetPasswordRequest.php b/src/Dto/ResetPasswordRequest.php new file mode 100644 index 000000000..9683b67d4 --- /dev/null +++ b/src/Dto/ResetPasswordRequest.php @@ -0,0 +1,17 @@ +username; + } +} diff --git a/src/Serializer/AssetNormalizer.php b/src/Serializer/AssetNormalizer.php new file mode 100644 index 000000000..88c83b1cd --- /dev/null +++ b/src/Serializer/AssetNormalizer.php @@ -0,0 +1,53 @@ +normalizer->normalize($object, $format, $context); + + if (isset($data['data']) && $data['data']) { + $data['data'] = base64_encode($data['data']); + } + + if ($object instanceof Asset\Image) { + $data['thumbnail'] = $object->getThumbnail()->getPath(['frontend' => true]); + } + + return $data; + } + + public function supportsNormalization($data, $format = null, array $context = []): bool + { + if (isset($context[self::ALREADY_CALLED])) { + return false; + } + + return $data instanceof Asset; + } + + public function getSupportedTypes(?string $format): array + { + return [ + Asset::class => false, + ]; + } +} diff --git a/src/State/AssetProvider.php b/src/State/AssetProvider.php new file mode 100644 index 000000000..c27f1fec7 --- /dev/null +++ b/src/State/AssetProvider.php @@ -0,0 +1,33 @@ +setLimit(10); + + if (isset($context['filters']['page'])) { + $assetListing->setOffset(10 * $context['filters']['page']); + } + return $assetListing; + } + // getting a single asset by id + $test = Asset::getById($uriVariables['id']); + + //$tag = Tag::getTagsForElement('asset', $test->getId()); + return $test; + } +} diff --git a/src/State/ResetPasswordProcessor.php b/src/State/ResetPasswordProcessor.php new file mode 100644 index 000000000..192f3635b --- /dev/null +++ b/src/State/ResetPasswordProcessor.php @@ -0,0 +1,114 @@ +getUriTemplate() !== '/users/reset-password' || !$data instanceof ResetPasswordRequest) { + // wrong operation + throw new OperationNotFoundException(); + } + + $user = User::getByName($data->getUsername()); + if (!$user instanceof User) { + return $data; + } + + $currentRequest = $this->requestStack->getCurrentRequest(); + $limiter = $this->resetPasswordLimiter->create($currentRequest->getClientIp()); + + if (false === $limiter->consume(1)->isAccepted()) { + throw new InvalidValueException('Rate limit exceeded'); + } + + if (!$user->isActive()) { + throw new InvalidValueException('User is inactive'); + } + + if (!$user->getEmail()) { + throw new InvalidValueException('User has no email address'); + } + + if (!$user->getPassword()) { + throw new InvalidValueException('User has no password'); + } + + $error = null; + $token = Authentication::generateTokenByUser($user); + + try { + $domain = SystemSettingsConfig::get()['general']['domain']; + if (!$domain) { + throw new Exception('No main domain set in system settings, unable to generate reset password link'); + } + + $routerContext = $this->router->getContext(); + $routerContext->setHost($domain); + + $loginUrl = $this->router->generate( + 'pimcore_admin_login_check', + [ + 'token' => $token, + 'reset' => 'true', + ], + UrlGeneratorInterface::ABSOLUTE_URL + ); + + //@TODO: get rid off admin ui dependencies -> move to core (?) + $event = new LostPasswordEvent($user, $loginUrl); + $this->eventDispatcher->dispatch($event, AdminEvents::LOGIN_LOSTPASSWORD); + + // only send mail if it wasn't prevented in event + if ($event->getSendMail()) { + $mail = Tool::getMail([$user->getEmail()], 'Pimcore lost password service'); + $mail->setIgnoreDebugMode(true); + $mail->text("Login to pimcore and change your password using the following link. This temporary login link will expire in 24 hours: \r\n\r\n" . $loginUrl); + $mail->send(); + } + + // directly return event response + if ($event->hasResponse()) { + return $event->getResponse(); + } + } catch (Exception $e) { + Logger::error('Error sending password recovery email: ' . $e->getMessage()); + $error = 'lost_password_email_error'; + } + + if ($error) { + Logger::error('Lost password service: ' . $error); + } + return $data; + } +} From 96f7c16b27e4c182c443d436d74bfd3ff0b50ff8 Mon Sep 17 00:00:00 2001 From: alexz707 Date: Fri, 26 Jan 2024 10:17:21 +0000 Subject: [PATCH 03/11] Apply php-cs-fixer changes --- src/DependencyInjection/Configuration.php | 7 ++----- .../PimcoreStudioApiExtension.php | 13 ++++++------- src/Dto/ResetPasswordRequest.php | 10 ++++++++++ src/PimcoreStudioApiBundle.php | 3 ++- src/Serializer/AssetNormalizer.php | 14 ++++++++++++-- src/State/AssetProvider.php | 12 +++++++++++- src/State/ResetPasswordProcessor.php | 12 +++++++++++- 7 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index e42451cee..86dee49de 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -4,14 +4,11 @@ /** * Pimcore * - * This source file is available under two different licenses: - * - GNU General Public License version 3 (GPLv3) + * This source file is available under following license: * - Pimcore Commercial License (PCL) - * Full copyright and license information is available in - * LICENSE.md which is distributed with this source code. * * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org) - * @license http://www.pimcore.org/license GPLv3 and PCL + * @license http://www.pimcore.org/license PCL */ namespace Pimcore\Bundle\StudioApiBundle\DependencyInjection; diff --git a/src/DependencyInjection/PimcoreStudioApiExtension.php b/src/DependencyInjection/PimcoreStudioApiExtension.php index bf642d874..85463ac08 100644 --- a/src/DependencyInjection/PimcoreStudioApiExtension.php +++ b/src/DependencyInjection/PimcoreStudioApiExtension.php @@ -20,7 +20,6 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; - /** * This is the class that loads and manages your bundle configuration. * @@ -58,12 +57,12 @@ public function load(array $configs, ContainerBuilder $container): void public function prepend(ContainerBuilder $container): void { $apiPlatformConfig = [ - "mapping"=>[ - "paths"=> [ - __DIR__ . '/../../config/api_platform/' - ] - ] + 'mapping'=>[ + 'paths'=> [ + __DIR__ . '/../../config/api_platform/', + ], + ], ]; $container->prependExtensionConfig('api_platform', $apiPlatformConfig); } -} \ No newline at end of file +} diff --git a/src/Dto/ResetPasswordRequest.php b/src/Dto/ResetPasswordRequest.php index 9683b67d4..31b1cd9e2 100644 --- a/src/Dto/ResetPasswordRequest.php +++ b/src/Dto/ResetPasswordRequest.php @@ -1,6 +1,16 @@ setOffset(10 * $context['filters']['page']); } + return $assetListing; } // getting a single asset by id diff --git a/src/State/ResetPasswordProcessor.php b/src/State/ResetPasswordProcessor.php index 192f3635b..755c95501 100644 --- a/src/State/ResetPasswordProcessor.php +++ b/src/State/ResetPasswordProcessor.php @@ -1,6 +1,16 @@ Date: Thu, 8 Feb 2024 08:33:16 +0100 Subject: [PATCH 04/11] Add first prototype for FE --- composer.json | 1 + config/api_platform/resources/asset.yaml | 41 ++--- .../api_platform/resources/asset/image.yaml | 10 + .../api_platform/resources/schedule/task.yaml | 10 + config/api_platform/resources/user.yaml | 5 - config/api_platform/resources/version.yaml | 16 ++ config/serialization/asset.yaml | 70 +++---- config/serialization/asset/image.yaml | 20 ++ config/serialization/asset/permissions.yaml | 20 ++ config/serialization/dependency.yaml | 16 ++ config/serialization/property.yaml | 18 ++ config/serialization/schedule/task.yaml | 18 ++ config/serialization/version.yaml | 32 ++++ config/services.yaml | 12 +- src/Dto/Asset.php | 173 ++++++++++++++++++ src/Dto/Asset/Image.php | 61 ++++++ src/Dto/Asset/Permissions.php | 66 +++++++ src/Dto/Property.php | 56 ++++++ src/Dto/Task.php | 41 +++++ src/Dto/Version.php | 110 +++++++++++ src/Filter/AssetParentIdFilter.php | 40 ++++ src/Serializer/AssetNormalizer.php | 9 +- src/State/AssetProvider.php | 62 +++++-- src/State/ScheduledTaskProvider.php | 42 +++++ src/State/VersionProvider.php | 41 +++++ 25 files changed, 902 insertions(+), 88 deletions(-) create mode 100644 config/api_platform/resources/asset/image.yaml create mode 100644 config/api_platform/resources/schedule/task.yaml create mode 100644 config/api_platform/resources/version.yaml create mode 100644 config/serialization/asset/image.yaml create mode 100644 config/serialization/asset/permissions.yaml create mode 100644 config/serialization/dependency.yaml create mode 100644 config/serialization/property.yaml create mode 100644 config/serialization/schedule/task.yaml create mode 100644 config/serialization/version.yaml create mode 100644 src/Dto/Asset.php create mode 100644 src/Dto/Asset/Image.php create mode 100644 src/Dto/Asset/Permissions.php create mode 100644 src/Dto/Property.php create mode 100644 src/Dto/Task.php create mode 100644 src/Dto/Version.php create mode 100644 src/Filter/AssetParentIdFilter.php create mode 100644 src/State/ScheduledTaskProvider.php create mode 100644 src/State/VersionProvider.php diff --git a/composer.json b/composer.json index aa46df9bc..27b78ad4c 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "require": { "php": "~8.1.0 || ~8.2.0", "pimcore/enterprise-subscription-tools": "^1.3", + "pimcore/static-website": "^1.0", "pimcore/pimcore": "^11.0", "api-platform/core": "^3.2" }, diff --git a/config/api_platform/resources/asset.yaml b/config/api_platform/resources/asset.yaml index 77d1edbd4..fb2a8fd30 100644 --- a/config/api_platform/resources/asset.yaml +++ b/config/api_platform/resources/asset.yaml @@ -1,31 +1,26 @@ resources: - Pimcore\Model\Asset: + Pimcore\Bundle\StudioApiBundle\Dto\Asset: + operations: + ApiPlatform\Metadata\GetCollection: + filters: [ Pimcore\Bundle\StudioApiBundle\Filter\AssetParentIdFilter ] + paginationClientItemsPerPage: true + ApiPlatform\Metadata\Get: + normalizationContext: + groups: [ 'asset:read', 'asset:item:get', 'dependency:read', 'property:read'] + ApiPlatform\Metadata\Put: + ApiPlatform\Metadata\Post: + ApiPlatform\Metadata\Delete: + ApiPlatform\Metadata\Patch: provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider normalizationContext: - groups: ['get'] + groups: ['asset:read', 'dependency:read', 'property:read'] denormalizationContext: - groups: ['set'] + groups: ['asset:write'] properties: id: identifier: true - parentId: ~ - type: ~ - data: ~ - fullPath: ~ - Pimcore\Model\Asset\Image: - provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider - properties: - id: - identifier: true - normalizationContext: - groups: ['get'] - denormalizationContext: - groups: ['set'] - - Pimcore\Model\Asset\Image\Thumbnail: - provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider - normalizationContext: - groups: ['get'] - denormalizationContext: - groups: ['set'] +properties: + Pimcore\Bundle\StudioApiBundle\Dto\Asset: + dependencies: + genId: false \ No newline at end of file diff --git a/config/api_platform/resources/asset/image.yaml b/config/api_platform/resources/asset/image.yaml new file mode 100644 index 000000000..c2763f008 --- /dev/null +++ b/config/api_platform/resources/asset/image.yaml @@ -0,0 +1,10 @@ +resources: + Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image: + provider: Pimcore\Bundle\StudioApiBundle\State\AssetProvider + properties: + id: + identifier: true + normalizationContext: + groups: ['image:read', 'asset:read', 'task:read', 'dependency:read', 'property:read', 'version:read'] + denormalizationContext: + groups: ['image:write', 'asset:write'] \ No newline at end of file diff --git a/config/api_platform/resources/schedule/task.yaml b/config/api_platform/resources/schedule/task.yaml new file mode 100644 index 000000000..6f6f2ecd0 --- /dev/null +++ b/config/api_platform/resources/schedule/task.yaml @@ -0,0 +1,10 @@ +resources: + Pimcore\Bundle\StudioApiBundle\Dto\Task: + provider: Pimcore\Bundle\StudioApiBundle\State\ScheduledTaskProvider + normalizationContext: + groups: ['task:read'] + denormalizationContext: + groups: ['task:write'] + properties: + id: + identifier: true \ No newline at end of file diff --git a/config/api_platform/resources/user.yaml b/config/api_platform/resources/user.yaml index a78d2be1e..52d7888de 100644 --- a/config/api_platform/resources/user.yaml +++ b/config/api_platform/resources/user.yaml @@ -7,11 +7,6 @@ resources: input: Pimcore\Bundle\StudioApiBundle\Dto\ResetPasswordRequest output: false uriTemplate: '/users/reset-password' -# ApiPlatform\Metadata\Get: -# controller: ApiPlatform\Action\NotFoundAction -# read: false -# output: false - normalizationContext: groups: [ 'get' ] diff --git a/config/api_platform/resources/version.yaml b/config/api_platform/resources/version.yaml new file mode 100644 index 000000000..15478a634 --- /dev/null +++ b/config/api_platform/resources/version.yaml @@ -0,0 +1,16 @@ +resources: + Pimcore\Bundle\StudioApiBundle\Dto\Version: + operations: + ApiPlatform\Metadata\Get: + ApiPlatform\Metadata\Put: + ApiPlatform\Metadata\Post: + ApiPlatform\Metadata\Delete: + ApiPlatform\Metadata\Patch: + provider: Pimcore\Bundle\StudioApiBundle\State\VersionProvider + normalizationContext: + groups: ['version:read'] + denormalizationContext: + groups: ['version:write'] + properties: + id: + identifier: true \ No newline at end of file diff --git a/config/serialization/asset.yaml b/config/serialization/asset.yaml index 8cf84b184..19f50f772 100644 --- a/config/serialization/asset.yaml +++ b/config/serialization/asset.yaml @@ -1,64 +1,48 @@ -Pimcore\Model\Asset: +Pimcore\Bundle\StudioApiBundle\Dto\Asset: attributes: id: - groups: ['get', 'bla:read'] + groups: ['asset:read'] parentId: - groups: ['get'] + groups: ['asset:read'] + permissions: + groups: [ 'asset:read' ] type: - groups: ['get'] + groups: ['asset:read'] + children: + groups: ['asset:read'] filename: - groups: ['get'] + groups: ['asset:read'] path: - groups: ['get'] + groups: ['asset:read'] mimetype: - groups: ['get'] + groups: ['asset:read'] creationDate: - groups: ['get'] + groups: ['asset:read'] modificationDate: - groups: ['get'] + groups: ['asset:read'] userOwner: - groups: ['get'] + groups: ['asset:read'] userModification: - groups: ['get'] + groups: ['asset:read'] properties: - groups: ['get'] + groups: ['asset:item:get'] versions: - groups: ['get'] + groups: ['asset:read'] metadata: - groups: ['get'] + groups: ['asset:read'] locked: - groups: ['get'] + groups: ['asset:read'] + lock: + groups: ['asset:read'] customSettings: - groups: ['get'] + groups: ['asset:item:get'] hasMetaData: - groups: ['get'] + groups: ['asset:read'] dependencies: - groups: ['get'] + groups: ['asset:item:get'] scheduledTasks: - groups: ['get'] + groups: ['asset:item:get'] versionCount: - groups: ['get'] + groups: ['asset:item:get'] fullPath: - groups: ['get'] - -Pimcore\Model\Asset\Image: - attributes: - thumbnail: - groups: ['get'] - format: - groups: ['get'] - dimensions: - groups: ['get'] - width: - groups: [ 'get' ] - height: - groups: [ 'get' ] - -Pimcore\Model\Asset\Image\Thumbnail: - attributes: - path: - groups: ['get'] - imageTag: - groups: ['get'] - media: - groups: ['get'] \ No newline at end of file + groups: ['asset:read'] \ No newline at end of file diff --git a/config/serialization/asset/image.yaml b/config/serialization/asset/image.yaml new file mode 100644 index 000000000..7209d8484 --- /dev/null +++ b/config/serialization/asset/image.yaml @@ -0,0 +1,20 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image: + attributes: + thumbnail: + groups: ['image:read'] + format: + groups: ['image:read'] + dimensions: + groups: ['image:read'] + width: + groups: ['image:read'] + height: + groups: ['image:read'] + animated: + groups: ['image:read'] + vectorGraphic: + groups: ['image:read'] + lowQualityPreviewDataUri: + groups: ['image:read'] + lowQualityPreviewPath: + groups: ['image:read'] \ No newline at end of file diff --git a/config/serialization/asset/permissions.yaml b/config/serialization/asset/permissions.yaml new file mode 100644 index 000000000..5f452b976 --- /dev/null +++ b/config/serialization/asset/permissions.yaml @@ -0,0 +1,20 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Asset\Permissions: + attributes: + list: + groups: ['asset:read'] + view: + groups: ['asset:read'] + publish: + groups: ['asset:read'] + delete: + groups: ['asset:read'] + rename: + groups: ['asset:read'] + create: + groups: ['asset:read'] + settings: + groups: ['asset:read'] + versions: + groups: ['asset:read'] + properties: + groups: ['asset:read'] \ No newline at end of file diff --git a/config/serialization/dependency.yaml b/config/serialization/dependency.yaml new file mode 100644 index 000000000..94ca83435 --- /dev/null +++ b/config/serialization/dependency.yaml @@ -0,0 +1,16 @@ +Pimcore\Model\Dependency: + attributes: + sourceId: + groups: ['dependency:read'] + sourceType: + groups: ['dependency:read'] + required: + groups: ['dependency:read'] + requiredByTotalCount: + groups: ['dependency:read'] + requiresTotalCount: + groups: ['dependency:read'] + requires: + groups: ['dependency:read'] + requiredBy: + groups: ['dependency:read'] \ No newline at end of file diff --git a/config/serialization/property.yaml b/config/serialization/property.yaml new file mode 100644 index 000000000..1c58e48e5 --- /dev/null +++ b/config/serialization/property.yaml @@ -0,0 +1,18 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Property: + attributes: + name: + groups: ['property:read'] + data: + groups: ['property:read'] + type: + groups: ['property:read'] + ctype: + groups: ['property:read'] + cpath: + groups: ['property:read'] + cid: + groups: ['property:read'] + inheritable: + groups: ['property:read'] + inherited: + groups: ['property:read'] \ No newline at end of file diff --git a/config/serialization/schedule/task.yaml b/config/serialization/schedule/task.yaml new file mode 100644 index 000000000..0c512851d --- /dev/null +++ b/config/serialization/schedule/task.yaml @@ -0,0 +1,18 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Task: + attributes: + id: + groups: ['task:read', 'task:write'] + cid: + groups: ['task:read', 'task:write'] + ctype: + groups: ['task:read', 'task:write'] + date: + groups: ['task:read', 'task:write'] + action: + groups: ['task:read', 'task:write'] + version: + groups: ['task:read', 'task:write'] + active: + groups: ['task:read', 'task:write'] + userId: + groups: ['task:read', 'task:write'] \ No newline at end of file diff --git a/config/serialization/version.yaml b/config/serialization/version.yaml new file mode 100644 index 000000000..9ab5c5729 --- /dev/null +++ b/config/serialization/version.yaml @@ -0,0 +1,32 @@ +Pimcore\Bundle\StudioApiBundle\Dto\Version: + attributes: + id: + groups: ['version:read', 'asset:item:get'] + cid: + groups: ['version:read', 'asset:item:get'] + ctype: + groups: ['version:read', 'asset:item:get'] + userId: + groups: ['version:read', 'asset:item:get'] + user: + groups: ['version:read', 'asset:item:get'] + note: + groups: ['version:read', 'asset:item:get'] + date: + groups: ['version:read', 'asset:item:get'] + data: + groups: ['version:read'] + public: + groups: ['version:read', 'asset:item:get'] + serialized: + groups: ['version:read', 'asset:item:get'] + versionCount: + groups: ['version:read', 'asset:item:get'] + binaryFileHash: + groups: ['version:read', 'asset:item:get'] + binaryFileId: + groups: ['version:read', 'asset:item:get'] + autosave: + groups: ['version:read', 'asset:item:get'] + storageType: + groups: ['version:read', 'asset:item:get'] diff --git a/config/services.yaml b/config/services.yaml index 6561874e7..6375b4f7c 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -19,9 +19,19 @@ services: public: true tags: [ 'controller.service_arguments' ] + # Providers Pimcore\Bundle\StudioApiBundle\State\AssetProvider: ~ + Pimcore\Bundle\StudioApiBundle\State\ScheduledTaskProvider: ~ + Pimcore\Bundle\StudioApiBundle\State\VersionProvider: ~ + + # Processors Pimcore\Bundle\StudioApiBundle\State\ResetPasswordProcessor: ~ + # Filters + Pimcore\Bundle\StudioApiBundle\Filter\AssetParentIdFilter: + tags: [ 'api_platform.filter' ] + + # Normalizers Pimcore\Bundle\StudioApiBundle\Serializer\AssetNormalizer: tags: - - { name: 'serializer.normalizer' } \ No newline at end of file + - { name: 'serializer.normalizer' } diff --git a/src/Dto/Asset.php b/src/Dto/Asset.php new file mode 100644 index 000000000..94624862b --- /dev/null +++ b/src/Dto/Asset.php @@ -0,0 +1,173 @@ +permission; + } + + public function getId(): ?int + { + return $this->asset->getId(); + } + + public function getParentId(): ?int + { + return $this->asset->getParentId(); + } + + public function hasChildren(): bool + { + return $this->asset->hasChildren(); + } + + public function getUserModification(): ?int + { + return $this->asset->getUserModification(); + } + + public function getCreationDate(): ?int + { + return $this->asset->getCreationDate(); + } + + public function getModificationDate(): ?int + { + return $this->asset->getModificationDate(); + } + + public function getUserOwner(): ?int + { + return $this->asset->getUserOwner(); + } + + /** + * enum('self','propagate') nullable + * + */ + public function getLock(): ?string + { + return $this->asset->getLocked(); + } + + public function isLocked(): bool + { + return $this->asset->isLocked(); + } + + /** + * @return Property[] the $properties + */ + public function getProperties(): array + { + $properties = []; + foreach ($this->asset->getProperties() as $property) { + $properties[] = new Property($property); + } + return $properties; + } + + public function getVersionCount(): int + { + return $this->asset->getVersionCount(); + } + + public function getFilename(): ?string + { + return $this->asset->getFilename(); + } + + public function getKey(): ?string + { + return $this->asset->getKey(); + } + + public function getType(): string + { + return $this->asset->getType(); + } + + /** + * @return Version[] the $versions + */ + public function getVersions(): array + { + $versions = []; + foreach ($this->asset->getVersions() as $version) { + $versions[] = new Version($version); + } + return $versions; + } + + public function getCustomSettings(): array + { + return $this->asset->getCustomSettings(); + } + + public function getMimeType(): ?string + { + return $this->asset->getMimeType(); + } + + /** + * @return Task[] the $scheduledTasks + */ + public function getScheduledTasks(): array + { + $tasks = []; + foreach ($this->asset->getScheduledTasks() as $task) { + $tasks[] = new Task($task); + } + return $tasks; + } + + public function getPath(): ?string + { + return $this->asset->getPath(); + } + + public function getMetadata(): array + { + return $this->asset->getMetadata(); + } + #[ApiProperty(genId: false)] + public function getDependencies(): Dependency + { + return $this->asset->getDependencies(); + } + + public function getHasMetaData(): bool + { + return $this->asset->getHasMetaData(); + } + + public function getFullPath(): string + { + return $this->asset->getFullPath(); + } + + public function getFrontendFullPath(): string + { + return $this->asset->getFrontendFullPath(); + } + + public function getUserPermissions(?User $user = null): array + { + return $this->asset->getUserPermissions($user); + } +} diff --git a/src/Dto/Asset/Image.php b/src/Dto/Asset/Image.php new file mode 100644 index 000000000..70b84e4e9 --- /dev/null +++ b/src/Dto/Asset/Image.php @@ -0,0 +1,61 @@ +asset->getLowQualityPreviewPath(); + } + + public function getLowQualityPreviewDataUri(): ?string + { + return $this->asset->getLowQualityPreviewDataUri(); + } + + public function getThumbnail(array|string|ModelImage\Thumbnail\Config|null $config = null, bool $deferred = true): ThumbnailInterface + { + return $this->asset->getThumbnail($config, $deferred); + } + + public function getFormat(): string + { + return $this->asset->getFormat(); + } + + public function getDimensions(string $path = null, bool $force = false): ?array + { + return $this->asset->getDimensions($path, $force); + } + + public function getWidth(): int + { + return $this->asset->getWidth(); + } + + public function getHeight(): int + { + return $this->asset->getHeight(); + } + + public function isVectorGraphic(): bool + { + return $this->asset->isVectorGraphic(); + } + + public function isAnimated(): bool + { + return $this->asset->isAnimated(); + } +} \ No newline at end of file diff --git a/src/Dto/Asset/Permissions.php b/src/Dto/Asset/Permissions.php new file mode 100644 index 000000000..fc717a74a --- /dev/null +++ b/src/Dto/Asset/Permissions.php @@ -0,0 +1,66 @@ +list; + } + + public function isView(): bool + { + return $this->view; + } + + public function isPublish(): bool + { + return $this->publish; + } + + public function isDelete(): bool + { + return $this->delete; + } + + public function isRename(): bool + { + return $this->rename; + } + + public function isCreate(): bool + { + return $this->create; + } + + public function isSettings(): bool + { + return $this->settings; + } + + public function isVersions(): bool + { + return $this->versions; + } + + public function isProperties(): bool + { + return $this->properties; + } +} diff --git a/src/Dto/Property.php b/src/Dto/Property.php new file mode 100644 index 000000000..f80e74584 --- /dev/null +++ b/src/Dto/Property.php @@ -0,0 +1,56 @@ +property->getCid(); + } + + /** + * enum('document','asset','object') + */ + public function getCtype(): ?string + { + return $this->property->getCtype(); + } + + public function getData(): mixed + { + return $this->property->getData(); + } + + public function getName(): ?string + { + return $this->property->getName(); + } + + /** + * enum('text','document','asset','object','bool','select') + */ + public function getType(): ?string + { + return $this->property->getType(); + } + + public function getCpath(): ?string + { + return $this->property->getCpath(); + } + + public function isInherited(): bool + { + return $this->property->isInherited(); + } + + public function getInheritable(): bool + { + return $this->property->getInheritable(); + } +} \ No newline at end of file diff --git a/src/Dto/Task.php b/src/Dto/Task.php new file mode 100644 index 000000000..9987bca62 --- /dev/null +++ b/src/Dto/Task.php @@ -0,0 +1,41 @@ +task->getId(); + } + + public function getCid(): ?int + { + return $this->task->getCid(); + } + + public function getCtype(): ?string + { + return $this->task->getCtype(); + } + + public function getDate(): ?int + { + return $this->task->getDate(); + } + + public function getAction(): ?string + { + return $this->task->getAction(); + } + + public function getVersion(): ?int + { + return $this->task->getVersion(); + } +} \ No newline at end of file diff --git a/src/Dto/Version.php b/src/Dto/Version.php new file mode 100644 index 000000000..325b9c1f0 --- /dev/null +++ b/src/Dto/Version.php @@ -0,0 +1,110 @@ +version->getBinaryFileStream(); + } + + public function getId(): ?int + { + return $this->version->getId(); + } + + public function getCid(): int + { + return $this->version->getCid(); + } + + public function getCtype(): string + { + return $this->version->getCtype(); + } + + public function getDate(): int + { + return $this->version->getDate(); + } + + public function getFileStream(): mixed + { + return $this->version->getFileStream(); + } + + public function getNote(): string + { + return $this->version->getNote(); + } + + public function getUserId(): int + { + return $this->version->getUserId(); + } + + /** + * + * @return mixed + */ + public function getData(): mixed + { + $data = $this->version->getData(); + if ($data instanceof Image) { + return new \Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image($data, new Permissions()); + } + return $data; + } + + public function getSerialized(): bool + { + return $this->version->getSerialized(); + } + + public function getUser(): ?User + { + return $this->version->getUser(); + } + + public function isPublic(): bool + { + return $this->version->isPublic(); + } + + public function getVersionCount(): int + { + return $this->version->getVersionCount(); + } + + public function getBinaryFileHash(): ?string + { + return $this->version->getBinaryFileHash(); + } + + public function getBinaryFileId(): ?int + { + return $this->version->getBinaryFileId(); + } + + public function isAutoSave(): bool + { + return $this->version->isAutoSave(); + } + + public function getStorageType(): ?string + { + return $this->version->getStorageType(); + } +} \ No newline at end of file diff --git a/src/Filter/AssetParentIdFilter.php b/src/Filter/AssetParentIdFilter.php new file mode 100644 index 000000000..30506d183 --- /dev/null +++ b/src/Filter/AssetParentIdFilter.php @@ -0,0 +1,40 @@ +query->get('parentId'); + + if (!$parentId) { + return; + } + + $context[self::ASSET_PARENT_ID_FILTER_CONTEXT] = $parentId; + } + + public function getDescription(string $resourceClass): array + { + return [ + 'parentId' => [ + 'property' => Asset::class, + 'type' => 'int', + 'required' => true, + 'is_collection' => false, + 'description' => 'Filters assets by parent id.', + 'openapi' => [ + 'description' => 'Filters assets by parent id.', + ], + ] + ]; + } +} \ No newline at end of file diff --git a/src/Serializer/AssetNormalizer.php b/src/Serializer/AssetNormalizer.php index 02efee9ec..44eb13835 100644 --- a/src/Serializer/AssetNormalizer.php +++ b/src/Serializer/AssetNormalizer.php @@ -1,4 +1,5 @@ getThumbnail()->getPath(['frontend' => true]); + $data['thumbnailXXX'] = $object->getThumbnail()->getPath(['frontend' => true]); } return $data; @@ -47,6 +49,7 @@ public function normalize($object, $format = null, array $context = []): array public function supportsNormalization($data, $format = null, array $context = []): bool { + return false; if (isset($context[self::ALREADY_CALLED])) { return false; } diff --git a/src/State/AssetProvider.php b/src/State/AssetProvider.php index 0f56769b4..feff09435 100644 --- a/src/State/AssetProvider.php +++ b/src/State/AssetProvider.php @@ -15,29 +15,65 @@ use ApiPlatform\Metadata\CollectionOperationInterface; use ApiPlatform\Metadata\Operation; +use ApiPlatform\State\Pagination\Pagination; +use ApiPlatform\State\Pagination\TraversablePaginator; use ApiPlatform\State\ProviderInterface; -use Pimcore\Model\Asset; -use Pimcore\Model\Element\Tag; +use ArrayIterator; +use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\Search\Tree\AssetTreeServiceInterface; +use Pimcore\Bundle\StaticResolverBundle\Models\Asset\AssetResolverInterface; +use Pimcore\Bundle\StudioApiBundle\Dto\Asset; +use Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image; +use Pimcore\Bundle\StudioApiBundle\Filter\AssetParentIdFilter; +use Pimcore\Model\Asset\Image as ImageModel; + final class AssetProvider implements ProviderInterface { + public function __construct( + private readonly AssetResolverInterface $assetResolver, + private readonly AssetTreeServiceInterface $assetTreeService, + private readonly Pagination $pagination + ) { + } + public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null { - // collection of assets, needs to be further investigated if ($operation instanceof CollectionOperationInterface) { - $assetListing = new Asset\Listing(); - $assetListing->setLimit(10); - - if (isset($context['filters']['page'])) { - $assetListing->setOffset(10 * $context['filters']['page']); + $result =[]; + $totalItems = 0; + if (array_key_exists(AssetParentIdFilter::ASSET_PARENT_ID_FILTER_CONTEXT, $context)){ + $parentId = (int)($context[AssetParentIdFilter::ASSET_PARENT_ID_FILTER_CONTEXT] ?? 1); + $items = $this->assetTreeService->fetchTreeItems( + $parentId, + $this->pagination->getPage($context), + $this->pagination->getLimit($operation, $context) + ); + $totalItems = $items->getPagination()->getTotalItems(); + foreach ($items->getItems() as $item) { + $assetModel = $this->assetResolver->getById($item->getId()); + if ($assetModel === null) { + continue; + } + $result[] = new Asset($assetModel, new Asset\Permissions()); + } } - return $assetListing; + return new TraversablePaginator( + new ArrayIterator($result), + $this->pagination->getPage($context), + $this->pagination->getLimit($operation, $context), + $totalItems + ); } - // getting a single asset by id - $test = Asset::getById($uriVariables['id']); + $assetModel = $this->assetResolver->getById($uriVariables['id']); - //$tag = Tag::getTagsForElement('asset', $test->getId()); - return $test; + if ($assetModel === null) { + return null; + } + + if ($assetModel instanceof ImageModel) { + return new Image($assetModel, new Asset\Permissions()); + } + return new Asset($assetModel, new Asset\Permissions()); } } diff --git a/src/State/ScheduledTaskProvider.php b/src/State/ScheduledTaskProvider.php new file mode 100644 index 000000000..8caec692e --- /dev/null +++ b/src/State/ScheduledTaskProvider.php @@ -0,0 +1,42 @@ +taskResolver->getById($uriVariables['id']); + if ($task === null) { + return null; + } + + return new Task($task); + } +} diff --git a/src/State/VersionProvider.php b/src/State/VersionProvider.php new file mode 100644 index 000000000..9aa2ed110 --- /dev/null +++ b/src/State/VersionProvider.php @@ -0,0 +1,41 @@ +versionResolver->getById($uriVariables['id']); + if ($version === null) { + return null; + } + + return new Version($version); + } +} From 1cd89ed57f0e08f9e780b166a09a5264ea5bd580 Mon Sep 17 00:00:00 2001 From: alexz707 Date: Thu, 8 Feb 2024 07:34:01 +0000 Subject: [PATCH 05/11] Apply php-cs-fixer changes --- src/Dto/Asset.php | 14 ++++++++++++++ src/Dto/Asset/Image.php | 12 +++++++++++- src/Dto/Asset/Permissions.php | 10 ++++++++++ src/Dto/Property.php | 13 ++++++++++++- src/Dto/Task.php | 12 +++++++++++- src/Dto/Version.php | 16 +++++++++++++--- src/Filter/AssetParentIdFilter.php | 15 +++++++++++++-- src/Serializer/AssetNormalizer.php | 1 - src/State/AssetProvider.php | 8 ++++---- 9 files changed, 88 insertions(+), 13 deletions(-) diff --git a/src/Dto/Asset.php b/src/Dto/Asset.php index 94624862b..ba8aaf6ca 100644 --- a/src/Dto/Asset.php +++ b/src/Dto/Asset.php @@ -1,6 +1,16 @@ asset->getProperties() as $property) { $properties[] = new Property($property); } + return $properties; } @@ -111,6 +122,7 @@ public function getVersions(): array foreach ($this->asset->getVersions() as $version) { $versions[] = new Version($version); } + return $versions; } @@ -133,6 +145,7 @@ public function getScheduledTasks(): array foreach ($this->asset->getScheduledTasks() as $task) { $tasks[] = new Task($task); } + return $tasks; } @@ -145,6 +158,7 @@ public function getMetadata(): array { return $this->asset->getMetadata(); } + #[ApiProperty(genId: false)] public function getDependencies(): Dependency { diff --git a/src/Dto/Asset/Image.php b/src/Dto/Asset/Image.php index 70b84e4e9..6924438cb 100644 --- a/src/Dto/Asset/Image.php +++ b/src/Dto/Asset/Image.php @@ -1,6 +1,16 @@ asset->isAnimated(); } -} \ No newline at end of file +} diff --git a/src/Dto/Asset/Permissions.php b/src/Dto/Asset/Permissions.php index fc717a74a..2eab8e350 100644 --- a/src/Dto/Asset/Permissions.php +++ b/src/Dto/Asset/Permissions.php @@ -1,6 +1,16 @@ property->getCid(); @@ -53,4 +64,4 @@ public function getInheritable(): bool { return $this->property->getInheritable(); } -} \ No newline at end of file +} diff --git a/src/Dto/Task.php b/src/Dto/Task.php index 9987bca62..8daf7cde3 100644 --- a/src/Dto/Task.php +++ b/src/Dto/Task.php @@ -1,6 +1,16 @@ task->getVersion(); } -} \ No newline at end of file +} diff --git a/src/Dto/Version.php b/src/Dto/Version.php index 325b9c1f0..77e07b48c 100644 --- a/src/Dto/Version.php +++ b/src/Dto/Version.php @@ -1,13 +1,22 @@ version->getBinaryFileStream(); + return $this->version->getBinaryFileStream(); } public function getId(): ?int @@ -65,6 +74,7 @@ public function getData(): mixed if ($data instanceof Image) { return new \Pimcore\Bundle\StudioApiBundle\Dto\Asset\Image($data, new Permissions()); } + return $data; } @@ -107,4 +117,4 @@ public function getStorageType(): ?string { return $this->version->getStorageType(); } -} \ No newline at end of file +} diff --git a/src/Filter/AssetParentIdFilter.php b/src/Filter/AssetParentIdFilter.php index 30506d183..b6a08e9e6 100644 --- a/src/Filter/AssetParentIdFilter.php +++ b/src/Filter/AssetParentIdFilter.php @@ -1,6 +1,16 @@ query->get('parentId'); @@ -34,7 +45,7 @@ public function getDescription(string $resourceClass): array 'openapi' => [ 'description' => 'Filters assets by parent id.', ], - ] + ], ]; } -} \ No newline at end of file +} diff --git a/src/Serializer/AssetNormalizer.php b/src/Serializer/AssetNormalizer.php index 44eb13835..2b27b8c74 100644 --- a/src/Serializer/AssetNormalizer.php +++ b/src/Serializer/AssetNormalizer.php @@ -13,7 +13,6 @@ namespace Pimcore\Bundle\StudioApiBundle\Serializer; - use Pimcore\Bundle\StudioApiBundle\Dto\Asset; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; diff --git a/src/State/AssetProvider.php b/src/State/AssetProvider.php index feff09435..aec2d7a5a 100644 --- a/src/State/AssetProvider.php +++ b/src/State/AssetProvider.php @@ -26,13 +26,12 @@ use Pimcore\Bundle\StudioApiBundle\Filter\AssetParentIdFilter; use Pimcore\Model\Asset\Image as ImageModel; - final class AssetProvider implements ProviderInterface { public function __construct( - private readonly AssetResolverInterface $assetResolver, + private readonly AssetResolverInterface $assetResolver, private readonly AssetTreeServiceInterface $assetTreeService, - private readonly Pagination $pagination + private readonly Pagination $pagination ) { } @@ -41,7 +40,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c if ($operation instanceof CollectionOperationInterface) { $result =[]; $totalItems = 0; - if (array_key_exists(AssetParentIdFilter::ASSET_PARENT_ID_FILTER_CONTEXT, $context)){ + if (array_key_exists(AssetParentIdFilter::ASSET_PARENT_ID_FILTER_CONTEXT, $context)) { $parentId = (int)($context[AssetParentIdFilter::ASSET_PARENT_ID_FILTER_CONTEXT] ?? 1); $items = $this->assetTreeService->fetchTreeItems( $parentId, @@ -74,6 +73,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c if ($assetModel instanceof ImageModel) { return new Image($assetModel, new Asset\Permissions()); } + return new Asset($assetModel, new Asset\Permissions()); } } From 2778ec3216ddebf89c856bc6a687b142ca7665f8 Mon Sep 17 00:00:00 2001 From: Alex Zamponi <562324+alexz707@users.noreply.github.com> Date: Thu, 8 Feb 2024 08:38:11 +0100 Subject: [PATCH 06/11] Fix composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 27b78ad4c..23e7c861b 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "require": { "php": "~8.1.0 || ~8.2.0", "pimcore/enterprise-subscription-tools": "^1.3", - "pimcore/static-website": "^1.0", + "pimcore/static-resolver-bundle": "^1.0", "pimcore/pimcore": "^11.0", "api-platform/core": "^3.2" }, From 83ea88bfb8768290d7cd7602c0dcbbddf8b9bdd4 Mon Sep 17 00:00:00 2001 From: Alex Zamponi <562324+alexz707@users.noreply.github.com> Date: Thu, 8 Feb 2024 08:48:49 +0100 Subject: [PATCH 07/11] Fix composer dependencies and not used code --- composer.json | 1 + src/Serializer/AssetNormalizer.php | 9 ++------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 23e7c861b..5d7628a8b 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,7 @@ "php": "~8.1.0 || ~8.2.0", "pimcore/enterprise-subscription-tools": "^1.3", "pimcore/static-resolver-bundle": "^1.0", + "pimcore/generic-data-index-bundle": "^1.0", "pimcore/pimcore": "^11.0", "api-platform/core": "^3.2" }, diff --git a/src/Serializer/AssetNormalizer.php b/src/Serializer/AssetNormalizer.php index 2b27b8c74..ced9ed95f 100644 --- a/src/Serializer/AssetNormalizer.php +++ b/src/Serializer/AssetNormalizer.php @@ -14,7 +14,6 @@ namespace Pimcore\Bundle\StudioApiBundle\Serializer; use Pimcore\Bundle\StudioApiBundle\Dto\Asset; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -25,10 +24,6 @@ final class AssetNormalizer implements NormalizerInterface, NormalizerAwareInter private const ALREADY_CALLED = 'ASSET_NORMALIZER_ALREADY_CALLED'; - public function __construct(private readonly RequestStack $requestStack) - { - } - public function normalize($object, $format = null, array $context = []): array { $context[self::ALREADY_CALLED] = true; @@ -49,11 +44,11 @@ public function normalize($object, $format = null, array $context = []): array public function supportsNormalization($data, $format = null, array $context = []): bool { return false; - if (isset($context[self::ALREADY_CALLED])) { + /*if (isset($context[self::ALREADY_CALLED])) { return false; } - return $data instanceof Asset; + return $data instanceof Asset;*/ } public function getSupportedTypes(?string $format): array From ab52399fb3a60ef24f081660d1821977700140a0 Mon Sep 17 00:00:00 2001 From: Alex Zamponi <562324+alexz707@users.noreply.github.com> Date: Thu, 8 Feb 2024 08:55:49 +0100 Subject: [PATCH 08/11] Fix qodana report --- .../PimcoreStudioApiExtension.php | 5 ++++- src/State/ResetPasswordProcessor.php | 21 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/DependencyInjection/PimcoreStudioApiExtension.php b/src/DependencyInjection/PimcoreStudioApiExtension.php index 85463ac08..6ba89f3b7 100644 --- a/src/DependencyInjection/PimcoreStudioApiExtension.php +++ b/src/DependencyInjection/PimcoreStudioApiExtension.php @@ -51,7 +51,10 @@ public function load(array $configs, ContainerBuilder $container): void } // Pass the configuration to the custom normalizer - $container->setParameter('pimcore_studio_api.serializer.mapping.paths', $config['serializer']['mapping']['paths']); + $container->setParameter( + 'pimcore_studio_api.serializer.mapping.paths', + $config['serializer']['mapping']['paths'] + ); } public function prepend(ContainerBuilder $container): void diff --git a/src/State/ResetPasswordProcessor.php b/src/State/ResetPasswordProcessor.php index 755c95501..b25284f20 100644 --- a/src/State/ResetPasswordProcessor.php +++ b/src/State/ResetPasswordProcessor.php @@ -35,16 +35,20 @@ final class ResetPasswordProcessor implements ProcessorInterface { public function __construct( - private UrlGeneratorInterface $router, - private RequestStack $requestStack, - private RateLimiterFactory $resetPasswordLimiter, - private EventDispatcherInterface $eventDispatcher + private readonly UrlGeneratorInterface $router, + private readonly RequestStack $requestStack, + private readonly RateLimiterFactory $resetPasswordLimiter, + private readonly EventDispatcherInterface $eventDispatcher ) { } public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []) { - if (!$operation instanceof Post || $operation->getUriTemplate() !== '/users/reset-password' || !$data instanceof ResetPasswordRequest) { + if ( + !$operation instanceof Post || + !$data instanceof ResetPasswordRequest || + $operation->getUriTemplate() !== '/users/reset-password' + ) { // wrong operation throw new OperationNotFoundException(); } @@ -57,7 +61,7 @@ public function process(mixed $data, Operation $operation, array $uriVariables = $currentRequest = $this->requestStack->getCurrentRequest(); $limiter = $this->resetPasswordLimiter->create($currentRequest->getClientIp()); - if (false === $limiter->consume(1)->isAccepted()) { + if (false === $limiter->consume()->isAccepted()) { throw new InvalidValueException('Rate limit exceeded'); } @@ -102,7 +106,10 @@ public function process(mixed $data, Operation $operation, array $uriVariables = if ($event->getSendMail()) { $mail = Tool::getMail([$user->getEmail()], 'Pimcore lost password service'); $mail->setIgnoreDebugMode(true); - $mail->text("Login to pimcore and change your password using the following link. This temporary login link will expire in 24 hours: \r\n\r\n" . $loginUrl); + $mail->text( + "Login to pimcore and change your password using the following link. ". + "This temporary login link will expire in 24 hours: \r\n\r\n" . $loginUrl + ); $mail->send(); } From 5bc2d74bb5a2ae12a24c0928f99926172d649c3b Mon Sep 17 00:00:00 2001 From: alexz707 Date: Thu, 8 Feb 2024 07:56:17 +0000 Subject: [PATCH 09/11] Apply php-cs-fixer changes --- src/State/ResetPasswordProcessor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/State/ResetPasswordProcessor.php b/src/State/ResetPasswordProcessor.php index b25284f20..dc9473f79 100644 --- a/src/State/ResetPasswordProcessor.php +++ b/src/State/ResetPasswordProcessor.php @@ -36,8 +36,8 @@ final class ResetPasswordProcessor implements ProcessorInterface { public function __construct( private readonly UrlGeneratorInterface $router, - private readonly RequestStack $requestStack, - private readonly RateLimiterFactory $resetPasswordLimiter, + private readonly RequestStack $requestStack, + private readonly RateLimiterFactory $resetPasswordLimiter, private readonly EventDispatcherInterface $eventDispatcher ) { } @@ -107,7 +107,7 @@ public function process(mixed $data, Operation $operation, array $uriVariables = $mail = Tool::getMail([$user->getEmail()], 'Pimcore lost password service'); $mail->setIgnoreDebugMode(true); $mail->text( - "Login to pimcore and change your password using the following link. ". + 'Login to pimcore and change your password using the following link. '. "This temporary login link will expire in 24 hours: \r\n\r\n" . $loginUrl ); $mail->send(); From faa770ad004428173a4ec3226c303b59ea625b58 Mon Sep 17 00:00:00 2001 From: Alex Zamponi <562324+alexz707@users.noreply.github.com> Date: Thu, 8 Feb 2024 09:12:30 +0100 Subject: [PATCH 10/11] Fix composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5d7628a8b..60d851a08 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "require": { "php": "~8.1.0 || ~8.2.0", "pimcore/enterprise-subscription-tools": "^1.3", - "pimcore/static-resolver-bundle": "^1.0", + "pimcore/static-resolver-bundle": "1.x-dev", "pimcore/generic-data-index-bundle": "^1.0", "pimcore/pimcore": "^11.0", "api-platform/core": "^3.2" From e7dd5bb9866d20fb3771b8a9a5f014a25e5ce12f Mon Sep 17 00:00:00 2001 From: Alex Zamponi <562324+alexz707@users.noreply.github.com> Date: Thu, 8 Feb 2024 09:17:12 +0100 Subject: [PATCH 11/11] Fix composer --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 60d851a08..24522c5ca 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,8 @@ "require": { "php": "~8.1.0 || ~8.2.0", "pimcore/enterprise-subscription-tools": "^1.3", - "pimcore/static-resolver-bundle": "1.x-dev", - "pimcore/generic-data-index-bundle": "^1.0", + "pimcore/static-resolver-bundle": "^1.3", + "pimcore/generic-data-index-bundle": "1.x-dev", "pimcore/pimcore": "^11.0", "api-platform/core": "^3.2" },