Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Image Editor] Add endpoint to return original image stream #642

Merged
merged 2 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Asset/Controller/Document/PreviewStreamController.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\UserPermissions;
use Pimcore\Model\Asset\Document;
Expand Down Expand Up @@ -97,7 +98,7 @@ public function streamDocumentPreview(int $id): StreamedResponse
);

if (!$asset instanceof Document) {
throw new InvalidElementTypeException($asset->getType());
throw new InvalidElementTypeException($asset->getType(), ElementTypes::TYPE_ASSET);
}

return $this->documentService->getPreviewStream($asset);
Expand Down
98 changes: 98 additions & 0 deletions src/Asset/Controller/Image/StreamController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php
declare(strict_types=1);

/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - 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
*/

namespace Pimcore\Bundle\StudioBackendBundle\Asset\Controller\Image;

use OpenApi\Attributes\Get;
use Pimcore\Bundle\StudioBackendBundle\Asset\Attribute\Response\Header\ContentDisposition;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\AssetServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\BinaryServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\AccessDeniedException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ElementStreamResourceNotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\NotFoundException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\UserNotFoundException;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Parameter\Path\IdParameter;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\Content\MediaType;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\Security\Service\SecurityServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseHeaders;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\UserPermissions;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
* @internal
*/
final class StreamController extends AbstractApiController
{
public function __construct(
private readonly AssetServiceInterface $assetService,
private readonly BinaryServiceInterface $binaryService,
private readonly SecurityServiceInterface $securityService,
SerializerInterface $serializer
) {
parent::__construct($serializer);
}

/**
* @throws AccessDeniedException
* @throws ElementStreamResourceNotFoundException
* @throws NotFoundException
* @throws InvalidElementTypeException
* @throws UserNotFoundException
*/
#[Route(
'/assets/{id}/image/stream',
name: 'pimcore_studio_api_stream_image',
methods: ['GET']
)]
#[IsGranted(UserPermissions::ASSETS->value)]
#[Get(
path: self::PREFIX . '/assets/{id}/image/stream',
operationId: 'asset_image_stream',
description: 'asset_image_stream_description',
summary: 'asset_image_stream_summary',
tags: [Tags::Assets->name]
)]
#[IdParameter(type: 'image')]
#[SuccessResponse(
description: 'asset_image_stream_success_response',
content: [new MediaType('image/*')],
headers: [new ContentDisposition(HttpResponseHeaders::INLINE_TYPE->value)]
)]
#[DefaultResponses([
HttpResponseCodes::BAD_REQUEST,
HttpResponseCodes::UNAUTHORIZED,
HttpResponseCodes::NOT_FOUND,
])]
public function streamOriginalImage(
int $id,
): StreamedResponse {
$asset = $this->assetService->getAssetElement(
$this->securityService->getCurrentUser(),
$id
);

return $this->binaryService->streamImage($asset);
}
}
10 changes: 9 additions & 1 deletion src/Asset/Encoder/TextEncoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\MaxFileSizeExceededException;
use Pimcore\Model\Asset\Text;
use Pimcore\Model\Element\ElementInterface;
use function sprintf;

final class TextEncoder implements TextEncoderInterface
{
Expand All @@ -32,7 +33,14 @@ final class TextEncoder implements TextEncoderInterface
public function encodeUTF8(ElementInterface $element): string
{
if (!$element instanceof Text) {
throw new InvalidElementTypeException('Element must be an instance of Text');
throw new InvalidElementTypeException(
sprintf(
'should have been (%s) but was (%s)',
Text::class,
$element->getType(),
),
'Asset'
);
}

if ($element->getFileSize() > self::MAX_FILE_SIZE) {
Expand Down
24 changes: 19 additions & 5 deletions src/Asset/Service/BinaryService.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidThumbnailConfigurationException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidThumbnailException;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseHeaders;
use Pimcore\Bundle\StudioBackendBundle\Util\Trait\StreamedResponseTrait;
use Pimcore\Messenger\AssetPreviewImageMessage;
Expand Down Expand Up @@ -59,19 +60,32 @@ public function downloadVideoByThumbnail(
string $thumbnailName
): StreamedResponse {
if (!$video instanceof Video) {
throw new InvalidElementTypeException($video->getType());
throw new InvalidElementTypeException($video->getType(), ElementTypes::TYPE_ASSET);
}

return $this->getVideoByThumbnail($video, $thumbnailName, HttpResponseHeaders::ATTACHMENT_TYPE->value);
}

/**
* @throws ElementStreamResourceNotFoundException|InvalidElementTypeException
*/
public function streamImage(
Asset $image
): StreamedResponse {
if (!$image instanceof Image) {
throw new InvalidElementTypeException($image->getType(), ElementTypes::TYPE_ASSET);
}

return $this->getStreamedResponse($image, HttpResponseHeaders::INLINE_TYPE->value);
}

/**
* @throws InvalidElementTypeException|InvalidThumbnailException
*/
public function streamPreviewImageThumbnail(Asset $image): StreamedResponse
{
if (!$image instanceof Image) {
throw new InvalidElementTypeException($image->getType());
throw new InvalidElementTypeException($image->getType(), ElementTypes::TYPE_ASSET);
}

return $this->getStreamedResponse(
Expand All @@ -85,7 +99,7 @@ public function streamImageThumbnailFromConfig(
ImageDownloadConfigParameter $configParameter
): StreamedResponse {
if (!$image instanceof Image) {
throw new InvalidElementTypeException($image->getType());
throw new InvalidElementTypeException($image->getType(), ElementTypes::TYPE_ASSET);
}

return $this->getStreamedResponse(
Expand All @@ -105,7 +119,7 @@ public function streamVideoByThumbnail(
string $thumbnailName
): StreamedResponse {
if (!$video instanceof Video) {
throw new InvalidElementTypeException($video->getType());
throw new InvalidElementTypeException($video->getType(), ElementTypes::TYPE_ASSET);
}

return $this->getVideoByThumbnail($video, $thumbnailName, HttpResponseHeaders::INLINE_TYPE->value);
Expand All @@ -122,7 +136,7 @@ public function streamVideoImageThumbnail(
VideoImageStreamConfigParameter $imageConfig
): StreamedResponse {
if (!$video instanceof Video) {
throw new InvalidElementTypeException($video->getType());
throw new InvalidElementTypeException($video->getType(), ElementTypes::TYPE_ASSET);
}
$this->thumbnailService->validateCustomVideoThumbnailConfig($imageConfig);

Expand Down
7 changes: 7 additions & 0 deletions src/Asset/Service/BinaryServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ public function downloadVideoByThumbnail(
string $thumbnailName
): StreamedResponse;

/**
* @throws ElementStreamResourceNotFoundException|InvalidElementTypeException
*/
public function streamImage(
Asset $image
): StreamedResponse;

/**
* @throws InvalidElementTypeException|InvalidThumbnailException
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Dependency/Controller/Element/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function __construct(
tags: [Tags::Dependencies->name]
)]
#[ElementTypeParameter]
#[IdParameter('element')]
#[IdParameter]
#[PageParameter]
#[PageSizeParameter]
#[DependencyModeParameter]
Expand Down
3 changes: 2 additions & 1 deletion src/Exception/Api/ElementProcessingNotCompletedException.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace Pimcore\Bundle\StudioBackendBundle\Exception\Api;

use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use function sprintf;

Expand All @@ -24,7 +25,7 @@
*/
final class ElementProcessingNotCompletedException extends AbstractApiException
{
public function __construct(int $id, string $type = 'Element')
public function __construct(int $id, string $type = ElementTypes::TYPE_ELEMENT)
{
parent::__construct(
HttpResponseCodes::NOT_COMPLETED->value,
Expand Down
3 changes: 2 additions & 1 deletion src/Exception/Api/ElementStreamResourceNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace Pimcore\Bundle\StudioBackendBundle\Exception\Api;

use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use function sprintf;

Expand All @@ -24,7 +25,7 @@
*/
final class ElementStreamResourceNotFoundException extends AbstractApiException
{
public function __construct(int $id, string $type = 'Element')
public function __construct(int $id, string $type = ElementTypes::TYPE_ELEMENT)
{
parent::__construct(
HttpResponseCodes::NOT_FOUND->value,
Expand Down
8 changes: 5 additions & 3 deletions src/Exception/Api/InvalidElementTypeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace Pimcore\Bundle\StudioBackendBundle\Exception\Api;

use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use function sprintf;

Expand All @@ -24,13 +25,14 @@
*/
final class InvalidElementTypeException extends AbstractApiException
{
public function __construct(string $type)
public function __construct(string $subType, string $elementType = ElementTypes::TYPE_ELEMENT)
{
parent::__construct(
HttpResponseCodes::BAD_REQUEST->value,
sprintf(
'Invalid element type: %s',
$type
'Invalid %s type: %s',
$elementType,
$subType
)
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Note/Controller/Element/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\UserPermissions;
use Pimcore\Bundle\StudioBackendBundle\Util\Trait\PaginatedResponseTrait;
Expand Down Expand Up @@ -78,7 +79,7 @@ public function __construct(
tags: [Tags::Notes->name]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter(type: ElementTypes::TYPE_ELEMENT)]
#[PageParameter]
#[PageSizeParameter(50)]
#[NoteSortByParameter]
Expand Down
3 changes: 2 additions & 1 deletion src/Note/Controller/Element/CreateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\DefaultResponses;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Attribute\Response\SuccessResponse;
use Pimcore\Bundle\StudioBackendBundle\OpenApi\Config\Tags;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\HttpResponseCodes;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\UserPermissions;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand Down Expand Up @@ -66,7 +67,7 @@ public function __construct(
tags: [Tags::Notes->name]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter(type: ElementTypes::TYPE_ELEMENT)]
#[CreateNoteRequestBody]
#[SuccessResponse(
description: 'note_element_create_success_response',
Expand Down
2 changes: 1 addition & 1 deletion src/Property/Controller/Element/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function __construct(
tags: [Tags::Properties->value]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter]
#[SuccessResponse(
description: 'property_get_collection_for_element_by_type_and_id_success_response',
content: new ItemsJson(ElementProperty::class)
Expand Down
2 changes: 1 addition & 1 deletion src/Schedule/Controller/Element/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function __construct(
tags: [Tags::Schedule->name]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter]
#[SuccessResponse(
description: 'schedule_get_collection_for_element_by_type_and_id_success_response',
content: new ItemsJson(Schedule::class)
Expand Down
2 changes: 1 addition & 1 deletion src/Schedule/Controller/Element/CreateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function __construct(
tags: [Tags::Schedule->name]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter]
#[SuccessResponse(
description: 'schedule_create_for_element_by_type_and_id_success_response',
content: new JsonContent(ref: Schedule::class)
Expand Down
2 changes: 1 addition & 1 deletion src/Schedule/Controller/Element/UpdateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function __construct(
tags: [Tags::Schedule->name]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter]
#[ElementScheduleRequestBody]
#[SuccessResponse(
description: 'schedule_update_for_element_by_type_and_id_success_response',
Expand Down
2 changes: 1 addition & 1 deletion src/Tag/Controller/Element/AssignController.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function __construct(
tags: [Tags::TagsForElement->value]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter]
#[IdParameter(type: 'tag', name: 'tagId')]
#[DefaultResponses([
HttpResponseCodes::UNAUTHORIZED,
Expand Down
2 changes: 1 addition & 1 deletion src/Tag/Controller/Element/CollectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function __construct(
tags: [Tags::TagsForElement->value]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter]
#[SuccessResponse(
description: 'tag_get_collection_for_element_by_type_and_id_success_response',
content: new CollectionJson(new TagCollection())
Expand Down
2 changes: 1 addition & 1 deletion src/Tag/Controller/Element/UnassignController.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function __construct(
tags: [Tags::TagsForElement->value]
)]
#[ElementTypeParameter]
#[IdParameter(type: 'element')]
#[IdParameter]
#[IdParameter(type: 'tag', name: 'tagId')]
#[DefaultResponses([
HttpResponseCodes::UNAUTHORIZED,
Expand Down
2 changes: 2 additions & 0 deletions src/Util/Constant/ElementTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

public const TYPE_DATA_OBJECT = 'data-object';

public const TYPE_ELEMENT = 'element';

public const TYPE_OBJECT = 'object';

public const TYPE_VARIANT = 'variant';
Expand Down
Loading
Loading