Files
immich/server/src/dtos/editing.dto.ts
T
Brandon Wees 3c9fb651d0 feat(server): SyncAssetEditV1 (#26446)
* feat: SyncAssetEditV1

* fix: audit table import

* fix: sql tools table fetch

* fix: medium tests (wip)

* fix: circ dependency

* chore: finalize tests

* chore: codegen/lint

* fix: code review
2026-02-25 18:12:41 +00:00

112 lines
3.1 KiB
TypeScript

import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { ArrayMinSize, IsEnum, IsInt, Min, ValidateNested } from 'class-validator';
import { IsAxisAlignedRotation, IsUniqueEditActions, ValidateEnum, ValidateUUID } from 'src/validation';
export enum AssetEditAction {
Crop = 'crop',
Rotate = 'rotate',
Mirror = 'mirror',
}
export enum MirrorAxis {
Horizontal = 'horizontal',
Vertical = 'vertical',
}
export class CropParameters {
@IsInt()
@Min(0)
@ApiProperty({ description: 'Top-Left X coordinate of crop' })
x!: number;
@IsInt()
@Min(0)
@ApiProperty({ description: 'Top-Left Y coordinate of crop' })
y!: number;
@IsInt()
@Min(1)
@ApiProperty({ description: 'Width of the crop' })
width!: number;
@IsInt()
@Min(1)
@ApiProperty({ description: 'Height of the crop' })
height!: number;
}
export class RotateParameters {
@IsAxisAlignedRotation()
@ApiProperty({ description: 'Rotation angle in degrees' })
angle!: number;
}
export class MirrorParameters {
@IsEnum(MirrorAxis)
@ApiProperty({ enum: MirrorAxis, enumName: 'MirrorAxis', description: 'Axis to mirror along' })
axis!: MirrorAxis;
}
export type AssetEditParameters = CropParameters | RotateParameters | MirrorParameters;
export type AssetEditActionItem =
| {
action: AssetEditAction.Crop;
parameters: CropParameters;
}
| {
action: AssetEditAction.Rotate;
parameters: RotateParameters;
}
| {
action: AssetEditAction.Mirror;
parameters: MirrorParameters;
};
@ApiExtraModels(CropParameters, RotateParameters, MirrorParameters)
export class AssetEditActionItemDto {
@ValidateEnum({ name: 'AssetEditAction', enum: AssetEditAction, description: 'Type of edit action to perform' })
action!: AssetEditAction;
@ApiProperty({
description: 'List of edit actions to apply (crop, rotate, or mirror)',
anyOf: [CropParameters, RotateParameters, MirrorParameters].map((type) => ({
$ref: getSchemaPath(type),
})),
})
@ValidateNested()
@Type((options) => actionParameterMap[options?.object.action as keyof AssetEditActionParameter])
parameters!: AssetEditActionItem['parameters'];
}
export class AssetEditActionItemResponseDto extends AssetEditActionItemDto {
@ValidateUUID()
id!: string;
}
export type AssetEditActionParameter = typeof actionParameterMap;
const actionParameterMap = {
[AssetEditAction.Crop]: CropParameters,
[AssetEditAction.Rotate]: RotateParameters,
[AssetEditAction.Mirror]: MirrorParameters,
};
export class AssetEditsCreateDto {
@ArrayMinSize(1)
@IsUniqueEditActions()
@ValidateNested({ each: true })
@Type(() => AssetEditActionItemDto)
@ApiProperty({ description: 'List of edit actions to apply (crop, rotate, or mirror)' })
edits!: AssetEditActionItemDto[];
}
export class AssetEditsResponseDto {
@ValidateUUID({ description: 'Asset ID these edits belong to' })
assetId!: string;
@ApiProperty({
description: 'List of edit actions applied to the asset',
})
edits!: AssetEditActionItemResponseDto[];
}