diff --git a/server/src/dtos/search.dto.ts b/server/src/dtos/search.dto.ts index ac7bf4feb2..5f8b018afe 100644 --- a/server/src/dtos/search.dto.ts +++ b/server/src/dtos/search.dto.ts @@ -6,7 +6,7 @@ import { PropertyLifecycle } from 'src/decorators'; import { AlbumResponseDto } from 'src/dtos/album.dto'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AssetOrder, AssetType, AssetVisibility } from 'src/enum'; -import { Optional, ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation'; +import { Optional, ValidateBoolean, ValidateDate, ValidateEnum, ValidateString, ValidateUUID } from 'src/validation'; class BaseSearchDto { @ValidateUUID({ optional: true, nullable: true }) @@ -144,9 +144,7 @@ export class MetadataSearchDto extends RandomSearchDto { @Optional() deviceAssetId?: string; - @IsString() - @IsNotEmpty() - @Optional() + @ValidateString({ optional: true, trim: true }) description?: string; @IsString() @@ -154,9 +152,7 @@ export class MetadataSearchDto extends RandomSearchDto { @Optional() checksum?: string; - @IsString() - @IsNotEmpty() - @Optional() + @ValidateString({ optional: true, trim: true }) originalFileName?: string; @IsString() @@ -190,16 +186,12 @@ export class MetadataSearchDto extends RandomSearchDto { } export class StatisticsSearchDto extends BaseSearchDto { - @IsString() - @IsNotEmpty() - @Optional() + @ValidateString({ optional: true, trim: true }) description?: string; } export class SmartSearchDto extends BaseSearchWithResultsDto { - @IsString() - @IsNotEmpty() - @Optional() + @ValidateString({ optional: true, trim: true }) query?: string; @ValidateUUID({ optional: true }) diff --git a/server/src/validation.ts b/server/src/validation.ts index e583f6a44e..6d4bbfbe36 100644 --- a/server/src/validation.ts +++ b/server/src/validation.ts @@ -211,6 +211,18 @@ export const ValidateDate = (options?: DateOptions & ApiPropertyOptions) => { return applyDecorators(...decorators); }; +type StringOptions = { optional?: boolean; nullable?: boolean; trim?: boolean }; +export const ValidateString = (options?: StringOptions & ApiPropertyOptions) => { + const { optional, nullable, trim, ...apiPropertyOptions } = options || {}; + const decorators = [ApiProperty(apiPropertyOptions), IsString(), optional ? Optional({ nullable }) : IsNotEmpty()]; + + if (trim) { + decorators.push(Transform(({ value }: { value: string }) => value?.trim())); + } + + return applyDecorators(...decorators); +}; + type BooleanOptions = { optional?: boolean; nullable?: boolean }; export const ValidateBoolean = (options?: BooleanOptions & ApiPropertyOptions) => { const { optional, nullable, ...apiPropertyOptions } = options || {};