Skip to content

Commit

Permalink
PS-598 fix indexer rendition definition duplicates
Browse files Browse the repository at this point in the history
  • Loading branch information
4rthem committed Dec 21, 2023
1 parent 57281dc commit 41cd0fb
Show file tree
Hide file tree
Showing 21 changed files with 358 additions and 25 deletions.
34 changes: 34 additions & 0 deletions databox/api/migrations/Version20231221125408.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?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 Version20231221125408 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 rendition_definition ADD key VARCHAR(150) DEFAULT NULL');
$this->addSql('CREATE UNIQUE INDEX uniq_rend_def_ws_key ON rendition_definition (workspace_id, key)');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('DROP INDEX uniq_rend_def_ws_key');
$this->addSql('ALTER TABLE rendition_definition DROP key');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

declare(strict_types=1);

namespace App\Api\InputTransformer;

use App\Api\Model\Input\RenditionDefinitionInput;
use App\Entity\Core\RenditionDefinition;
use App\Entity\Core\Workspace;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;

class RenditionDefinitionInputTransformer extends AbstractInputTransformer
{
public function supports(string $resourceClass, object $data): bool
{
return RenditionDefinition::class === $resourceClass && $data instanceof RenditionDefinitionInput;
}

/**
* @param RenditionDefinitionInput $data
*/
public function transform(object $data, string $resourceClass, array $context = []): object|iterable
{
$isNew = !isset($context[AbstractNormalizer::OBJECT_TO_POPULATE]);
/** @var RenditionDefinition $object */
$object = $context[AbstractNormalizer::OBJECT_TO_POPULATE] ?? new RenditionDefinition();

$workspace = null;
if ($data->workspace) {
$workspace = $data->workspace;
}

if ($isNew) {
if (!$workspace instanceof Workspace) {
throw new BadRequestHttpException('Missing workspace');
}

if ($data->key) {
$rendDef = $this->em->getRepository(RenditionDefinition::class)
->findOneBy([
'key' => $data->key,
'workspace' => $workspace->getId()
]);

if ($rendDef) {
$isNew = false;
$object = $rendDef;
}
}
}

if ($isNew) {
$object->setWorkspace($workspace);
$object->setKey($data->key);
}

if (null !== $data->name) {
$object->setName($data->name);
}
if (null !== $data->class) {
$object->setClass($data->class);
}

if (null !== $data->download) {
$object->setDownload($data->download);
}
if (null !== $data->pickSourceFile) {
$object->setPickSourceFile($data->pickSourceFile);
}
if (null !== $data->useAsOriginal) {
$object->setUseAsOriginal($data->useAsOriginal);
}
if (null !== $data->useAsPreview) {
$object->setUseAsPreview($data->useAsPreview);
}
if (null !== $data->useAsThumbnail) {
$object->setUseAsThumbnail($data->useAsThumbnail);
}
if (null !== $data->useAsThumbnailActive) {
$object->setUseAsThumbnailActive($data->useAsThumbnailActive);
}
if (null !== $data->definition) {
$object->setDefinition($data->definition);
}
if (null !== $data->priority) {
$object->setPriority($data->priority);
}

return $object;
}
}
85 changes: 85 additions & 0 deletions databox/api/src/Api/Model/Input/RenditionDefinitionInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

namespace App\Api\Model\Input;

use App\Entity\Core\RenditionClass;
use App\Entity\Core\RenditionDefinition;
use App\Entity\Core\Workspace;
use Symfony\Component\Serializer\Attribute\Groups;

class RenditionDefinitionInput
{
/**
* @var Workspace
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $workspace;

/**
* @var RenditionClass
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $class;

/**
* @var string
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $name;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $download = true;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $pickSourceFile = false;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsOriginal = false;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsPreview = false;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsThumbnail = false;

/**
* @var bool
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $useAsThumbnailActive = false;

/**
* @var string|null
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $definition = '';

/**
* @var int|null
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $priority = null;

/**
* @var string|null
*/
#[Groups([RenditionDefinition::GROUP_WRITE])]
public $key = null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public function configureFields(string $pageName): iterable
$id = IdField::new();
$workspace = AssociationField::new('workspace');
$name = TextField::new('name');
$key = TextField::new('key');
$class = AssociationField::new('class');
$pickSourceFile = Field::new('pickSourceFile');
$useAsOriginal = Field::new('useAsOriginal');
Expand All @@ -59,11 +60,11 @@ public function configureFields(string $pageName): iterable
if (Crud::PAGE_INDEX === $pageName) {
return [$id, $workspace, $name, $class, $pickSourceFile, $useAsOriginal, $useAsPreview, $useAsThumbnail, $useAsThumbnailActive, $priority, $createdAt];
} elseif (Crud::PAGE_DETAIL === $pageName) {
return [$id, $name, $download, $pickSourceFile, $useAsOriginal, $useAsPreview, $useAsThumbnail, $useAsThumbnailActive, $definition, $priority, $createdAt, $updatedAt, $workspace, $class, $renditions];
return [$id, $name, $key, $download, $pickSourceFile, $useAsOriginal, $useAsPreview, $useAsThumbnail, $useAsThumbnailActive, $definition, $priority, $createdAt, $updatedAt, $workspace, $class, $renditions];
} elseif (Crud::PAGE_NEW === $pageName) {
return [$workspace, $name, $class, $pickSourceFile, $useAsOriginal, $useAsPreview, $useAsThumbnail, $useAsThumbnailActive, $priority];
} elseif (Crud::PAGE_EDIT === $pageName) {
return [$workspace, $name, $class, $pickSourceFile, $useAsOriginal, $useAsPreview, $useAsThumbnail, $useAsThumbnailActive, $priority];
return [$workspace, $name, $key, $class, $pickSourceFile, $useAsOriginal, $useAsPreview, $useAsThumbnail, $useAsThumbnailActive, $priority];
}

return [];
Expand Down
19 changes: 19 additions & 0 deletions databox/api/src/Entity/Core/RenditionDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Api\Model\Input\RenditionDefinitionInput;
use App\Api\Provider\RenditionDefinitionCollectionProvider;
use App\Controller\Core\RenditionDefinitionSortAction;
use App\Entity\AbstractUuidEntity;
Expand Down Expand Up @@ -65,12 +66,14 @@
denormalizationContext: [
'groups' => [RenditionDefinition::GROUP_WRITE],
],
input: RenditionDefinitionInput::class,
order: ['priority' => 'DESC'],
provider: RenditionDefinitionCollectionProvider::class,
)]

#[ORM\Table]
#[ORM\Index(columns: ['workspace_id', 'name'], name: 'rend_def_ws_name')]
#[ORM\UniqueConstraint(name: 'uniq_rend_def_ws_key', columns: ['workspace_id', 'key'])]
#[ORM\Entity]
class RenditionDefinition extends AbstractUuidEntity implements \Stringable
{
Expand All @@ -90,6 +93,12 @@ class RenditionDefinition extends AbstractUuidEntity implements \Stringable
#[Groups(['_'])]
protected ?Workspace $workspace = null;

/**
* Unique key by workspace. Used to prevent duplicates.
*/
#[ORM\Column(type: Types::STRING, length: 150, nullable: true)]
private ?string $key = null;

#[Groups([RenditionDefinition::GROUP_LIST, RenditionDefinition::GROUP_READ, RenditionDefinition::GROUP_WRITE])]
#[ORM\Column(type: Types::STRING, length: 80)]
private ?string $name = null;
Expand Down Expand Up @@ -255,4 +264,14 @@ public function setPickSourceFile(bool $pickSourceFile): void
{
$this->pickSourceFile = $pickSourceFile;
}

public function getKey(): ?string
{
return $this->key;
}

public function setKey(?string $key): void
{
$this->key = $key;
}
}
1 change: 1 addition & 0 deletions databox/api/src/Workspace/WorkspaceDuplicateManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ private function copyRenditionDefinitions(Workspace $from, Workspace $to): void
$i->setWorkspace($to);
$i->setClass($classMap[$item->getClass()->getId()]);
$i->setPriority($item->getPriority());
$i->setKey($item->getKey());
$i->setUseAsOriginal($item->isUseAsOriginal());
$i->setUseAsPreview($item->isUseAsPreview());
$i->setUseAsThumbnail($item->isUseAsThumbnail());
Expand Down
3 changes: 2 additions & 1 deletion databox/indexer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"scripts": {
"console": "node dist/console.mjs",
"dev": "nodemon",
"build": "rimraf ./dist && vite build",
"validate": "tsc -p ./tsconfig.check.json",
"build": "pnpm validate && rimraf ./dist && vite build",
"test": "jest",
"sync-databox-types": "generate-api-platform-client --generator typescript http://databox-api src/",
"format": "prettier --ignore-path .gitignore --write \"**/*.+(js|ts|json|cjs|tsx|jsx)\"",
Expand Down
4 changes: 2 additions & 2 deletions databox/indexer/src/alternateUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export function getAlternateUrls(
return alternateUrls.map((c): AlternateUrl => {
return {
type: c.name,
url: c.pathPattern.replace(/\${(.+)}/g, (_m, m1) => {
return dict[m1];
url: c.pathPattern.replace(/\${(.+)}/g, (_m, m1: string) => {
return dict[m1 as keyof typeof dict] as string;
}),
};
});
Expand Down
8 changes: 8 additions & 0 deletions databox/indexer/src/command/commandUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {setLogLevel} from "../lib/logger";
import {CommandCommonOptions} from "../types";

export function applyCommonOptions<O extends CommandCommonOptions>(opts: O): void {
if (opts.debug) {
setLogLevel('debug');
}
}
5 changes: 4 additions & 1 deletion databox/indexer/src/command/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ import {indexers} from '../indexers.js';
import {getLocation} from '../locations.js';
import {consume} from '../databox/entrypoint.js';
import {runServer} from '../server';
import {CommandCommonOptions} from "../types";
import {applyCommonOptions} from "./commandUtil";

export type IndexOptions = {
createNewWorkspace?: boolean;
};
} & CommandCommonOptions;

export default async function indexCommand(
locationName: string,
options: IndexOptions
) {
applyCommonOptions(options);
const location = getLocation(locationName);

const databoxLogger = createLogger('databox');
Expand Down
5 changes: 4 additions & 1 deletion databox/indexer/src/command/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import {runServer} from '../server';
import {IndexLocation} from '../types/config';
import {getConfig} from '../configLoader';
import {watchers} from '../watchers';
import {CommandCommonOptions} from "../types";
import {applyCommonOptions} from "./commandUtil";

export type WatchOptions = {};
export type WatchOptions = {} & CommandCommonOptions;

export default async function watchCommand(options: WatchOptions) {
applyCommonOptions(options);
const mainLogger = createLogger('app');
const databoxLogger = createLogger('databox');

Expand Down
9 changes: 5 additions & 4 deletions databox/indexer/src/configLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function loadConfig(): object {
}

function replaceEnv(str: string): string | boolean | number | undefined {
let transform;
let transform: string | undefined;
let hasEnv = false;
let result: string | undefined = str.replace(
/%env\(([^^)]+)\)%/g,
Expand Down Expand Up @@ -62,8 +62,8 @@ function parseConfig(config: any): any {
if (Array.isArray(config)) {
return config.map(parseConfig);
} else {
const sub = {};
Object.keys(config).forEach(k => {
const sub: Record<string, any> = {};
Object.keys(config).forEach((k: string) => {
sub[k] = parseConfig(config[k]);
});
return sub;
Expand All @@ -84,10 +84,11 @@ export function getConfig(
let p = root;

for (let i = 0; i < parts.length; ++i) {
const k = parts[i];
const k = parts[i] as string;
if (!p.hasOwnProperty(k)) {
return defaultValue;
}
// @ts-expect-error any
p = p[parts[i]];
}

Expand Down
Loading

0 comments on commit 41cd0fb

Please sign in to comment.