Skip to content

Commit

Permalink
PS-698 add rendition substitution, projection and lock (#470)
Browse files Browse the repository at this point in the history
* PS-698 add rendition substitution, projection and lock

* remove projection from transformation context
  • Loading branch information
4rthem authored Oct 30, 2024
1 parent 34133bf commit ce359b0
Show file tree
Hide file tree
Showing 31 changed files with 246 additions and 44 deletions.
33 changes: 33 additions & 0 deletions databox/api/migrations/Version20241023151611.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20241023151611 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE asset_rendition ADD locked BOOLEAN NOT NULL DEFAULT FALSE');
$this->addSql('ALTER TABLE asset_rendition ADD substituted BOOLEAN NOT NULL DEFAULT FALSE');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE asset_rendition DROP locked');
$this->addSql('ALTER TABLE asset_rendition DROP substituted');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@

namespace App\Api\InputTransformer;

use App\Api\Model\Input\RenditionInput;
use App\Api\Model\Input\AssetRenditionInput;
use App\Consumer\Handler\File\CopyFileToRendition;
use App\Entity\Core\Asset;
use App\Entity\Core\AssetRendition;
use App\Entity\Core\RenditionDefinition;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;

class RenditionInputTransformer extends AbstractFileInputTransformer
class AssetRenditionInputTransformer extends AbstractFileInputTransformer
{
public function supports(string $resourceClass, object $data): bool
{
return AssetRendition::class === $resourceClass && $data instanceof RenditionInput;
return AssetRendition::class === $resourceClass && $data instanceof AssetRenditionInput;
}

/**
* @param RenditionInput $data
* @param AssetRenditionInput $data
*/
public function transform(object $data, string $resourceClass, array $context = []): object|iterable
{
Expand All @@ -39,12 +39,21 @@ public function transform(object $data, string $resourceClass, array $context =
}

$object = $this->renditionManager->getOrCreateRendition($asset, $definition);
if ($object->isLocked()) {
throw new BadRequestHttpException('Cannot update locked rendition');
}

if ($object->isSubstituted() && !$data->force) {
throw new BadRequestHttpException('Cannot update rendition that has been substituted without the "force" parameter');
}
}

if (!$object->getDefinition()->isSubstitutable()) {
throw new BadRequestHttpException(sprintf('Cannot substitute rendition "%s"', $object->getDefinition()->getName()));
}

$object->setSubstituted($data->substituted);

$workspace = $object->getAsset()->getWorkspace();

if (null !== $file = $this->handleSource($data->sourceFile, $workspace)) {
Expand Down
2 changes: 1 addition & 1 deletion databox/api/src/Api/Model/Input/AssetInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class AssetInput extends AbstractOwnerIdInput
public $relationship;

/**
* @var RenditionInput[]
* @var AssetRenditionInput[]
*/
public ?array $renditions = null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace App\Api\Model\Input;

class RenditionInput
class AssetRenditionInput
{
/**
* Rendition definition ID. Or provide name.
Expand All @@ -31,4 +31,8 @@ class RenditionInput
* @var string|null
*/
public $sourceFileId;

public $substituted;

public $force;
}
9 changes: 9 additions & 0 deletions databox/api/src/Api/Model/Output/AssetRenditionOutput.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ class AssetRenditionOutput extends AbstractUuidOutput
#[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ, Share::GROUP_PUBLIC_READ])]
public ?string $name = null;

#[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])]
public ?bool $projection = null;

#[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])]
public ?bool $dirty = null;

#[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])]
public bool $locked = false;

#[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])]
public bool $substituted = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public function transform($data, string $outputClass, array &$context = []): obj
$output->definition = $definition;
$output->file = $data->getFile();
$output->name = $data->getName();
$output->projection = $data->getProjection();
$output->locked = $data->isLocked();
$output->substituted = $data->isSubstituted();

if ($this->hasGroup([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ], $context)) {
$output->dirty = $this->renditionBuildHashManager->isRenditionDirty($data);
Expand Down
10 changes: 10 additions & 0 deletions databox/api/src/Asset/RenditionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public function __construct(

public function buildRendition(RenditionDefinition $renditionDefinition, Asset $asset, bool $force = false): void
{
$isProjection = true;
if ($asset->getWorkspaceId() !== $renditionDefinition->getWorkspaceId()) {
throw new \LogicException(sprintf('Asset "%s" and rendition definition "%s" are not in the same workspace', $asset->getId(), $renditionDefinition->getId()));
}
Expand All @@ -44,6 +45,9 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $
throw new \LogicException(sprintf('Parent rendition "%s" not found for asset "%s"', $parentDefinition->getName(), $asset->getId()));
}

if (false === $parentRendition->getProjection()) {
$isProjection = false;
}
$source = $parentRendition->getFile();
} else {
$source = $asset->getSource();
Expand All @@ -59,6 +63,7 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $
$source,
null,
null,
projection: $isProjection,
);
$this->em->flush();

Expand Down Expand Up @@ -87,6 +92,10 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $
}

if (null !== $outputFile) {
if (!$outputFile->isProjection()) {
$isProjection = false;
}

$file = $this->fileManager->createFileFromPath(
$asset->getWorkspace(),
$outputFile->getPath(),
Expand All @@ -102,6 +111,7 @@ public function buildRendition(RenditionDefinition $renditionDefinition, Asset $
$file,
$buildHash,
$outputFile?->getBuildHashes(),
projection: $isProjection,
);
$this->em->flush();
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ public function configureFields(string $pageName): iterable
yield AssociationField::new('file');
yield BooleanField::new('ready')
->renderAsSwitch(false);
yield BooleanField::new('locked');
yield BooleanField::new('substituted');
yield BooleanField::new('projection')
->renderAsSwitch(false);
yield DateTimeField::new('updatedAt')
->hideOnForm();
yield DateTimeField::new('createdAt')
Expand Down
37 changes: 31 additions & 6 deletions databox/api/src/Entity/Core/AssetRendition.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Api\Model\Input\RenditionInput;
use App\Api\Model\Input\AssetRenditionInput;
use App\Api\Model\Output\AssetRenditionOutput;
use App\Api\Provider\RenditionCollectionProvider;
use App\Entity\Traits\CreatedAtTrait;
Expand All @@ -22,7 +22,6 @@
use App\Security\Voter\AbstractVoter;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

#[ApiResource(
shortName: 'rendition',
Expand Down Expand Up @@ -113,7 +112,7 @@
normalizationContext: [
'groups' => [AssetRendition::GROUP_LIST],
],
input: RenditionInput::class,
input: AssetRenditionInput::class,
output: AssetRenditionOutput::class,
provider: RenditionCollectionProvider::class,
)]
Expand Down Expand Up @@ -142,10 +141,18 @@ class AssetRendition extends AbstractUuidEntity
/**
* Homothetic and same format has original.
*/
#[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ])]
#[ORM\Column(type: Types::BOOLEAN, nullable: true)]
private ?bool $projection = null;

/**
* Rendition cannot be substituted.
*/
#[ORM\Column(type: Types::BOOLEAN)]
private bool $locked = false;

#[ORM\Column(type: Types::BOOLEAN)]
private bool $substituted = false;

/**
* Hash based on the build process.
*/
Expand Down Expand Up @@ -189,8 +196,6 @@ public function setDefinition(RenditionDefinition $definition): void
$this->definition = $definition;
}

#[ApiProperty]
#[Groups([AssetRendition::GROUP_LIST, AssetRendition::GROUP_READ, Asset::GROUP_LIST, Asset::GROUP_READ])]
public function getName(): string
{
return $this->definition->getName();
Expand Down Expand Up @@ -230,4 +235,24 @@ public function setModuleHashes(?array $moduleHashes): void
{
$this->moduleHashes = $moduleHashes;
}

public function isLocked(): bool
{
return $this->locked;
}

public function setLocked(bool $locked): void
{
$this->locked = $locked;
}

public function isSubstituted(): bool
{
return $this->substituted;
}

public function setSubstituted(bool $substituted): void
{
$this->substituted = $substituted;
}
}
24 changes: 23 additions & 1 deletion databox/api/src/Storage/RenditionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,41 @@ public function createOrReplaceRenditionByPath(
);
}

/**
* @param bool $force Force replace a substitution
*/
public function createOrReplaceRenditionFile(
Asset $asset,
RenditionDefinition $definition,
File $file,
?string $buildHash,
?array $moduleHashes,
bool $substituted = false,
bool $locked = false,
bool $force = false,
?bool $projection = null,
): AssetRendition {
if (null === $asset->getSource() && $definition->isUseAsOriginal()) {
$asset->setSource($file);
$this->em->persist($asset);
}

$rendition = $this->getOrCreateRendition($asset, $definition);

if ($rendition->isLocked()) {
throw new \InvalidArgumentException(sprintf('Rendition "%s" is locked', $definition->getName()));
}

if ($rendition->isSubstituted() && !$force) {
throw new \InvalidArgumentException(sprintf('Rendition "%s" is a substitution and cannot be replaced without the "force" option', $definition->getName()));
}

$rendition->setFile($file);
$rendition->setBuildHash($buildHash);
$rendition->setModuleHashes($moduleHashes);
$rendition->setSubstituted($substituted);
$rendition->setLocked($locked);
$rendition->setProjection($projection);
$this->em->persist($rendition);

$this->postFlushStack->addBusMessage($this->pusherManager->createBusMessage(
Expand All @@ -85,7 +104,10 @@ public function createOrReplaceRenditionFile(
return $rendition;
}

public function getOrCreateRendition(Asset $asset, RenditionDefinition $definition): AssetRendition
public function getOrCreateRendition(
Asset $asset,
RenditionDefinition $definition
): AssetRendition
{
if (null !== $assetRendition = $this->getAssetRenditionByDefinition($asset, $definition)) {
return $assetRendition;
Expand Down
2 changes: 2 additions & 0 deletions databox/client/src/api/rendition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type RenditionInput = {
definitionId?: string | undefined;
sourceFileId?: string | undefined;
assetId: string;
substituted?: boolean;
force?: boolean;
};

export async function postRendition(
Expand Down
16 changes: 16 additions & 0 deletions databox/client/src/components/Dialog/Asset/InfoAsset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import InfoRow from '../Info/InfoRow';
import {useTranslation} from 'react-i18next';
import BusinessIcon from '@mui/icons-material/Business';
import FolderIcon from '@mui/icons-material/Folder';
import {useNavigateToModal} from "../../Routing/ModalLink.tsx";
import {modalRoutes} from "../../../routes.ts";

type Props = {
data: Asset;
} & DialogTabProps;

export default function InfoAsset({data, onClose, minHeight}: Props) {
const {t} = useTranslation();
const navigateToModal = useNavigateToModal();

return (
<ContentTab onClose={onClose} minHeight={minHeight}>
<MenuList>
Expand Down Expand Up @@ -61,6 +65,12 @@ export default function InfoAsset({data, onClose, minHeight}: Props) {
label={t('asset.info.workspace', `Workspace`)}
value={data.workspace.name}
copyValue={data.workspace.id}
onClick={() => {
navigateToModal(modalRoutes.workspaces.routes.manage, {
id: data.workspace.id,
tab: 'info',
});
}}
/>
<InfoRow
icon={<FolderIcon />}
Expand All @@ -70,6 +80,12 @@ export default function InfoAsset({data, onClose, minHeight}: Props) {
t('asset.info.collection.none', 'None')
}
copyValue={data.referenceCollection?.id}
onClick={data.referenceCollection ? () => {
navigateToModal(modalRoutes.collections.routes.manage, {
id: data.referenceCollection!.id,
tab: 'info',
});
} : undefined}
/>
</MenuList>
</ContentTab>
Expand Down
Loading

0 comments on commit ce359b0

Please sign in to comment.