import { Type } from 'class-transformer'; import { PartialType } from '@nestjs/swagger'; import { ArrayMaxSize, IsArray, IsBoolean, IsIn, IsInt, IsObject, IsOptional, IsString, IsUrl, IsDateString, Matches, Max, MaxLength, Min, MinLength, ValidateNested, } from 'class-validator'; import { IsBoundedJsonObject } from './bounded-json-object.validator'; import { DRAINAGE_TARGET_ERROR, DRAINAGE_TARGET_PATTERN } from './drainage-target'; export class ClientCertificationSubmissionDto { @IsString() @MinLength(1) @MaxLength(200) companyName!: string; @IsOptional() @IsString() @MaxLength(100) licenseNo?: string; @IsOptional() @IsString() @MaxLength(100) contactName?: string; @IsOptional() @Matches(/^\+?[0-9-]{6,24}$/) contactPhone?: string; @IsOptional() @IsObject() @IsBoundedJsonObject({ maxKeys: 100, maxDepth: 4 }) materials?: Record; } export class ClientTaskBaseDto { @IsOptional() @IsString() @MaxLength(64) applicationId?: string; @IsOptional() @IsString() @MaxLength(64) templateId?: string; @IsString() @MinLength(1) @MaxLength(5000) content!: string; @IsOptional() @IsString() @MaxLength(64) category?: string; @IsOptional() @IsIn(['immediate', 'scheduled']) sendMode?: 'immediate' | 'scheduled'; @IsOptional() @IsDateString({ strict: true }) scheduledAt?: string; @IsOptional() @IsObject() @IsBoundedJsonObject({ maxKeys: 100, maxDepth: 4 }) variables?: Record; @IsOptional() @IsDateString({ strict: true }) requestedAt?: string; @IsOptional() @IsString() @MaxLength(128) clientMessageId?: string; } export class ClientBatchTaskDto extends ClientTaskBaseDto { @IsArray() @ArrayMaxSize(100000) @Matches(/^1\d{10}$/, { each: true }) phones!: string[]; } export class ClientImportPreviewDto { @IsOptional() @IsString() @MaxLength(64) applicationId?: string; @IsString() @MinLength(1) @MaxLength(5_000_000) content!: string; @IsOptional() @IsString() @MaxLength(255) fileName?: string; @IsOptional() @IsIn(['utf8', 'gbk']) encoding?: 'utf8' | 'gbk'; @IsOptional() @IsIn([',', '\t']) delimiter?: ',' | '\t'; @IsOptional() @IsArray() @ArrayMaxSize(100) @IsString({ each: true }) requiredVariables?: string[]; } export class ClientImportConfirmDto extends ClientTaskBaseDto { @IsString() @MinLength(1) @MaxLength(5_000_000) importContent!: string; @IsOptional() @IsArray() @ArrayMaxSize(100) @IsString({ each: true }) requiredVariables?: string[]; } export class ClientBillingEstimateDto { @IsOptional() @IsString() @MaxLength(64) applicationId?: string; @IsString() @MinLength(1) @MaxLength(5000) content!: string; @Type(() => Number) @IsInt() @Min(1) @Max(100000) phoneCount!: number; @IsOptional() @Type(() => Number) @Min(0) unitPrice?: number; @IsOptional() @IsString() @MaxLength(64) taskId?: string; } export class ClientSmsApplicationDto { @IsString() @MinLength(1) @MaxLength(100) name!: string; @IsOptional() @IsString() @MaxLength(500) scene?: string; @IsOptional() @IsUrl({ require_tld: false }) @MaxLength(2048) callbackUrl?: string; @IsOptional() @IsString() @MaxLength(64) cmppAccount?: string; @IsOptional() @IsString() @MaxLength(64) cmppEnterpriseCode?: string; @IsOptional() @IsString() @MaxLength(32) cmppApplicationExtension?: string; @IsOptional() @IsBoolean() cmppAccessNumberFillEnabled?: boolean; @IsOptional() @IsString() @MaxLength(32) cmppAccessNumberFillPrefix?: string; @IsOptional() @IsString() @MaxLength(4096) passwordCipher?: string; @IsOptional() @IsBoolean() interfaceEnabled?: boolean; @IsOptional() @IsString() @MaxLength(32) interfaceType?: string; @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(100) cmppMaxConnections?: number; @IsOptional() @Type(() => Number) @IsInt() @Min(1) @Max(1000) cmppWindowSize?: number; @IsOptional() @Type(() => Number) @IsInt() @Min(0) dailyLimit?: number; @IsOptional() @Type(() => Number) @Min(0) customerUnitPrice?: number; @IsOptional() @IsString() @MaxLength(32) queuePriority?: string; @IsOptional() @IsString() @MaxLength(32) templateMismatchMode?: string; @IsOptional() @IsBoolean() downstreamReceiptRetryEnabled?: boolean; @IsOptional() @IsBoolean() downstreamUplinkRetryEnabled?: boolean; @IsOptional() @IsArray() @ArrayMaxSize(100) @IsString({ each: true }) ipAllowlist?: string[]; } export class ClientSmsSignatureDto { @IsOptional() @IsString() @MaxLength(64) applicationId?: string; @IsString() @MinLength(1) @MaxLength(100) name!: string; @IsOptional() @IsString() @MaxLength(500) purpose?: string; @IsOptional() @IsObject() @IsBoundedJsonObject({ maxKeys: 100, maxDepth: 4 }) drainageInfo?: Record; } export class ClientSmsSignatureUpdateDto extends PartialType(ClientSmsSignatureDto) { @IsOptional() @IsString() @MaxLength(32) auditStatus?: string; } export class ClientDrainageInfoDto { @IsOptional() @IsString() @MaxLength(200) siteName?: string; @IsString() @MinLength(1) @MaxLength(2048) @Matches(DRAINAGE_TARGET_PATTERN, { message: DRAINAGE_TARGET_ERROR, }) url!: string; @IsOptional() @IsString() @MaxLength(1000) remark?: string; @IsOptional() @IsObject() @IsBoundedJsonObject({ maxKeys: 200, maxDepth: 4 }) reportValues?: Record; } export class ClientDrainageInfoUpdateDto extends PartialType(ClientDrainageInfoDto) {} export class ClientSignatureMaterialDto { @IsOptional() @IsString() @MaxLength(64) fileObjectId?: string; @IsString() @MinLength(1) @MaxLength(64) materialType!: string; @IsString() @MinLength(1) @MaxLength(200) title!: string; @IsOptional() @IsString() @MaxLength(2000) description?: string; } class TemplateVariableDto { @IsString() @MinLength(1) @MaxLength(64) name!: string; @IsOptional() @IsString() @MaxLength(500) example?: string; @IsOptional() @IsBoolean() required?: boolean; } export class ClientSmsTemplateDto { @IsString() @MaxLength(64) applicationId!: string; @IsOptional() @IsString() @MaxLength(64) signatureId?: string; @IsString() @MinLength(1) @MaxLength(200) name!: string; @IsString() @MinLength(1) @MaxLength(5000) content!: string; @IsOptional() @IsString() @MaxLength(64) category?: string; @IsOptional() @IsArray() @ArrayMaxSize(100) @ValidateNested({ each: true }) @Type(() => TemplateVariableDto) variables?: TemplateVariableDto[]; } export class ClientSmsTemplateUpdateDto extends PartialType(ClientSmsTemplateDto) { @IsOptional() @IsString() @MaxLength(32) auditStatus?: string; } export class ClientStatusChangeDto { @IsOptional() @IsString() @MaxLength(32) status?: string; @IsOptional() @IsString() @MaxLength(1000) reason?: string; @IsOptional() @IsBoolean() force?: boolean; @IsOptional() @IsString() @MaxLength(200) confirmName?: string; @IsOptional() @IsString() @MaxLength(200) confirmText?: string; @IsOptional() @IsString() @MaxLength(64) expectedUpdatedAt?: string; @IsOptional() @IsString() @MaxLength(128) idempotencyKey?: string; @IsOptional() @IsBoolean() deleteAssociatedTemplates?: boolean; @IsOptional() @IsBoolean() deleteAssociatedDrainage?: boolean; @IsOptional() @IsBoolean() abandonAssociatedReportTasks?: boolean; } export class ClientSecretResetDto { @IsOptional() @IsString() @MaxLength(1000) reason?: string; @IsOptional() @IsString() @MaxLength(64) expectedUpdatedAt?: string; @IsOptional() @IsString() @MaxLength(128) idempotencyKey?: string; } export class ClientApplicationStatusDto { @IsOptional() @IsIn(['active', 'disabled', 'disabling', 'deleted']) status?: string; @IsOptional() @IsString() @MaxLength(1000) reason?: string; @IsOptional() @IsBoolean() force?: boolean; @IsOptional() @IsString() @MaxLength(200) confirmName?: string; @IsOptional() @IsString() @MaxLength(200) confirmText?: string; @IsOptional() @IsString() @MaxLength(64) expectedUpdatedAt?: string; @IsOptional() @IsString() @MaxLength(128) idempotencyKey?: string; } export class ClientDeleteResourceDto { @IsIn(['deleted']) status!: 'deleted'; @IsOptional() @IsString() @MaxLength(1000) reason?: string; @IsOptional() @IsBoolean() force?: boolean; @IsOptional() @IsString() @MaxLength(200) confirmName?: string; @IsOptional() @IsString() @MaxLength(200) confirmText?: string; @IsOptional() @IsString() @MaxLength(64) expectedUpdatedAt?: string; @IsOptional() @IsString() @MaxLength(128) idempotencyKey?: string; @IsOptional() @IsBoolean() deleteAssociatedTemplates?: boolean; @IsOptional() @IsBoolean() deleteAssociatedDrainage?: boolean; @IsOptional() @IsBoolean() abandonAssociatedReportTasks?: boolean; }