add dto validation and swagger schemas

This commit is contained in:
2026-05-12 16:17:39 +03:30
parent abb387e743
commit 460537090b
21 changed files with 510 additions and 0 deletions
+30
View File
@@ -557,6 +557,11 @@
"undici-types": "~6.21.0" "undici-types": "~6.21.0"
} }
}, },
"@types/validator": {
"version": "13.15.10",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz",
"integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA=="
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
@@ -1083,6 +1088,21 @@
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"dev": true "dev": true
}, },
"class-transformer": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
},
"class-validator": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.15.1.tgz",
"integrity": "sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==",
"requires": {
"@types/validator": "^13.15.3",
"libphonenumber-js": "^1.11.1",
"validator": "^13.15.22"
}
},
"cli-cursor": { "cli-cursor": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -2247,6 +2267,11 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"libphonenumber-js": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.13.1.tgz",
"integrity": "sha512-GEw0GLL7YUUA6nv21IsCvVjtI5Ejn84sjbdfQ9KxdbqEVOk1PZh7xejn01EEiniKw+dBeCfim+8MGeuvVuE2BA=="
},
"lines-and-columns": { "lines-and-columns": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -3476,6 +3501,11 @@
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true "dev": true
}, },
"validator": {
"version": "13.15.35",
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz",
"integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw=="
},
"vary": { "vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+2
View File
@@ -20,6 +20,8 @@
"@nestjs/platform-express": "^10.4.8", "@nestjs/platform-express": "^10.4.8",
"@nestjs/swagger": "^7.4.2", "@nestjs/swagger": "^7.4.2",
"@nestjs/typeorm": "^10.0.2", "@nestjs/typeorm": "^10.0.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.15.1",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"pg": "^8.13.1", "pg": "^8.13.1",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
+9
View File
@@ -1,10 +1,19 @@
import 'reflect-metadata'; import 'reflect-metadata';
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
forbidNonWhitelisted: true,
transform: true,
whitelist: true,
}),
);
const swaggerConfig = new DocumentBuilder() const swaggerConfig = new DocumentBuilder()
.setTitle('Montime API') .setTitle('Montime API')
.setDescription('Local services super app API') .setDescription('Local services super app API')
@@ -1,13 +1,53 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
IsArray,
IsBoolean,
IsEnum,
IsOptional,
IsString,
IsUUID,
Matches,
MaxLength,
} from 'class-validator';
import { AttributeType } from '../../../entities/attribute-definition.entity'; import { AttributeType } from '../../../entities/attribute-definition.entity';
export class CreateAttributeDefinitionDto { export class CreateAttributeDefinitionDto {
@ApiProperty({ example: 'Has Waiting Room' })
@IsString()
@MaxLength(120)
title!: string; title!: string;
/** یکتا در محدوده همان دسته شغلی */ /** یکتا در محدوده همان دسته شغلی */
@ApiProperty({ example: 'has-waiting-room' })
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'key must be lowercase words separated by hyphens',
})
key!: string; key!: string;
@ApiProperty({ enum: AttributeType, example: AttributeType.BOOLEAN })
@IsEnum(AttributeType)
type!: AttributeType; type!: AttributeType;
@ApiProperty({ format: 'uuid' })
@IsUUID()
categoryId!: string; categoryId!: string;
/** برای type=select آرایه گزینه‌ها */ /** برای type=select آرایه گزینه‌ها */
@ApiPropertyOptional({ type: [String], example: ['small', 'medium', 'large'] })
@IsOptional()
@IsArray()
@IsString({ each: true })
options?: string[]; options?: string[];
@ApiPropertyOptional({ example: false })
@IsOptional()
@IsBoolean()
required?: boolean; required?: boolean;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isFilterable?: boolean; isFilterable?: boolean;
} }
@@ -1,11 +1,59 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import {
IsArray,
IsBoolean,
IsEnum,
IsOptional,
IsString,
IsUUID,
Matches,
MaxLength,
} from 'class-validator';
import { AttributeType } from '../../../entities/attribute-definition.entity'; import { AttributeType } from '../../../entities/attribute-definition.entity';
export class UpdateAttributeDefinitionDto { export class UpdateAttributeDefinitionDto {
@ApiPropertyOptional({ example: 'Has Waiting Room' })
@IsOptional()
@IsString()
@MaxLength(120)
title?: string; title?: string;
@ApiPropertyOptional({ example: 'has-waiting-room' })
@IsOptional()
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'key must be lowercase words separated by hyphens',
})
key?: string; key?: string;
@ApiPropertyOptional({ enum: AttributeType, example: AttributeType.BOOLEAN })
@IsOptional()
@IsEnum(AttributeType)
type?: AttributeType; type?: AttributeType;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID()
categoryId?: string; categoryId?: string;
@ApiPropertyOptional({
type: [String],
example: ['small', 'medium', 'large'],
nullable: true,
})
@IsOptional()
@IsArray()
@IsString({ each: true })
options?: string[] | null; options?: string[] | null;
@ApiPropertyOptional({ example: false })
@IsOptional()
@IsBoolean()
required?: boolean; required?: boolean;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isFilterable?: boolean; isFilterable?: boolean;
} }
+8
View File
@@ -1,3 +1,11 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, Matches } from 'class-validator';
export class RequestOtpDto { export class RequestOtpDto {
@ApiProperty({ example: '09122222222' })
@IsString()
@Matches(/^(\+?\d{10,15}|09\d{9})$/, {
message: 'mobile must be a valid mobile number',
})
mobile!: string; mobile!: string;
} }
+14
View File
@@ -1,4 +1,18 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, Matches } from 'class-validator';
export class VerifyOtpDto { export class VerifyOtpDto {
@ApiProperty({ example: '09122222222' })
@IsString()
@Matches(/^(\+?\d{10,15}|09\d{9})$/, {
message: 'mobile must be a valid mobile number',
})
mobile!: string; mobile!: string;
@ApiProperty({ example: '123456' })
@IsString()
@Matches(/^\d{4,8}$/, {
message: 'code must be 4 to 8 digits',
})
code!: string; code!: string;
} }
@@ -1,8 +1,27 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsISO8601, IsOptional, IsString, IsUUID, MaxLength } from 'class-validator';
export class CreateBookingDto { export class CreateBookingDto {
@ApiProperty({ format: 'uuid' })
@IsUUID()
customerId!: string; customerId!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
businessId!: string; businessId!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
businessServiceId!: string; businessServiceId!: string;
/** ISO 8601 datetime string */ /** ISO 8601 datetime string */
@ApiProperty({ example: '2026-05-13T10:00:00.000Z' })
@IsISO8601()
scheduledAt!: string; scheduledAt!: string;
@ApiPropertyOptional({ example: 'Test booking', nullable: true })
@IsOptional()
@IsString()
@MaxLength(500)
note?: string | null; note?: string | null;
} }
@@ -1,7 +1,21 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsEnum, IsISO8601, IsOptional, IsString, MaxLength } from 'class-validator';
import { BookingStatus } from '../../../entities/booking.entity'; import { BookingStatus } from '../../../entities/booking.entity';
export class UpdateBookingDto { export class UpdateBookingDto {
@ApiPropertyOptional({ example: '2026-05-13T10:00:00.000Z' })
@IsOptional()
@IsISO8601()
scheduledAt?: string; scheduledAt?: string;
@ApiPropertyOptional({ enum: BookingStatus, example: BookingStatus.CONFIRMED })
@IsOptional()
@IsEnum(BookingStatus)
status?: BookingStatus; status?: BookingStatus;
@ApiPropertyOptional({ example: 'Customer asked for morning slot', nullable: true })
@IsOptional()
@IsString()
@MaxLength(500)
note?: string | null; note?: string | null;
} }
@@ -1,6 +1,19 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString, IsUUID, MaxLength } from 'class-validator';
export class CreateBusinessAttributeValueDto { export class CreateBusinessAttributeValueDto {
@ApiProperty({ format: 'uuid' })
@IsUUID()
businessId!: string; businessId!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
attributeDefinitionId!: string; attributeDefinitionId!: string;
/** مقدار به صورت رشته ذخیره می‌شود؛ برای boolean مثلا true/false */ /** مقدار به صورت رشته ذخیره می‌شود؛ برای boolean مثلا true/false */
@ApiPropertyOptional({ example: 'true', nullable: true })
@IsOptional()
@IsString()
@MaxLength(500)
value?: string | null; value?: string | null;
} }
@@ -1,3 +1,10 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString, MaxLength } from 'class-validator';
export class UpdateBusinessAttributeValueDto { export class UpdateBusinessAttributeValueDto {
@ApiPropertyOptional({ example: 'true', nullable: true })
@IsOptional()
@IsString()
@MaxLength(500)
value?: string | null; value?: string | null;
} }
@@ -1,5 +1,22 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsBoolean, IsOptional, IsString, Matches, MaxLength } from 'class-validator';
export class CreateBusinessCategoryDto { export class CreateBusinessCategoryDto {
@ApiProperty({ example: 'Car Wash' })
@IsString()
@MaxLength(150)
title!: string; title!: string;
@ApiProperty({ example: 'car-wash' })
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'slug must be lowercase words separated by hyphens',
})
slug!: string; slug!: string;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
@@ -1,5 +1,24 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsBoolean, IsOptional, IsString, Matches, MaxLength } from 'class-validator';
export class UpdateBusinessCategoryDto { export class UpdateBusinessCategoryDto {
@ApiPropertyOptional({ example: 'Car Wash' })
@IsOptional()
@IsString()
@MaxLength(150)
title?: string; title?: string;
@ApiPropertyOptional({ example: 'car-wash' })
@IsOptional()
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'slug must be lowercase words separated by hyphens',
})
slug?: string; slug?: string;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
@@ -1,9 +1,31 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsBoolean, IsInt, IsNumber, IsOptional, IsUUID, Max, Min } from 'class-validator';
export class CreateBusinessServiceDto { export class CreateBusinessServiceDto {
@ApiProperty({ format: 'uuid' })
@IsUUID()
businessId!: string; businessId!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
serviceTemplateId!: string; serviceTemplateId!: string;
/** قیمت به واحد پول (عدد اعشاری مجاز است) */ /** قیمت به واحد پول (عدد اعشاری مجاز است) */
@ApiProperty({ example: 100000 })
@IsNumber({ maxDecimalPlaces: 2 })
@Min(0)
price!: number; price!: number;
/** اگر خالی باشد از template.defaultDurationMinutes استفاده می‌شود */ /** اگر خالی باشد از template.defaultDurationMinutes استفاده می‌شود */
@ApiPropertyOptional({ example: 30, nullable: true })
@IsOptional()
@IsInt()
@Min(1)
@Max(1440)
durationMinutes?: number | null; durationMinutes?: number | null;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
@@ -1,6 +1,27 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsBoolean, IsInt, IsNumber, IsOptional, IsUUID, Max, Min } from 'class-validator';
export class UpdateBusinessServiceDto { export class UpdateBusinessServiceDto {
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID()
serviceTemplateId?: string; serviceTemplateId?: string;
@ApiPropertyOptional({ example: 100000 })
@IsOptional()
@IsNumber({ maxDecimalPlaces: 2 })
@Min(0)
price?: number; price?: number;
@ApiPropertyOptional({ example: 30, nullable: true })
@IsOptional()
@IsInt()
@Min(1)
@Max(1440)
durationMinutes?: number | null; durationMinutes?: number | null;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
@@ -1,4 +1,17 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString, Matches, MaxLength } from 'class-validator';
export class AssignBusinessOwnerDto { export class AssignBusinessOwnerDto {
@ApiProperty({ example: '09111111111' })
@IsString()
@Matches(/^(\+?\d{10,15}|09\d{9})$/, {
message: 'mobile must be a valid mobile number',
})
mobile!: string; mobile!: string;
@ApiPropertyOptional({ example: 'Business Admin', nullable: true })
@IsOptional()
@IsString()
@MaxLength(150)
fullName?: string | null; fullName?: string | null;
} }
@@ -1,12 +1,68 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
IsBoolean,
IsLatitude,
IsLongitude,
IsOptional,
IsString,
IsUUID,
Matches,
MaxLength,
} from 'class-validator';
export class CreateBusinessDto { export class CreateBusinessDto {
@ApiProperty({ example: 'Shine Carwash' })
@IsString()
@MaxLength(150)
title!: string; title!: string;
@ApiProperty({ example: 'shine-carwash' })
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'slug must be lowercase words separated by hyphens',
})
slug!: string; slug!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
categoryId!: string; categoryId!: string;
@ApiPropertyOptional({ example: 'Premium carwash service' })
@IsOptional()
@IsString()
@MaxLength(500)
description?: string; description?: string;
@ApiPropertyOptional({ example: '09123456789' })
@IsOptional()
@IsString()
@MaxLength(20)
contactPhone?: string; contactPhone?: string;
@ApiPropertyOptional({ example: 'Main street' })
@IsOptional()
@IsString()
@MaxLength(500)
address?: string; address?: string;
@ApiPropertyOptional({ example: 35.6892 })
@IsOptional()
@IsLatitude()
latitude?: number; latitude?: number;
@ApiPropertyOptional({ example: 51.389 })
@IsOptional()
@IsLongitude()
longitude?: number; longitude?: number;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID()
ownerId?: string; ownerId?: string;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
@@ -1,12 +1,71 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import {
IsBoolean,
IsLatitude,
IsLongitude,
IsOptional,
IsString,
IsUUID,
Matches,
MaxLength,
} from 'class-validator';
export class UpdateBusinessDto { export class UpdateBusinessDto {
@ApiPropertyOptional({ example: 'Shine Carwash' })
@IsOptional()
@IsString()
@MaxLength(150)
title?: string; title?: string;
@ApiPropertyOptional({ example: 'shine-carwash' })
@IsOptional()
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'slug must be lowercase words separated by hyphens',
})
slug?: string; slug?: string;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID()
categoryId?: string; categoryId?: string;
@ApiPropertyOptional({ example: 'Premium carwash service', nullable: true })
@IsOptional()
@IsString()
@MaxLength(500)
description?: string | null; description?: string | null;
@ApiPropertyOptional({ example: '09123456789', nullable: true })
@IsOptional()
@IsString()
@MaxLength(20)
contactPhone?: string | null; contactPhone?: string | null;
@ApiPropertyOptional({ example: 'Main street', nullable: true })
@IsOptional()
@IsString()
@MaxLength(500)
address?: string | null; address?: string | null;
@ApiPropertyOptional({ example: 35.6892, nullable: true })
@IsOptional()
@IsLatitude()
latitude?: number | null; latitude?: number | null;
@ApiPropertyOptional({ example: 51.389, nullable: true })
@IsOptional()
@IsLongitude()
longitude?: number | null; longitude?: number | null;
@ApiPropertyOptional({ format: 'uuid', nullable: true })
@IsOptional()
@IsUUID()
ownerId?: string | null; ownerId?: string | null;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
@@ -1,8 +1,49 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
IsBoolean,
IsInt,
IsOptional,
IsString,
IsUUID,
Matches,
Max,
MaxLength,
Min,
} from 'class-validator';
export class CreateServiceTemplateDto { export class CreateServiceTemplateDto {
@ApiProperty({ example: 'Basic Wash' })
@IsString()
@MaxLength(150)
title!: string; title!: string;
@ApiProperty({ example: 'basic-wash' })
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'slug must be lowercase words separated by hyphens',
})
slug!: string; slug!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
categoryId!: string; categoryId!: string;
@ApiPropertyOptional({ example: 'Exterior wash' })
@IsOptional()
@IsString()
@MaxLength(500)
description?: string; description?: string;
@ApiPropertyOptional({ example: 30 })
@IsOptional()
@IsInt()
@Min(1)
@Max(1440)
defaultDurationMinutes?: number; defaultDurationMinutes?: number;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
@@ -1,8 +1,52 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import {
IsBoolean,
IsInt,
IsOptional,
IsString,
IsUUID,
Matches,
Max,
MaxLength,
Min,
} from 'class-validator';
export class UpdateServiceTemplateDto { export class UpdateServiceTemplateDto {
@ApiPropertyOptional({ example: 'Basic Wash' })
@IsOptional()
@IsString()
@MaxLength(150)
title?: string; title?: string;
@ApiPropertyOptional({ example: 'basic-wash' })
@IsOptional()
@IsString()
@MaxLength(120)
@Matches(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, {
message: 'slug must be lowercase words separated by hyphens',
})
slug?: string; slug?: string;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID()
categoryId?: string; categoryId?: string;
@ApiPropertyOptional({ example: 'Exterior wash', nullable: true })
@IsOptional()
@IsString()
@MaxLength(500)
description?: string | null; description?: string | null;
@ApiPropertyOptional({ example: 30 })
@IsOptional()
@IsInt()
@Min(1)
@Max(1440)
defaultDurationMinutes?: number; defaultDurationMinutes?: number;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }
+14
View File
@@ -1,7 +1,21 @@
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsBoolean, IsEnum, IsOptional, IsString, MaxLength } from 'class-validator';
import { UserRole } from '../../../entities/user.entity'; import { UserRole } from '../../../entities/user.entity';
export class UpdateUserDto { export class UpdateUserDto {
@ApiPropertyOptional({ example: 'Mahdi', nullable: true })
@IsOptional()
@IsString()
@MaxLength(150)
fullName?: string | null; fullName?: string | null;
@ApiPropertyOptional({ enum: UserRole, example: UserRole.BUSINESS_OWNER })
@IsOptional()
@IsEnum(UserRole)
role?: UserRole; role?: UserRole;
@ApiPropertyOptional({ example: true })
@IsOptional()
@IsBoolean()
isActive?: boolean; isActive?: boolean;
} }