add user module

This commit is contained in:
liuyi 2025-06-22 13:10:49 +08:00
parent 92cfd94093
commit 040b0b71d5
5 changed files with 220 additions and 1 deletions

View File

@ -21,7 +21,7 @@ export class MatchConstraint implements ValidatorConstraintInterface {
}
}
export function isMatch(
export function IsMatch(
relatedProperty: string,
reverse = false,
validationOptions?: ValidationOptions,

View File

@ -0,0 +1,40 @@
import { PickType } from '@nestjs/swagger';
import { Length } from 'class-validator';
import { IsPassword } from '@/modules/core/constraints/password.constraint';
import { DtoValidation } from '@/modules/core/decorator/dto.validation.decorator';
import { UserCommonDto } from '@/modules/user/dtos/user.common.dto';
/**
*
*/
@DtoValidation({ whitelist: false, groups: [UserValidateGroup.ACCOUNT_UPDATE] })
export class UpdateAccountDto extends PickType(UserCommonDto, ['username', 'nickname']) {
/**
* ID
*/
@IsUUID(undefined, { message: '用户ID格式不正确', groups: [UserValidateGroup.USER_UPDATE] })
@IsDefined({ groups: ['update'], message: '用户ID必须指定' })
id: string;
}
/**
*
*/
@DtoValidation({ groups: [UserValidateGroup.CHANGE_PASSWORD] })
export class UpdatePasswordDto extends PickType(UserCommonDto, ['password', 'plainPassword']) {
/**
* ID
*/
@IsUUID(undefined, { message: '用户ID格式不正确', groups: [UserValidateGroup.USER_UPDATE] })
@IsDefined({ groups: ['update'], message: '用户ID必须指定' })
id: string;
/**
* 旧密码:用户在更改密码时需要输入的原密码
*/
@IsPassword(5, { message: '密码必须由小写字母,大写字母,数字以及特殊字符组成', always: true })
@Length(8, 50, { message: '密码长度不得少于$constraint1', always: true })
oldPassword: string;
}

View File

@ -0,0 +1,21 @@
import { PickType } from '@nestjs/swagger';
import { DtoValidation } from '@/modules/core/decorator/dto.validation.decorator';
import { UserValidateGroup } from '@/modules/user/constants';
import { UserCommonDto } from '@/modules/user/dtos/user.common.dto';
/**
*
*/
export class CredentialDto extends PickType(UserCommonDto, ['credential', 'password']) {}
/**
*
*/
@DtoValidation({ groups: [UserValidateGroup.USER_REGISTER] })
export class RegisterDto extends PickType(UserCommonDto, [
'username',
'nickname',
'password',
'plainPassword',
] as const) {}

View File

@ -0,0 +1,114 @@
import { Injectable } from '@nestjs/common';
import { IsEmail, IsNotEmpty, IsOptional, Length } from 'class-validator';
import { IsMatch } from '@/modules/core/constraints/match.constraint';
import { IsPassword } from '@/modules/core/constraints/password.constraint';
import { IsMatchPhone } from '@/modules/core/constraints/phone.number.constraint';
import { IsUnique, IsUniqueExist } from '@/modules/database/constraints';
import { UserValidateGroup } from '@/modules/user/constants';
import { UserEntity } from '@/modules/user/entities/UserEntity';
/**
* DTO的通用基础字段
*/
@Injectable()
export class UserCommonDto {
/**
* 登录凭证:可以是用户名,,
*/
@Length(4, 30, { message: '登录凭证长度必须为$constraint1到$constraint2', always: true })
@IsNotEmpty({ message: '登录凭证不得为空', always: true })
credential: string;
/**
*
*/
@IsUnique(
{ entity: UserEntity },
{
groups: [UserValidateGroup.USER_CREATE, UserValidateGroup.USER_REGISTER],
message: '该用户名已被注册',
},
)
@IsUniqueExist(
{ entity: UserEntity, ignore: 'id' },
{ groups: [UserValidateGroup.USER_UPDATE], message: '该用户名已被注册' },
)
@IsUniqueExist(
{ entity: UserEntity, ignore: 'id', ignoreKey: 'userId' },
{ groups: [UserValidateGroup.ACCOUNT_UPDATE], message: '该用户名已被注册' },
)
@Length(4, 50, { always: true, message: '用户名长度必须为$constraint1到$constraint2' })
@IsOptional({ groups: [UserValidateGroup.USER_UPDATE, UserValidateGroup.ACCOUNT_UPDATE] })
username: string;
/**
* 昵称:不设置则为用户名
*/
@Length(3, 20, { message: '昵称必须为$constraint1到$constraint2', always: true })
@IsOptional({ always: true })
nickname: string;
/**
* 手机号:必须是区域开头的,+86.15005255555
*/
@IsUnique(
{ entity: UserEntity },
{
message: '手机号已被注册',
groups: [UserValidateGroup.USER_CREATE, UserValidateGroup.USER_REGISTER],
},
)
@IsMatchPhone(
undefined,
{ strictMode: trus },
{ message: '手机格式错误,示例: +86.15005255555', always: true },
)
@IsOptional({
groups: [
UserValidateGroup.USER_UPDATE,
UserValidateGroup.USER_CREATE,
UserValidateGroup.USER_REGISTER,
],
})
phone: string;
/**
* 邮箱地址:必须符合邮箱地址规则
*/
@IsUnique(
{ entity: UserEntity },
{
message: '邮箱已被注册',
groups: [UserValidateGroup.USER_CREATE, UserValidateGroup.USER_REGISTER],
},
)
@IsEmail(undefined, { message: '邮箱地址格式错误', always: true })
@IsOptional({
groups: [
UserValidateGroup.USER_UPDATE,
UserValidateGroup.USER_CREATE,
UserValidateGroup.USER_REGISTER,
],
})
email: string;
/**
* 用户密码:密码必须由小写字母,,
*/
@IsPassword(5, { message: '密码必须由小写字母,大写字母,数字以及特殊字符组成', always: true })
@Length(8, 50, { message: '密码长度不得少于$constraint1', always: true })
@IsMatch('oldPassword', true, {
message: '新密码与旧密码不得相同',
groups: [UserValidateGroup.CHANGE_PASSWORD],
})
@IsOptional({ groups: [UserValidateGroup.USER_UPDATE] })
password: string;
/**
* 确认密码:必须与用户密码输入相同的字符串
*/
@IsMatch('password', false, { message: '两次输入密码不同', always: true })
@IsNotEmpty({ message: '请再次输入密码以确认', always: true })
plainPassword: string;
}

View File

@ -0,0 +1,44 @@
import { PartialType, PickType } from '@nestjs/swagger';
import { IsDefined, IsEnum, IsUUID } from 'class-validator';
import { DtoValidation } from '@/modules/core/decorator/dto.validation.decorator';
import { PaginateWithTrashedDto } from '@/modules/restful/dtos/paginate-width-trashed.dto';
import { UserOrderType } from '@/modules/user/constants';
import { UserCommonDto } from '@/modules/user/dtos/user.common.dto';
/**
*
*/
@DtoValidation({ groups: [UserValidateGroup.USER_CREATE] })
export class CreateUserDto extends PickType(UserCommonDto, [
'username',
'nickname',
'email',
'password',
'phone',
]) {}
/**
*
*/
@DtoValidation({ groups: [UserValidateGroup.USER_UPDATE] })
export class UpdateUserDto extends PartialType(CreateUserDto) {
/**
* ID
*/
@IsUUID(undefined, { message: '用户ID格式不正确', groups: [UserValidateGroup.USER_UPDATE] })
@IsDefined({ groups: ['update'], message: '用户ID必须指定' })
id: string;
}
/**
* Query数据验证
*/
export class QueryUserDto extends PaginateWithTrashedDto {
/**
* 排序规则:可指定用户列表的排序规则,
*/
@IsEnum(UserOrderType)
orderBy?: UserOrderType;
}