From 6761d09ffd490afdd7dd912a853e1bd32cdc555d Mon Sep 17 00:00:00 2001 From: Booyaka101 Date: Fri, 1 May 2026 20:13:34 +0800 Subject: [PATCH] fix: allow empty URL when saving asset profile (#6811) `@IsOptional()` from class-validator only skips validation for `undefined` or `null` - not for empty string `""`. The asset profile dialog submits `url: ""` when the optional URL field is left blank, so `@IsUrl()` runs and the form fails with "url must be a URL address" despite URL being documented as optional. Fix: add a `@Transform` that coerces empty/whitespace-only strings to `undefined`, letting `@IsOptional()` short-circuit the validation chain. Same pattern as the `comment` field in `update-account.dto.ts`. Applied to both `UpdateAssetProfileDto` (the form path in the bug repro) and `CreateAssetProfileDto` (same flaw, same flow). Platform DTOs are left alone since their `url` field is required (not optional). Closes #6811. --- CHANGELOG.md | 4 ++++ libs/common/src/lib/dtos/create-asset-profile.dto.ts | 5 +++++ libs/common/src/lib/dtos/update-asset-profile.dto.ts | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 536453dbf..30cd0b206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgraded `stripe` from version `20.4.1` to `21.0.1` +### Fixed + +- Fixed the asset profile validation to allow saving with an empty URL field + ## 3.1.0 - 2026-04-29 ### Added diff --git a/libs/common/src/lib/dtos/create-asset-profile.dto.ts b/libs/common/src/lib/dtos/create-asset-profile.dto.ts index 85ad73cc0..eb7c59b20 100644 --- a/libs/common/src/lib/dtos/create-asset-profile.dto.ts +++ b/libs/common/src/lib/dtos/create-asset-profile.dto.ts @@ -1,6 +1,7 @@ import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code'; import { AssetClass, AssetSubClass, DataSource, Prisma } from '@prisma/client'; +import { Transform, TransformFnParams } from 'class-transformer'; import { IsArray, IsBoolean, @@ -9,6 +10,7 @@ import { IsString, IsUrl } from 'class-validator'; +import { isString } from 'lodash'; export class CreateAssetProfileDto { @IsEnum(AssetClass, { each: true }) @@ -77,5 +79,8 @@ export class CreateAssetProfileDto { protocols: ['https'], require_protocol: true }) + @Transform(({ value }: TransformFnParams) => + isString(value) && value.trim() === '' ? undefined : value + ) url?: string; } diff --git a/libs/common/src/lib/dtos/update-asset-profile.dto.ts b/libs/common/src/lib/dtos/update-asset-profile.dto.ts index 43f5aa617..5a86d5485 100644 --- a/libs/common/src/lib/dtos/update-asset-profile.dto.ts +++ b/libs/common/src/lib/dtos/update-asset-profile.dto.ts @@ -1,6 +1,7 @@ import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code'; import { AssetClass, AssetSubClass, DataSource, Prisma } from '@prisma/client'; +import { Transform, TransformFnParams } from 'class-transformer'; import { IsArray, IsBoolean, @@ -10,6 +11,7 @@ import { IsString, IsUrl } from 'class-validator'; +import { isString } from 'lodash'; export class UpdateAssetProfileDto { @IsEnum(AssetClass, { each: true }) @@ -67,5 +69,8 @@ export class UpdateAssetProfileDto { protocols: ['https'], require_protocol: true }) + @Transform(({ value }: TransformFnParams) => + isString(value) && value.trim() === '' ? undefined : value + ) url?: string; }