Skip to content
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
97 changes: 97 additions & 0 deletions src/Asset/Controller/Video/ThumbnailStatusController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php
declare(strict_types=1);

/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

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

use OpenApi\Attributes\Get;
use OpenApi\Attributes\JsonContent;
use Pimcore\Bundle\StudioBackendBundle\Asset\OpenApi\Attribute\Parameter\Path\ThumbnailNameParameter;
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video\VideoThumbnailStatus;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\AssetServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\VideoServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Controller\AbstractApiController;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\ForbiddenException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidThumbnailException;
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\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\UserPermissions;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Serializer\SerializerInterface;

/**
* @internal
*/
final class ThumbnailStatusController extends AbstractApiController
{
public function __construct(

Check notice on line 45 in src/Asset/Controller/Video/ThumbnailStatusController.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Controller/Video/ThumbnailStatusController.php#L45

Expected 2 blank lines before function; 0 found
SerializerInterface $serializer,
private readonly AssetServiceInterface $assetService,
private readonly SecurityServiceInterface $securityService,
private readonly VideoServiceInterface $videoService,
) {
parent::__construct($serializer);
}

Check notice on line 52 in src/Asset/Controller/Video/ThumbnailStatusController.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Controller/Video/ThumbnailStatusController.php#L52

Expected 1 blank line before closing function brace; 0 found

Check notice on line 52 in src/Asset/Controller/Video/ThumbnailStatusController.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Controller/Video/ThumbnailStatusController.php#L52

Expected 2 blank lines after function; 1 found

/**
* @throws ForbiddenException
* @throws InvalidElementTypeException
* @throws InvalidThumbnailException
* @throws NotFoundException
* @throws UserNotFoundException
*/
#[Route(
'/assets/{id}/video/thumbnail/{thumbnailName}/status',
name: 'pimcore_studio_api_video_thumbnail_status',
methods: ['GET']
)]
#[IsGranted(UserPermissions::ASSETS->value)]
#[Get(
path: self::PREFIX . '/assets/{id}/video/thumbnail/{thumbnailName}/status',
operationId: 'asset_video_thumbnail_status',
description: 'asset_video_thumbnail_status_description',
summary: 'asset_video_thumbnail_status_summary',
tags: [Tags::Assets->name]
)]
#[IdParameter(type: 'video')]
#[ThumbnailNameParameter]
#[SuccessResponse(
description: 'asset_video_thumbnail_status_success_response',
content: new JsonContent(ref: VideoThumbnailStatus::class)
)]
#[DefaultResponses([

Check notice on line 80 in src/Asset/Controller/Video/ThumbnailStatusController.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Controller/Video/ThumbnailStatusController.php#L80

Opening parenthesis of a multi-line function call must be the last content on the line
HttpResponseCodes::BAD_REQUEST,
HttpResponseCodes::FORBIDDEN,
HttpResponseCodes::UNAUTHORIZED,
HttpResponseCodes::NOT_FOUND,
])]

Check notice on line 85 in src/Asset/Controller/Video/ThumbnailStatusController.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Controller/Video/ThumbnailStatusController.php#L85

Closing parenthesis of a multi-line function call must be on a line by itself
public function getVideoThumbnailStatus(int $id, string $thumbnailName): JsonResponse
{
$asset = $this->assetService->getAssetElement(
$this->securityService->getCurrentUser(),
$id
);

return $this->jsonResponse(
$this->videoService->getThumbnailStatus($asset, $thumbnailName)
);
}
}
59 changes: 59 additions & 0 deletions src/Asset/Schema/Type/Video/VideoThumbnailStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);

/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

namespace Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video;

use OpenApi\Attributes\Property;
use OpenApi\Attributes\Schema;
use Pimcore\Bundle\StudioBackendBundle\Util\Schema\AdditionalAttributesInterface;
use Pimcore\Bundle\StudioBackendBundle\Util\Trait\AdditionalAttributesTrait;

#[Schema(
schema: 'VideoThumbnailStatus',
title: 'Video Thumbnail Status',
required: ['status'],
type: 'object'
)]
final class VideoThumbnailStatus implements AdditionalAttributesInterface
{
use AdditionalAttributesTrait;

public const string STATUS_FINISHED = 'finished';

public const string STATUS_INPROGRESS = 'inprogress';

public const string STATUS_ERROR = 'error';

public const string STATUS_NOT_STARTED = 'not_started';

public function __construct(

Check notice on line 39 in src/Asset/Schema/Type/Video/VideoThumbnailStatus.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Schema/Type/Video/VideoThumbnailStatus.php#L39

Expected 2 blank lines before function; 1 found
#[Property(
description: 'Conversion status of the requested video thumbnail.',
type: 'string',
enum: [
self::STATUS_FINISHED,
self::STATUS_INPROGRESS,
self::STATUS_ERROR,
self::STATUS_NOT_STARTED,
],
example: self::STATUS_INPROGRESS,
)]
private readonly string $status,
) {
}

Check notice on line 53 in src/Asset/Schema/Type/Video/VideoThumbnailStatus.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Schema/Type/Video/VideoThumbnailStatus.php#L53

Expected 1 blank line before closing function brace; 0 found

Check notice on line 53 in src/Asset/Schema/Type/Video/VideoThumbnailStatus.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Schema/Type/Video/VideoThumbnailStatus.php#L53

Expected 2 blank lines after function; 1 found

public function getStatus(): string
{
return $this->status;
}
}
25 changes: 25 additions & 0 deletions src/Asset/Service/VideoService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
namespace Pimcore\Bundle\StudioBackendBundle\Asset\Service;

use Pimcore\Bundle\StudioBackendBundle\Asset\Event\PreResponse\VideoTypeEvent;
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video\VideoThumbnailStatus;
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video\VideoType;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Bundle\StudioBackendBundle\Util\Constant\ElementTypes;
use Pimcore\Model\Asset;
use Pimcore\Model\Asset\Video as VideoAsset;
use Pimcore\Model\DataObject\ClassDefinition\Data\Video;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

Expand All @@ -25,6 +30,7 @@
{
public function __construct(
private EventDispatcherInterface $eventDispatcher,
private ThumbnailServiceInterface $thumbnailService,
) {
}

Expand All @@ -40,4 +46,23 @@

return $types;
}

public function getThumbnailStatus(Asset $video, string $thumbnailName): VideoThumbnailStatus
{
if (!$video instanceof VideoAsset) {
throw new InvalidElementTypeException($video->getType(), ElementTypes::TYPE_ASSET);

Check failure on line 53 in src/Asset/Service/VideoService.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Service/VideoService.php#L53

All output should be run through an escaping function (see the Security sections in the WordPress Developer Handbooks), found '$video'.
}

$configuration = $this->thumbnailService->getVideoThumbnailConfig($thumbnailName);

// Read the status from the custom setting directly: Asset\Video::getThumbnail() would
// start a conversion as a side effect and returns null for errored conversions,
// which would make the error status unreachable for polling clients.
$customSetting = $video->getCustomSetting('thumbnails');
$status = is_array($customSetting)
? ($customSetting[$configuration->getName()]['status'] ?? VideoThumbnailStatus::STATUS_NOT_STARTED)

Check notice on line 63 in src/Asset/Service/VideoService.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Service/VideoService.php#L63

Expected 1 space before "?"; newline found
: VideoThumbnailStatus::STATUS_NOT_STARTED;

Check notice on line 64 in src/Asset/Service/VideoService.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Service/VideoService.php#L64

Expected 1 space before ":"; newline found

return new VideoThumbnailStatus((string) $status);
}
}
10 changes: 10 additions & 0 deletions src/Asset/Service/VideoServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@

namespace Pimcore\Bundle\StudioBackendBundle\Asset\Service;

use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video\VideoThumbnailStatus;
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video\VideoType;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidThumbnailException;
use Pimcore\Model\Asset;

/**
* @internal
Expand All @@ -24,4 +28,10 @@
* @return VideoType[]
*/
public function getVideoTypes(): array;

/**
* @throws InvalidElementTypeException
* @throws InvalidThumbnailException
*/
public function getThumbnailStatus(Asset $video, string $thumbnailName): VideoThumbnailStatus;

Check notice on line 36 in src/Asset/Service/VideoServiceInterface.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/Asset/Service/VideoServiceInterface.php#L36

Expected 2 blank lines after function; 0 found
}
104 changes: 104 additions & 0 deletions tests/Unit/Asset/Service/VideoServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);

/**
* This source file is available under the terms of the
* Pimcore Open Core License (POCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
* @license Pimcore Open Core License (POCL)
*/

namespace Pimcore\Bundle\StudioBackendBundle\Tests\Unit\Asset\Service;

use Codeception\Test\Unit;
use Exception;
use Pimcore\Bundle\StudioBackendBundle\Asset\Schema\Type\Video\VideoThumbnailStatus;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\ThumbnailServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\VideoService;
use Pimcore\Bundle\StudioBackendBundle\Asset\Service\VideoServiceInterface;
use Pimcore\Bundle\StudioBackendBundle\Exception\Api\InvalidElementTypeException;
use Pimcore\Model\Asset\Document;
use Pimcore\Model\Asset\Video;
use Pimcore\Model\Asset\Video\Thumbnail\Config;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
* @internal
*/
final class VideoServiceTest extends Unit
{
private const string THUMBNAIL_NAME = 'content';

public function testGetThumbnailStatusWithWrongElementType(): void

Check notice on line 35 in tests/Unit/Asset/Service/VideoServiceTest.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Unit/Asset/Service/VideoServiceTest.php#L35

Expected 2 blank lines before function; 1 found
{
$this->expectException(InvalidElementTypeException::class);

$this->getVideoService()->getThumbnailStatus(new Document(), self::THUMBNAIL_NAME);
}

Check notice on line 40 in tests/Unit/Asset/Service/VideoServiceTest.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Unit/Asset/Service/VideoServiceTest.php#L40

Expected 1 blank line before closing function brace; 0 found

Check notice on line 40 in tests/Unit/Asset/Service/VideoServiceTest.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Unit/Asset/Service/VideoServiceTest.php#L40

Expected 2 blank lines after function; 1 found

/**
* @throws Exception
*/
public function testGetThumbnailStatusReturnsStatusFromCustomSetting(): void
{
$video = $this->makeEmpty(Video::class, [

Check notice on line 47 in tests/Unit/Asset/Service/VideoServiceTest.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Unit/Asset/Service/VideoServiceTest.php#L47

Opening parenthesis of a multi-line function call must be the last content on the line
'getCustomSetting' => [
self::THUMBNAIL_NAME => [
'status' => VideoThumbnailStatus::STATUS_ERROR,
],
],
]);

Check notice on line 53 in tests/Unit/Asset/Service/VideoServiceTest.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Unit/Asset/Service/VideoServiceTest.php#L53

Closing parenthesis of a multi-line function call must be on a line by itself

$status = $this->getVideoService()->getThumbnailStatus($video, self::THUMBNAIL_NAME);

$this->assertSame(VideoThumbnailStatus::STATUS_ERROR, $status->getStatus());
}

/**
* @throws Exception
*/
public function testGetThumbnailStatusReturnsNotStartedWithoutCustomSetting(): void
{
$video = $this->makeEmpty(Video::class, [
'getCustomSetting' => null,
]);

$status = $this->getVideoService()->getThumbnailStatus($video, self::THUMBNAIL_NAME);

$this->assertSame(VideoThumbnailStatus::STATUS_NOT_STARTED, $status->getStatus());
}

/**
* @throws Exception
*/
public function testGetThumbnailStatusReturnsNotStartedForUnknownThumbnail(): void
{
$video = $this->makeEmpty(Video::class, [
'getCustomSetting' => [
'other-thumbnail' => [
'status' => VideoThumbnailStatus::STATUS_FINISHED,
],
],
]);

$status = $this->getVideoService()->getThumbnailStatus($video, self::THUMBNAIL_NAME);

$this->assertSame(VideoThumbnailStatus::STATUS_NOT_STARTED, $status->getStatus());
}

private function getVideoService(): VideoServiceInterface
{
$config = new Config();
$config->setName(self::THUMBNAIL_NAME);

return new VideoService(
$this->makeEmpty(EventDispatcherInterface::class),
$this->makeEmpty(ThumbnailServiceInterface::class, [

Check notice on line 99 in tests/Unit/Asset/Service/VideoServiceTest.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Unit/Asset/Service/VideoServiceTest.php#L99

Opening parenthesis of a multi-line function call must be the last content on the line
'getVideoThumbnailConfig' => $config,
]),

Check notice on line 101 in tests/Unit/Asset/Service/VideoServiceTest.php

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Unit/Asset/Service/VideoServiceTest.php#L101

Closing parenthesis of a multi-line function call must be on a line by itself
);
}
}
6 changes: 6 additions & 0 deletions translations/studio_api_docs.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ asset_video_stream_by_thumbnail_description: |
List of <b>thumbnail names</b> can be obtained via the thumbnail video collection endpoint
asset_video_stream_by_thumbnail_success_response: Video stream based on thumbnail name
asset_video_stream_by_thumbnail_summary: Stream video asset by ID and thumbnail name
asset_video_thumbnail_status_description: |
Get the conversion status of a video thumbnail based on the provided <strong>{id}</strong> and <strong>{thumbnailName}</strong>. <br>
The <strong>{id}</strong> must be an ID of existing asset video <br>
List of <b>thumbnail names</b> can be obtained via the thumbnail video collection endpoint
asset_video_thumbnail_status_success_response: Conversion status of the video thumbnail
asset_video_thumbnail_status_summary: Get video thumbnail conversion status by asset ID and thumbnail name
asset_get_search_configuration: Get asset search configuration
asset_get_search_configuration_description: Get asset configuration
asset_get_search_configuration_summary: Get asset search configuration
Expand Down
Loading